mirror of
https://github.com/nextcloud/talk-android.git
synced 2024-11-26 23:25:20 +03:00
Merge pull request #2413 from nextcloud/feature/1353/shareToChooseAccount
add account switcher for "share to"
This commit is contained in:
commit
dc6083334b
6 changed files with 345 additions and 21 deletions
|
@ -100,6 +100,7 @@ import com.nextcloud.talk.models.json.status.Status
|
|||
import com.nextcloud.talk.models.json.statuses.StatusesOverall
|
||||
import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository
|
||||
import com.nextcloud.talk.ui.dialog.ChooseAccountDialogFragment
|
||||
import com.nextcloud.talk.ui.dialog.ChooseAccountShareToDialogFragment
|
||||
import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
|
@ -180,6 +181,7 @@ class ConversationsListController(bundle: Bundle) :
|
|||
private var conversationItemsWithHeader: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
||||
private val searchableConversationItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
||||
private var searchItem: MenuItem? = null
|
||||
private var chooseAccountItem: MenuItem? = null
|
||||
private var searchView: SearchView? = null
|
||||
private var searchQuery: String? = null
|
||||
private var credentials: String? = null
|
||||
|
@ -250,6 +252,43 @@ class ConversationsListController(bundle: Bundle) :
|
|||
}
|
||||
}
|
||||
|
||||
private fun loadUserAvatar(menuItem: MenuItem) {
|
||||
if (activity != null) {
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
currentUser!!.baseUrl,
|
||||
currentUser!!.userId,
|
||||
true
|
||||
),
|
||||
currentUser
|
||||
)
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||
dataSource.subscribe(
|
||||
object : BaseBitmapDataSubscriber() {
|
||||
override fun onNewResultImpl(bitmap: Bitmap?) {
|
||||
if (bitmap != null && resources != null) {
|
||||
val roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(
|
||||
resources!!,
|
||||
bitmap
|
||||
)
|
||||
roundedBitmapDrawable.isCircular = true
|
||||
roundedBitmapDrawable.setAntiAlias(true)
|
||||
menuItem.icon = roundedBitmapDrawable
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage?>>) {
|
||||
if (resources != null) {
|
||||
menuItem.icon = ResourcesCompat.getDrawable(resources!!, R.drawable.ic_user, null)
|
||||
}
|
||||
}
|
||||
},
|
||||
UiThreadImmediateExecutorService.getInstance()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
Log.d(
|
||||
TAG,
|
||||
|
@ -257,6 +296,9 @@ class ConversationsListController(bundle: Bundle) :
|
|||
" Activity: " + System.identityHashCode(activity)
|
||||
)
|
||||
super.onAttach(view)
|
||||
|
||||
showShareToScreen = hasActivityActionSendIntent()
|
||||
|
||||
ClosedInterfaceImpl().setUpPushTokenRegistration()
|
||||
if (!eventBus.isRegistered(this)) {
|
||||
eventBus.register(this)
|
||||
|
@ -328,15 +370,32 @@ class ConversationsListController(bundle: Bundle) :
|
|||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
|
||||
inflater.inflate(R.menu.menu_conversation_plus_filter, menu)
|
||||
searchItem = menu.findItem(R.id.action_search)
|
||||
chooseAccountItem = menu.findItem(R.id.action_choose_account)
|
||||
loadUserAvatar(chooseAccountItem!!)
|
||||
|
||||
chooseAccountItem?.setOnMenuItemClickListener {
|
||||
if (resources != null && resources!!.getBoolean(R.bool.multiaccount_support)) {
|
||||
val newFragment: DialogFragment = ChooseAccountShareToDialogFragment.newInstance()
|
||||
newFragment.show(
|
||||
(activity as MainActivity?)!!.supportFragmentManager,
|
||||
ChooseAccountShareToDialogFragment.TAG
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
initSearchView()
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
searchView = MenuItemCompat.getActionView(searchItem) as SearchView
|
||||
showShareToScreen = !showShareToScreen && hasActivityActionSendIntent()
|
||||
|
||||
val moreAccountsAvailable = userManager.users.blockingGet().size > 1
|
||||
menu.findItem(R.id.action_choose_account).isVisible = showShareToScreen && moreAccountsAvailable
|
||||
|
||||
if (showShareToScreen) {
|
||||
hideSearchBar()
|
||||
actionBar?.setTitle(R.string.send_to_three_dots)
|
||||
|
@ -679,7 +738,7 @@ class ConversationsListController(bundle: Bundle) :
|
|||
val newFragment: DialogFragment = ChooseAccountDialogFragment.newInstance()
|
||||
newFragment.show(
|
||||
(getActivity() as MainActivity?)!!.supportFragmentManager,
|
||||
"ChooseAccountDialogFragment"
|
||||
ChooseAccountDialogFragment.TAG
|
||||
)
|
||||
} else {
|
||||
router.pushController(
|
||||
|
@ -858,7 +917,7 @@ class ConversationsListController(bundle: Bundle) :
|
|||
loadMoreMessages()
|
||||
}
|
||||
ConversationItem.VIEW_TYPE -> {
|
||||
showConversation((Objects.requireNonNull(item) as ConversationItem).model)
|
||||
handleConversation((Objects.requireNonNull(item) as ConversationItem).model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -870,21 +929,24 @@ class ConversationsListController(bundle: Bundle) :
|
|||
val conversationItem = absItem as ConversationItem
|
||||
if (conversationItem.model.token == conversationToken) {
|
||||
val conversation = conversationItem.model
|
||||
showConversation(conversation)
|
||||
handleConversation(conversation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showConversation(conversation: Conversation?) {
|
||||
@Suppress("Detekt.ComplexMethod")
|
||||
private fun handleConversation(conversation: Conversation?) {
|
||||
selectedConversation = conversation
|
||||
if (selectedConversation != null && activity != null) {
|
||||
val hasChatPermission = AttendeePermissionsUtil(selectedConversation!!.permissions).hasChatPermission(
|
||||
currentUser!!
|
||||
)
|
||||
if (showShareToScreen) {
|
||||
if (hasChatPermission && !isReadOnlyConversation(selectedConversation!!)) {
|
||||
if (hasChatPermission &&
|
||||
!isReadOnlyConversation(selectedConversation!!) &&
|
||||
!selectedConversation!!.shouldShowLobby(currentUser!!)
|
||||
) {
|
||||
handleSharedData()
|
||||
showShareToScreen = false
|
||||
} else {
|
||||
Toast.makeText(context, R.string.send_to_forbidden, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
@ -947,7 +1009,6 @@ class ConversationsListController(bundle: Bundle) :
|
|||
}
|
||||
.setNegativeButton(R.string.nc_no) { _, _ ->
|
||||
Log.d(TAG, "sharing files aborted, going back to share-to screen")
|
||||
showShareToScreen = true
|
||||
}
|
||||
viewThemeUtils.dialog
|
||||
.colorMaterialAlertDialogBackground(binding.floatingActionButton.context, dialogBuilder)
|
||||
|
@ -961,6 +1022,10 @@ class ConversationsListController(bundle: Bundle) :
|
|||
}
|
||||
}
|
||||
|
||||
private fun clearIntentAction() {
|
||||
activity!!.intent.action = ""
|
||||
}
|
||||
|
||||
override fun onItemLongClick(position: Int) {
|
||||
if (showShareToScreen) {
|
||||
Log.d(TAG, "sharing to multiple rooms not yet implemented. onItemLongClick is ignored.")
|
||||
|
@ -1085,6 +1150,7 @@ class ConversationsListController(bundle: Bundle) :
|
|||
bundle,
|
||||
false
|
||||
)
|
||||
clearIntentAction()
|
||||
}
|
||||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.BACKGROUND)
|
||||
|
|
|
@ -49,8 +49,8 @@ import com.nextcloud.talk.models.json.participants.Participant;
|
|||
import com.nextcloud.talk.models.json.status.Status;
|
||||
import com.nextcloud.talk.models.json.status.StatusOverall;
|
||||
import com.nextcloud.talk.ui.StatusDrawable;
|
||||
import com.nextcloud.talk.users.UserManager;
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils;
|
||||
import com.nextcloud.talk.users.UserManager;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew;
|
||||
|
@ -74,7 +74,7 @@ import io.reactivex.schedulers.Schedulers;
|
|||
|
||||
@AutoInjector(NextcloudTalkApplication.class)
|
||||
public class ChooseAccountDialogFragment extends DialogFragment {
|
||||
private static final String TAG = ChooseAccountDialogFragment.class.getSimpleName();
|
||||
public static final String TAG = ChooseAccountDialogFragment.class.getSimpleName();
|
||||
|
||||
private static final float STATUS_SIZE_IN_DP = 9f;
|
||||
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Mario Danic
|
||||
* @author Marcel Hibbe
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
|
||||
* 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/>.
|
||||
*
|
||||
* Parts related to account import were either copied from or inspired by the great work done by David Luhmer at:
|
||||
* https://github.com/nextcloud/ownCloud-Account-Importer
|
||||
*/
|
||||
package com.nextcloud.talk.ui.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import autodagger.AutoInjector
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.interfaces.DraweeController
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.nextcloud.talk.activities.MainActivity
|
||||
import com.nextcloud.talk.adapters.items.AdvancedUserItem
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.databinding.DialogChooseAccountShareToBinding
|
||||
import com.nextcloud.talk.models.json.participants.Participant
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
import java.net.CookieManager
|
||||
import javax.inject.Inject
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ChooseAccountShareToDialogFragment : DialogFragment() {
|
||||
@JvmField
|
||||
@Inject
|
||||
var userManager: UserManager? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var cookieManager: CookieManager? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var viewThemeUtils: ViewThemeUtils? = null
|
||||
private var binding: DialogChooseAccountShareToBinding? = null
|
||||
private var dialogView: View? = null
|
||||
private var adapter: FlexibleAdapter<AdvancedUserItem>? = null
|
||||
private val userItems: MutableList<AdvancedUserItem> = ArrayList()
|
||||
@SuppressLint("InflateParams")
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
binding = DialogChooseAccountShareToBinding.inflate(LayoutInflater.from(requireContext()))
|
||||
dialogView = binding!!.root
|
||||
return MaterialAlertDialogBuilder(requireContext()).setView(dialogView).create()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedApplication!!.componentApplication.inject(this)
|
||||
val user = userManager!!.currentUser.blockingGet()
|
||||
themeViews()
|
||||
setupCurrentUser(user)
|
||||
setupListeners(user)
|
||||
setupAdapter()
|
||||
prepareViews()
|
||||
}
|
||||
|
||||
private fun setupCurrentUser(user: User?) {
|
||||
binding!!.currentAccount.userIcon.tag = ""
|
||||
if (user != null) {
|
||||
binding!!.currentAccount.userName.text = user.displayName
|
||||
binding!!.currentAccount.ticker.visibility = View.GONE
|
||||
binding!!.currentAccount.account.text = Uri.parse(user.baseUrl).host
|
||||
viewThemeUtils!!.platform.colorImageView(binding!!.currentAccount.accountMenu)
|
||||
if (user.baseUrl != null &&
|
||||
(user.baseUrl!!.startsWith("http://") || user.baseUrl!!.startsWith("https://"))
|
||||
) {
|
||||
binding!!.currentAccount.userIcon.visibility = View.VISIBLE
|
||||
val draweeController: DraweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(binding!!.currentAccount.userIcon.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
ApiUtils.getUrlForAvatar(
|
||||
user.baseUrl,
|
||||
user.userId,
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
binding!!.currentAccount.userIcon.controller = draweeController
|
||||
} else {
|
||||
binding!!.currentAccount.userIcon.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("Detekt.NestedBlockDepth")
|
||||
private fun setupAdapter() {
|
||||
if (adapter == null) {
|
||||
adapter = FlexibleAdapter(userItems, activity, false)
|
||||
var userEntity: User
|
||||
var participant: Participant
|
||||
for (userItem in userManager!!.users.blockingGet()) {
|
||||
userEntity = userItem
|
||||
if (!userEntity.current) {
|
||||
var userId: String?
|
||||
userId = if (userEntity.userId != null) {
|
||||
userEntity.userId
|
||||
} else {
|
||||
userEntity.username
|
||||
}
|
||||
participant = Participant()
|
||||
participant.actorType = Participant.ActorType.USERS
|
||||
participant.actorId = userId
|
||||
participant.displayName = userEntity.displayName
|
||||
userItems.add(AdvancedUserItem(participant, userEntity, null, viewThemeUtils))
|
||||
}
|
||||
}
|
||||
adapter!!.addListener(onSwitchItemClickListener)
|
||||
adapter!!.updateDataSet(userItems, false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListeners(user: User) {
|
||||
binding!!.currentAccount.root.setOnClickListener { v: View? -> dismiss() }
|
||||
}
|
||||
|
||||
private fun themeViews() {
|
||||
viewThemeUtils!!.platform.themeDialog(binding!!.root)
|
||||
}
|
||||
|
||||
private fun prepareViews() {
|
||||
if (activity != null) {
|
||||
val layoutManager: LinearLayoutManager = SmoothScrollLinearLayoutManager(activity)
|
||||
binding!!.accountsList.layoutManager = layoutManager
|
||||
}
|
||||
binding!!.accountsList.setHasFixedSize(true)
|
||||
binding!!.accountsList.adapter = adapter
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return dialogView
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
binding = null
|
||||
}
|
||||
|
||||
private val onSwitchItemClickListener = FlexibleAdapter.OnItemClickListener { view, position ->
|
||||
if (userItems.size > position) {
|
||||
val user = userItems[position].user
|
||||
if (userManager!!.setUserAsActive(user).blockingGet()) {
|
||||
cookieManager!!.cookieStore.removeAll()
|
||||
activity?.runOnUiThread { (activity as MainActivity?)!!.resetConversationsList() }
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = ChooseAccountShareToDialogFragment::class.java.simpleName
|
||||
fun newInstance(): ChooseAccountShareToDialogFragment {
|
||||
return ChooseAccountShareToDialogFragment()
|
||||
}
|
||||
}
|
||||
}
|
51
app/src/main/res/layout/dialog_choose_account_share_to.xml
Normal file
51
app/src/main/res/layout/dialog_choose_account_share_to.xml
Normal file
|
@ -0,0 +1,51 @@
|
|||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
<LinearLayout 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"
|
||||
tools:background="@color/white"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/current_account"
|
||||
layout="@layout/current_account_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
android:layout_margin="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/accounts_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/add_account"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/divider"
|
||||
tools:listitem="@layout/account_item" />
|
||||
|
||||
</LinearLayout>
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Nextcloud Talk application
|
||||
~
|
||||
~ @author Mario Danic
|
||||
~ @author Marcel Hibbe
|
||||
~ Copyright (C) 2022 Marcel Hibbe <dev@mhibbe.de>
|
||||
~ Copyright (C) 2017 Mario Danic
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
|
@ -20,14 +21,23 @@
|
|||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Search, should appear as action button -->
|
||||
<item android:id="@+id/action_search"
|
||||
android:title="@string/nc_search"
|
||||
android:icon="@drawable/ic_search_white_24dp"
|
||||
app:showAsAction="collapseActionView|always"
|
||||
android:animateLayoutChanges="true"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView" />
|
||||
<!-- Search, should appear as action button -->
|
||||
<item
|
||||
android:id="@+id/action_search"
|
||||
android:animateLayoutChanges="true"
|
||||
android:icon="@drawable/ic_search_white_24dp"
|
||||
android:title="@string/nc_search"
|
||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
app:showAsAction="collapseActionView|always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_choose_account"
|
||||
android:animateLayoutChanges="true"
|
||||
android:title="@string/nc_share_to_choose_account"
|
||||
app:showAsAction="collapseActionView|ifRoom"
|
||||
tools:icon="@drawable/account_circle_48dp" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -455,6 +455,9 @@
|
|||
<string name="nc_shared_items_location">Location</string>
|
||||
<string name="nc_shared_items_deck_card">Deck card</string>
|
||||
|
||||
<!-- share to screen -->
|
||||
<string name="nc_share_to_choose_account">Choose account</string>
|
||||
|
||||
<!-- voice messages -->
|
||||
<string name="nc_voice_message_filename">Talk recording from %1$s (%2$s)</string>
|
||||
<string name="nc_voice_message_hold_to_record_info">Hold to record, release to send.</string>
|
||||
|
@ -599,5 +602,4 @@
|
|||
<string name="nc_expire_message_one_hour">1 hour</string>
|
||||
<string name="nc_expire_messages_explanation">Chat messages can be expired after a certain time. Note: Files shared in chat will not be deleted for the owner, but will no longer be shared in the conversation.</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue