mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-18 03:48:08 +00:00
Improved delivery bottom sheet
This commit is contained in:
parent
170e441744
commit
c151ef1526
17 changed files with 266 additions and 66 deletions
|
|
@ -77,7 +77,7 @@ dependencies {
|
|||
implementation "androidx.core:core-ktx:1.12.0"
|
||||
implementation "androidx.core:core-telecom:1.0.0-alpha02"
|
||||
implementation "androidx.media:media:1.6.0"
|
||||
implementation "androidx.recyclerview:recyclerview:1.3.1"
|
||||
implementation "androidx.recyclerview:recyclerview:1.3.2"
|
||||
implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0"
|
||||
implementation "androidx.window:window:1.1.0"
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,10 @@ class ConversationEventAdapter(
|
|||
with(binding) {
|
||||
model = message
|
||||
|
||||
setShowDeliveryInfoClickListener {
|
||||
showDeliveryForChatMessageModelEvent.value = Event(message)
|
||||
}
|
||||
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
executePendingBindings()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,13 +43,17 @@ import androidx.navigation.fragment.findNavController
|
|||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import kotlinx.coroutines.launch
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.R
|
||||
import org.linphone.core.ChatMessage
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.databinding.ChatConversationFragmentBinding
|
||||
import org.linphone.databinding.ChatConversationLongPressMenuBinding
|
||||
import org.linphone.ui.main.chat.adapter.ConversationEventAdapter
|
||||
import org.linphone.ui.main.chat.model.ChatMessageDeliveryModel
|
||||
import org.linphone.ui.main.chat.model.ChatMessageModel
|
||||
import org.linphone.ui.main.chat.viewmodel.ConversationViewModel
|
||||
import org.linphone.ui.main.fragment.GenericFragment
|
||||
|
|
@ -177,13 +181,9 @@ class ConversationFragment : GenericFragment() {
|
|||
emojisBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
emojisBottomSheetBehavior.isDraggable = false // To allow scrolling through the emojis
|
||||
|
||||
val imdnBottomSheetBehavior = BottomSheetBehavior.from(binding.deliveryBottomSheet.root)
|
||||
imdnBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
|
||||
adapter.showDeliveryForChatMessageModelEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { model ->
|
||||
binding.deliveryBottomSheet.model = model
|
||||
imdnBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
showDeliveryBottomSheetDialog(model)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -303,4 +303,62 @@ class ConversationFragment : GenericFragment() {
|
|||
dialog.window?.setBackgroundDrawable(d)
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private fun showDeliveryBottomSheetDialog(chatMessageModel: ChatMessageModel) {
|
||||
val deliveryBottomSheetBehavior = BottomSheetBehavior.from(binding.messageDelivery.root)
|
||||
if (deliveryBottomSheetBehavior.state == BottomSheetBehavior.STATE_HALF_EXPANDED) {
|
||||
deliveryBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
|
||||
binding.messageDelivery.setHandleClickedListener {
|
||||
deliveryBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
|
||||
coreContext.postOnCoreThread {
|
||||
val model = ChatMessageDeliveryModel(chatMessageModel.chatMessage)
|
||||
|
||||
coreContext.postOnMainThread {
|
||||
binding.messageDelivery.tabs.removeAllTabs()
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(model.readLabel.value).setId(
|
||||
ChatMessage.State.Displayed.toInt()
|
||||
)
|
||||
)
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(model.receivedLabel.value).setId(
|
||||
ChatMessage.State.DeliveredToUser.toInt()
|
||||
)
|
||||
)
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(model.sentLabel.value).setId(
|
||||
ChatMessage.State.Delivered.toInt()
|
||||
)
|
||||
)
|
||||
binding.messageDelivery.tabs.addTab(
|
||||
binding.messageDelivery.tabs.newTab().setText(model.errorLabel.value).setId(
|
||||
ChatMessage.State.NotDelivered.toInt()
|
||||
)
|
||||
)
|
||||
|
||||
binding.messageDelivery.tabs.setOnTabSelectedListener(object : OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
val state = tab?.id ?: ChatMessage.State.Displayed.toInt()
|
||||
model.computeListForState(ChatMessage.State.fromInt(state))
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
})
|
||||
|
||||
binding.messageDelivery.model = model
|
||||
|
||||
binding.messageDelivery.root.visibility = View.VISIBLE
|
||||
deliveryBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-android
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* 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 org.linphone.ui.main.chat.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.UiThread
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import org.linphone.databinding.ChatMessageDeliveryBottomSheetBinding
|
||||
import org.linphone.ui.main.chat.model.ChatMessageDeliveryModel
|
||||
import org.linphone.ui.main.chat.model.ChatMessageModel
|
||||
|
||||
@UiThread
|
||||
class MessageDeliveryDialogFragment(
|
||||
chatMessageModel: ChatMessageModel
|
||||
) : BottomSheetDialogFragment() {
|
||||
companion object {
|
||||
const val TAG = "MessageDeliveryDialogFragment"
|
||||
}
|
||||
|
||||
val model = ChatMessageDeliveryModel(chatMessageModel.chatMessage)
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val view = ChatMessageDeliveryBottomSheetBinding.inflate(layoutInflater)
|
||||
view.model = model
|
||||
return view.root
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,102 @@
|
|||
package org.linphone.ui.main.chat.model
|
||||
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.linphone.LinphoneApplication
|
||||
import org.linphone.core.ParticipantImdnState
|
||||
import org.linphone.utils.TimestampUtils
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import org.linphone.R
|
||||
import org.linphone.core.ChatMessage
|
||||
import org.linphone.core.ChatMessage.State
|
||||
import org.linphone.utils.AppUtils
|
||||
|
||||
class ChatMessageDeliveryModel @WorkerThread constructor(
|
||||
imdnState: ParticipantImdnState
|
||||
private val chatMessage: ChatMessage
|
||||
) {
|
||||
val address = imdnState.participant.address
|
||||
companion object {
|
||||
private const val TAG = "[Chat Message Delivery Model]"
|
||||
}
|
||||
|
||||
val avatarModel = LinphoneApplication.coreContext.contactsManager.getContactAvatarModelForAddress(
|
||||
address
|
||||
)
|
||||
val readLabel = MutableLiveData<String>()
|
||||
|
||||
val time = TimestampUtils.toString(imdnState.stateChangeTime)
|
||||
val receivedLabel = MutableLiveData<String>()
|
||||
|
||||
val sentLabel = MutableLiveData<String>()
|
||||
|
||||
val errorLabel = MutableLiveData<String>()
|
||||
|
||||
val deliveryModels = MutableLiveData<ArrayList<ChatMessageParticipantDeliveryModel>>()
|
||||
|
||||
private val displayedModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
|
||||
private val deliveredModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
|
||||
private val sentModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
|
||||
private val errorModels = arrayListOf<ChatMessageParticipantDeliveryModel>()
|
||||
|
||||
init {
|
||||
computeDeliveryStatus()
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun computeListForState(state: State) {
|
||||
when (state) {
|
||||
State.DeliveredToUser -> {
|
||||
deliveryModels.value = deliveredModels
|
||||
}
|
||||
State.Delivered -> {
|
||||
deliveryModels.value = sentModels
|
||||
}
|
||||
State.NotDelivered -> {
|
||||
deliveryModels.value = errorModels
|
||||
}
|
||||
else -> {
|
||||
deliveryModels.value = displayedModels
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun computeDeliveryStatus() {
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.Displayed)) {
|
||||
displayedModels.add(ChatMessageParticipantDeliveryModel(participant))
|
||||
}
|
||||
readLabel.postValue(
|
||||
AppUtils.getFormattedString(
|
||||
R.string.message_delivery_info_read_title,
|
||||
displayedModels.size.toString()
|
||||
)
|
||||
)
|
||||
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.DeliveredToUser)) {
|
||||
deliveredModels.add(ChatMessageParticipantDeliveryModel(participant))
|
||||
}
|
||||
receivedLabel.postValue(
|
||||
AppUtils.getFormattedString(
|
||||
R.string.message_delivery_info_received_title,
|
||||
deliveredModels.size.toString()
|
||||
)
|
||||
)
|
||||
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.Delivered)) {
|
||||
sentModels.add(ChatMessageParticipantDeliveryModel(participant))
|
||||
}
|
||||
sentLabel.postValue(
|
||||
AppUtils.getFormattedString(
|
||||
R.string.message_delivery_info_sent_title,
|
||||
sentModels.size.toString()
|
||||
)
|
||||
)
|
||||
|
||||
for (participant in chatMessage.getParticipantsByImdnState(State.NotDelivered)) {
|
||||
errorModels.add(ChatMessageParticipantDeliveryModel(participant))
|
||||
}
|
||||
errorLabel.postValue(
|
||||
AppUtils.getFormattedString(
|
||||
R.string.message_delivery_info_error_title,
|
||||
errorModels.size.toString()
|
||||
)
|
||||
)
|
||||
|
||||
deliveryModels.postValue(displayedModels)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ class ChatMessageModel @WorkerThread constructor(
|
|||
|
||||
val chatRoomIsReadOnly = chatMessage.chatRoom.isReadOnly
|
||||
|
||||
val deliveryModels = MutableLiveData<ArrayList<ChatMessageDeliveryModel>>()
|
||||
|
||||
val dismissLongPressMenuEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
|
|
@ -87,8 +85,6 @@ class ChatMessageModel @WorkerThread constructor(
|
|||
init {
|
||||
chatMessage.addListener(chatMessageListener)
|
||||
computeStatusIcon(chatMessage.state)
|
||||
|
||||
computeDeliveryStatus()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
|
@ -127,15 +123,4 @@ class ChatMessageModel @WorkerThread constructor(
|
|||
}
|
||||
statusIcon.postValue(icon)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun computeDeliveryStatus() {
|
||||
val list = arrayListOf<ChatMessageDeliveryModel>()
|
||||
|
||||
/*for (participant in chatMessage.getParticipantsByImdnState(ChatMessage.State.Displayed)) {
|
||||
list.add(ChatMessageDeliveryModel(participant))
|
||||
}*/
|
||||
|
||||
deliveryModels.postValue(list)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package org.linphone.ui.main.chat.model
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.linphone.LinphoneApplication
|
||||
import org.linphone.core.ParticipantImdnState
|
||||
import org.linphone.utils.TimestampUtils
|
||||
|
||||
class ChatMessageParticipantDeliveryModel @WorkerThread constructor(
|
||||
imdnState: ParticipantImdnState
|
||||
) {
|
||||
val address = imdnState.participant.address
|
||||
|
||||
val avatarModel = LinphoneApplication.coreContext.contactsManager.getContactAvatarModelForAddress(
|
||||
address
|
||||
)
|
||||
|
||||
val time = TimestampUtils.toString(imdnState.stateChangeTime)
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<corners android:topRightRadius="20dp" android:topLeftRadius="20dp" />
|
||||
<solid android:color="@color/white"/>
|
||||
</shape>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<corners android:topRightRadius="16dp" android:bottomRightRadius="16dp" android:bottomLeftRadius="16dp" />
|
||||
<solid android:color="@color/white"/>
|
||||
<solid android:color="@color/gray_100"/>
|
||||
</shape>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<corners android:radius="16dp" />
|
||||
<solid android:color="@color/white"/>
|
||||
<solid android:color="@color/gray_100"/>
|
||||
</shape>
|
||||
|
|
@ -9,6 +9,9 @@
|
|||
<variable
|
||||
name="onLongClickListener"
|
||||
type="View.OnLongClickListener" />
|
||||
<variable
|
||||
name="showDeliveryInfoClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="model"
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageModel" />
|
||||
|
|
@ -75,6 +78,7 @@
|
|||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style_300"
|
||||
android:id="@+id/date_time"
|
||||
android:onClick="@{showDeliveryInfoClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
|
|
@ -90,6 +94,7 @@
|
|||
<ImageView
|
||||
style="@style/default_text_style_300"
|
||||
android:id="@+id/delivery_status"
|
||||
android:onClick="@{showDeliveryInfoClickListener}"
|
||||
android:layout_width="@dimen/small_icon_size"
|
||||
android:layout_height="@dimen/small_icon_size"
|
||||
android:layout_marginEnd="18dp"
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:background="@color/gray_100"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintTop_toBottomOf="@id/top_bar_barrier"
|
||||
app:layout_constraintBottom_toTopOf="@id/composing" />
|
||||
|
||||
|
|
@ -203,7 +203,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:background="@color/gray_100"
|
||||
android:background="@color/white"
|
||||
android:text="@{viewModel.composingLabel, default=`John Doe is composing...`}"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/gray_main2_400"
|
||||
|
|
@ -223,7 +223,8 @@
|
|||
layout="@layout/chat_conversation_send_area"/>
|
||||
|
||||
<include
|
||||
android:id="@+id/delivery_bottom_sheet"
|
||||
android:id="@+id/message_delivery"
|
||||
android:visibility="gone"
|
||||
layout="@layout/chat_message_delivery_bottom_sheet" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<import type="org.linphone.core.ChatRoom.SecurityLevel" />
|
||||
<variable
|
||||
name="model"
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageDeliveryModel" />
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageParticipantDeliveryModel" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
|
|||
|
|
@ -9,15 +9,14 @@
|
|||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="model"
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageModel" />
|
||||
type="org.linphone.ui.main.chat.model.ChatMessageDeliveryModel" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/shape_bottom_sheet_background"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="@drawable/shape_bottom_sheet_white_background"
|
||||
android:elevation="16dp"
|
||||
app:behavior_hideable="true"
|
||||
app:behavior_peekHeight="0dp"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||
|
|
@ -39,40 +38,25 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/transparent_color"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/handle"
|
||||
app:layout_constraintBottom_toTopOf="@id/scrollview"
|
||||
app:tabMode="fixed"
|
||||
app:tabUnboundedRipple="true"
|
||||
app:tabRippleColor="@color/orange_main_100"
|
||||
app:tabGravity="fill"
|
||||
app:tabPadding="0dp"
|
||||
app:tabInlineLabel="true"
|
||||
app:tabIndicatorColor="@color/orange_main_500"
|
||||
app:tabTextColor="@color/gray_main2_400"
|
||||
app:tabSelectedTextColor="@color/gray_main2_600">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Lu" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Reçu" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Envoyé" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Erreur" />
|
||||
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
app:tabSelectedTextColor="@color/gray_main2_600" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toBottomOf="@id/tabs">
|
||||
android:layout_height="250dp"
|
||||
app:layout_constraintHeight_min="50dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/shape_bottom_sheet_background"
|
||||
android:background="@drawable/shape_bottom_sheet_gray_100_background"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:behavior_hideable="true"
|
||||
|
|
|
|||
|
|
@ -361,6 +361,11 @@
|
|||
<string name="conversation_info_admin_menu_set_participant_admin">Give admin rights</string>
|
||||
<string name="conversation_info_admin_menu_unset_participant_admin">Remove admin rights</string>
|
||||
|
||||
<string name="message_delivery_info_read_title">Read (%s)</string>
|
||||
<string name="message_delivery_info_received_title">Received (%s)</string>
|
||||
<string name="message_delivery_info_sent_title">Sent (%s)</string>
|
||||
<string name="message_delivery_info_error_title">Error (%s)</string>
|
||||
|
||||
<string name="meetings_list_empty">No meeting for the moment…</string>
|
||||
<string name="meeting_schedule_title">New meeting</string>
|
||||
<string name="meeting_schedule_meeting_label">Meeting</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue