mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 11:39:42 +01:00
Remove EntryMenuController and OperationMenuController
The "operation view" at the bottom is replaced by snackbars. I have removed the join via public link feature for now. This was buggy, complex and incomplete. This feature must be reimplemented in a more useful place (login screen, so you can use it as a guest without using an existing instance). Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
parent
da541d3fc3
commit
32dbe70399
@ -41,6 +41,7 @@ import androidx.core.content.res.ResourcesCompat
|
|||||||
import androidx.core.view.MenuItemCompat
|
import androidx.core.view.MenuItemCompat
|
||||||
import androidx.work.Data
|
import androidx.work.Data
|
||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import com.bluelinelabs.logansquare.LoganSquare
|
import com.bluelinelabs.logansquare.LoganSquare
|
||||||
@ -51,9 +52,10 @@ import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
|
|||||||
import com.nextcloud.talk.api.NcApi
|
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.chat.ChatActivity
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum
|
import com.nextcloud.talk.conversation.CreateConversationDialogFragment
|
||||||
import com.nextcloud.talk.data.user.model.User
|
import com.nextcloud.talk.data.user.model.User
|
||||||
import com.nextcloud.talk.databinding.ActivityContactsBinding
|
import com.nextcloud.talk.databinding.ActivityContactsBinding
|
||||||
|
import com.nextcloud.talk.events.EventStatus
|
||||||
import com.nextcloud.talk.events.OpenConversationEvent
|
import com.nextcloud.talk.events.OpenConversationEvent
|
||||||
import com.nextcloud.talk.jobs.AddParticipantsToConversation
|
import com.nextcloud.talk.jobs.AddParticipantsToConversation
|
||||||
import com.nextcloud.talk.models.RetrofitBucket
|
import com.nextcloud.talk.models.RetrofitBucket
|
||||||
@ -64,9 +66,9 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall
|
|||||||
import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
|
import com.nextcloud.talk.models.json.converters.EnumActorTypeConverter
|
||||||
import com.nextcloud.talk.models.json.participants.Participant
|
import com.nextcloud.talk.models.json.participants.Participant
|
||||||
import com.nextcloud.talk.openconversations.ListOpenConversationsActivity
|
import com.nextcloud.talk.openconversations.ListOpenConversationsActivity
|
||||||
import com.nextcloud.talk.ui.dialog.ContactsBottomDialog
|
|
||||||
import com.nextcloud.talk.users.UserManager
|
import com.nextcloud.talk.users.UserManager
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
|
import com.nextcloud.talk.utils.UserIdUtils.getIdForUser
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||||
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
|
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
@ -82,7 +84,6 @@ import org.greenrobot.eventbus.Subscribe
|
|||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
import org.parceler.Parcels
|
import org.parceler.Parcels
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Collections
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -120,7 +121,6 @@ class ContactsActivity :
|
|||||||
private var existingParticipants: List<String>? = null
|
private var existingParticipants: List<String>? = null
|
||||||
private var isAddingParticipantsView = false
|
private var isAddingParticipantsView = false
|
||||||
private var conversationToken: String? = null
|
private var conversationToken: String? = null
|
||||||
private var contactsBottomDialog: ContactsBottomDialog? = null
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -160,12 +160,8 @@ class ContactsActivity :
|
|||||||
toggleConversationPrivacyLayout(!isPublicCall)
|
toggleConversationPrivacyLayout(!isPublicCall)
|
||||||
}
|
}
|
||||||
if (isAddingParticipantsView) {
|
if (isAddingParticipantsView) {
|
||||||
binding.joinConversationViaLink.visibility = View.GONE
|
|
||||||
binding.callHeaderLayout.visibility = View.GONE
|
binding.callHeaderLayout.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
binding.joinConversationViaLink.setOnClickListener {
|
|
||||||
joinConversationViaLink()
|
|
||||||
}
|
|
||||||
binding.listOpenConversations.setOnClickListener {
|
binding.listOpenConversations.setOnClickListener {
|
||||||
listOpenConversations()
|
listOpenConversations()
|
||||||
}
|
}
|
||||||
@ -228,7 +224,7 @@ class ContactsActivity :
|
|||||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||||
super.onPrepareOptionsMenu(menu)
|
super.onPrepareOptionsMenu(menu)
|
||||||
if (searchItem != null) {
|
if (searchItem != null) {
|
||||||
binding?.titleTextView?.let {
|
binding.titleTextView.let {
|
||||||
viewThemeUtils.platform.colorToolbarMenuIcon(
|
viewThemeUtils.platform.colorToolbarMenuIcon(
|
||||||
it.context,
|
it.context,
|
||||||
searchItem!!
|
searchItem!!
|
||||||
@ -270,7 +266,10 @@ class ContactsActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun selectionDone() {
|
private fun selectionDone() {
|
||||||
if (!isAddingParticipantsView) {
|
if (isAddingParticipantsView) {
|
||||||
|
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) {
|
if (!isPublicCall && selectedCircleIds.size + selectedGroupIds.size + selectedUserIds.size == 1) {
|
||||||
val userId: String
|
val userId: String
|
||||||
var sourceType: String? = null
|
var sourceType: String? = null
|
||||||
@ -290,8 +289,9 @@ class ContactsActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
createRoom(roomType, sourceType, userId)
|
createRoom(roomType, sourceType, userId)
|
||||||
|
|
||||||
|
// if there are more participants to add, ask for roomName and add them one after another
|
||||||
} else {
|
} else {
|
||||||
val bundle = Bundle()
|
|
||||||
val roomType: Conversation.ConversationType = if (isPublicCall) {
|
val roomType: Conversation.ConversationType = if (isPublicCall) {
|
||||||
Conversation.ConversationType.ROOM_PUBLIC_CALL
|
Conversation.ConversationType.ROOM_PUBLIC_CALL
|
||||||
} else {
|
} else {
|
||||||
@ -301,16 +301,19 @@ class ContactsActivity :
|
|||||||
val groupIdsArray = ArrayList(selectedGroupIds)
|
val groupIdsArray = ArrayList(selectedGroupIds)
|
||||||
val emailsArray = ArrayList(selectedEmails)
|
val emailsArray = ArrayList(selectedEmails)
|
||||||
val circleIdsArray = ArrayList(selectedCircleIds)
|
val circleIdsArray = ArrayList(selectedCircleIds)
|
||||||
bundle.putParcelable(BundleKeys.KEY_CONVERSATION_TYPE, Parcels.wrap(roomType))
|
|
||||||
bundle.putStringArrayList(BundleKeys.KEY_INVITED_PARTICIPANTS, userIdsArray)
|
val createConversationDialog = CreateConversationDialogFragment.newInstance(
|
||||||
bundle.putStringArrayList(BundleKeys.KEY_INVITED_GROUP, groupIdsArray)
|
userIdsArray,
|
||||||
bundle.putStringArrayList(BundleKeys.KEY_INVITED_EMAIL, emailsArray)
|
groupIdsArray,
|
||||||
bundle.putStringArrayList(BundleKeys.KEY_INVITED_CIRCLE, circleIdsArray)
|
emailsArray,
|
||||||
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, ConversationOperationEnum.OPS_CODE_INVITE_USERS)
|
circleIdsArray,
|
||||||
prepareAndShowBottomSheetWithBundle(bundle)
|
Parcels.wrap(roomType)
|
||||||
|
)
|
||||||
|
createConversationDialog.show(
|
||||||
|
supportFragmentManager,
|
||||||
|
TAG
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
addParticipantsToConversation()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,7 +376,38 @@ class ContactsActivity :
|
|||||||
AddParticipantsToConversation::class.java
|
AddParticipantsToConversation::class.java
|
||||||
).setInputData(data.build()).build()
|
).setInputData(data.build()).build()
|
||||||
WorkManager.getInstance().enqueue(addParticipantsToConversationWorker)
|
WorkManager.getInstance().enqueue(addParticipantsToConversationWorker)
|
||||||
finish()
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkInfo.State.FAILED -> {
|
||||||
|
Log.d(TAG, "failed AddParticipantsToConversation")
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSearchView() {
|
private fun initSearchView() {
|
||||||
@ -401,14 +435,14 @@ class ContactsActivity :
|
|||||||
private fun fetchData() {
|
private fun fetchData() {
|
||||||
dispose(null)
|
dispose(null)
|
||||||
alreadyFetching = true
|
alreadyFetching = true
|
||||||
userHeaderItems = HashMap<String, GenericTextHeaderItem>()
|
userHeaderItems = HashMap()
|
||||||
val query = adapter!!.getFilter(String::class.java) as String?
|
val query = adapter!!.getFilter(String::class.java)
|
||||||
val retrofitBucket: RetrofitBucket =
|
val retrofitBucket: RetrofitBucket =
|
||||||
ApiUtils.getRetrofitBucketForContactsSearchFor14(currentUser!!.baseUrl, query)
|
ApiUtils.getRetrofitBucketForContactsSearchFor14(currentUser!!.baseUrl, query)
|
||||||
val modifiedQueryMap: HashMap<String, Any?> = HashMap<String, Any?>(retrofitBucket.queryMap)
|
val modifiedQueryMap: HashMap<String, Any?> = HashMap(retrofitBucket.queryMap)
|
||||||
modifiedQueryMap.put("limit", CONTACTS_BATCH_SIZE)
|
modifiedQueryMap["limit"] = CONTACTS_BATCH_SIZE
|
||||||
if (isAddingParticipantsView) {
|
if (isAddingParticipantsView) {
|
||||||
modifiedQueryMap.put("itemId", conversationToken)
|
modifiedQueryMap["itemId"] = conversationToken
|
||||||
}
|
}
|
||||||
val shareTypesList: ArrayList<String> = ArrayList()
|
val shareTypesList: ArrayList<String> = ArrayList()
|
||||||
// users
|
// users
|
||||||
@ -426,7 +460,7 @@ class ContactsActivity :
|
|||||||
// circles
|
// circles
|
||||||
shareTypesList.add("7")
|
shareTypesList.add("7")
|
||||||
}
|
}
|
||||||
modifiedQueryMap.put("shareTypes[]", shareTypesList)
|
modifiedQueryMap["shareTypes[]"] = shareTypesList
|
||||||
ncApi.getContactsWithSearchParam(
|
ncApi.getContactsWithSearchParam(
|
||||||
credentials,
|
credentials,
|
||||||
retrofitBucket.url,
|
retrofitBucket.url,
|
||||||
@ -444,7 +478,7 @@ class ContactsActivity :
|
|||||||
override fun onNext(responseBody: ResponseBody) {
|
override fun onNext(responseBody: ResponseBody) {
|
||||||
val newUserItemList = processAutocompleteUserList(responseBody)
|
val newUserItemList = processAutocompleteUserList(responseBody)
|
||||||
|
|
||||||
userHeaderItems = HashMap<String, GenericTextHeaderItem>()
|
userHeaderItems = HashMap()
|
||||||
contactItems!!.addAll(newUserItemList)
|
contactItems!!.addAll(newUserItemList)
|
||||||
|
|
||||||
sortUserItems(newUserItemList)
|
sortUserItems(newUserItemList)
|
||||||
@ -455,16 +489,16 @@ class ContactsActivity :
|
|||||||
adapter?.filterItems()
|
adapter?.filterItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding?.controllerGenericRv?.swipeRefreshLayout?.isRefreshing = false
|
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
override fun onError(e: Throwable) {
|
||||||
binding?.controllerGenericRv?.swipeRefreshLayout?.isRefreshing = false
|
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
|
||||||
dispose(contactsQueryDisposable)
|
dispose(contactsQueryDisposable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onComplete() {
|
override fun onComplete() {
|
||||||
binding?.controllerGenericRv?.swipeRefreshLayout?.isRefreshing = false
|
binding.controllerGenericRv.swipeRefreshLayout.isRefreshing = false
|
||||||
dispose(contactsQueryDisposable)
|
dispose(contactsQueryDisposable)
|
||||||
alreadyFetching = false
|
alreadyFetching = false
|
||||||
disengageProgressBar()
|
disengageProgressBar()
|
||||||
@ -474,18 +508,18 @@ class ContactsActivity :
|
|||||||
|
|
||||||
private fun processAutocompleteUserList(responseBody: ResponseBody): MutableList<AbstractFlexibleItem<*>> {
|
private fun processAutocompleteUserList(responseBody: ResponseBody): MutableList<AbstractFlexibleItem<*>> {
|
||||||
try {
|
try {
|
||||||
val autocompleteOverall: AutocompleteOverall = LoganSquare.parse<AutocompleteOverall>(
|
val autocompleteOverall: AutocompleteOverall = LoganSquare.parse(
|
||||||
responseBody.string(),
|
responseBody.string(),
|
||||||
AutocompleteOverall::class.java
|
AutocompleteOverall::class.java
|
||||||
)
|
)
|
||||||
val autocompleteUsersList: ArrayList<AutocompleteUser> = ArrayList<AutocompleteUser>()
|
val autocompleteUsersList: ArrayList<AutocompleteUser> = ArrayList()
|
||||||
autocompleteUsersList.addAll(autocompleteOverall.ocs!!.data!!)
|
autocompleteUsersList.addAll(autocompleteOverall.ocs!!.data!!)
|
||||||
return processAutocompleteUserList(autocompleteUsersList)
|
return processAutocompleteUserList(autocompleteUsersList)
|
||||||
} catch (ioe: IOException) {
|
} catch (ioe: IOException) {
|
||||||
Log.e(TAG, "Parsing response body failed while getting contacts", ioe)
|
Log.e(TAG, "Parsing response body failed while getting contacts", ioe)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ArrayList<AbstractFlexibleItem<*>>()
|
return ArrayList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processAutocompleteUserList(
|
private fun processAutocompleteUserList(
|
||||||
@ -493,7 +527,7 @@ class ContactsActivity :
|
|||||||
): MutableList<AbstractFlexibleItem<*>> {
|
): MutableList<AbstractFlexibleItem<*>> {
|
||||||
var participant: Participant
|
var participant: Participant
|
||||||
val actorTypeConverter = EnumActorTypeConverter()
|
val actorTypeConverter = EnumActorTypeConverter()
|
||||||
val newUserItemList: MutableList<AbstractFlexibleItem<*>> = ArrayList<AbstractFlexibleItem<*>>()
|
val newUserItemList: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
||||||
for (autocompleteUser in autocompleteUsersList) {
|
for (autocompleteUser in autocompleteUsersList) {
|
||||||
if (autocompleteUser.id != null &&
|
if (autocompleteUser.id != null &&
|
||||||
autocompleteUser.id != currentUser!!.userId &&
|
autocompleteUser.id != currentUser!!.userId &&
|
||||||
@ -529,7 +563,7 @@ class ContactsActivity :
|
|||||||
resources!!.getString(R.string.nc_circles)
|
resources!!.getString(R.string.nc_circles)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
participant.displayName!!.substring(0, 1).toUpperCase(Locale.getDefault())
|
participant.displayName!!.substring(0, 1).uppercase(Locale.getDefault())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -547,76 +581,72 @@ class ContactsActivity :
|
|||||||
return participant
|
return participant
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongMethod")
|
||||||
private fun sortUserItems(newUserItemList: MutableList<AbstractFlexibleItem<*>>) {
|
private fun sortUserItems(newUserItemList: MutableList<AbstractFlexibleItem<*>>) {
|
||||||
Collections.sort(
|
newUserItemList.sortWith sort@{ o1: AbstractFlexibleItem<*>, o2: AbstractFlexibleItem<*> ->
|
||||||
newUserItemList,
|
|
||||||
{ o1: AbstractFlexibleItem<*>, o2: AbstractFlexibleItem<*> ->
|
|
||||||
val firstName: String = if (o1 is ContactItem) {
|
|
||||||
(o1 as ContactItem).model.displayName!!
|
|
||||||
} else {
|
|
||||||
(o1 as GenericTextHeaderItem).model
|
|
||||||
}
|
|
||||||
val secondName: String = if (o2 is ContactItem) {
|
|
||||||
(o2 as ContactItem).model.displayName!!
|
|
||||||
} else {
|
|
||||||
(o2 as GenericTextHeaderItem).model
|
|
||||||
}
|
|
||||||
if (o1 is ContactItem && o2 is ContactItem) {
|
|
||||||
val firstSource: String = (o1 as ContactItem).model.source!!
|
|
||||||
val secondSource: String = (o2 as ContactItem).model.source!!
|
|
||||||
if (firstSource == secondSource) {
|
|
||||||
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// First users
|
|
||||||
if ("users" == firstSource) {
|
|
||||||
return@sort -1
|
|
||||||
} else if ("users" == secondSource) {
|
|
||||||
return@sort 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then groups
|
|
||||||
if ("groups" == firstSource) {
|
|
||||||
return@sort -1
|
|
||||||
} else if ("groups" == secondSource) {
|
|
||||||
return@sort 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then circles
|
|
||||||
if ("circles" == firstSource) {
|
|
||||||
return@sort -1
|
|
||||||
} else if ("circles" == secondSource) {
|
|
||||||
return@sort 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise fall back to name sorting
|
|
||||||
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
}
|
|
||||||
firstName.compareTo(secondName, ignoreCase = true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Collections.sort(
|
|
||||||
contactItems
|
|
||||||
) { o1: AbstractFlexibleItem<*>, o2: AbstractFlexibleItem<*> ->
|
|
||||||
val firstName: String = if (o1 is ContactItem) {
|
val firstName: String = if (o1 is ContactItem) {
|
||||||
(o1 as ContactItem).model.displayName!!
|
o1.model.displayName!!
|
||||||
} else {
|
} else {
|
||||||
(o1 as GenericTextHeaderItem).model
|
(o1 as GenericTextHeaderItem).model
|
||||||
}
|
}
|
||||||
val secondName: String = if (o2 is ContactItem) {
|
val secondName: String = if (o2 is ContactItem) {
|
||||||
(o2 as ContactItem).model.displayName!!
|
o2.model.displayName!!
|
||||||
} else {
|
} else {
|
||||||
(o2 as GenericTextHeaderItem).model
|
(o2 as GenericTextHeaderItem).model
|
||||||
}
|
}
|
||||||
if (o1 is ContactItem && o2 is ContactItem) {
|
if (o1 is ContactItem && o2 is ContactItem) {
|
||||||
if ("groups" == (o1 as ContactItem).model.source &&
|
val firstSource: String = o1.model.source!!
|
||||||
"groups" == (o2 as ContactItem).model.source
|
val secondSource: String = o2.model.source!!
|
||||||
|
if (firstSource == secondSource) {
|
||||||
|
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First users
|
||||||
|
if ("users" == firstSource) {
|
||||||
|
return@sort -1
|
||||||
|
} else if ("users" == secondSource) {
|
||||||
|
return@sort 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then groups
|
||||||
|
if ("groups" == firstSource) {
|
||||||
|
return@sort -1
|
||||||
|
} else if ("groups" == secondSource) {
|
||||||
|
return@sort 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then circles
|
||||||
|
if ("circles" == firstSource) {
|
||||||
|
return@sort -1
|
||||||
|
} else if ("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 ("groups" == o1.model.source &&
|
||||||
|
"groups" == o2.model.source
|
||||||
) {
|
) {
|
||||||
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
return@sort firstName.compareTo(secondName, ignoreCase = true)
|
||||||
} else if ("groups" == (o1 as ContactItem).model.source) {
|
} else if ("groups" == o1.model.source) {
|
||||||
return@sort -1
|
return@sort -1
|
||||||
} else if ("groups" == (o2 as ContactItem).model.source) {
|
} else if ("groups" == o2.model.source) {
|
||||||
return@sort 1
|
return@sort 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,24 +656,19 @@ class ContactsActivity :
|
|||||||
|
|
||||||
private fun prepareViews() {
|
private fun prepareViews() {
|
||||||
layoutManager = SmoothScrollLinearLayoutManager(this)
|
layoutManager = SmoothScrollLinearLayoutManager(this)
|
||||||
binding?.controllerGenericRv?.recyclerView?.layoutManager = layoutManager
|
binding.controllerGenericRv.recyclerView.layoutManager = layoutManager
|
||||||
binding?.controllerGenericRv?.recyclerView?.setHasFixedSize(true)
|
binding.controllerGenericRv.recyclerView.setHasFixedSize(true)
|
||||||
binding?.controllerGenericRv?.recyclerView?.adapter = adapter
|
binding.controllerGenericRv.recyclerView.adapter = adapter
|
||||||
binding?.controllerGenericRv?.swipeRefreshLayout?.setOnRefreshListener { fetchData() }
|
binding.controllerGenericRv.swipeRefreshLayout.setOnRefreshListener { fetchData() }
|
||||||
|
|
||||||
binding?.controllerGenericRv?.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it.swipeRefreshLayout) }
|
binding.controllerGenericRv.let { viewThemeUtils.androidx.themeSwipeRefreshLayout(it.swipeRefreshLayout) }
|
||||||
|
|
||||||
binding.listOpenConversationsImage.background?.setColorFilter(
|
binding.listOpenConversationsImage.background?.setColorFilter(
|
||||||
ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
|
ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
|
||||||
PorterDuff.Mode.SRC_IN
|
PorterDuff.Mode.SRC_IN
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.joinConversationViaLinkImage.background?.setColorFilter(
|
binding.let {
|
||||||
ResourcesCompat.getColor(resources!!, R.color.colorBackgroundDarker, null),
|
|
||||||
PorterDuff.Mode.SRC_IN
|
|
||||||
)
|
|
||||||
|
|
||||||
binding?.let {
|
|
||||||
viewThemeUtils.platform.colorImageViewBackgroundAndIcon(it.publicCallLink)
|
viewThemeUtils.platform.colorImageViewBackgroundAndIcon(it.publicCallLink)
|
||||||
}
|
}
|
||||||
disengageProgressBar()
|
disengageProgressBar()
|
||||||
@ -655,7 +680,6 @@ class ContactsActivity :
|
|||||||
binding.controllerGenericRv.root.visibility = View.VISIBLE
|
binding.controllerGenericRv.root.visibility = View.VISIBLE
|
||||||
if (isNewConversationView) {
|
if (isNewConversationView) {
|
||||||
binding.callHeaderLayout.visibility = View.VISIBLE
|
binding.callHeaderLayout.visibility = View.VISIBLE
|
||||||
binding.joinConversationViaLink.visibility = View.VISIBLE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -708,21 +732,12 @@ class ContactsActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareAndShowBottomSheetWithBundle(bundle: Bundle) {
|
|
||||||
// 11: create conversation-enter name for new conversation
|
|
||||||
// 10: get&join room when enter link
|
|
||||||
contactsBottomDialog = ContactsBottomDialog(this, bundle)
|
|
||||||
contactsBottomDialog?.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onMessageEvent(openConversationEvent: OpenConversationEvent) {
|
fun onMessageEvent(openConversationEvent: OpenConversationEvent) {
|
||||||
val chatIntent = Intent(context, ChatActivity::class.java)
|
val chatIntent = Intent(context, ChatActivity::class.java)
|
||||||
chatIntent.putExtras(openConversationEvent.bundle!!)
|
chatIntent.putExtras(openConversationEvent.bundle!!)
|
||||||
chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
startActivity(chatIntent)
|
startActivity(chatIntent)
|
||||||
|
|
||||||
contactsBottomDialog?.dismiss()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClick(view: View, position: Int): Boolean {
|
override fun onItemClick(view: View, position: Int): Boolean {
|
||||||
@ -730,7 +745,6 @@ class ContactsActivity :
|
|||||||
if (!isNewConversationView && !isAddingParticipantsView) {
|
if (!isNewConversationView && !isAddingParticipantsView) {
|
||||||
createRoom(adapter?.getItem(position) as ContactItem)
|
createRoom(adapter?.getItem(position) as ContactItem)
|
||||||
} else {
|
} else {
|
||||||
val participant: Participant = (adapter?.getItem(position) as ContactItem).model
|
|
||||||
updateSelection((adapter?.getItem(position) as ContactItem))
|
updateSelection((adapter?.getItem(position) as ContactItem))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -840,12 +854,6 @@ class ContactsActivity :
|
|||||||
return "groups" == contactItem.model.source && participant.selected && adapter?.selectedItemCount!! > 1
|
return "groups" == contactItem.model.source && participant.selected && adapter?.selectedItemCount!! > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun joinConversationViaLink() {
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM)
|
|
||||||
prepareAndShowBottomSheetWithBundle(bundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun listOpenConversations() {
|
private fun listOpenConversations() {
|
||||||
val intent = Intent(this, ListOpenConversationsActivity::class.java)
|
val intent = Intent(this, ListOpenConversationsActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
@ -854,30 +862,11 @@ class ContactsActivity :
|
|||||||
private fun toggleCallHeader() {
|
private fun toggleCallHeader() {
|
||||||
toggleConversationPrivacyLayout(isPublicCall)
|
toggleConversationPrivacyLayout(isPublicCall)
|
||||||
isPublicCall = !isPublicCall
|
isPublicCall = !isPublicCall
|
||||||
toggleConversationViaLinkVisibility(isPublicCall)
|
|
||||||
|
|
||||||
enableContactForNonPublicCall()
|
enableContactForNonPublicCall()
|
||||||
checkAndHandleDoneMenuItem()
|
checkAndHandleDoneMenuItem()
|
||||||
adapter?.notifyDataSetChanged()
|
adapter?.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateGroupParticipantSelection() {
|
|
||||||
val currentItems: List<AbstractFlexibleItem<*>> = adapter?.currentItems as
|
|
||||||
List<AbstractFlexibleItem<*>>
|
|
||||||
var internalParticipant: Participant
|
|
||||||
for (i in currentItems.indices) {
|
|
||||||
if (currentItems[i] is ContactItem) {
|
|
||||||
internalParticipant = (currentItems[i] as ContactItem).model
|
|
||||||
if (internalParticipant.calculatedActorType == Participant.ActorType.GROUPS &&
|
|
||||||
internalParticipant.selected
|
|
||||||
) {
|
|
||||||
internalParticipant.selected = false
|
|
||||||
selectedGroupIds.remove(internalParticipant.calculatedActorId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun enableContactForNonPublicCall() {
|
private fun enableContactForNonPublicCall() {
|
||||||
for (i in 0 until adapter!!.itemCount) {
|
for (i in 0 until adapter!!.itemCount) {
|
||||||
if (adapter?.getItem(i) is ContactItem) {
|
if (adapter?.getItem(i) is ContactItem) {
|
||||||
@ -891,20 +880,12 @@ class ContactsActivity :
|
|||||||
|
|
||||||
private fun toggleConversationPrivacyLayout(showInitialLayout: Boolean) {
|
private fun toggleConversationPrivacyLayout(showInitialLayout: Boolean) {
|
||||||
if (showInitialLayout) {
|
if (showInitialLayout) {
|
||||||
binding.initialRelativeLayout.visibility = View.VISIBLE
|
binding.publicConversationCreate.visibility = View.VISIBLE
|
||||||
binding.secondaryRelativeLayout.visibility = View.GONE
|
binding.publicConversationInfo.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
binding.initialRelativeLayout.visibility = View.GONE
|
binding.publicConversationCreate.visibility = View.GONE
|
||||||
binding.secondaryRelativeLayout.visibility = View.VISIBLE
|
binding.publicConversationInfo.visibility = View.VISIBLE
|
||||||
}
|
binding.listOpenConversations.visibility = View.GONE
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleConversationViaLinkVisibility(isPublicCall: Boolean) {
|
|
||||||
if (isPublicCall) {
|
|
||||||
binding.joinConversationViaLink.visibility = View.GONE
|
|
||||||
updateGroupParticipantSelection()
|
|
||||||
} else {
|
|
||||||
binding.joinConversationViaLink.visibility = View.VISIBLE
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Marcel Hibbe
|
|
||||||
* Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nextcloud.talk.controllers.bottomsheet
|
|
||||||
|
|
||||||
enum class ConversationOperationEnum {
|
|
||||||
OPS_CODE_RENAME_ROOM,
|
|
||||||
OPS_CODE_GET_AND_JOIN_ROOM,
|
|
||||||
OPS_CODE_INVITE_USERS,
|
|
||||||
OPS_CODE_MARK_AS_READ,
|
|
||||||
OPS_CODE_MARK_AS_UNREAD,
|
|
||||||
OPS_CODE_REMOVE_FAVORITE,
|
|
||||||
OPS_CODE_ADD_FAVORITE,
|
|
||||||
OPS_CODE_JOIN_ROOM
|
|
||||||
}
|
|
@ -1,377 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Mario Danic
|
|
||||||
* @author Marcel Hibbe
|
|
||||||
* @author Andy Scherzinger
|
|
||||||
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
|
||||||
* Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
|
||||||
* Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.nextcloud.talk.controllers.bottomsheet
|
|
||||||
|
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.Editable
|
|
||||||
import android.text.InputType
|
|
||||||
import android.text.TextUtils
|
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import android.view.inputmethod.EditorInfo
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import autodagger.AutoInjector
|
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
|
||||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
|
||||||
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
|
||||||
import com.nextcloud.talk.R
|
|
||||||
import com.nextcloud.talk.api.NcApi
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
|
||||||
import com.nextcloud.talk.controllers.base.BaseController
|
|
||||||
import com.nextcloud.talk.controllers.util.viewBinding
|
|
||||||
import com.nextcloud.talk.data.user.model.User
|
|
||||||
import com.nextcloud.talk.databinding.ControllerEntryMenuBinding
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
|
||||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
|
||||||
import com.nextcloud.talk.users.UserManager
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
|
||||||
import com.nextcloud.talk.utils.UriUtils
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
|
||||||
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
|
|
||||||
import com.vanniktech.emoji.EmojiPopup
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.disposables.Disposable
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
|
||||||
import okhttp3.internal.immutableListOf
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
|
||||||
class EntryMenuController(args: Bundle) :
|
|
||||||
BaseController(
|
|
||||||
R.layout.controller_entry_menu,
|
|
||||||
args
|
|
||||||
) {
|
|
||||||
private val binding: ControllerEntryMenuBinding? by viewBinding(ControllerEntryMenuBinding::bind)
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var ncApi: NcApi
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var eventBus: EventBus
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var userManager: UserManager
|
|
||||||
|
|
||||||
private val operation: ConversationOperationEnum
|
|
||||||
private var conversation: Conversation? = null
|
|
||||||
private val packageName: String
|
|
||||||
private val name: String
|
|
||||||
|
|
||||||
private var emojiPopup: EmojiPopup? = null
|
|
||||||
private val originalBundle: Bundle
|
|
||||||
private var currentUser: User? = null
|
|
||||||
private val roomToken: String
|
|
||||||
|
|
||||||
override val appBarLayoutType: AppBarLayoutType
|
|
||||||
get() = AppBarLayoutType.SEARCH_BAR
|
|
||||||
|
|
||||||
override fun onAttach(view: View) {
|
|
||||||
super.onAttach(view)
|
|
||||||
if (ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG ==
|
|
||||||
ApplicationWideMessageHolder.getInstance().messageType
|
|
||||||
) {
|
|
||||||
binding?.textInputLayout?.error = resources?.getString(R.string.nc_wrong_password)
|
|
||||||
ApplicationWideMessageHolder.getInstance().messageType = null
|
|
||||||
if (binding?.okButton?.isEnabled == true) {
|
|
||||||
binding?.okButton?.isEnabled = false
|
|
||||||
binding?.okButton?.alpha = OPACITY_BUTTON_DISABLED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emojiPopup = binding?.let {
|
|
||||||
EmojiPopup(
|
|
||||||
rootView = view,
|
|
||||||
editText = it.textEdit,
|
|
||||||
onEmojiPopupShownListener = {
|
|
||||||
viewThemeUtils.platform.colorImageView(it.smileyButton, ColorRole.PRIMARY)
|
|
||||||
},
|
|
||||||
onEmojiPopupDismissListener = {
|
|
||||||
it.smileyButton.imageTintList = ColorStateList.valueOf(
|
|
||||||
ResourcesCompat.getColor(
|
|
||||||
resources!!,
|
|
||||||
R.color.medium_emphasis_text,
|
|
||||||
context.theme
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onEmojiClickListener = {
|
|
||||||
binding?.textEdit?.editableText?.append(" ")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewBound(view: View) {
|
|
||||||
super.onViewBound(view)
|
|
||||||
|
|
||||||
currentUser = userManager.currentUser.blockingGet()
|
|
||||||
|
|
||||||
if (operation == ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM) {
|
|
||||||
binding?.textEdit?.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI
|
|
||||||
|
|
||||||
textEditAddChangedListener()
|
|
||||||
|
|
||||||
binding?.textInputLayout?.let { viewThemeUtils.material.colorTextInputLayout(it) }
|
|
||||||
binding?.okButton?.let { viewThemeUtils.material.colorMaterialButtonText(it) }
|
|
||||||
|
|
||||||
binding?.textInputLayout?.hint = resources!!.getString(R.string.nc_conversation_link)
|
|
||||||
|
|
||||||
binding?.textInputLayout?.requestFocus()
|
|
||||||
|
|
||||||
binding?.smileyButton?.setOnClickListener { onSmileyClick() }
|
|
||||||
binding?.okButton?.setOnClickListener { onOkButtonClick() }
|
|
||||||
} else if (operation == ConversationOperationEnum.OPS_CODE_INVITE_USERS) {
|
|
||||||
binding?.textEdit?.inputType = InputType.TYPE_CLASS_TEXT
|
|
||||||
|
|
||||||
textEditAddChangedListener()
|
|
||||||
binding?.smileyButton?.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
binding?.textInputLayout?.let { viewThemeUtils.material.colorTextInputLayout(it) }
|
|
||||||
binding?.okButton?.let { viewThemeUtils.material.colorMaterialButtonText(it) }
|
|
||||||
|
|
||||||
binding?.textInputLayout?.requestFocus()
|
|
||||||
|
|
||||||
binding?.smileyButton?.setOnClickListener { onSmileyClick() }
|
|
||||||
binding?.okButton?.setOnClickListener { onOkButtonClick() }
|
|
||||||
} else {
|
|
||||||
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1))
|
|
||||||
ncApi.getRoom(
|
|
||||||
ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token),
|
|
||||||
ApiUtils.getUrlForRoom(apiVersion, currentUser!!.baseUrl, roomToken)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("Detekt.LongMethod")
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
|
|
||||||
if (conversation != null && operation === ConversationOperationEnum.OPS_CODE_RENAME_ROOM) {
|
|
||||||
binding?.textEdit?.setText(conversation!!.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding?.textEdit?.setOnEditorActionListener { v, actionId, event ->
|
|
||||||
@Suppress("IMPLICIT_BOXING_IN_IDENTITY_EQUALS")
|
|
||||||
if (actionId === EditorInfo.IME_ACTION_DONE && binding?.okButton?.isEnabled == true) {
|
|
||||||
binding?.okButton?.callOnClick()
|
|
||||||
return@setOnEditorActionListener true
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
textEditAddChangedListener()
|
|
||||||
|
|
||||||
var labelText = ""
|
|
||||||
when (operation) {
|
|
||||||
ConversationOperationEnum.OPS_CODE_RENAME_ROOM -> {
|
|
||||||
labelText = resources!!.getString(R.string.nc_call_name)
|
|
||||||
binding?.textEdit?.inputType = InputType.TYPE_CLASS_TEXT
|
|
||||||
binding?.smileyButton?.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
|
|
||||||
ConversationOperationEnum.OPS_CODE_JOIN_ROOM -> {
|
|
||||||
// 99 is joining a conversation via password
|
|
||||||
labelText = resources!!.getString(R.string.nc_password)
|
|
||||||
binding?.textEdit?.inputType =
|
|
||||||
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (PASSWORD_ENTRY_OPERATIONS.contains(operation)) {
|
|
||||||
binding?.textInputLayout?.endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE
|
|
||||||
} else {
|
|
||||||
binding?.textInputLayout?.endIconMode = TextInputLayout.END_ICON_NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
binding?.textInputLayout?.let { viewThemeUtils.material.colorTextInputLayout(it) }
|
|
||||||
binding?.okButton?.let { viewThemeUtils.material.colorMaterialButtonText(it) }
|
|
||||||
|
|
||||||
binding?.textInputLayout?.hint = labelText
|
|
||||||
binding?.textInputLayout?.requestFocus()
|
|
||||||
|
|
||||||
binding?.smileyButton?.setOnClickListener { onSmileyClick() }
|
|
||||||
binding?.okButton?.setOnClickListener { onOkButtonClick() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
Log.e("EntryMenuController", "error")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun textEditAddChangedListener() {
|
|
||||||
binding?.textEdit?.addTextChangedListener(object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable) {
|
|
||||||
if (!TextUtils.isEmpty(s)) {
|
|
||||||
if (operation === ConversationOperationEnum.OPS_CODE_RENAME_ROOM) {
|
|
||||||
if (conversation!!.name == null || !conversation!!.name.equals(s.toString())) {
|
|
||||||
if (!binding?.okButton?.isEnabled!!) {
|
|
||||||
binding?.okButton?.isEnabled = true
|
|
||||||
binding?.okButton?.alpha = OPACITY_ENABLED
|
|
||||||
}
|
|
||||||
binding?.textInputLayout?.isErrorEnabled = false
|
|
||||||
} else {
|
|
||||||
if (binding?.okButton?.isEnabled == true) {
|
|
||||||
binding?.okButton?.isEnabled = false
|
|
||||||
binding?.okButton?.alpha = OPACITY_DISABLED
|
|
||||||
}
|
|
||||||
binding?.textInputLayout?.error = resources?.getString(R.string.nc_call_name_is_same)
|
|
||||||
}
|
|
||||||
} else if (operation !== ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM) {
|
|
||||||
if (!binding?.okButton?.isEnabled!!) {
|
|
||||||
binding?.okButton?.isEnabled = true
|
|
||||||
binding?.okButton?.alpha = OPACITY_ENABLED
|
|
||||||
}
|
|
||||||
binding?.textInputLayout?.isErrorEnabled = false
|
|
||||||
} else if (
|
|
||||||
UriUtils.hasHttpProtocolPrefixed(binding?.textEdit?.text.toString()) &&
|
|
||||||
binding?.textEdit?.text.toString().contains("/call/")
|
|
||||||
) {
|
|
||||||
if (!binding?.okButton?.isEnabled!!) {
|
|
||||||
binding?.okButton?.isEnabled = true
|
|
||||||
binding?.okButton?.alpha = OPACITY_ENABLED
|
|
||||||
}
|
|
||||||
binding?.textInputLayout?.isErrorEnabled = false
|
|
||||||
} else {
|
|
||||||
if (binding?.okButton?.isEnabled == true) {
|
|
||||||
binding?.okButton?.isEnabled = false
|
|
||||||
binding?.okButton?.alpha = OPACITY_DISABLED
|
|
||||||
}
|
|
||||||
binding?.textInputLayout?.error = resources?.getString(R.string.nc_wrong_link)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (binding?.okButton?.isEnabled == true) {
|
|
||||||
binding?.okButton?.isEnabled = false
|
|
||||||
binding?.okButton?.alpha = OPACITY_DISABLED
|
|
||||||
}
|
|
||||||
binding?.textInputLayout?.isErrorEnabled = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onSmileyClick() {
|
|
||||||
emojiPopup?.toggle()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onOkButtonClick() {
|
|
||||||
if (operation === ConversationOperationEnum.OPS_CODE_JOIN_ROOM) {
|
|
||||||
joinRoom()
|
|
||||||
} else if (
|
|
||||||
operation !== ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM &&
|
|
||||||
operation !== ConversationOperationEnum.OPS_CODE_INVITE_USERS
|
|
||||||
) {
|
|
||||||
val bundle = Bundle()
|
|
||||||
conversation!!.name = binding?.textEdit?.text.toString()
|
|
||||||
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
|
|
||||||
bundle.putString(BundleKeys.KEY_NEW_ROOM_NAME, binding?.textEdit?.text.toString())
|
|
||||||
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
|
|
||||||
router.pushController(
|
|
||||||
RouterTransaction.with(OperationsMenuController(bundle))
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
|
||||||
} else if (operation !== ConversationOperationEnum.OPS_CODE_INVITE_USERS) {
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
|
|
||||||
bundle.putString(BundleKeys.KEY_CALL_URL, binding?.textEdit?.text.toString())
|
|
||||||
router.pushController(
|
|
||||||
RouterTransaction.with(OperationsMenuController(bundle))
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
|
||||||
} else if (operation === ConversationOperationEnum.OPS_CODE_INVITE_USERS) {
|
|
||||||
originalBundle.putString(BundleKeys.KEY_CONVERSATION_NAME, binding?.textEdit?.text.toString())
|
|
||||||
router.pushController(
|
|
||||||
RouterTransaction.with(
|
|
||||||
OperationsMenuController(
|
|
||||||
originalBundle
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun joinRoom() {
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
|
|
||||||
bundle.putString(BundleKeys.KEY_CONVERSATION_PASSWORD, binding?.textEdit?.text.toString())
|
|
||||||
bundle.putSerializable(BundleKeys.KEY_OPERATION_CODE, operation)
|
|
||||||
router.pushController(
|
|
||||||
RouterTransaction.with(OperationsMenuController(bundle))
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
sharedApplication!!.componentApplication.inject(this)
|
|
||||||
|
|
||||||
originalBundle = args
|
|
||||||
operation = args.getSerializable(BundleKeys.KEY_OPERATION_CODE) as ConversationOperationEnum
|
|
||||||
roomToken = args.getString(KEY_ROOM_TOKEN, "")
|
|
||||||
name = args.getString(BundleKeys.KEY_APP_ITEM_NAME, "")
|
|
||||||
packageName = args.getString(BundleKeys.KEY_APP_ITEM_PACKAGE_NAME, "")
|
|
||||||
// callUrl = args.getString(BundleKeys.KEY_CALL_URL, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val PASSWORD_ENTRY_OPERATIONS: List<ConversationOperationEnum> =
|
|
||||||
immutableListOf(
|
|
||||||
ConversationOperationEnum.OPS_CODE_JOIN_ROOM
|
|
||||||
)
|
|
||||||
const val OPACITY_DISABLED = 0.38f
|
|
||||||
const val OPACITY_BUTTON_DISABLED = 0.7f
|
|
||||||
const val OPACITY_ENABLED = 1.0f
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,753 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Mario Danic
|
|
||||||
* @author Andy Scherzinger
|
|
||||||
* Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package com.nextcloud.talk.controllers.bottomsheet
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.text.TextUtils
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import autodagger.AutoInjector
|
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
|
||||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
|
||||||
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
|
||||||
import com.nextcloud.talk.R
|
|
||||||
import com.nextcloud.talk.api.NcApi
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
|
||||||
import com.nextcloud.talk.controllers.base.BaseController
|
|
||||||
import com.nextcloud.talk.controllers.util.viewBinding
|
|
||||||
import com.nextcloud.talk.data.user.model.User
|
|
||||||
import com.nextcloud.talk.databinding.ControllerOperationsMenuBinding
|
|
||||||
import com.nextcloud.talk.events.ConversationsListFetchDataEvent
|
|
||||||
import com.nextcloud.talk.events.OpenConversationEvent
|
|
||||||
import com.nextcloud.talk.models.RetrofitBucket
|
|
||||||
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType
|
|
||||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
|
||||||
import com.nextcloud.talk.models.json.generic.GenericOverall
|
|
||||||
import com.nextcloud.talk.models.json.participants.AddParticipantOverall
|
|
||||||
import com.nextcloud.talk.users.UserManager
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
|
||||||
import com.nextcloud.talk.utils.DisplayUtils
|
|
||||||
import com.nextcloud.talk.utils.NoSupportedApiException
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_URL
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_PASSWORD
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TYPE
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INVITED_GROUP
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INVITED_PARTICIPANTS
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NEW_ROOM_NAME
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPERATION_CODE
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
|
||||||
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
|
|
||||||
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.disposables.Disposable
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import org.parceler.Parcels
|
|
||||||
import retrofit2.HttpException
|
|
||||||
import java.io.IOException
|
|
||||||
import java.util.Collections
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
|
||||||
class OperationsMenuController(args: Bundle) : BaseController(
|
|
||||||
R.layout.controller_operations_menu,
|
|
||||||
args
|
|
||||||
) {
|
|
||||||
private val binding: ControllerOperationsMenuBinding? by viewBinding(ControllerOperationsMenuBinding::bind)
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var ncApi: NcApi
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var userManager: UserManager
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var eventBus: EventBus
|
|
||||||
|
|
||||||
private val operation: ConversationOperationEnum?
|
|
||||||
private var conversation: Conversation? = null
|
|
||||||
private var currentUser: User? = null
|
|
||||||
private val callPassword: String
|
|
||||||
private val callUrl: String
|
|
||||||
private var roomToken: String
|
|
||||||
private val roomNameNew: String
|
|
||||||
private var baseUrl: String? = null
|
|
||||||
private var conversationToken: String? = null
|
|
||||||
private var disposable: Disposable? = null
|
|
||||||
private var conversationType: ConversationType? = null
|
|
||||||
private var invitedUsers: ArrayList<String>? = ArrayList()
|
|
||||||
private var invitedGroups: ArrayList<String>? = ArrayList()
|
|
||||||
private var credentials: String? = null
|
|
||||||
private val conversationName: String
|
|
||||||
|
|
||||||
override val appBarLayoutType: AppBarLayoutType
|
|
||||||
get() = AppBarLayoutType.SEARCH_BAR
|
|
||||||
|
|
||||||
override fun onViewBound(view: View) {
|
|
||||||
super.onViewBound(view)
|
|
||||||
sharedApplication!!.componentApplication.inject(this)
|
|
||||||
currentUser = userManager.currentUser.blockingGet()
|
|
||||||
|
|
||||||
binding?.progressBar?.let { viewThemeUtils.platform.colorCircularProgressBar(it, ColorRole.PRIMARY) }
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(callUrl) && callUrl.contains("/call")) {
|
|
||||||
conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1)
|
|
||||||
if (callUrl.contains("/index.php")) {
|
|
||||||
baseUrl = callUrl.substring(0, callUrl.indexOf("/index.php"))
|
|
||||||
} else {
|
|
||||||
baseUrl = callUrl.substring(0, callUrl.indexOf("/call"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (roomToken.isNotEmpty()) {
|
|
||||||
val apiVersion = apiVersion()
|
|
||||||
ncApi.getRoom(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForRoom(apiVersion, currentUser!!.baseUrl, roomToken)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
disposable = d
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(baseUrl) && baseUrl != currentUser!!.baseUrl) {
|
|
||||||
fetchCapabilitiesForGuest()
|
|
||||||
} else {
|
|
||||||
processOperation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
Log.e(TAG, "error while fetching room", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
processOperation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchCapabilitiesForGuest() {
|
|
||||||
ncApi.getCapabilities(null, ApiUtils.getUrlForCapabilities(baseUrl))
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(object : Observer<CapabilitiesOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(capabilitiesOverall: CapabilitiesOverall) {
|
|
||||||
currentUser = User()
|
|
||||||
currentUser!!.baseUrl = baseUrl
|
|
||||||
currentUser!!.userId = "?"
|
|
||||||
try {
|
|
||||||
currentUser!!.capabilities = capabilitiesOverall.ocs!!.data!!.capabilities
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e("OperationsMenu", "Failed to serialize capabilities")
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
checkCapabilities(currentUser!!)
|
|
||||||
processOperation()
|
|
||||||
} catch (e: NoSupportedApiException) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
Log.d(TAG, "No supported server version found", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
Log.e(TAG, "Error fetching capabilities for guest", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("Detekt.ComplexMethod")
|
|
||||||
private fun processOperation() {
|
|
||||||
if (currentUser == null) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = true)
|
|
||||||
Log.e(TAG, "Ended up in processOperation without a valid currentUser")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
|
|
||||||
when (operation) {
|
|
||||||
ConversationOperationEnum.OPS_CODE_RENAME_ROOM -> operationRenameRoom()
|
|
||||||
ConversationOperationEnum.OPS_CODE_GET_AND_JOIN_ROOM -> operationGetAndJoinRoom()
|
|
||||||
ConversationOperationEnum.OPS_CODE_INVITE_USERS -> operationInviteUsers()
|
|
||||||
ConversationOperationEnum.OPS_CODE_MARK_AS_READ -> operationMarkAsRead()
|
|
||||||
ConversationOperationEnum.OPS_CODE_MARK_AS_UNREAD -> operationMarkAsUnread()
|
|
||||||
ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE,
|
|
||||||
ConversationOperationEnum.OPS_CODE_ADD_FAVORITE -> operationToggleFavorite()
|
|
||||||
|
|
||||||
ConversationOperationEnum.OPS_CODE_JOIN_ROOM -> operationJoinRoom()
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun apiVersion(): Int {
|
|
||||||
return ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun chatApiVersion(): Int {
|
|
||||||
return ApiUtils.getChatApiVersion(currentUser, intArrayOf(ApiUtils.APIv1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun operationJoinRoom() {
|
|
||||||
ncApi.joinRoom(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForParticipantsActive(
|
|
||||||
apiVersion(),
|
|
||||||
baseUrl,
|
|
||||||
conversationToken
|
|
||||||
),
|
|
||||||
callPassword
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(RoomOperationsObserver())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun operationMarkAsRead() {
|
|
||||||
ncApi.setChatReadMarker(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForChatReadMarker(
|
|
||||||
chatApiVersion(),
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token
|
|
||||||
),
|
|
||||||
conversation!!.lastMessage!!.jsonMessageId
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(GenericOperationsObserver())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun operationMarkAsUnread() {
|
|
||||||
ncApi.markRoomAsUnread(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForChatReadMarker(
|
|
||||||
chatApiVersion(),
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(GenericOperationsObserver())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun operationRenameRoom() {
|
|
||||||
ncApi.renameRoom(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForRoom(
|
|
||||||
apiVersion(),
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token
|
|
||||||
),
|
|
||||||
roomNameNew
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(GenericOperationsObserver())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun operationToggleFavorite() {
|
|
||||||
val genericOperationsObserver = GenericOperationsObserver()
|
|
||||||
val apiVersion = apiVersion()
|
|
||||||
if (operation === ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE) {
|
|
||||||
ncApi.removeConversationFromFavorites(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForRoomFavorite(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(genericOperationsObserver)
|
|
||||||
} else {
|
|
||||||
ncApi.addConversationToFavorites(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForRoomFavorite(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(genericOperationsObserver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun operationInviteUsers() {
|
|
||||||
val retrofitBucket: RetrofitBucket
|
|
||||||
val apiVersion = apiVersion()
|
|
||||||
var invite: String? = null
|
|
||||||
if (invitedGroups!!.size > 0) {
|
|
||||||
invite = invitedGroups!![0]
|
|
||||||
}
|
|
||||||
retrofitBucket = if (conversationType == ConversationType.ROOM_PUBLIC_CALL) {
|
|
||||||
ApiUtils.getRetrofitBucketForCreateRoom(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
"3",
|
|
||||||
null,
|
|
||||||
invite,
|
|
||||||
conversationName
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
ApiUtils.getRetrofitBucketForCreateRoom(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
"2",
|
|
||||||
null,
|
|
||||||
invite,
|
|
||||||
conversationName
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ncApi.createRoom(credentials, retrofitBucket.url, retrofitBucket.queryMap)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
ncApi.getRoom(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForRoom(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(
|
|
||||||
roomOverall: RoomOverall
|
|
||||||
) {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
inviteUsersToAConversation()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun operationGetAndJoinRoom() {
|
|
||||||
val apiVersion = apiVersion()
|
|
||||||
ncApi.getRoom(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForRoom(apiVersion, baseUrl, conversationToken)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
disposable = d
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
if (conversation!!.hasPassword && conversation!!.isGuest) {
|
|
||||||
eventBus.post(ConversationsListFetchDataEvent())
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
|
|
||||||
bundle.putSerializable(KEY_OPERATION_CODE, ConversationOperationEnum.OPS_CODE_JOIN_ROOM)
|
|
||||||
router.pushController(
|
|
||||||
RouterTransaction.with(EntryMenuController(bundle))
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
|
||||||
} else if (conversation!!.isGuest) {
|
|
||||||
ncApi.joinRoom(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForParticipantsActive(
|
|
||||||
apiVersion,
|
|
||||||
baseUrl,
|
|
||||||
conversationToken
|
|
||||||
),
|
|
||||||
null
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(object : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
initiateConversation()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
initiateConversation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
|
||||||
private fun showResultImage(everythingOK: Boolean, isGuestSupportError: Boolean) {
|
|
||||||
try {
|
|
||||||
binding?.progressBar?.visibility = View.GONE
|
|
||||||
if (resources != null) {
|
|
||||||
if (everythingOK) {
|
|
||||||
binding?.resultImageView?.setImageDrawable(
|
|
||||||
DisplayUtils.getTintedDrawable(
|
|
||||||
resources,
|
|
||||||
R.drawable.ic_check_circle_black_24dp,
|
|
||||||
R.color.nc_darkGreen
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
binding?.resultImageView?.setImageDrawable(
|
|
||||||
DisplayUtils.getTintedDrawable(
|
|
||||||
resources,
|
|
||||||
R.drawable.ic_cancel_black_24dp,
|
|
||||||
R.color.nc_darkRed
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding?.resultImageView?.visibility = View.VISIBLE
|
|
||||||
if (everythingOK) {
|
|
||||||
binding?.resultTextView?.setText(R.string.nc_all_ok_operation)
|
|
||||||
} else {
|
|
||||||
binding?.resultTextView?.setTextColor(resources!!.getColor(R.color.nc_darkRed, null))
|
|
||||||
binding?.resultTextView?.setText(R.string.nc_failed_to_perform_operation)
|
|
||||||
}
|
|
||||||
binding?.resultTextView?.visibility = View.VISIBLE
|
|
||||||
if (everythingOK) {
|
|
||||||
eventBus.post(ConversationsListFetchDataEvent())
|
|
||||||
} else {
|
|
||||||
binding?.resultImageView?.setImageDrawable(
|
|
||||||
DisplayUtils.getTintedDrawable(
|
|
||||||
resources,
|
|
||||||
R.drawable.ic_cancel_black_24dp,
|
|
||||||
R.color.nc_darkRed
|
|
||||||
)
|
|
||||||
)
|
|
||||||
binding?.okButton?.setOnClickListener { v: View? -> eventBus.post(ConversationsListFetchDataEvent()) }
|
|
||||||
binding?.okButton?.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
} catch (npe: NullPointerException) {
|
|
||||||
Log.i(TAG, "Controller already closed", npe)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dispose() {
|
|
||||||
if (disposable != null && !disposable!!.isDisposed) {
|
|
||||||
disposable!!.dispose()
|
|
||||||
}
|
|
||||||
disposable = null
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
@kotlin.Throws(NoSupportedApiException::class)
|
|
||||||
private fun checkCapabilities(currentUser: User) {
|
|
||||||
ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1))
|
|
||||||
ApiUtils.getCallApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, 1))
|
|
||||||
ApiUtils.getChatApiVersion(currentUser, intArrayOf(1))
|
|
||||||
ApiUtils.getSignalingApiVersion(currentUser, intArrayOf(ApiUtils.APIv3, 2, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun inviteUsersToAConversation() {
|
|
||||||
val localInvitedUsers = invitedUsers
|
|
||||||
val localInvitedGroups = invitedGroups
|
|
||||||
if (localInvitedGroups!!.size > 0) {
|
|
||||||
localInvitedGroups.removeAt(0)
|
|
||||||
}
|
|
||||||
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, API_CONVERSATION_VERSIONS)
|
|
||||||
if (localInvitedUsers!!.size > 0 || localInvitedGroups.size > 0 &&
|
|
||||||
CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails")
|
|
||||||
) {
|
|
||||||
addGroupsToConversation(localInvitedUsers, localInvitedGroups, apiVersion)
|
|
||||||
addUsersToConversation(localInvitedUsers, localInvitedGroups, apiVersion)
|
|
||||||
} else {
|
|
||||||
initiateConversation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addUsersToConversation(
|
|
||||||
localInvitedUsers: ArrayList<String>?,
|
|
||||||
localInvitedGroups: ArrayList<String>?,
|
|
||||||
apiVersion: Int
|
|
||||||
) {
|
|
||||||
var retrofitBucket: RetrofitBucket
|
|
||||||
for (i in localInvitedUsers!!.indices) {
|
|
||||||
val userId = invitedUsers!![i]
|
|
||||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token,
|
|
||||||
userId
|
|
||||||
)
|
|
||||||
ncApi.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(object : Observer<AddParticipantOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(addParticipantOverall: AddParticipantOverall) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
Collections.synchronizedList(localInvitedUsers).remove(userId)
|
|
||||||
if (localInvitedGroups!!.size == 0 && localInvitedUsers.size == 0) {
|
|
||||||
initiateConversation()
|
|
||||||
}
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addGroupsToConversation(
|
|
||||||
localInvitedUsers: ArrayList<String>?,
|
|
||||||
localInvitedGroups: ArrayList<String>?,
|
|
||||||
apiVersion: Int
|
|
||||||
) {
|
|
||||||
var retrofitBucket: RetrofitBucket
|
|
||||||
if (localInvitedGroups!!.size > 0 &&
|
|
||||||
CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails")
|
|
||||||
) {
|
|
||||||
for (i in localInvitedGroups.indices) {
|
|
||||||
val groupId = localInvitedGroups[i]
|
|
||||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipantWithSource(
|
|
||||||
apiVersion,
|
|
||||||
currentUser!!.baseUrl,
|
|
||||||
conversation!!.token,
|
|
||||||
"groups",
|
|
||||||
groupId
|
|
||||||
)
|
|
||||||
ncApi.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.retry(1)
|
|
||||||
.subscribe(object : Observer<AddParticipantOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(addParticipantOverall: AddParticipantOverall) {
|
|
||||||
// unused atm
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
Collections.synchronizedList(localInvitedGroups).remove(groupId)
|
|
||||||
if (localInvitedGroups.size == 0 && localInvitedUsers!!.size == 0) {
|
|
||||||
initiateConversation()
|
|
||||||
}
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initiateConversation() {
|
|
||||||
eventBus.post(ConversationsListFetchDataEvent())
|
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putString(KEY_ROOM_TOKEN, conversation!!.token)
|
|
||||||
bundle.putString(KEY_ROOM_ID, conversation!!.roomId)
|
|
||||||
bundle.putString(KEY_CONVERSATION_NAME, conversation!!.displayName)
|
|
||||||
bundle.putString(KEY_CONVERSATION_PASSWORD, callPassword)
|
|
||||||
eventBus.post(OpenConversationEvent(conversation, bundle))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleObserverError(e: Throwable) {
|
|
||||||
if (operation !== ConversationOperationEnum.OPS_CODE_JOIN_ROOM || e !is HttpException) {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
} else {
|
|
||||||
val response = e.response()
|
|
||||||
if (response != null && response.code() == FORBIDDEN) {
|
|
||||||
ApplicationWideMessageHolder.getInstance()
|
|
||||||
.setMessageType(ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG)
|
|
||||||
router.popCurrentController()
|
|
||||||
} else {
|
|
||||||
showResultImage(everythingOK = false, isGuestSupportError = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class GenericOperationsObserver : Observer<GenericOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
disposable = d
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(genericOverall: GenericOverall) {
|
|
||||||
if (operation !== ConversationOperationEnum.OPS_CODE_JOIN_ROOM) {
|
|
||||||
showResultImage(everythingOK = true, isGuestSupportError = false)
|
|
||||||
} else {
|
|
||||||
throw IllegalArgumentException("Unsupported operation code observed!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
handleObserverError(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class RoomOperationsObserver : Observer<RoomOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
disposable = d
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(roomOverall: RoomOverall) {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
if (operation !== ConversationOperationEnum.OPS_CODE_JOIN_ROOM) {
|
|
||||||
showResultImage(everythingOK = true, isGuestSupportError = false)
|
|
||||||
} else {
|
|
||||||
conversation = roomOverall.ocs!!.data
|
|
||||||
initiateConversation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
handleObserverError(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "OperationsMenu"
|
|
||||||
private const val FORBIDDEN = 403
|
|
||||||
private val API_CONVERSATION_VERSIONS = intArrayOf(4, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
operation = args.getSerializable(KEY_OPERATION_CODE) as ConversationOperationEnum?
|
|
||||||
callPassword = args.getString(KEY_CONVERSATION_PASSWORD, "")
|
|
||||||
callUrl = args.getString(KEY_CALL_URL, "")
|
|
||||||
roomToken = args.getString(KEY_ROOM_TOKEN, "")
|
|
||||||
roomNameNew = args.getString(KEY_NEW_ROOM_NAME, "")
|
|
||||||
if (args.containsKey(KEY_INVITED_PARTICIPANTS)) {
|
|
||||||
invitedUsers = args.getStringArrayList(KEY_INVITED_PARTICIPANTS)
|
|
||||||
}
|
|
||||||
if (args.containsKey(KEY_INVITED_GROUP)) {
|
|
||||||
invitedGroups = args.getStringArrayList(KEY_INVITED_GROUP)
|
|
||||||
}
|
|
||||||
if (args.containsKey(KEY_CONVERSATION_TYPE)) {
|
|
||||||
conversationType = Parcels.unwrap(args.getParcelable(KEY_CONVERSATION_TYPE))
|
|
||||||
}
|
|
||||||
conversationName = args.getString(KEY_CONVERSATION_NAME, "")
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,310 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.conversation
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkInfo
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import autodagger.AutoInjector
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||||
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
|
import com.nextcloud.talk.chat.ChatActivity
|
||||||
|
import com.nextcloud.talk.conversation.viewmodel.ConversationViewModel
|
||||||
|
import com.nextcloud.talk.databinding.DialogCreateConversationBinding
|
||||||
|
import com.nextcloud.talk.jobs.AddParticipantsToConversation
|
||||||
|
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||||
|
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||||
|
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||||
|
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
|
||||||
|
import com.vanniktech.emoji.EmojiPopup
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.parceler.Parcels
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
|
class CreateConversationDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewThemeUtils: ViewThemeUtils
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var eventBus: EventBus
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var currentUserProvider: CurrentUserProviderNew
|
||||||
|
|
||||||
|
private lateinit var binding: DialogCreateConversationBinding
|
||||||
|
private lateinit var viewModel: ConversationViewModel
|
||||||
|
|
||||||
|
private var emojiPopup: EmojiPopup? = null
|
||||||
|
|
||||||
|
private var conversationType: Conversation.ConversationType? = null
|
||||||
|
private var usersToInvite: ArrayList<String> = ArrayList()
|
||||||
|
private var groupsToInvite: ArrayList<String> = ArrayList()
|
||||||
|
private var emailsToInvite: ArrayList<String> = ArrayList()
|
||||||
|
private var circlesToInvite: ArrayList<String> = ArrayList()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this, viewModelFactory)[ConversationViewModel::class.java]
|
||||||
|
|
||||||
|
if (arguments?.containsKey(USERS_TO_INVITE) == true) {
|
||||||
|
usersToInvite = arguments?.getStringArrayList(USERS_TO_INVITE)!!
|
||||||
|
}
|
||||||
|
if (arguments?.containsKey(GROUPS_TO_INVITE) == true) {
|
||||||
|
groupsToInvite = arguments?.getStringArrayList(GROUPS_TO_INVITE)!!
|
||||||
|
}
|
||||||
|
if (arguments?.containsKey(EMAILS_TO_INVITE) == true) {
|
||||||
|
emailsToInvite = arguments?.getStringArrayList(EMAILS_TO_INVITE)!!
|
||||||
|
}
|
||||||
|
if (arguments?.containsKey(CIRCLES_TO_INVITE) == true) {
|
||||||
|
circlesToInvite = arguments?.getStringArrayList(CIRCLES_TO_INVITE)!!
|
||||||
|
}
|
||||||
|
if (arguments?.containsKey(KEY_CONVERSATION_TYPE) == true) {
|
||||||
|
conversationType = Parcels.unwrap(arguments?.getParcelable(KEY_CONVERSATION_TYPE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
binding = DialogCreateConversationBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
|
val dialogBuilder = MaterialAlertDialogBuilder(binding.root.context)
|
||||||
|
.setTitle(resources.getString(R.string.nc_call_name))
|
||||||
|
// listener is null for now to avoid closing after button was clicked.
|
||||||
|
// listener is set later in onStart
|
||||||
|
.setPositiveButton(R.string.nc_common_create, null)
|
||||||
|
.setNegativeButton(R.string.nc_common_dismiss, null)
|
||||||
|
.setView(binding.root)
|
||||||
|
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.root.context, dialogBuilder)
|
||||||
|
|
||||||
|
return dialogBuilder.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
setupListeners()
|
||||||
|
setupStateObserver()
|
||||||
|
|
||||||
|
setupEmojiPopup()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
|
||||||
|
val positiveButton = (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
positiveButton.isEnabled = false
|
||||||
|
positiveButton.setOnClickListener {
|
||||||
|
viewModel.createConversation(
|
||||||
|
binding.textEdit.text.toString(),
|
||||||
|
conversationType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupEmojiPopup() {
|
||||||
|
emojiPopup = binding.let {
|
||||||
|
EmojiPopup(
|
||||||
|
rootView = requireView(),
|
||||||
|
editText = it.textEdit,
|
||||||
|
onEmojiPopupShownListener = {
|
||||||
|
viewThemeUtils.platform.colorImageView(it.smileyButton, ColorRole.PRIMARY)
|
||||||
|
},
|
||||||
|
onEmojiPopupDismissListener = {
|
||||||
|
it.smileyButton.imageTintList = ColorStateList.valueOf(
|
||||||
|
ResourcesCompat.getColor(
|
||||||
|
resources,
|
||||||
|
R.color.medium_emphasis_text,
|
||||||
|
context?.theme
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onEmojiClickListener = {
|
||||||
|
binding.textEdit.editableText?.append(" ")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListeners() {
|
||||||
|
binding.smileyButton.setOnClickListener { emojiPopup?.toggle() }
|
||||||
|
binding.textEdit.addTextChangedListener(object : TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterTextChanged(s: Editable) {
|
||||||
|
val positiveButton = (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(s)) {
|
||||||
|
if (!positiveButton.isEnabled) {
|
||||||
|
positiveButton.isEnabled = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (positiveButton.isEnabled) {
|
||||||
|
positiveButton.isEnabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupStateObserver() {
|
||||||
|
viewModel.viewState.observe(viewLifecycleOwner) { state ->
|
||||||
|
when (state) {
|
||||||
|
is ConversationViewModel.InitialState -> {}
|
||||||
|
is ConversationViewModel.CreatingState -> {}
|
||||||
|
is ConversationViewModel.CreatingSuccessState -> addParticipants(state.roomToken)
|
||||||
|
is ConversationViewModel.CreatingFailedState -> {
|
||||||
|
Log.e(TAG, "Failed to create conversation")
|
||||||
|
showError()
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addParticipants(roomToken: String) {
|
||||||
|
val data = Data.Builder()
|
||||||
|
data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, currentUserProvider.currentUser.blockingGet().id!!)
|
||||||
|
data.putString(BundleKeys.KEY_TOKEN, roomToken)
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_USERS, usersToInvite.toTypedArray())
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_GROUPS, groupsToInvite.toTypedArray())
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_EMAILS, emailsToInvite.toTypedArray())
|
||||||
|
data.putStringArray(BundleKeys.KEY_SELECTED_CIRCLES, circlesToInvite.toTypedArray())
|
||||||
|
|
||||||
|
val addParticipantsToConversationWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(
|
||||||
|
AddParticipantsToConversation::class.java
|
||||||
|
)
|
||||||
|
.setInputData(data.build())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
WorkManager.getInstance(requireContext()).enqueue(addParticipantsToConversationWorker)
|
||||||
|
|
||||||
|
WorkManager.getInstance(requireContext()).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")
|
||||||
|
initiateConversation(roomToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkInfo.State.FAILED -> {
|
||||||
|
Log.e(TAG, "failed to AddParticipantsToConversation")
|
||||||
|
showError()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initiateConversation(roomToken: String) {
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
|
||||||
|
|
||||||
|
val chatIntent = Intent(context, ChatActivity::class.java)
|
||||||
|
chatIntent.putExtras(bundle)
|
||||||
|
chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
startActivity(chatIntent)
|
||||||
|
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showError() {
|
||||||
|
dismiss()
|
||||||
|
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragment creator
|
||||||
|
*/
|
||||||
|
companion object {
|
||||||
|
private val TAG = CreateConversationDialogFragment::class.java.simpleName
|
||||||
|
private const val USERS_TO_INVITE = "usersToInvite"
|
||||||
|
private const val GROUPS_TO_INVITE = "groupsToInvite"
|
||||||
|
private const val EMAILS_TO_INVITE = "emailsToInvite"
|
||||||
|
private const val CIRCLES_TO_INVITE = "circlesToInvite"
|
||||||
|
private const val KEY_CONVERSATION_TYPE = "keyConversationType"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(
|
||||||
|
usersToInvite: ArrayList<String>?,
|
||||||
|
groupsToInvite: ArrayList<String>?,
|
||||||
|
emailsToInvite: ArrayList<String>?,
|
||||||
|
circlesToInvite: ArrayList<String>?,
|
||||||
|
conversationType: Parcelable
|
||||||
|
): CreateConversationDialogFragment {
|
||||||
|
val args = Bundle()
|
||||||
|
args.putStringArrayList(USERS_TO_INVITE, usersToInvite)
|
||||||
|
args.putStringArrayList(GROUPS_TO_INVITE, groupsToInvite)
|
||||||
|
args.putStringArrayList(EMAILS_TO_INVITE, emailsToInvite)
|
||||||
|
args.putStringArrayList(CIRCLES_TO_INVITE, circlesToInvite)
|
||||||
|
args.putParcelable(KEY_CONVERSATION_TYPE, conversationType)
|
||||||
|
val fragment = CreateConversationDialogFragment()
|
||||||
|
fragment.arguments = args
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.conversation
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.text.TextWatcher
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import autodagger.AutoInjector
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||||
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
|
import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel
|
||||||
|
import com.nextcloud.talk.conversationlist.ConversationsListActivity
|
||||||
|
import com.nextcloud.talk.databinding.DialogRenameConversationBinding
|
||||||
|
import com.nextcloud.talk.events.ConversationsListFetchDataEvent
|
||||||
|
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||||
|
import com.vanniktech.emoji.EmojiPopup
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
|
class RenameConversationDialogFragment : DialogFragment() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var viewThemeUtils: ViewThemeUtils
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var eventBus: EventBus
|
||||||
|
|
||||||
|
private lateinit var binding: DialogRenameConversationBinding
|
||||||
|
private lateinit var viewModel: RenameConversationViewModel
|
||||||
|
|
||||||
|
private var emojiPopup: EmojiPopup? = null
|
||||||
|
|
||||||
|
private var roomToken = ""
|
||||||
|
private var initialName = ""
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(this, viewModelFactory)[RenameConversationViewModel::class.java]
|
||||||
|
roomToken = arguments?.getString(KEY_ROOM_TOKEN)!!
|
||||||
|
initialName = arguments?.getString(INITIAL_NAME)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
binding = DialogRenameConversationBinding.inflate(LayoutInflater.from(context))
|
||||||
|
|
||||||
|
val dialogBuilder = MaterialAlertDialogBuilder(binding.root.context)
|
||||||
|
.setTitle(resources.getString(R.string.nc_call_name))
|
||||||
|
// listener is null for now to avoid closing after button was clicked.
|
||||||
|
// listener is set later in onStart
|
||||||
|
.setPositiveButton(R.string.nc_rename_confirm, null)
|
||||||
|
.setNegativeButton(R.string.nc_common_dismiss, null)
|
||||||
|
.setView(binding.root)
|
||||||
|
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.root.context, dialogBuilder)
|
||||||
|
|
||||||
|
return dialogBuilder.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
setupListeners()
|
||||||
|
setupStateObserver()
|
||||||
|
|
||||||
|
setupEmojiPopup()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
binding.textEdit.setText(initialName)
|
||||||
|
|
||||||
|
val positiveButton = (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
positiveButton.isEnabled = false
|
||||||
|
positiveButton.setOnClickListener {
|
||||||
|
viewModel.renameConversation(roomToken, binding.textEdit.text.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupEmojiPopup() {
|
||||||
|
emojiPopup = binding.let {
|
||||||
|
EmojiPopup(
|
||||||
|
rootView = requireView(),
|
||||||
|
editText = it.textEdit,
|
||||||
|
onEmojiPopupShownListener = {
|
||||||
|
viewThemeUtils.platform.colorImageView(it.smileyButton, ColorRole.PRIMARY)
|
||||||
|
},
|
||||||
|
onEmojiPopupDismissListener = {
|
||||||
|
it.smileyButton.imageTintList = ColorStateList.valueOf(
|
||||||
|
ResourcesCompat.getColor(
|
||||||
|
resources,
|
||||||
|
R.color.medium_emphasis_text,
|
||||||
|
context?.theme
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onEmojiClickListener = {
|
||||||
|
binding.textEdit.editableText?.append(" ")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListeners() {
|
||||||
|
binding.smileyButton.setOnClickListener { emojiPopup?.toggle() }
|
||||||
|
binding.textEdit.addTextChangedListener(object : TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun afterTextChanged(s: Editable) {
|
||||||
|
val positiveButton = (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(s)) {
|
||||||
|
if (initialName == s.toString()) {
|
||||||
|
positiveButton.isEnabled = false
|
||||||
|
} else if (!positiveButton.isEnabled) {
|
||||||
|
positiveButton.isEnabled = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (positiveButton.isEnabled) {
|
||||||
|
positiveButton.isEnabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupStateObserver() {
|
||||||
|
viewModel.viewState.observe(viewLifecycleOwner) { state ->
|
||||||
|
when (state) {
|
||||||
|
is RenameConversationViewModel.InitialState -> {}
|
||||||
|
is RenameConversationViewModel.RenamingState -> {}
|
||||||
|
is RenameConversationViewModel.RenamingSuccessState -> handleSuccess()
|
||||||
|
is RenameConversationViewModel.RenamingFailedState -> showError()
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSuccess() {
|
||||||
|
eventBus.post(ConversationsListFetchDataEvent())
|
||||||
|
|
||||||
|
context?.resources?.let {
|
||||||
|
String.format(
|
||||||
|
it.getString(R.string.renamed_conversation),
|
||||||
|
initialName
|
||||||
|
)
|
||||||
|
}?.let {
|
||||||
|
(activity as ConversationsListActivity?)?.showSnackbar(
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showError() {
|
||||||
|
dismiss()
|
||||||
|
Log.e(TAG, "Failed to rename conversation")
|
||||||
|
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragment creator
|
||||||
|
*/
|
||||||
|
companion object {
|
||||||
|
private val TAG = RenameConversationDialogFragment::class.java.simpleName
|
||||||
|
private const val KEY_ROOM_TOKEN = "keyRoomToken"
|
||||||
|
private const val INITIAL_NAME = "initialName"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(roomTokenParam: String, initialName: String): RenameConversationDialogFragment {
|
||||||
|
val args = Bundle()
|
||||||
|
args.putString(KEY_ROOM_TOKEN, roomTokenParam)
|
||||||
|
args.putString(INITIAL_NAME, initialName)
|
||||||
|
val fragment = RenameConversationDialogFragment()
|
||||||
|
fragment.arguments = args
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.conversation.repository
|
||||||
|
|
||||||
|
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||||
|
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||||
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||||
|
import io.reactivex.Observable
|
||||||
|
|
||||||
|
interface ConversationRepository {
|
||||||
|
|
||||||
|
fun renameConversation(
|
||||||
|
roomToken: String,
|
||||||
|
roomNameNew: String
|
||||||
|
): Observable<GenericOverall>
|
||||||
|
|
||||||
|
fun createConversation(
|
||||||
|
roomName: String,
|
||||||
|
conversationType: Conversation.ConversationType?
|
||||||
|
): Observable<RoomOverall>
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.conversation.repository
|
||||||
|
|
||||||
|
import com.nextcloud.talk.api.NcApi
|
||||||
|
import com.nextcloud.talk.data.user.model.User
|
||||||
|
import com.nextcloud.talk.models.RetrofitBucket
|
||||||
|
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||||
|
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||||
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||||
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
|
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
||||||
|
class ConversationRepositoryImpl(private val ncApi: NcApi, currentUserProvider: CurrentUserProviderNew) :
|
||||||
|
ConversationRepository {
|
||||||
|
|
||||||
|
val currentUser: User = currentUserProvider.currentUser.blockingGet()
|
||||||
|
val credentials: String = ApiUtils.getCredentials(currentUser.username, currentUser.token)
|
||||||
|
|
||||||
|
override fun renameConversation(
|
||||||
|
roomToken: String,
|
||||||
|
roomNameNew: String
|
||||||
|
): Observable<GenericOverall> {
|
||||||
|
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1))
|
||||||
|
|
||||||
|
return ncApi.renameRoom(
|
||||||
|
credentials,
|
||||||
|
ApiUtils.getUrlForRoom(
|
||||||
|
apiVersion,
|
||||||
|
currentUser.baseUrl,
|
||||||
|
roomToken
|
||||||
|
),
|
||||||
|
roomNameNew
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.retry(API_RETRIES)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createConversation(
|
||||||
|
roomName: String,
|
||||||
|
conversationType: Conversation.ConversationType?
|
||||||
|
): Observable<RoomOverall> {
|
||||||
|
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1))
|
||||||
|
|
||||||
|
val retrofitBucket: RetrofitBucket = if (conversationType == Conversation.ConversationType.ROOM_PUBLIC_CALL) {
|
||||||
|
ApiUtils.getRetrofitBucketForCreateRoom(
|
||||||
|
apiVersion,
|
||||||
|
currentUser.baseUrl,
|
||||||
|
ROOM_TYPE_PUBLIC,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
roomName
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ApiUtils.getRetrofitBucketForCreateRoom(
|
||||||
|
apiVersion,
|
||||||
|
currentUser.baseUrl,
|
||||||
|
ROOM_TYPE_GROUP,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
roomName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return ncApi.createRoom(credentials, retrofitBucket.url, retrofitBucket.queryMap)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.retry(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ROOM_TYPE_PUBLIC = "3"
|
||||||
|
private const val ROOM_TYPE_GROUP = "2"
|
||||||
|
const val API_RETRIES: Long = 3
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.conversation.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.nextcloud.talk.conversation.repository.ConversationRepository
|
||||||
|
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||||
|
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||||
|
import io.reactivex.Observer
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ConversationViewModel @Inject constructor(private val repository: ConversationRepository) : ViewModel() {
|
||||||
|
|
||||||
|
sealed class ViewState
|
||||||
|
object InitialState : ViewState()
|
||||||
|
|
||||||
|
object CreatingState : ViewState()
|
||||||
|
class CreatingSuccessState(val roomToken: String) : ViewState()
|
||||||
|
object CreatingFailedState : ViewState()
|
||||||
|
|
||||||
|
private val _viewState: MutableLiveData<ViewState> = MutableLiveData(
|
||||||
|
InitialState
|
||||||
|
)
|
||||||
|
val viewState: LiveData<ViewState>
|
||||||
|
get() = _viewState
|
||||||
|
|
||||||
|
private var disposable: Disposable? = null
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
disposable?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createConversation(
|
||||||
|
roomName: String,
|
||||||
|
conversationType: Conversation.ConversationType?
|
||||||
|
) {
|
||||||
|
_viewState.value = CreatingState
|
||||||
|
|
||||||
|
repository.createConversation(
|
||||||
|
roomName,
|
||||||
|
conversationType
|
||||||
|
)
|
||||||
|
.doOnSubscribe { disposable = it }
|
||||||
|
?.subscribeOn(Schedulers.io())
|
||||||
|
?.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
?.subscribe(CreateConversationObserver())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class CreateConversationObserver : Observer<RoomOverall> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(roomOverall: RoomOverall) {
|
||||||
|
val conversation = roomOverall.ocs!!.data
|
||||||
|
_viewState.value = CreatingSuccessState(conversation?.token!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
// dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
// dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = ConversationViewModel::class.java.simpleName
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Marcel Hibbe
|
||||||
|
* Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.conversation.viewmodel
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.nextcloud.talk.conversation.repository.ConversationRepository
|
||||||
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||||
|
import io.reactivex.Observer
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RenameConversationViewModel @Inject constructor(private val repository: ConversationRepository) : ViewModel() {
|
||||||
|
|
||||||
|
sealed class ViewState
|
||||||
|
object InitialState : ViewState()
|
||||||
|
object RenamingState : ViewState()
|
||||||
|
object RenamingSuccessState : ViewState()
|
||||||
|
object RenamingFailedState : ViewState()
|
||||||
|
|
||||||
|
private val _viewState: MutableLiveData<ViewState> = MutableLiveData(
|
||||||
|
InitialState
|
||||||
|
)
|
||||||
|
val viewState: LiveData<ViewState>
|
||||||
|
get() = _viewState
|
||||||
|
|
||||||
|
fun renameConversation(roomToken: String, roomNameNew: String) {
|
||||||
|
_viewState.value = RenamingState
|
||||||
|
|
||||||
|
repository.renameConversation(
|
||||||
|
roomToken,
|
||||||
|
roomNameNew
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
?.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
?.subscribe(RenameConversationObserver())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class RenameConversationObserver : Observer<GenericOverall> {
|
||||||
|
|
||||||
|
lateinit var genericOverall: GenericOverall
|
||||||
|
|
||||||
|
override fun onSubscribe(d: Disposable) = Unit
|
||||||
|
|
||||||
|
override fun onNext(response: GenericOverall) {
|
||||||
|
genericOverall = response
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
Log.e(TAG, "Failed to rename conversation", e)
|
||||||
|
_viewState.value = RenamingFailedState
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
_viewState.value = RenamingSuccessState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = RenameConversationViewModel::class.java.simpleName
|
||||||
|
}
|
||||||
|
}
|
@ -58,6 +58,7 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.work.Data
|
import androidx.work.Data
|
||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import coil.imageLoader
|
import coil.imageLoader
|
||||||
@ -86,7 +87,6 @@ import com.nextcloud.talk.data.user.model.User
|
|||||||
import com.nextcloud.talk.databinding.ControllerConversationsRvBinding
|
import com.nextcloud.talk.databinding.ControllerConversationsRvBinding
|
||||||
import com.nextcloud.talk.events.ConversationsListFetchDataEvent
|
import com.nextcloud.talk.events.ConversationsListFetchDataEvent
|
||||||
import com.nextcloud.talk.events.EventStatus
|
import com.nextcloud.talk.events.EventStatus
|
||||||
import com.nextcloud.talk.interfaces.ConversationMenuInterface
|
|
||||||
import com.nextcloud.talk.jobs.AccountRemovalWorker
|
import com.nextcloud.talk.jobs.AccountRemovalWorker
|
||||||
import com.nextcloud.talk.jobs.ContactAddressBookWorker.Companion.run
|
import com.nextcloud.talk.jobs.ContactAddressBookWorker.Companion.run
|
||||||
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
||||||
@ -143,8 +143,7 @@ import javax.inject.Inject
|
|||||||
class ConversationsListActivity :
|
class ConversationsListActivity :
|
||||||
BaseActivity(),
|
BaseActivity(),
|
||||||
FlexibleAdapter.OnItemClickListener,
|
FlexibleAdapter.OnItemClickListener,
|
||||||
FlexibleAdapter.OnItemLongClickListener,
|
FlexibleAdapter.OnItemLongClickListener {
|
||||||
ConversationMenuInterface {
|
|
||||||
|
|
||||||
private lateinit var binding: ControllerConversationsRvBinding
|
private lateinit var binding: ControllerConversationsRvBinding
|
||||||
|
|
||||||
@ -181,7 +180,6 @@ class ConversationsListActivity :
|
|||||||
private var credentials: String? = null
|
private var credentials: String? = null
|
||||||
private var adapterWasNull = true
|
private var adapterWasNull = true
|
||||||
private var isRefreshing = false
|
private var isRefreshing = false
|
||||||
private var conversationMenuBundle: Bundle? = null
|
|
||||||
private var showShareToScreen = false
|
private var showShareToScreen = false
|
||||||
private var filesToShare: ArrayList<String>? = null
|
private var filesToShare: ArrayList<String>? = null
|
||||||
private var selectedConversation: Conversation? = null
|
private var selectedConversation: Conversation? = null
|
||||||
@ -600,6 +598,9 @@ class ConversationsListActivity :
|
|||||||
searchItem!!.expandActionView()
|
searchItem!!.expandActionView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showSnackbar(text: String) {
|
||||||
|
Snackbar.make(binding.root, text, Snackbar.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
fun fetchRooms() {
|
fun fetchRooms() {
|
||||||
val includeStatus = isUserStatusAvailable(userManager.currentUser.blockingGet())
|
val includeStatus = isUserStatusAvailable(userManager.currentUser.blockingGet())
|
||||||
|
|
||||||
@ -999,7 +1000,7 @@ class ConversationsListActivity :
|
|||||||
|
|
||||||
@SuppressLint("CheckResult") // handled by helper
|
@SuppressLint("CheckResult") // handled by helper
|
||||||
private fun loadMoreMessages() {
|
private fun loadMoreMessages() {
|
||||||
binding?.swipeRefreshLayoutView?.isRefreshing = true
|
binding.swipeRefreshLayoutView.isRefreshing = true
|
||||||
val observable = searchHelper!!.loadMore()
|
val observable = searchHelper!!.loadMore()
|
||||||
observable?.observeOn(AndroidSchedulers.mainThread())
|
observable?.observeOn(AndroidSchedulers.mainThread())
|
||||||
?.subscribe({ results: MessageSearchResults -> onMessageSearchResult(results) }) { throwable: Throwable ->
|
?.subscribe({ results: MessageSearchResults -> onMessageSearchResult(results) }) { throwable: Throwable ->
|
||||||
@ -1302,50 +1303,33 @@ class ConversationsListActivity :
|
|||||||
}, BOTTOM_SHEET_DELAY)
|
}, BOTTOM_SHEET_DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showDeleteConversationDialog(bundle: Bundle) {
|
fun showDeleteConversationDialog(conversation: Conversation) {
|
||||||
conversationMenuBundle = bundle
|
binding.floatingActionButton.let {
|
||||||
if (conversationMenuBundle != null &&
|
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
|
||||||
isInternalUserEqualsCurrentUser(currentUser, conversationMenuBundle)
|
.setIcon(
|
||||||
) {
|
viewThemeUtils.dialog
|
||||||
binding?.floatingActionButton?.let {
|
.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp)
|
||||||
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
|
|
||||||
.setIcon(
|
|
||||||
viewThemeUtils.dialog
|
|
||||||
.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp)
|
|
||||||
)
|
|
||||||
.setTitle(R.string.nc_delete_call)
|
|
||||||
.setMessage(R.string.nc_delete_conversation_more)
|
|
||||||
.setPositiveButton(R.string.nc_delete) { _, _ ->
|
|
||||||
val data = Data.Builder()
|
|
||||||
data.putLong(
|
|
||||||
KEY_INTERNAL_USER_ID,
|
|
||||||
conversationMenuBundle!!.getLong(KEY_INTERNAL_USER_ID)
|
|
||||||
)
|
|
||||||
data.putString(KEY_ROOM_TOKEN, bundle.getString(KEY_ROOM_TOKEN))
|
|
||||||
conversationMenuBundle = null
|
|
||||||
deleteConversation(data.build())
|
|
||||||
}
|
|
||||||
.setNegativeButton(R.string.nc_cancel) { _, _ ->
|
|
||||||
conversationMenuBundle = null
|
|
||||||
}
|
|
||||||
|
|
||||||
viewThemeUtils.dialog
|
|
||||||
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
|
|
||||||
val dialog = dialogBuilder.show()
|
|
||||||
viewThemeUtils.platform.colorTextButtons(
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
|
||||||
)
|
)
|
||||||
}
|
.setTitle(R.string.nc_delete_call)
|
||||||
|
.setMessage(R.string.nc_delete_conversation_more)
|
||||||
|
.setPositiveButton(R.string.nc_delete) { _, _ ->
|
||||||
|
deleteConversation(conversation)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.nc_cancel) { _, _ ->
|
||||||
|
}
|
||||||
|
|
||||||
|
viewThemeUtils.dialog
|
||||||
|
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
|
||||||
|
val dialog = dialogBuilder.show()
|
||||||
|
viewThemeUtils.platform.colorTextButtons(
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isInternalUserEqualsCurrentUser(currentUser: User?, conversationMenuBundle: Bundle?): Boolean {
|
|
||||||
return currentUser != null && conversationMenuBundle!!.getLong(KEY_INTERNAL_USER_ID) == currentUser.id
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showUnauthorizedDialog() {
|
private fun showUnauthorizedDialog() {
|
||||||
binding?.floatingActionButton?.let {
|
binding.floatingActionButton.let {
|
||||||
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
|
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
|
||||||
.setIcon(
|
.setIcon(
|
||||||
viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
|
viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
|
||||||
@ -1517,10 +1501,40 @@ class ConversationsListActivity :
|
|||||||
Runtime.getRuntime().exit(0)
|
Runtime.getRuntime().exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteConversation(data: Data) {
|
private fun deleteConversation(conversation: Conversation) {
|
||||||
|
val data = Data.Builder()
|
||||||
|
data.putLong(
|
||||||
|
KEY_INTERNAL_USER_ID,
|
||||||
|
currentUser?.id!!
|
||||||
|
)
|
||||||
|
data.putString(KEY_ROOM_TOKEN, conversation.token)
|
||||||
|
|
||||||
val deleteConversationWorker =
|
val deleteConversationWorker =
|
||||||
OneTimeWorkRequest.Builder(DeleteConversationWorker::class.java).setInputData(data).build()
|
OneTimeWorkRequest.Builder(DeleteConversationWorker::class.java).setInputData(data.build()).build()
|
||||||
WorkManager.getInstance().enqueue(deleteConversationWorker)
|
WorkManager.getInstance().enqueue(deleteConversationWorker)
|
||||||
|
|
||||||
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(deleteConversationWorker.id)
|
||||||
|
.observeForever { workInfo: WorkInfo? ->
|
||||||
|
if (workInfo != null) {
|
||||||
|
when (workInfo.state) {
|
||||||
|
WorkInfo.State.SUCCEEDED -> {
|
||||||
|
showSnackbar(
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.deleted_conversation),
|
||||||
|
conversation.displayName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkInfo.State.FAILED -> {
|
||||||
|
showSnackbar(context.resources.getString(R.string.nc_common_error_sorry))
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onMessageSearchResult(results: MessageSearchResults) {
|
private fun onMessageSearchResult(results: MessageSearchResults) {
|
||||||
|
@ -28,6 +28,8 @@ package com.nextcloud.talk.dagger.modules
|
|||||||
import com.nextcloud.talk.api.NcApi
|
import com.nextcloud.talk.api.NcApi
|
||||||
import com.nextcloud.talk.chat.data.ChatRepository
|
import com.nextcloud.talk.chat.data.ChatRepository
|
||||||
import com.nextcloud.talk.chat.data.ChatRepositoryImpl
|
import com.nextcloud.talk.chat.data.ChatRepositoryImpl
|
||||||
|
import com.nextcloud.talk.conversation.repository.ConversationRepository
|
||||||
|
import com.nextcloud.talk.conversation.repository.ConversationRepositoryImpl
|
||||||
import com.nextcloud.talk.conversationinfoedit.data.ConversationInfoEditRepository
|
import com.nextcloud.talk.conversationinfoedit.data.ConversationInfoEditRepository
|
||||||
import com.nextcloud.talk.conversationinfoedit.data.ConversationInfoEditRepositoryImpl
|
import com.nextcloud.talk.conversationinfoedit.data.ConversationInfoEditRepositoryImpl
|
||||||
import com.nextcloud.talk.data.source.local.TalkDatabase
|
import com.nextcloud.talk.data.source.local.TalkDatabase
|
||||||
@ -139,4 +141,10 @@ class RepositoryModule {
|
|||||||
ConversationInfoEditRepository {
|
ConversationInfoEditRepository {
|
||||||
return ConversationInfoEditRepositoryImpl(ncApi, userProvider)
|
return ConversationInfoEditRepositoryImpl(ncApi, userProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun provideConversationRepository(ncApi: NcApi, userProvider: CurrentUserProviderNew):
|
||||||
|
ConversationRepository {
|
||||||
|
return ConversationRepositoryImpl(ncApi, userProvider)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import com.nextcloud.talk.callnotification.viewmodel.CallNotificationViewModel
|
import com.nextcloud.talk.callnotification.viewmodel.CallNotificationViewModel
|
||||||
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
|
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
|
||||||
|
import com.nextcloud.talk.conversation.viewmodel.ConversationViewModel
|
||||||
|
import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel
|
||||||
import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel
|
import com.nextcloud.talk.conversationinfoedit.viewmodel.ConversationInfoEditViewModel
|
||||||
import com.nextcloud.talk.messagesearch.MessageSearchViewModel
|
import com.nextcloud.talk.messagesearch.MessageSearchViewModel
|
||||||
import com.nextcloud.talk.openconversations.viewmodels.OpenConversationsViewModel
|
import com.nextcloud.talk.openconversations.viewmodels.OpenConversationsViewModel
|
||||||
@ -132,4 +134,14 @@ abstract class ViewModelModule {
|
|||||||
@IntoMap
|
@IntoMap
|
||||||
@ViewModelKey(ConversationInfoEditViewModel::class)
|
@ViewModelKey(ConversationInfoEditViewModel::class)
|
||||||
abstract fun conversationInfoEditViewModel(viewModel: ConversationInfoEditViewModel): ViewModel
|
abstract fun conversationInfoEditViewModel(viewModel: ConversationInfoEditViewModel): ViewModel
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ViewModelKey(RenameConversationViewModel::class)
|
||||||
|
abstract fun renameConversationViewModel(viewModel: RenameConversationViewModel): ViewModel
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ViewModelKey(ConversationViewModel::class)
|
||||||
|
abstract fun conversationViewModel(viewModel: ConversationViewModel): ViewModel
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,9 @@ import android.content.Context;
|
|||||||
import com.nextcloud.talk.api.NcApi;
|
import com.nextcloud.talk.api.NcApi;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.data.user.model.User;
|
import com.nextcloud.talk.data.user.model.User;
|
||||||
import com.nextcloud.talk.events.EventStatus;
|
|
||||||
import com.nextcloud.talk.models.RetrofitBucket;
|
import com.nextcloud.talk.models.RetrofitBucket;
|
||||||
import com.nextcloud.talk.users.UserManager;
|
import com.nextcloud.talk.users.UserManager;
|
||||||
import com.nextcloud.talk.utils.ApiUtils;
|
import com.nextcloud.talk.utils.ApiUtils;
|
||||||
import com.nextcloud.talk.utils.UserIdUtils;
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
@ -138,9 +136,6 @@ public class AddParticipantsToConversation extends Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus.post(new EventStatus(UserIdUtils.INSTANCE.getIdForUser(user),
|
|
||||||
EventStatus.EventType.PARTICIPANTS_UPDATE,
|
|
||||||
true));
|
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Marcel Hibbe
|
|
||||||
* Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nextcloud.talk.ui.dialog
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import autodagger.AutoInjector
|
|
||||||
import com.bluelinelabs.conductor.Conductor
|
|
||||||
import com.bluelinelabs.conductor.Router
|
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
|
||||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
||||||
import com.nextcloud.talk.R
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController
|
|
||||||
import com.nextcloud.talk.databinding.DialogBottomContactsBinding
|
|
||||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
|
||||||
class ContactsBottomDialog(
|
|
||||||
val activity: Activity,
|
|
||||||
val bundle: Bundle
|
|
||||||
) : BottomSheetDialog(activity) {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var viewThemeUtils: ViewThemeUtils
|
|
||||||
|
|
||||||
private var dialogRouter: Router? = null
|
|
||||||
|
|
||||||
private lateinit var binding: DialogBottomContactsBinding
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this)
|
|
||||||
|
|
||||||
binding = DialogBottomContactsBinding.inflate(layoutInflater)
|
|
||||||
setContentView(binding.root)
|
|
||||||
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
|
||||||
|
|
||||||
viewThemeUtils.platform.themeDialog(binding.root)
|
|
||||||
executeEntryMenuController(bundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun executeEntryMenuController(bundle: Bundle) {
|
|
||||||
dialogRouter = Conductor.attachRouter(activity, binding.root, null)
|
|
||||||
|
|
||||||
dialogRouter!!.pushController(
|
|
||||||
RouterTransaction.with(EntryMenuController(bundle))
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
val bottomSheet = findViewById<View>(R.id.design_bottom_sheet)
|
|
||||||
val behavior = BottomSheetBehavior.from(bottomSheet as View)
|
|
||||||
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "ContactsBottomDialog"
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,36 +26,31 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.work.Data
|
import androidx.work.Data
|
||||||
import androidx.work.OneTimeWorkRequest
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import com.bluelinelabs.conductor.Conductor
|
|
||||||
import com.bluelinelabs.conductor.Router
|
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
|
||||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
import com.nextcloud.talk.api.NcApi
|
import com.nextcloud.talk.api.NcApi
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum
|
import com.nextcloud.talk.conversation.RenameConversationDialogFragment
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_ADD_FAVORITE
|
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MARK_AS_READ
|
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MARK_AS_UNREAD
|
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_REMOVE_FAVORITE
|
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM
|
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController
|
|
||||||
import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController
|
|
||||||
import com.nextcloud.talk.conversationlist.ConversationsListActivity
|
import com.nextcloud.talk.conversationlist.ConversationsListActivity
|
||||||
import com.nextcloud.talk.data.user.model.User
|
import com.nextcloud.talk.data.user.model.User
|
||||||
import com.nextcloud.talk.databinding.DialogConversationOperationsBinding
|
import com.nextcloud.talk.databinding.DialogConversationOperationsBinding
|
||||||
import com.nextcloud.talk.jobs.LeaveConversationWorker
|
import com.nextcloud.talk.jobs.LeaveConversationWorker
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||||
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
||||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||||
import com.nextcloud.talk.users.UserManager
|
import com.nextcloud.talk.users.UserManager
|
||||||
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPERATION_CODE
|
|
||||||
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.database.user.CapabilitiesUtilNew
|
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew
|
||||||
|
import io.reactivex.Observer
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.Disposable
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
@ -65,8 +60,6 @@ class ConversationsListBottomDialog(
|
|||||||
val conversation: Conversation
|
val conversation: Conversation
|
||||||
) : BottomSheetDialog(activity) {
|
) : BottomSheetDialog(activity) {
|
||||||
|
|
||||||
private var dialogRouter: Router? = null
|
|
||||||
|
|
||||||
private lateinit var binding: DialogConversationOperationsBinding
|
private lateinit var binding: DialogConversationOperationsBinding
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ -78,6 +71,8 @@ class ConversationsListBottomDialog(
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var userManager: UserManager
|
lateinit var userManager: UserManager
|
||||||
|
|
||||||
|
lateinit var credentials: String
|
||||||
|
|
||||||
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)
|
||||||
@ -90,6 +85,15 @@ class ConversationsListBottomDialog(
|
|||||||
initHeaderDescription()
|
initHeaderDescription()
|
||||||
initItemsVisibility()
|
initItemsVisibility()
|
||||||
initClickListeners()
|
initClickListeners()
|
||||||
|
|
||||||
|
credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
val bottomSheet = findViewById<View>(R.id.design_bottom_sheet)
|
||||||
|
val behavior = BottomSheetBehavior.from(bottomSheet as View)
|
||||||
|
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initHeaderDescription() {
|
private fun initHeaderDescription() {
|
||||||
@ -104,18 +108,18 @@ class ConversationsListBottomDialog(
|
|||||||
val hasFavoritesCapability = CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "favorites")
|
val hasFavoritesCapability = CapabilitiesUtilNew.hasSpreedFeatureCapability(currentUser, "favorites")
|
||||||
val canModerate = conversation.canModerate(currentUser)
|
val canModerate = conversation.canModerate(currentUser)
|
||||||
|
|
||||||
binding.conversationOperationRemoveFavorite.visibility = setVisibleIf(
|
binding.conversationRemoveFromFavorites.visibility = setVisibleIf(
|
||||||
hasFavoritesCapability && conversation.favorite
|
hasFavoritesCapability && conversation.favorite
|
||||||
)
|
)
|
||||||
binding.conversationOperationAddFavorite.visibility = setVisibleIf(
|
binding.conversationAddToFavorites.visibility = setVisibleIf(
|
||||||
hasFavoritesCapability && !conversation.favorite
|
hasFavoritesCapability && !conversation.favorite
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.conversationOperationMarkAsRead.visibility = setVisibleIf(
|
binding.conversationMarkAsRead.visibility = setVisibleIf(
|
||||||
conversation.unreadMessages > 0 && CapabilitiesUtilNew.canSetChatReadMarker(currentUser)
|
conversation.unreadMessages > 0 && CapabilitiesUtilNew.canSetChatReadMarker(currentUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.conversationOperationMarkAsUnread.visibility = setVisibleIf(
|
binding.conversationMarkAsUnread.visibility = setVisibleIf(
|
||||||
conversation.unreadMessages <= 0 && CapabilitiesUtilNew.canMarkRoomAsUnread(currentUser)
|
conversation.unreadMessages <= 0 && CapabilitiesUtilNew.canMarkRoomAsUnread(currentUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -144,98 +148,258 @@ class ConversationsListBottomDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initClickListeners() {
|
private fun initClickListeners() {
|
||||||
binding.conversationOperationAddFavorite.setOnClickListener {
|
binding.conversationAddToFavorites.setOnClickListener {
|
||||||
executeOperationsMenuController(OPS_CODE_ADD_FAVORITE)
|
addConversationToFavorites()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.conversationOperationRemoveFavorite.setOnClickListener {
|
binding.conversationRemoveFromFavorites.setOnClickListener {
|
||||||
executeOperationsMenuController(OPS_CODE_REMOVE_FAVORITE)
|
removeConversationFromFavorites()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.conversationOperationLeave.setOnClickListener {
|
binding.conversationMarkAsRead.setOnClickListener {
|
||||||
val dataBuilder = Data.Builder()
|
markConversationAsRead()
|
||||||
dataBuilder.putString(KEY_ROOM_TOKEN, conversation.token)
|
|
||||||
dataBuilder.putLong(KEY_INTERNAL_USER_ID, currentUser.id!!)
|
|
||||||
val data = dataBuilder.build()
|
|
||||||
|
|
||||||
val leaveConversationWorker =
|
|
||||||
OneTimeWorkRequest.Builder(LeaveConversationWorker::class.java).setInputData(
|
|
||||||
data
|
|
||||||
).build()
|
|
||||||
WorkManager.getInstance().enqueue(leaveConversationWorker)
|
|
||||||
|
|
||||||
dismiss()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.conversationOperationDelete.setOnClickListener {
|
binding.conversationMarkAsUnread.setOnClickListener {
|
||||||
if (!TextUtils.isEmpty(conversation.token)) {
|
markConversationAsUnread()
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putLong(KEY_INTERNAL_USER_ID, currentUser.id!!)
|
|
||||||
bundle.putString(KEY_ROOM_TOKEN, conversation.token)
|
|
||||||
activity.showDeleteConversationDialog(bundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.conversationOperationRename.setOnClickListener {
|
binding.conversationOperationRename.setOnClickListener {
|
||||||
executeEntryMenuController(OPS_CODE_RENAME_ROOM)
|
renameConversation()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.conversationOperationMarkAsRead.setOnClickListener {
|
binding.conversationOperationLeave.setOnClickListener {
|
||||||
executeOperationsMenuController(OPS_CODE_MARK_AS_READ)
|
leaveConversation()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.conversationOperationMarkAsUnread.setOnClickListener {
|
binding.conversationOperationDelete.setOnClickListener {
|
||||||
executeOperationsMenuController(OPS_CODE_MARK_AS_UNREAD)
|
deleteConversation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeOperationsMenuController(operation: ConversationOperationEnum) {
|
private fun addConversationToFavorites() {
|
||||||
val bundle = Bundle()
|
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1))
|
||||||
bundle.putSerializable(KEY_OPERATION_CODE, operation)
|
ncApi.addConversationToFavorites(
|
||||||
bundle.putString(KEY_ROOM_TOKEN, conversation.token)
|
credentials,
|
||||||
|
ApiUtils.getUrlForRoomFavorite(
|
||||||
binding.operationItemsLayout.visibility = View.GONE
|
apiVersion,
|
||||||
|
currentUser.baseUrl,
|
||||||
dialogRouter = Conductor.attachRouter(activity, binding.root, null)
|
conversation.token
|
||||||
|
)
|
||||||
dialogRouter!!.pushController(
|
|
||||||
RouterTransaction.with(OperationsMenuController(bundle))
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.retry(1)
|
||||||
|
.subscribe(object : Observer<GenericOverall> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
activity.fetchRooms()
|
override fun onNext(genericOverall: GenericOverall) {
|
||||||
|
activity.fetchRooms()
|
||||||
|
activity.showSnackbar(
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.added_to_favorites),
|
||||||
|
conversation.displayName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry))
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeEntryMenuController(operation: ConversationOperationEnum) {
|
private fun removeConversationFromFavorites() {
|
||||||
val bundle = Bundle()
|
val apiVersion = ApiUtils.getConversationApiVersion(currentUser, intArrayOf(ApiUtils.APIv4, ApiUtils.APIv1))
|
||||||
bundle.putSerializable(KEY_OPERATION_CODE, operation)
|
ncApi.removeConversationFromFavorites(
|
||||||
bundle.putString(KEY_ROOM_TOKEN, conversation.token)
|
credentials,
|
||||||
|
ApiUtils.getUrlForRoomFavorite(
|
||||||
binding.operationItemsLayout.visibility = View.GONE
|
apiVersion,
|
||||||
|
currentUser.baseUrl,
|
||||||
dialogRouter = Conductor.attachRouter(activity, binding.root, null)
|
conversation.token
|
||||||
|
)
|
||||||
dialogRouter!!.pushController(
|
|
||||||
|
|
||||||
// TODO refresh conversation list after EntryMenuController finished (throw event? / pass controller
|
|
||||||
// into EntryMenuController to execute fetch data... ?!)
|
|
||||||
// for example if you set a password, the dialog items should be refreshed for the next time you open it
|
|
||||||
// without to manually have to refresh the conversations list
|
|
||||||
// also see BottomSheetLockEvent ??
|
|
||||||
|
|
||||||
RouterTransaction.with(EntryMenuController(bundle))
|
|
||||||
.pushChangeHandler(HorizontalChangeHandler())
|
|
||||||
.popChangeHandler(HorizontalChangeHandler())
|
|
||||||
)
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.retry(1)
|
||||||
|
.subscribe(object : Observer<GenericOverall> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(genericOverall: GenericOverall) {
|
||||||
|
activity.fetchRooms()
|
||||||
|
activity.showSnackbar(
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.removed_from_favorites),
|
||||||
|
conversation.displayName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry))
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
private fun markConversationAsUnread() {
|
||||||
super.onStart()
|
ncApi.markRoomAsUnread(
|
||||||
val bottomSheet = findViewById<View>(R.id.design_bottom_sheet)
|
credentials,
|
||||||
val behavior = BottomSheetBehavior.from(bottomSheet as View)
|
ApiUtils.getUrlForChatReadMarker(
|
||||||
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
chatApiVersion(),
|
||||||
|
currentUser.baseUrl,
|
||||||
|
conversation.token
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.retry(1)
|
||||||
|
.subscribe(object : Observer<GenericOverall> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(genericOverall: GenericOverall) {
|
||||||
|
activity.fetchRooms()
|
||||||
|
activity.showSnackbar(
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.marked_as_unread),
|
||||||
|
conversation.displayName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry))
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun markConversationAsRead() {
|
||||||
|
ncApi.setChatReadMarker(
|
||||||
|
credentials,
|
||||||
|
ApiUtils.getUrlForChatReadMarker(
|
||||||
|
chatApiVersion(),
|
||||||
|
currentUser.baseUrl,
|
||||||
|
conversation.token
|
||||||
|
),
|
||||||
|
conversation.lastMessage!!.jsonMessageId
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.retry(1)
|
||||||
|
.subscribe(object : Observer<GenericOverall> {
|
||||||
|
override fun onSubscribe(d: Disposable) {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNext(genericOverall: GenericOverall) {
|
||||||
|
activity.fetchRooms()
|
||||||
|
activity.showSnackbar(
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.marked_as_read),
|
||||||
|
conversation.displayName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(e: Throwable) {
|
||||||
|
activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry))
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete() {
|
||||||
|
// unused atm
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renameConversation() {
|
||||||
|
if (!TextUtils.isEmpty(conversation.token)) {
|
||||||
|
dismiss()
|
||||||
|
val conversationDialog = RenameConversationDialogFragment.newInstance(
|
||||||
|
conversation.token!!,
|
||||||
|
conversation.displayName!!
|
||||||
|
)
|
||||||
|
conversationDialog.show(
|
||||||
|
activity.supportFragmentManager,
|
||||||
|
TAG
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun leaveConversation() {
|
||||||
|
val dataBuilder = Data.Builder()
|
||||||
|
dataBuilder.putString(KEY_ROOM_TOKEN, conversation.token)
|
||||||
|
dataBuilder.putLong(KEY_INTERNAL_USER_ID, currentUser.id!!)
|
||||||
|
val data = dataBuilder.build()
|
||||||
|
|
||||||
|
val leaveConversationWorker =
|
||||||
|
OneTimeWorkRequest.Builder(LeaveConversationWorker::class.java).setInputData(
|
||||||
|
data
|
||||||
|
).build()
|
||||||
|
WorkManager.getInstance().enqueue(leaveConversationWorker)
|
||||||
|
|
||||||
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(leaveConversationWorker.id)
|
||||||
|
.observeForever { workInfo: WorkInfo? ->
|
||||||
|
if (workInfo != null) {
|
||||||
|
when (workInfo.state) {
|
||||||
|
WorkInfo.State.SUCCEEDED -> {
|
||||||
|
activity.showSnackbar(
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.left_conversation),
|
||||||
|
conversation.displayName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkInfo.State.FAILED -> {
|
||||||
|
activity.showSnackbar(context.resources.getString(R.string.nc_common_error_sorry))
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteConversation() {
|
||||||
|
if (!TextUtils.isEmpty(conversation.token)) {
|
||||||
|
activity.showDeleteConversationDialog(conversation)
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun chatApiVersion(): Int {
|
||||||
|
return ApiUtils.getChatApiVersion(currentUser, intArrayOf(ApiUtils.APIv1))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val TAG = ConversationsListBottomDialog::class.simpleName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package com.nextcloud.talk.utils.remapchat
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
|
||||||
import com.bluelinelabs.conductor.Router
|
|
||||||
|
|
||||||
data class RemapChatModel(
|
|
||||||
val router: Router,
|
|
||||||
val controllerChangeHandler: ControllerChangeHandler,
|
|
||||||
val chatControllerTag: String,
|
|
||||||
val bundle: Bundle
|
|
||||||
)
|
|
@ -1,25 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Nextcloud Talk application
|
|
||||||
~
|
|
||||||
~ @author Mario Danic
|
|
||||||
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
|
||||||
~
|
|
||||||
~ This program is free software: you can redistribute it and/or modify
|
|
||||||
~ it under the terms of the GNU General Public License as published by
|
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
|
||||||
~ at your option) any later version.
|
|
||||||
~
|
|
||||||
~ This program is distributed in the hope that it will be useful,
|
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
~ GNU General Public License for more details.
|
|
||||||
~
|
|
||||||
~ You should have received a copy of the GNU General Public License
|
|
||||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<vector android:autoMirrored="true" android:height="24dp"
|
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
|
|
||||||
</vector>
|
|
@ -1,25 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Nextcloud Talk application
|
|
||||||
~
|
|
||||||
~ @author Mario Danic
|
|
||||||
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
|
||||||
~
|
|
||||||
~ This program is free software: you can redistribute it and/or modify
|
|
||||||
~ it under the terms of the GNU General Public License as published by
|
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
|
||||||
~ at your option) any later version.
|
|
||||||
~
|
|
||||||
~ This program is distributed in the hope that it will be useful,
|
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
~ GNU General Public License for more details.
|
|
||||||
~
|
|
||||||
~ You should have received a copy of the GNU General Public License
|
|
||||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<vector android:autoMirrored="true" android:height="24dp"
|
|
||||||
android:viewportHeight="16.0" android:viewportWidth="16.0"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FF000000" android:pathData="m9.236,2.166 l-3.182,3.184c-0.707,0.707 -1.038,1.618 -0.988,2.457 0.05,0.839 0.433,1.584 0.988,2.139l1.412,-1.416c-0.567,-0.567 -0.544,-1.219 0.002,-1.766l3.181,-3.182c0.525,-0.525 1.251,-0.523 1.772,-0.002 0.482,0.556 0.527,1.238 -0.004,1.77l-0.82,0.82c0.555,0.785 0.645,1.366 0.593,2.234l1.641,-1.641c1.237,-1.237 1.237,-3.365 0,-4.602 -1.236,-1.236 -3.342,-1.211 -4.596,0.004zM9.943,6.051 L8.529,7.469c0,0 0.003,0 0.004,0 0.55,0.55 0.507,1.258 -0.004,1.77l-3.182,3.182c-0.696,0.592 -1.298,0.471 -1.77,0 -0.626,-0.626 -0.5,-1.268 0,-1.768l0.85,-0.847c-0.556,-0.784 -0.648,-1.365 -0.598,-2.232l-1.666,1.666c-1.239,1.239 -1.236,3.36 0,4.596 1.235,1.235 3.362,1.236 4.598,0l3.182,-3.182c0.709,-0.708 1.04,-1.618 0.991,-2.459 -0.048,-0.84 -0.432,-1.586 -0.989,-2.141z"/>
|
|
||||||
</vector>
|
|
@ -93,7 +93,7 @@
|
|||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/initial_relative_layout"
|
android:id="@+id/public_conversation_create"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
@ -124,7 +124,7 @@
|
|||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/secondary_relative_layout"
|
android:id="@+id/public_conversation_info"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
@ -178,40 +178,6 @@
|
|||||||
android:textAppearance="@style/ListItem" />
|
android:textAppearance="@style/ListItem" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/join_conversation_via_link"
|
|
||||||
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">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/join_conversation_via_link_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/ic_public_black_24px"
|
|
||||||
app:tint="@color/white" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_toEndOf="@id/join_conversation_via_link_image"
|
|
||||||
android:ellipsize="middle"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/nc_join_via_link"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textAppearance="@style/ListItem" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/controller_generic_rv"
|
android:id="@+id/controller_generic_rv"
|
||||||
layout="@layout/controller_generic_rv" />
|
layout="@layout/controller_generic_rv" />
|
||||||
|
@ -75,36 +75,36 @@
|
|||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/conversation_info_name"
|
android:id="@+id/conversation_info_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/standard_margin"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:layout_marginEnd="@dimen/standard_margin"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/avatar_image"
|
||||||
|
android:layout_width="@dimen/avatar_size_big"
|
||||||
|
android:layout_height="@dimen/avatar_size_big"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginTop="@dimen/standard_margin"
|
||||||
|
android:contentDescription="@string/avatar"
|
||||||
|
tools:src="@drawable/account_circle_48dp" />
|
||||||
|
|
||||||
|
<androidx.emoji2.widget.EmojiTextView
|
||||||
|
android:id="@+id/display_name_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
android:layout_below="@id/avatar_image"
|
||||||
android:animateLayoutChanges="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:visibility="gone"
|
android:layout_marginTop="@dimen/margin_between_elements"
|
||||||
tools:visibility="visible"
|
android:textSize="@dimen/headline_text_size"
|
||||||
android:layout_marginStart="@dimen/standard_margin"
|
tools:text="Jane Doe" />
|
||||||
android:layout_marginEnd="@dimen/standard_margin">
|
|
||||||
|
|
||||||
<ImageView
|
</RelativeLayout>
|
||||||
android:id="@+id/avatar_image"
|
|
||||||
android:layout_width="@dimen/avatar_size_big"
|
|
||||||
android:layout_height="@dimen/avatar_size_big"
|
|
||||||
android:layout_marginTop="@dimen/standard_margin"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:contentDescription="@string/avatar"
|
|
||||||
tools:src="@drawable/account_circle_48dp" />
|
|
||||||
|
|
||||||
<androidx.emoji2.widget.EmojiTextView
|
|
||||||
android:id="@+id/display_name_text"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/avatar_image"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_marginTop="@dimen/margin_between_elements"
|
|
||||||
android:textSize="@dimen/headline_text_size"
|
|
||||||
tools:text="Jane Doe" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/conversation_description"
|
android:id="@+id/conversation_description"
|
||||||
@ -119,43 +119,41 @@
|
|||||||
android:id="@+id/description_text"
|
android:id="@+id/description_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/standard_half_margin"
|
|
||||||
android:layout_marginBottom="@dimen/standard_half_margin"
|
|
||||||
android:layout_marginStart="@dimen/standard_margin"
|
android:layout_marginStart="@dimen/standard_margin"
|
||||||
|
android:layout_marginTop="@dimen/standard_half_margin"
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
android:layout_marginEnd="@dimen/standard_margin"
|
||||||
|
android:layout_marginBottom="@dimen/standard_half_margin"
|
||||||
android:autoLink="web"
|
android:autoLink="web"
|
||||||
tools:text="Hello world!" />
|
tools:text="Hello world!" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/add_to_favorites_button"
|
android:id="@+id/add_to_favorites_button"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="@dimen/standard_half_padding"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
android:background="@color/transparent"
|
||||||
android:orientation="horizontal"
|
app:icon="@drawable/ic_star_black_24dp"
|
||||||
android:padding="@dimen/standard_half_padding"
|
app:iconGravity="textStart"
|
||||||
android:visibility="gone"
|
app:iconSize="@dimen/sm_icon_height"
|
||||||
tools:visibility="gone">
|
app:iconTint="@color/grey_600" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/nc_add_to_favorites"
|
||||||
|
android:textSize="@dimen/two_line_primary_text_size" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
</LinearLayout>
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/transparent"
|
|
||||||
app:icon="@drawable/ic_star_black_24dp"
|
|
||||||
app:iconGravity="textStart"
|
|
||||||
app:iconSize="@dimen/sm_icon_height"
|
|
||||||
app:iconTint="@color/grey_600" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="@string/nc_add_to_favorites"
|
|
||||||
android:textSize="@dimen/two_line_primary_text_size" />
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/settings"
|
android:id="@+id/settings"
|
||||||
@ -187,251 +185,244 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/shared_items"
|
android:id="@+id/shared_items"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/shared_items_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
android:padding="@dimen/standard_padding"
|
||||||
android:orientation="vertical"
|
android:text="@string/nc_shared_items"
|
||||||
>
|
android:textSize="@dimen/headline_text_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/shared_items_button"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="@dimen/standard_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="@dimen/standard_margin"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_folder_multiple_image"
|
||||||
|
app:tint="@color/grey_600" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/shared_items_title"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:gravity="center_vertical"
|
||||||
android:text="@string/nc_shared_items"
|
android:text="@string/nc_shared_items_description"
|
||||||
android:textSize="@dimen/headline_text_size"
|
android:textSize="@dimen/two_line_primary_text_size" />
|
||||||
android:textStyle="bold"
|
|
||||||
android:padding="@dimen/standard_padding"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/shared_items_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/standard_padding"
|
|
||||||
android:background="?android:attr/selectableItemBackground">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:src="@drawable/ic_folder_multiple_image"
|
|
||||||
app:tint="@color/grey_600" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="@string/nc_shared_items_description"
|
|
||||||
android:textSize="@dimen/two_line_primary_text_size" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/conversation_settings"
|
android:id="@+id/conversation_settings"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/conversation_settings_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
android:padding="@dimen/standard_padding"
|
||||||
android:orientation="vertical"
|
android:text="@string/nc_conversation_settings"
|
||||||
>
|
android:textSize="@dimen/headline_text_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/conversation_settings_title"
|
android:id="@+id/conversation_info_chat_settings_input_layout"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/standard_margin"
|
||||||
|
android:layout_marginTop="@dimen/standard_half_margin"
|
||||||
|
android:hint="@string/nc_expire_messages">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
|
android:id="@+id/conversation_settings_dropdown"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/nc_conversation_settings"
|
android:inputType="none"
|
||||||
android:textSize="@dimen/headline_text_size"
|
android:lines="1"
|
||||||
android:textStyle="bold"
|
android:popupTheme="@style/ThemeOverlay.AppTheme.PopupMenu"
|
||||||
android:padding="@dimen/standard_padding"/>
|
android:text="" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:id="@+id/conversation_info_chat_settings_input_layout"
|
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/standard_half_margin"
|
|
||||||
android:layout_marginHorizontal="@dimen/standard_margin"
|
|
||||||
android:hint="@string/nc_expire_messages">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
|
||||||
android:id="@+id/conversation_settings_dropdown"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:inputType="none"
|
|
||||||
android:lines="1"
|
|
||||||
android:popupTheme="@style/ThemeOverlay.AppTheme.PopupMenu"
|
|
||||||
android:text="" />
|
|
||||||
|
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/conversation_info_expire_messages_explanation"
|
android:id="@+id/conversation_info_expire_messages_explanation"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="@dimen/standard_margin"
|
android:layout_margin="@dimen/standard_margin"
|
||||||
android:text="@string/nc_expire_messages_explanation"
|
android:text="@string/nc_expire_messages_explanation"
|
||||||
android:textColor="@color/disabled_text"
|
android:textColor="@color/disabled_text"
|
||||||
android:textSize="@dimen/supporting_text_text_size"/>
|
android:textSize="@dimen/supporting_text_text_size" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/participants"
|
android:id="@+id/participants"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="UnknownIdInLayout"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/participants_list_category"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="@dimen/standard_padding"
|
||||||
|
android:text="@string/nc_participants"
|
||||||
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:textSize="@dimen/headline_text_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/addParticipantsAction"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
android:visibility="gone"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
tools:ignore="UnknownIdInLayout"
|
android:orientation="horizontal"
|
||||||
tools:visibility="visible"
|
android:padding="@dimen/standard_padding">
|
||||||
android:orientation="vertical">
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="@dimen/standard_margin"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_account_plus"
|
||||||
|
app:tint="@color/grey_600" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/participants_list_category"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:gravity="center_vertical"
|
||||||
android:padding="@dimen/standard_padding"
|
android:text="@string/nc_participants_add"
|
||||||
android:text="@string/nc_participants"
|
android:textSize="@dimen/two_line_primary_text_size" />
|
||||||
android:textColor="@color/colorPrimary"
|
|
||||||
android:textSize="@dimen/headline_text_size"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/addParticipantsAction"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/standard_padding"
|
|
||||||
android:background="?android:attr/selectableItemBackground">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:src="@drawable/ic_account_plus"
|
|
||||||
app:tint="@color/grey_600" />
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="@string/nc_participants_add"
|
|
||||||
android:textSize="@dimen/two_line_primary_text_size" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/recycler_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
tools:listitem="@layout/rv_item_conversation_info_participant" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:listitem="@layout/rv_item_conversation_info_participant" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/danger_zone_options"
|
android:id="@+id/danger_zone_options"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="@dimen/standard_padding"
|
||||||
|
android:text="@string/danger_zone"
|
||||||
|
android:textColor="@color/design_default_color_error"
|
||||||
|
android:textSize="@dimen/headline_text_size"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/leaveConversationAction"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
android:orientation="vertical"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
>
|
android:orientation="horizontal"
|
||||||
|
android:padding="@dimen/standard_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="@dimen/standard_margin"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_exit_to_app_black_24dp"
|
||||||
|
app:tint="@color/design_default_color_error" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:text="@string/danger_zone"
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/nc_leave"
|
||||||
android:textColor="@color/design_default_color_error"
|
android:textColor="@color/design_default_color_error"
|
||||||
android:textSize="@dimen/headline_text_size"
|
android:textSize="@dimen/two_line_primary_text_size" />
|
||||||
android:textStyle="bold"
|
|
||||||
android:padding="@dimen/standard_padding"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/leaveConversationAction"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/standard_padding"
|
|
||||||
android:background="?android:attr/selectableItemBackground">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:src="@drawable/ic_exit_to_app_black_24dp"
|
|
||||||
app:tint="@color/design_default_color_error" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="@string/nc_leave"
|
|
||||||
android:textColor="@color/design_default_color_error"
|
|
||||||
android:textSize="@dimen/two_line_primary_text_size" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/clearConversationHistory"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/standard_padding"
|
|
||||||
android:background="?android:attr/selectableItemBackground">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:src="@drawable/ic_delete_black_24dp"
|
|
||||||
app:tint="@color/design_default_color_error" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="@string/nc_clear_history"
|
|
||||||
android:textColor="@color/design_default_color_error"
|
|
||||||
android:textSize="@dimen/two_line_primary_text_size" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/deleteConversationAction"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/standard_quarter_margin"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:padding="@dimen/standard_padding"
|
|
||||||
android:background="?android:attr/selectableItemBackground">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_marginEnd="@dimen/standard_margin"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:src="@drawable/ic_delete_black_24dp"
|
|
||||||
app:tint="@color/design_default_color_error" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:text="@string/nc_delete_call"
|
|
||||||
android:textColor="@color/design_default_color_error"
|
|
||||||
android:textSize="@dimen/two_line_primary_text_size" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/clearConversationHistory"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="@dimen/standard_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="@dimen/standard_margin"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_delete_black_24dp"
|
||||||
|
app:tint="@color/design_default_color_error" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/nc_clear_history"
|
||||||
|
android:textColor="@color/design_default_color_error"
|
||||||
|
android:textSize="@dimen/two_line_primary_text_size" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/deleteConversationAction"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/standard_quarter_margin"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="@dimen/standard_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="@dimen/standard_margin"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_delete_black_24dp"
|
||||||
|
app:tint="@color/design_default_color_error" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/nc_delete_call"
|
||||||
|
android:textColor="@color/design_default_color_error"
|
||||||
|
android:textSize="@dimen/two_line_primary_text_size" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
|
||||||
~ Nextcloud Talk application
|
|
||||||
~
|
|
||||||
~ @author Mario Danic
|
|
||||||
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
|
||||||
~
|
|
||||||
~ This program is free software: you can redistribute it and/or modify
|
|
||||||
~ it under the terms of the GNU General Public License as published by
|
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
|
||||||
~ at your option) any later version.
|
|
||||||
~
|
|
||||||
~ This program is distributed in the hope that it will be useful,
|
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
~ GNU General Public License for more details.
|
|
||||||
~
|
|
||||||
~ You should have received a copy of the GNU General Public License
|
|
||||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/controller_operations_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/result_image_view"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:layout_marginTop="24dp"
|
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:tintMode="src_in"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progress_bar"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_marginTop="24dp"
|
|
||||||
android:layout_marginBottom="24dp"
|
|
||||||
android:indeterminate="true"
|
|
||||||
android:indeterminateTint="@color/colorPrimary"
|
|
||||||
android:indeterminateTintMode="src_in"
|
|
||||||
android:keepScreenOn="true" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/result_text_view"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/result_image_view"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:maxLines="3"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textColor="@color/colorPrimary"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/ok_button"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/result_text_view"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:background="@color/bg_inverse"
|
|
||||||
android:text="@string/nc_ok"
|
|
||||||
android:textColor="@color/colorPrimary"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/web_button"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/result_text_view"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:layout_toStartOf="@id/ok_button"
|
|
||||||
android:background="@color/bg_inverse"
|
|
||||||
android:text="@string/nc_join_via_web"
|
|
||||||
android:textColor="@color/nc_darkGreen"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -1,31 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Nextcloud Talk application
|
|
||||||
~
|
|
||||||
~ @author Marcel Hibbe
|
|
||||||
~ @author Andy Scherzinger
|
|
||||||
~ Copyright (C) 2022 Andy Scherzinger <info@andy-scherzinger.de>
|
|
||||||
~ Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
|
||||||
~
|
|
||||||
~ This program is free software: you can redistribute it and/or modify
|
|
||||||
~ it under the terms of the GNU General Public License as published by
|
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
|
||||||
~ at your option) any later version.
|
|
||||||
~
|
|
||||||
~ This program is distributed in the hope that it will be useful,
|
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
~ GNU General Public License for more details.
|
|
||||||
~
|
|
||||||
~ You should have received a copy of the GNU General Public License
|
|
||||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingStart="@dimen/standard_padding"
|
|
||||||
android:paddingEnd="@dimen/standard_padding"
|
|
||||||
android:paddingBottom="@dimen/standard_half_padding">
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -47,7 +47,7 @@
|
|||||||
tools:text="conversation name" />
|
tools:text="conversation name" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/conversation_operation_remove_favorite"
|
android:id="@+id/conversation_remove_from_favorites"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/bottom_sheet_item_height"
|
android:layout_height="@dimen/bottom_sheet_item_height"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
@ -77,7 +77,7 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/conversation_operation_add_favorite"
|
android:id="@+id/conversation_add_to_favorites"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/bottom_sheet_item_height"
|
android:layout_height="@dimen/bottom_sheet_item_height"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
@ -107,7 +107,7 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/conversation_operation_mark_as_read"
|
android:id="@+id/conversation_mark_as_read"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/bottom_sheet_item_height"
|
android:layout_height="@dimen/bottom_sheet_item_height"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
@ -137,7 +137,7 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/conversation_operation_mark_as_unread"
|
android:id="@+id/conversation_mark_as_unread"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/bottom_sheet_item_height"
|
android:layout_height="@dimen/bottom_sheet_item_height"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
@ -27,22 +27,6 @@
|
|||||||
android:paddingTop="@dimen/standard_padding"
|
android:paddingTop="@dimen/standard_padding"
|
||||||
android:paddingEnd="@dimen/standard_half_padding">
|
android:paddingEnd="@dimen/standard_half_padding">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/ok_button"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/text_input_layout"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_marginTop="@dimen/standard_half_margin"
|
|
||||||
android:layout_marginBottom="@dimen/standard_half_margin"
|
|
||||||
android:alpha="0.7"
|
|
||||||
android:background="@color/bg_default"
|
|
||||||
android:enabled="false"
|
|
||||||
android:text="@string/nc_proceed"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="@color/colorPrimary" />
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/text_input_layout"
|
android:id="@+id/text_input_layout"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
@ -77,7 +61,6 @@
|
|||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
android:contentDescription="@string/nc_add_emojis"
|
android:contentDescription="@string/nc_add_emojis"
|
||||||
android:src="@drawable/ic_insert_emoticon_black_24dp"
|
android:src="@drawable/ic_insert_emoticon_black_24dp"
|
||||||
android:visibility="gone"
|
|
||||||
app:tint="@color/medium_emphasis_text"
|
app:tint="@color/medium_emphasis_text"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
69
app/src/main/res/layout/dialog_rename_conversation.xml
Normal file
69
app/src/main/res/layout/dialog_rename_conversation.xml
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ @author Marcel Hibbe
|
||||||
|
~ Copyright (C) 2023 Marcel Hibbe <dev@mhibbe.de>
|
||||||
|
~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<RelativeLayout 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="wrap_content"
|
||||||
|
android:paddingStart="@dimen/standard_padding"
|
||||||
|
android:paddingTop="@dimen/standard_padding"
|
||||||
|
android:paddingEnd="@dimen/standard_half_padding">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/text_input_layout"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="@dimen/standard_half_margin"
|
||||||
|
android:layout_toStartOf="@id/smileyButton"
|
||||||
|
app:errorTextAppearance="@style/ErrorAppearance"
|
||||||
|
app:passwordToggleTint="@color/grey_600"
|
||||||
|
app:boxStrokeColor="@color/colorPrimary"
|
||||||
|
app:hintTextColor="@color/colorPrimary">
|
||||||
|
|
||||||
|
<com.nextcloud.talk.utils.EmojiTextInputEditText
|
||||||
|
android:id="@+id/text_edit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="textUri"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textColor="@color/high_emphasis_text" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/smileyButton"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_alignBottom="@id/text_input_layout"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_marginStart="-4dp"
|
||||||
|
android:background="@color/transparent"
|
||||||
|
android:contentDescription="@string/nc_add_emojis"
|
||||||
|
android:src="@drawable/ic_insert_emoticon_black_24dp"
|
||||||
|
app:tint="@color/medium_emphasis_text"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -44,7 +44,6 @@
|
|||||||
|
|
||||||
<color name="bg_default">#121212</color>
|
<color name="bg_default">#121212</color>
|
||||||
<color name="bg_default_semitransparent">#99121212</color>
|
<color name="bg_default_semitransparent">#99121212</color>
|
||||||
<color name="bg_inverse">@color/grey950</color>
|
|
||||||
|
|
||||||
<color name="fg_default">#FFFFFF</color>
|
<color name="fg_default">#FFFFFF</color>
|
||||||
<color name="fg_inverse">#121212</color>
|
<color name="fg_inverse">#121212</color>
|
||||||
|
@ -74,7 +74,6 @@
|
|||||||
|
|
||||||
<color name="bg_default">#FFFFFF</color>
|
<color name="bg_default">#FFFFFF</color>
|
||||||
<color name="bg_default_semitransparent">#99FFFFFF</color>
|
<color name="bg_default_semitransparent">#99FFFFFF</color>
|
||||||
<color name="bg_inverse">@color/grey950</color>
|
|
||||||
<color name="bg_dark_mention_chips">#333333</color>
|
<color name="bg_dark_mention_chips">#333333</color>
|
||||||
|
|
||||||
<color name="bg_message_list_incoming_bubble">#EFEFEF</color>
|
<color name="bg_message_list_incoming_bubble">#EFEFEF</color>
|
||||||
|
@ -49,6 +49,8 @@ How to translate with transifex:
|
|||||||
<string name="nc_common_set">Set</string>
|
<string name="nc_common_set">Set</string>
|
||||||
<string name="nc_common_dismiss">Dismiss</string>
|
<string name="nc_common_dismiss">Dismiss</string>
|
||||||
<string name="nc_common_error_sorry">Sorry, something went wrong!</string>
|
<string name="nc_common_error_sorry">Sorry, something went wrong!</string>
|
||||||
|
<string name="nc_common_create">Create</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- Bottom Navigation -->
|
<!-- Bottom Navigation -->
|
||||||
<string name="nc_settings">Settings</string>
|
<string name="nc_settings">Settings</string>
|
||||||
@ -168,10 +170,6 @@ How to translate with transifex:
|
|||||||
<string name="nc_cancel">Cancel</string>
|
<string name="nc_cancel">Cancel</string>
|
||||||
|
|
||||||
<string name="nc_no_proxy">No proxy</string>
|
<string name="nc_no_proxy">No proxy</string>
|
||||||
<string name="nc_password">Password</string>
|
|
||||||
<string name="nc_conversation_link">Conversation link</string>
|
|
||||||
<string name="nc_new_password">New password</string>
|
|
||||||
<string name="nc_wrong_password">Wrong password</string>
|
|
||||||
<string name="nc_about">About</string>
|
<string name="nc_about">About</string>
|
||||||
<string name="nc_privacy">Privacy</string>
|
<string name="nc_privacy">Privacy</string>
|
||||||
<string name="nc_get_source_code">Get source code</string>
|
<string name="nc_get_source_code">Get source code</string>
|
||||||
@ -190,20 +188,27 @@ How to translate with transifex:
|
|||||||
<string name="nc_clear_history_warning">Do you really want to delete all messages in this conversation?</string>
|
<string name="nc_clear_history_warning">Do you really want to delete all messages in this conversation?</string>
|
||||||
<string name="nc_clear_history_success">All messages were deleted</string>
|
<string name="nc_clear_history_success">All messages were deleted</string>
|
||||||
<string name="nc_rename">Rename conversation</string>
|
<string name="nc_rename">Rename conversation</string>
|
||||||
|
<string name="nc_rename_confirm">Rename</string>
|
||||||
<string name="nc_delete_call">Delete conversation</string>
|
<string name="nc_delete_call">Delete conversation</string>
|
||||||
<string name="nc_delete">Delete</string>
|
<string name="nc_delete">Delete</string>
|
||||||
<string name="nc_delete_all">Delete all</string>
|
<string name="nc_delete_all">Delete all</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_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_join_via_link">Join with a link</string>
|
|
||||||
<string name="nc_list_open_conversations">List open conversations</string>
|
<string name="nc_list_open_conversations">List open conversations</string>
|
||||||
<string name="nc_join_via_web">Join via web</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>
|
||||||
<string name="nc_remove_from_favorites">Remove from favorites</string>
|
<string name="nc_remove_from_favorites">Remove from favorites</string>
|
||||||
|
|
||||||
|
<string name="added_to_favorites">Added conversation %1$s to favorites</string>
|
||||||
|
<string name="removed_from_favorites">Removed conversation %1$s from favorites</string>
|
||||||
|
<string name="marked_as_unread">Marked conversation %1$s as unread</string>
|
||||||
|
<string name="marked_as_read">Marked conversation %1$s as read</string>
|
||||||
|
<string name="deleted_conversation">Deleted conversation %1$s</string>
|
||||||
|
<string name="left_conversation">You left the conversation %1$s</string>
|
||||||
|
<string name="renamed_conversation">Conversation %1$s was renamed</string>
|
||||||
|
|
||||||
<string name="nc_forward_to_three_dots">Forward to …</string>
|
<string name="nc_forward_to_three_dots">Forward to …</string>
|
||||||
|
|
||||||
<!-- Open conversations -->
|
<!-- Open conversations -->
|
||||||
@ -279,16 +284,10 @@ How to translate with transifex:
|
|||||||
<string name="nc_important_conversation">Important conversation</string>
|
<string name="nc_important_conversation">Important conversation</string>
|
||||||
<string name="nc_important_conversation_desc">Notifications in this conversation will override Do Not Disturb settings</string>
|
<string name="nc_important_conversation_desc">Notifications in this conversation will override Do Not Disturb settings</string>
|
||||||
|
|
||||||
<!-- Bottom sheet menu -->
|
|
||||||
<string name="nc_failed_to_perform_operation">Sorry, something went wrong!</string>
|
|
||||||
<string name="nc_failed_signaling_settings">Target server does not support joining public conversations via mobile phones. You may attempt to join the conversation via web browser.</string>
|
|
||||||
<string name="nc_all_ok_operation">OK, all done!</string>
|
<string name="nc_all_ok_operation">OK, all done!</string>
|
||||||
<string name="nc_ok">OK</string>
|
<string name="nc_ok">OK</string>
|
||||||
<string name="nc_call_name">Conversation name</string>
|
<string name="nc_call_name">Conversation name</string>
|
||||||
<string name="nc_proceed">Proceed</string>
|
|
||||||
<string name="nc_add_emojis">Add emojis</string>
|
<string name="nc_add_emojis">Add emojis</string>
|
||||||
<string name="nc_call_name_is_same">The name you entered is the same as the existing one</string>
|
|
||||||
<string name="nc_wrong_link">Conversation link is not valid</string>
|
|
||||||
<string name="nc_share_text">Join the conversation at %1$s/index.php/call/%2$s</string>
|
<string name="nc_share_text">Join the conversation at %1$s/index.php/call/%2$s</string>
|
||||||
<string name="nc_share_subject">%1$s invitation</string>
|
<string name="nc_share_subject">%1$s invitation</string>
|
||||||
<string name="nc_share_text_pass">\nPassword: %1$s</string>
|
<string name="nc_share_text_pass">\nPassword: %1$s</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user