From 6d0144db1af31b5904bb9b74a6e07a0a7cf43b2c Mon Sep 17 00:00:00 2001 From: sowjanyakch Date: Fri, 16 Aug 2024 23:31:12 +0200 Subject: [PATCH] add participants list Signed-off-by: sowjanyakch --- .../talk/contacts/ContactsActivityCompose.kt | 48 ++--- .../talk/contacts/ContactsRepository.kt | 2 - .../talk/contacts/ContactsRepositoryImpl.kt | 27 --- .../talk/contacts/ContactsViewModel.kt | 18 +- .../ConversationCreationActivity.kt | 164 ++++++++++++++++-- .../ConversationCreationRepository.kt | 2 + .../ConversationCreationRepositoryImpl.kt | 28 +++ .../ConversationCreationViewModel.kt | 15 ++ .../ConversationsListActivity.kt | 3 +- app/src/main/res/values/strings.xml | 1 + 10 files changed, 211 insertions(+), 97 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt index d8625af87..f8d7f6f25 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsActivityCompose.kt @@ -12,7 +12,7 @@ import android.app.Activity import android.content.Context import android.content.Intent import android.os.Bundle -import android.util.Log +import android.os.Parcelable import androidx.activity.compose.setContent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -127,12 +127,12 @@ fun ContactItemRow( ) { val isSelected = contact in selectedContacts val roomUiState by contactsViewModel.roomViewState.collectAsState() - val isAddParticipants = contactsViewModel.isAddParticipantsView.value + val isAddParticipants = contactsViewModel.isAddParticipantsView.collectAsState() Row( modifier = Modifier .fillMaxWidth() .clickable { - if (!isAddParticipants) { + if (!isAddParticipants.value) { contactsViewModel.createRoom( CompanionClass.ROOM_TYPE_ONE_ONE, contact.source!!, @@ -159,7 +159,7 @@ fun ContactItemRow( modifier = Modifier.size(width = 45.dp, height = 45.dp) ) Text(modifier = Modifier.padding(16.dp), text = contact.label!!) - if (isAddParticipants) { + if (isAddParticipants.value) { if (isSelected) { Spacer(modifier = Modifier.weight(1f)) Icon( @@ -176,7 +176,6 @@ fun ContactItemRow( val conversation = (roomUiState as RoomUiState.Success).conversation val bundle = Bundle() bundle.putString(BundleKeys.KEY_ROOM_TOKEN, conversation?.token) - // bundle.putString(BundleKeys.KEY_ROOM_ID, conversation?.roomId) val chatIntent = Intent(context, ChatActivity::class.java) chatIntent.putExtras(bundle) chatIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) @@ -198,8 +197,7 @@ fun ContactItemRow( fun AppBar(title: String, context: Context, contactsViewModel: ContactsViewModel) { val searchQuery by contactsViewModel.searchQuery.collectAsState() val searchState = contactsViewModel.searchState.collectAsState() - val addParticipantsUiState = contactsViewModel.addParticipantsUiState.collectAsState() - val conversationToken:String? = null + val isAddParticipants = contactsViewModel.isAddParticipantsView.collectAsState() TopAppBar( title = { Text(text = title) }, @@ -216,42 +214,22 @@ fun AppBar(title: String, context: Context, contactsViewModel: ContactsViewModel }) { Icon(Icons.Filled.Search, contentDescription = stringResource(R.string.search_icon)) } - if (contactsViewModel.isAddParticipantsView.value) { + if (isAddParticipants.value) { Text( text = stringResource(id = R.string.nc_contacts_done), modifier = Modifier.clickable { - for(contacts in contactsViewModel.selectedParticipantsList){ - contacts.let { contact -> - contactsViewModel.addParticipants( - conversationToken, - contact.id!!, - contact.source!! - ) - } - } + val selectedParticipants: List = contactsViewModel.selectedParticipantsList + val intent = Intent(context, ConversationCreationActivity::class.java) + intent.putParcelableArrayListExtra( + "selectedParticipants", + selectedParticipants as ArrayList + ) + context.startActivity(intent) } ) } } ) - val state = addParticipantsUiState.value - when(state){ - is AddParticipantsUiState.Error -> { - val errorMessage = state.message - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Text(text = "Error: $errorMessage", color = Color.Red) - } - - } - is AddParticipantsUiState.None -> { - - - } - is AddParticipantsUiState.Success -> { - val conversation = state.participants - Log.d("ContactsActivityCompose", "$conversation") - } - } if (searchState.value) { Row { DisplaySearch( diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt index e610909c2..8655b79e1 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepository.kt @@ -9,11 +9,9 @@ package com.nextcloud.talk.contacts import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall import com.nextcloud.talk.models.json.conversations.RoomOverall -import com.nextcloud.talk.models.json.participants.AddParticipantOverall interface ContactsRepository { suspend fun getContacts(searchQuery: String?, shareTypes: List): AutocompleteOverall suspend fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?): RoomOverall fun getImageUri(avatarId: String, requestBigSize: Boolean): String - suspend fun addParticipants(conversationToken: String?, userId: String, sourceType: String): AddParticipantOverall } diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt index 04634ff4c..6fcd27512 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt @@ -12,11 +12,8 @@ import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.RetrofitBucket import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall import com.nextcloud.talk.models.json.conversations.RoomOverall -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.ApiUtils.getRetrofitBucketForAddParticipant -import com.nextcloud.talk.utils.ApiUtils.getRetrofitBucketForAddParticipantWithSource import com.nextcloud.talk.utils.ContactUtils class ContactsRepositoryImpl( @@ -75,28 +72,4 @@ class ContactsRepositoryImpl( requestBigSize ) } - - override suspend fun addParticipants( - conversationToken: String?, - userId: String, - sourceType: String - ): AddParticipantOverall { - val retrofitBucket: RetrofitBucket = if (sourceType == "users") { - getRetrofitBucketForAddParticipant( - apiVersion, - _currentUser.baseUrl, - conversationToken, - userId - ) - } else { - getRetrofitBucketForAddParticipantWithSource( - apiVersion, - _currentUser.baseUrl, - conversationToken, - sourceType, - userId - ) - } - return ncApiCoroutines.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap) - } } diff --git a/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt b/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt index ac0c7596a..7cbf47db4 100644 --- a/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/contacts/ContactsViewModel.kt @@ -24,18 +24,16 @@ class ContactsViewModel @Inject constructor( val contactsViewState: StateFlow = _contactsViewState private val _roomViewState = MutableStateFlow(RoomUiState.None) val roomViewState: StateFlow = _roomViewState - private val addParticipantsViewState = MutableStateFlow(AddParticipantsUiState.None) - val addParticipantsUiState: StateFlow = addParticipantsViewState private val _searchQuery = MutableStateFlow("") val searchQuery: StateFlow = _searchQuery private val shareTypes: MutableList = mutableListOf(ShareType.User.shareType) val shareTypeList: List = shareTypes private val _searchState = MutableStateFlow(false) val searchState: StateFlow = _searchState - private val _isAddParticipantsView = MutableStateFlow(false) - val isAddParticipantsView: StateFlow = _isAddParticipantsView private val selectedParticipants = mutableListOf() val selectedParticipantsList: List = selectedParticipants + private val _isAddParticipantsView = MutableStateFlow(false) + val isAddParticipantsView: StateFlow = _isAddParticipantsView init { getContactsFromSearchParams() @@ -75,7 +73,6 @@ class ContactsViewModel @Inject constructor( } } } - fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?) { viewModelScope.launch { try { @@ -96,17 +93,6 @@ class ContactsViewModel @Inject constructor( fun getImageUri(avatarId: String, requestBigSize: Boolean): String { return repository.getImageUri(avatarId, requestBigSize) } - fun addParticipants(conversationToken: String?, userId: String, sourceType: String){ - viewModelScope.launch { - try { - val participantsOverall = repository.addParticipants(conversationToken, userId, sourceType) - val participants = participantsOverall.ocs?.data - addParticipantsViewState.value = AddParticipantsUiState.Success(participants) - } catch (exception: Exception) { - addParticipantsViewState.value = AddParticipantsUiState.Error(exception.message ?: "") - } - } - } } sealed class ContactsUiState { diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt index 31d0c176b..2092eb8ad 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationActivity.kt @@ -10,6 +10,7 @@ package com.nextcloud.talk.conversationcreation import android.app.Activity import android.content.Context import android.content.Intent +import android.os.Build import android.os.Bundle import androidx.activity.compose.setContent import androidx.compose.foundation.clickable @@ -22,9 +23,13 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -37,9 +42,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.ViewModelProvider @@ -49,7 +56,7 @@ import com.nextcloud.talk.R import com.nextcloud.talk.activities.BaseActivity import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.contacts.ContactsActivityCompose -import com.nextcloud.talk.contacts.ContactsViewModel +import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -64,7 +71,13 @@ class ConversationCreationActivity : BaseActivity() { NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) conversationCreationViewModel = ViewModelProvider(this, viewModelFactory)[ConversationCreationViewModel::class.java] - val contactsViewModel = ViewModelProvider(this, viewModelFactory)[ContactsViewModel::class.java] + val selectedParticipants: List? = when ( + Build.VERSION.SDK_INT >= Build.VERSION_CODES + .TIRAMISU + ) { + true -> intent.getParcelableArrayListExtra("selectedParticipants") + else -> intent.extras?.getParcelableArrayList("selectedParticipants") + } ?: emptyList() setContent { val colorScheme = viewThemeUtils.getColorScheme(this) @@ -93,8 +106,9 @@ class ConversationCreationActivity : BaseActivity() { DefaultUserAvatar() UploadAvatar() ConversationNameAndDescription(conversationCreationViewModel) - AddParticipants(contactsViewModel, context) + AddParticipants(selectedParticipants, context) RoomCreationOptions(conversationCreationViewModel) + CreateConversation() } } ) @@ -192,12 +206,26 @@ fun ConversationNameAndDescription(conversationCreationViewModel: ConversationCr } @Composable -fun AddParticipants(contactsViewModel: ContactsViewModel, context: Context) { - Text( - text = stringResource(id = R.string.nc_participants).uppercase(), - fontSize = 14.sp, - modifier = Modifier.padding(top = 24.dp, start = 16.dp, end = 16.dp, bottom = 16.dp) - ) +fun AddParticipants(selectedParticipants: List?, context: Context) { + Row { + Text( + text = stringResource(id = R.string.nc_participants).uppercase(), + fontSize = 14.sp, + modifier = Modifier.padding(top = 24.dp, start = 16.dp, end = 16.dp, bottom = 16.dp) + ) + if (selectedParticipants?.isNotEmpty() == true) { + Text( + text = stringResource(id = R.string.nc_edit), + fontSize = 12.sp, + modifier = Modifier.padding(top = 24.dp, start = 16.dp, end = 16.dp, bottom = 16.dp) + .clickable { + val intent = Intent(context, ContactsActivityCompose::class.java) + context.startActivity(intent) + }, + textAlign = TextAlign.Right + ) + } + } Row( modifier = Modifier @@ -210,13 +238,27 @@ fun AddParticipants(contactsViewModel: ContactsViewModel, context: Context) { verticalAlignment = Alignment .CenterVertically ) { - Icon( - painter = painterResource(id = R.drawable.ic_account_plus), - contentDescription = null, - modifier = Modifier.size(24.dp) - ) + if (selectedParticipants?.isEmpty() == true) { + Icon( + painter = painterResource(id = R.drawable.ic_account_plus), + contentDescription = null, + modifier = Modifier.size(24.dp) + ) - Text(text = stringResource(id = R.string.nc_add_participants), modifier = Modifier.padding(start = 16.dp)) + Text(text = stringResource(id = R.string.nc_add_participants), modifier = Modifier.padding(start = 16.dp)) + } else { + LazyColumn { + items(selectedParticipants!!) { participant -> + participant.label?.let { + Text( + text = it, + modifier = Modifier.padding(all = 16.dp) + ) + } + HorizontalDivider(thickness = 0.1.dp, color = Color.Black) + } + } + } } } @@ -307,3 +349,95 @@ fun ConversationOptions(icon: Int? = null, text: Int, switch: @Composable (() -> switch?.invoke() } } + +@Composable +fun CreateConversation() { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(all = 16.dp), + contentAlignment = Alignment.Center + ) { + Button( + onClick = { + } + ) { + Text(text = stringResource(id = R.string.create_conversation)) + } + } +} + +// +// @SuppressLint("UnrememberedMutableState") +// @OptIn(ExperimentalMaterial3Api::class) +// @Composable +// fun AppBar(title: String, context: Context, contactsViewModel: ContactsViewModel) { +// val searchQuery by contactsViewModel.searchQuery.collectAsState() +// val searchState = contactsViewModel.searchState.collectAsState() +// val addParticipantsUiState = contactsViewModel.addParticipantsUiState.collectAsState() +// val conversationToken:String? = null +// +// TopAppBar( +// title = { Text(text = title) }, +// navigationIcon = { +// IconButton(onClick = { +// (context as? Activity)?.finish() +// }) { +// Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.back_button)) +// } +// }, +// actions = { +// IconButton(onClick = { +// contactsViewModel.updateSearchState(true) +// }) { +// Icon(Icons.Filled.Search, contentDescription = stringResource(R.string.search_icon)) +// } +// if (contactsViewModel.isAddParticipantsView.value) { +// Text( +// text = stringResource(id = R.string.nc_contacts_done), +// modifier = Modifier.clickable { +// for(contacts in contactsViewModel.selectedParticipantsList){ +// contacts.let { contact -> +// contactsViewModel.addParticipants( +// conversationToken, +// contact.id!!, +// contact.source!! +// ) +// } +// } +// } +// ) +// } +// } +// ) +// val state = addParticipantsUiState.value +// when(state){ +// is AddParticipantsUiState.Error -> { +// val errorMessage = state.message +// Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { +// Text(text = "Error: $errorMessage", color = Color.Red) +// } +// +// } +// is AddParticipantsUiState.None -> { +// +// +// } +// is AddParticipantsUiState.Success -> { +// val conversation = state.participants +// Log.d("ContactsActivityCompose", "$conversation") +// } +// } +// if (searchState.value) { +// Row { +// DisplaySearch( +// text = searchQuery, +// onTextChange = { searchQuery -> +// contactsViewModel.updateSearchQuery(query = searchQuery) +// contactsViewModel.getContactsFromSearchParams() +// }, +// contactsViewModel = contactsViewModel +// ) +// } +// } +// } diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt index d241e8993..889b89849 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepository.kt @@ -8,8 +8,10 @@ package com.nextcloud.talk.conversationcreation import com.nextcloud.talk.models.json.generic.GenericOverall +import com.nextcloud.talk.models.json.participants.AddParticipantOverall interface ConversationCreationRepository { suspend fun renameConversation(roomToken: String, roomNameNew: String?): GenericOverall suspend fun setConversationDescription(roomToken: String, description: String?): GenericOverall + suspend fun addParticipants(conversationToken: String?, userId: String, sourceType: String): AddParticipantOverall } diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt index ab41d84f9..bfac8a244 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationRepositoryImpl.kt @@ -9,9 +9,13 @@ package com.nextcloud.talk.conversationcreation import com.nextcloud.talk.api.NcApiCoroutines import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.RetrofitBucket 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.ApiUtils.getRetrofitBucketForAddParticipant +import com.nextcloud.talk.utils.ApiUtils.getRetrofitBucketForAddParticipantWithSource class ConversationCreationRepositoryImpl( private val ncApiCoroutines: NcApiCoroutines, @@ -45,4 +49,28 @@ class ConversationCreationRepositoryImpl( description ) } + + override suspend fun addParticipants( + conversationToken: String?, + userId: String, + sourceType: String + ): AddParticipantOverall { + val retrofitBucket: RetrofitBucket = if (sourceType == "users") { + getRetrofitBucketForAddParticipant( + apiVersion, + _currentUser.baseUrl, + conversationToken, + userId + ) + } else { + getRetrofitBucketForAddParticipantWithSource( + apiVersion, + _currentUser.baseUrl, + conversationToken, + sourceType, + userId + ) + } + return ncApiCoroutines.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap) + } } diff --git a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt index 9ba08cbec..25b13daea 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationcreation/ConversationCreationViewModel.kt @@ -11,6 +11,7 @@ import android.util.Log import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.nextcloud.talk.contacts.AddParticipantsUiState import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -28,6 +29,9 @@ class ConversationCreationViewModel @Inject constructor( var isConversationAvailableForRegisteredUsers = mutableStateOf(false) var openForGuestAppUsers = mutableStateOf(false) + private val addParticipantsViewState = MutableStateFlow(AddParticipantsUiState.None) + val addParticipantsUiState: StateFlow = addParticipantsViewState + fun updateRoomName(roomName: String) { _roomName.value = roomName } @@ -54,4 +58,15 @@ class ConversationCreationViewModel @Inject constructor( } } } + fun addParticipants(conversationToken: String?, userId: String, sourceType: String) { + viewModelScope.launch { + try { + val participantsOverall = repository.addParticipants(conversationToken, userId, sourceType) + val participants = participantsOverall.ocs?.data + addParticipantsViewState.value = AddParticipantsUiState.Success(participants) + } catch (exception: Exception) { + addParticipantsViewState.value = AddParticipantsUiState.Error(exception.message ?: "") + } + } + } } diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index d7ef33ffc..9b9d74f54 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -79,7 +79,6 @@ import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager import com.nextcloud.talk.chat.ChatActivity -import com.nextcloud.talk.contacts.ContactsActivity import com.nextcloud.talk.contacts.ContactsActivityCompose import com.nextcloud.talk.conversationlist.viewmodels.ConversationsListViewModel import com.nextcloud.talk.data.network.NetworkMonitor @@ -1067,7 +1066,7 @@ class ConversationsListActivity : conversation.type === ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL private fun showNewConversationsScreen() { - val intent = Intent(context, ContactsActivity::class.java) + val intent = Intent(context, ContactsActivityCompose::class.java) intent.putExtra(KEY_NEW_CONVERSATION, true) startActivity(intent) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8c3d0f3ef..eba1ad002 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -567,6 +567,7 @@ How to translate with transifex: No phone number integration due to missing permissions Chat via %s Account not found + Edit Save