mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-18 20:29:10 +03:00
Add InviteUsersToRoomActivity and mvrx classes.
This commit is contained in:
parent
a4eba653a3
commit
57a87ba620
17 changed files with 347 additions and 1 deletions
|
@ -28,6 +28,7 @@ import im.vector.matrix.android.api.session.room.send.UserDraft
|
|||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.api.util.toOptional
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
|
@ -95,6 +96,10 @@ class RxRoom(private val room: Room) {
|
|||
fun liveNotificationState(): Observable<RoomNotificationState> {
|
||||
return room.getLiveRoomNotificationState().asObservable()
|
||||
}
|
||||
|
||||
fun invite(userId: String, reason: String? = null): Completable = completableBuilder<Unit> {
|
||||
room.invite(userId, reason, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun Room.rx(): RxRoom {
|
||||
|
|
|
@ -39,6 +39,8 @@ internal class DefaultInviteTask @Inject constructor(
|
|||
return executeRequest(eventBus) {
|
||||
val body = InviteBody(params.userId, params.reason)
|
||||
apiCall = roomAPI.invite(params.roomId, body)
|
||||
isRetryable = true
|
||||
maxRetryCount = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
</activity>
|
||||
<activity android:name=".features.debug.DebugMenuActivity" />
|
||||
<activity android:name="im.vector.riotx.features.createdirect.CreateDirectRoomActivity" />
|
||||
<activity android:name="im.vector.riotx.features.invite.InviteUsersToRoomActivity" />
|
||||
<activity android:name=".features.webview.VectorWebViewActivity" />
|
||||
<activity android:name=".features.link.LinkHandlerActivity">
|
||||
<intent-filter>
|
||||
|
|
|
@ -39,6 +39,7 @@ import im.vector.riotx.features.home.room.detail.timeline.reactions.ViewReaction
|
|||
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
|
||||
import im.vector.riotx.features.home.room.list.RoomListModule
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
import im.vector.riotx.features.invite.InviteUsersToRoomActivity
|
||||
import im.vector.riotx.features.invite.VectorInviteView
|
||||
import im.vector.riotx.features.link.LinkHandlerActivity
|
||||
import im.vector.riotx.features.login.LoginActivity
|
||||
|
@ -116,6 +117,7 @@ interface ScreenComponent {
|
|||
fun inject(activity: DebugMenuActivity)
|
||||
fun inject(activity: SharedSecureStorageActivity)
|
||||
fun inject(activity: BigImageViewerActivity)
|
||||
fun inject(activity: InviteUsersToRoomActivity)
|
||||
|
||||
/* ==========================================================================================
|
||||
* BottomSheets
|
||||
|
|
|
@ -26,6 +26,7 @@ import im.vector.matrix.android.api.session.Session
|
|||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.extensions.hideKeyboard
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.activity.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -107,4 +108,15 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() {
|
|||
}
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
protected fun <T : VectorViewEvents> VectorViewModel<*, *, T>.observeViewEvents(observer: (T) -> Unit) {
|
||||
viewEvents
|
||||
.observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
hideWaitingView()
|
||||
observer(it)
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.invite
|
||||
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class InviteUsersToRoomAction : VectorViewModelAction {
|
||||
data class InviteSelectedUsers(val selectedUsers: Set<User>) : InviteUsersToRoomAction()
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.invite
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.room.failure.CreateRoomFailure
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.error.ErrorFormatter
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
import im.vector.riotx.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotx.core.platform.SimpleFragmentActivity
|
||||
import im.vector.riotx.core.platform.WaitingViewData
|
||||
import im.vector.riotx.core.utils.toast
|
||||
import im.vector.riotx.features.userdirectory.KnownUsersFragment
|
||||
import im.vector.riotx.features.userdirectory.KnownUsersFragmentArgs
|
||||
import im.vector.riotx.features.userdirectory.UserDirectoryFragment
|
||||
import im.vector.riotx.features.userdirectory.UserDirectorySharedAction
|
||||
import im.vector.riotx.features.userdirectory.UserDirectorySharedActionViewModel
|
||||
import im.vector.riotx.features.userdirectory.UserDirectoryViewModel
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.activity.*
|
||||
import java.net.HttpURLConnection
|
||||
import javax.inject.Inject
|
||||
|
||||
@Parcelize
|
||||
data class InviteUsersToRoomArgs(val roomId: String) : Parcelable
|
||||
|
||||
class InviteUsersToRoomActivity : SimpleFragmentActivity() {
|
||||
|
||||
private val viewModel: InviteUsersToRoomViewModel by viewModel()
|
||||
private lateinit var sharedActionViewModel: UserDirectorySharedActionViewModel
|
||||
@Inject lateinit var userDirectoryViewModelFactory: UserDirectoryViewModel.Factory
|
||||
@Inject lateinit var inviteUsersToRoomViewModelFactory: InviteUsersToRoomViewModel.Factory
|
||||
@Inject lateinit var errorFormatter: ErrorFormatter
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
super.injectWith(injector)
|
||||
injector.inject(this)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
toolbar.visibility = View.GONE
|
||||
sharedActionViewModel = viewModelProvider.get(UserDirectorySharedActionViewModel::class.java)
|
||||
sharedActionViewModel
|
||||
.observe()
|
||||
.subscribe { sharedAction ->
|
||||
when (sharedAction) {
|
||||
UserDirectorySharedAction.OpenUsersDirectory ->
|
||||
addFragmentToBackstack(R.id.container, UserDirectoryFragment::class.java)
|
||||
UserDirectorySharedAction.Close -> finish()
|
||||
UserDirectorySharedAction.GoBack -> onBackPressed()
|
||||
is UserDirectorySharedAction.OnMenuItemSelected -> onMenuItemSelected(sharedAction)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
if (isFirstCreation()) {
|
||||
addFragment(
|
||||
R.id.container,
|
||||
KnownUsersFragment::class.java,
|
||||
KnownUsersFragmentArgs(
|
||||
title = getString(R.string.invite_users_to_room_title),
|
||||
menuResId = R.menu.vector_invite_users_to_room
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
viewModel.observeViewEvents { renderInviteEvents(it) }
|
||||
}
|
||||
|
||||
private fun onMenuItemSelected(action: UserDirectorySharedAction.OnMenuItemSelected) {
|
||||
if (action.itemId == R.id.action_invite_users_to_room_invite) {
|
||||
viewModel.handle(InviteUsersToRoomAction.InviteSelectedUsers(action.selectedUsers))
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderInviteEvents(viewEvent: InviteUsersToRoomViewEvents) {
|
||||
when (viewEvent) {
|
||||
is InviteUsersToRoomViewEvents.Loading -> renderInviteLoading()
|
||||
is InviteUsersToRoomViewEvents.Success -> renderInvitationSuccess()
|
||||
is InviteUsersToRoomViewEvents.Failure -> renderInviteFailure(viewEvent.throwable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderInviteLoading() {
|
||||
updateWaitingView(WaitingViewData(getString(R.string.inviting_users_to_room)))
|
||||
}
|
||||
|
||||
private fun renderInviteFailure(error: Throwable) {
|
||||
hideWaitingView()
|
||||
if (error is CreateRoomFailure.CreatedWithTimeout) {
|
||||
finish()
|
||||
} else {
|
||||
val message = if (error is Failure.ServerError && error.httpCode == HttpURLConnection.HTTP_INTERNAL_ERROR /*500*/) {
|
||||
// This error happen if the invited userId does not exist.
|
||||
getString(R.string.invite_users_to_room_failure)
|
||||
} else {
|
||||
errorFormatter.toHumanReadable(error)
|
||||
}
|
||||
AlertDialog.Builder(this)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderInvitationSuccess() = withState(viewModel) {
|
||||
toast(R.string.invitations_sent_successfully)
|
||||
finish()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun getIntent(context: Context, roomId: String): Intent {
|
||||
return Intent(context, InviteUsersToRoomActivity::class.java).also {
|
||||
it.putExtra(MvRx.KEY_ARG, InviteUsersToRoomArgs(roomId))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.invite
|
||||
|
||||
import im.vector.riotx.core.platform.VectorViewEvents
|
||||
|
||||
sealed class InviteUsersToRoomViewEvents : VectorViewEvents {
|
||||
object Loading : InviteUsersToRoomViewEvents()
|
||||
data class Failure(val throwable: Throwable) : InviteUsersToRoomViewEvents()
|
||||
object Success : InviteUsersToRoomViewEvents()
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.invite
|
||||
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import io.reactivex.Observable
|
||||
|
||||
class InviteUsersToRoomViewModel @AssistedInject constructor(@Assisted
|
||||
initialState: InviteUsersToRoomViewState,
|
||||
session: Session)
|
||||
: VectorViewModel<InviteUsersToRoomViewState, InviteUsersToRoomAction, InviteUsersToRoomViewEvents>(initialState) {
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)!!
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: InviteUsersToRoomViewState): InviteUsersToRoomViewModel
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<InviteUsersToRoomViewModel, InviteUsersToRoomViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: InviteUsersToRoomViewState): InviteUsersToRoomViewModel? {
|
||||
val activity: InviteUsersToRoomActivity = (viewModelContext as ActivityViewModelContext).activity()
|
||||
return activity.inviteUsersToRoomViewModelFactory.create(state)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: InviteUsersToRoomAction) {
|
||||
when (action) {
|
||||
is InviteUsersToRoomAction.InviteSelectedUsers -> inviteUsersToRoom(action.selectedUsers)
|
||||
}
|
||||
}
|
||||
|
||||
private fun inviteUsersToRoom(selectedUsers: Set<User>) {
|
||||
_viewEvents.post(InviteUsersToRoomViewEvents.Loading)
|
||||
|
||||
Observable.fromIterable(selectedUsers).flatMapCompletable { user ->
|
||||
room.rx().invite(user.userId, null)
|
||||
}.subscribe(
|
||||
{
|
||||
_viewEvents.post(InviteUsersToRoomViewEvents.Success)
|
||||
},
|
||||
{
|
||||
_viewEvents.post(InviteUsersToRoomViewEvents.Failure(it))
|
||||
}).disposeOnClear()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotx.features.invite
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
|
||||
data class InviteUsersToRoomViewState(
|
||||
val roomId: String,
|
||||
val inviteState: Async<Unit> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: InviteUsersToRoomArgs) : this(roomId = args.roomId)
|
||||
}
|
|
@ -41,6 +41,7 @@ import im.vector.riotx.features.debug.DebugMenuActivity
|
|||
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
||||
import im.vector.riotx.features.home.room.detail.RoomDetailArgs
|
||||
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
|
||||
import im.vector.riotx.features.invite.InviteUsersToRoomActivity
|
||||
import im.vector.riotx.features.media.BigImageViewerActivity
|
||||
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
|
||||
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
|
||||
|
@ -163,6 +164,11 @@ class DefaultNavigator @Inject constructor(
|
|||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun openInviteUsersToRoom(context: Context, roomId: String) {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun openRoomsFiltering(context: Context) {
|
||||
val intent = FilteredRoomsActivity.newIntent(context)
|
||||
context.startActivity(intent)
|
||||
|
|
|
@ -46,6 +46,8 @@ interface Navigator {
|
|||
|
||||
fun openCreateDirectRoom(context: Context)
|
||||
|
||||
fun openInviteUsersToRoom(context: Context, roomId: String)
|
||||
|
||||
fun openRoomDirectory(context: Context, initialFilter: String = "")
|
||||
|
||||
fun openRoomsFiltering(context: Context)
|
||||
|
|
|
@ -49,7 +49,7 @@ class RoomMemberListFragment @Inject constructor(
|
|||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.menu_room_member_list_add_member -> {
|
||||
navigator.openCreateDirectRoom(requireContext())
|
||||
navigator.openInviteUsersToRoom(requireContext(), roomProfileArgs.roomId)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.view.View
|
|||
import android.widget.ScrollView
|
||||
import androidx.core.view.forEach
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.jakewharton.rxbinding3.widget.textChanges
|
||||
|
@ -43,6 +44,8 @@ class KnownUsersFragment @Inject constructor(
|
|||
private val dimensionConverter: DimensionConverter
|
||||
) : VectorBaseFragment(), KnownUsersController.Callback {
|
||||
|
||||
private val args: KnownUsersFragmentArgs by args()
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_known_users
|
||||
|
||||
override fun getMenuRes() = withState(viewModel) {
|
||||
|
@ -55,6 +58,9 @@ class KnownUsersFragment @Inject constructor(
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(UserDirectorySharedActionViewModel::class.java)
|
||||
|
||||
knownUsersTitle.text = args.title
|
||||
|
||||
vectorBaseActivity.setSupportActionBar(knownUsersToolbar)
|
||||
setupRecyclerView()
|
||||
setupFilterView()
|
||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.matrix.rx.rx
|
|||
import im.vector.riotx.core.extensions.toggle
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.features.createdirect.CreateDirectRoomActivity
|
||||
import im.vector.riotx.features.invite.InviteUsersToRoomActivity
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -59,6 +60,7 @@ class UserDirectoryViewModel @AssistedInject constructor(@Assisted
|
|||
is ActivityViewModelContext -> {
|
||||
when (viewModelContext.activity<FragmentActivity>()) {
|
||||
is CreateDirectRoomActivity -> viewModelContext.activity<CreateDirectRoomActivity>().userDirectoryViewModelFactory.create(state)
|
||||
is InviteUsersToRoomActivity -> viewModelContext.activity<InviteUsersToRoomActivity>().userDirectoryViewModelFactory.create(state)
|
||||
else -> error("Wrong activity or fragment")
|
||||
}
|
||||
}
|
||||
|
|
10
vector/src/main/res/menu/vector_invite_users_to_room.xml
Executable file
10
vector/src/main/res/menu/vector_invite_users_to_room.xml
Executable file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_invite_users_to_room_invite"
|
||||
android:title="@string/invite_users_to_room_action_invite"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
|
@ -37,6 +37,11 @@
|
|||
<string name="external_link_confirmation_title">Double-check this link</string>
|
||||
<string name="external_link_confirmation_message">The link %1$s is taking you to another site: %2$s.\n\nAre you sure you want to continue?</string>
|
||||
<string name="add_members_to_room">Add members</string>
|
||||
<string name="invite_users_to_room_action_invite">INVITE</string>
|
||||
<string name="inviting_users_to_room">Inviting users…</string>
|
||||
<string name="invite_users_to_room_title">Invite Users</string>
|
||||
<string name="invitations_sent_successfully">Invitation sent successfully</string>
|
||||
<string name="invite_users_to_room_failure">We could not invite users. Please check the users you want to invite and try again.</string>
|
||||
<!-- END Strings added by Onuray -->
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue