mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 03:18:06 +00:00
Added back auto export media to native gallery feature
This commit is contained in:
parent
17511a4c26
commit
875198164d
21 changed files with 208 additions and 13 deletions
|
|
@ -37,6 +37,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
- If next message is also a voice recording, playback will automatically start after the currently playing one ends.
|
||||
- Chat while in call: a shortcut to a conversation screen with the remote.
|
||||
- Chat while in a conference: if the conference has a text stream enabled, you can chat with the other participants of the conference while it lasts. At the end, you'll find the messages history in the call history (and not in the list of conversations).
|
||||
- Auto export of media to native gallery even when auto download is enabled (but still not if VFS is enabled nor for ephemeral messages).
|
||||
- Notification showing upload/download of files shared through chat will let user know the progress and keep the app alive during that process.
|
||||
- Screen sharing in conference: only desktop app starting with 6.0 version is able to start it, but on mobiles you'll be able to see it.
|
||||
- You can choose whatever ringtone you'd like for incoming calls (in Android notification channel settings).
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import org.linphone.ui.call.CallActivity
|
|||
import org.linphone.utils.ActivityMonitor
|
||||
import org.linphone.utils.AppUtils
|
||||
import org.linphone.utils.Event
|
||||
import org.linphone.utils.FileUtils
|
||||
import org.linphone.utils.LinphoneUtils
|
||||
|
||||
class CoreContext
|
||||
|
|
@ -112,6 +113,11 @@ class CoreContext
|
|||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
|
||||
private var filesToExportToNativeMediaGallery = arrayListOf<String>()
|
||||
val filesToExportToNativeMediaGalleryEvent: MutableLiveData<Event<List<String>>> by lazy {
|
||||
MutableLiveData<Event<List<String>>>()
|
||||
}
|
||||
|
||||
@SuppressLint("HandlerLeak")
|
||||
private lateinit var coreThread: Handler
|
||||
|
||||
|
|
@ -155,6 +161,42 @@ class CoreContext
|
|||
private var previousCallState = Call.State.Idle
|
||||
|
||||
private val coreListener = object : CoreListenerStub() {
|
||||
@WorkerThread
|
||||
override fun onMessagesReceived(
|
||||
core: Core,
|
||||
chatRoom: ChatRoom,
|
||||
messages: Array<out ChatMessage?>
|
||||
) {
|
||||
if (corePreferences.makePublicMediaFilesDownloaded && core.maxSizeForAutoDownloadIncomingFiles >= 0) {
|
||||
for (message in messages) {
|
||||
// Never do auto media export for ephemeral messages!
|
||||
if (message?.isEphemeral == true) continue
|
||||
|
||||
for (content in message?.contents.orEmpty()) {
|
||||
if (content.isFile) {
|
||||
val path = content.filePath
|
||||
if (path.isNullOrEmpty()) continue
|
||||
|
||||
val mime = "${content.type}/${content.subtype}"
|
||||
val mimeType = FileUtils.getMimeType(mime)
|
||||
when (mimeType) {
|
||||
FileUtils.MimeType.Image, FileUtils.MimeType.Video, FileUtils.MimeType.Audio -> {
|
||||
Log.i("$TAG Added file path [$path] to the list of media to export to native media gallery")
|
||||
filesToExportToNativeMediaGallery.add(path)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filesToExportToNativeMediaGallery.isNotEmpty()) {
|
||||
Log.i("$TAG Creating event with [${filesToExportToNativeMediaGallery.size}] files to export to native media gallery")
|
||||
filesToExportToNativeMediaGalleryEvent.postValue(Event(filesToExportToNativeMediaGallery))
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onGlobalStateChanged(core: Core, state: GlobalState, message: String) {
|
||||
Log.i("$TAG Global state changed [$state]")
|
||||
|
|
@ -628,6 +670,11 @@ class CoreContext
|
|||
return found != null
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun clearFilesToExportToNativeGallery() {
|
||||
filesToExportToNativeMediaGallery.clear()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
fun startAudioCall(
|
||||
address: Address,
|
||||
|
|
|
|||
|
|
@ -149,6 +149,13 @@ class CorePreferences
|
|||
config.setBool("app", "mark_as_read_notif_dismissal", value)
|
||||
}
|
||||
|
||||
var makePublicMediaFilesDownloaded: Boolean
|
||||
// Keep old name for backward compatibility
|
||||
get() = config.getBool("app", "make_downloaded_images_public_in_gallery", false)
|
||||
set(value) {
|
||||
config.setBool("app", "make_downloaded_images_public_in_gallery", value)
|
||||
}
|
||||
|
||||
// Conference related
|
||||
|
||||
@get:WorkerThread @set:WorkerThread
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import android.util.Base64
|
|||
import android.util.Pair
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import java.math.BigInteger
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.KeyStore
|
||||
|
|
@ -73,6 +74,12 @@ class VFS {
|
|||
}
|
||||
|
||||
preferences.edit().putBoolean("vfs_enabled", true).apply()
|
||||
|
||||
if (corePreferences.makePublicMediaFilesDownloaded) {
|
||||
Log.w("$TAG VFS is now enabled, disabling auto export of media files to native gallery")
|
||||
corePreferences.makePublicMediaFilesDownloaded = false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,8 @@ class MediaViewerActivity : GenericActivity() {
|
|||
val timestamp = args.getLong("timestamp", -1)
|
||||
val isEncrypted = args.getBoolean("isEncrypted", false)
|
||||
val originalPath = args.getString("originalPath", "")
|
||||
viewModel.initTempModel(path, timestamp, isEncrypted, originalPath)
|
||||
val isFromEphemeralMessage = args.getBoolean("isFromEphemeralMessage", false)
|
||||
viewModel.initTempModel(path, timestamp, isEncrypted, originalPath, isFromEphemeralMessage)
|
||||
|
||||
val conversationId = args.getString("conversationId").orEmpty()
|
||||
Log.i(
|
||||
|
|
@ -183,6 +184,12 @@ class MediaViewerActivity : GenericActivity() {
|
|||
val currentItem = binding.mediaViewPager.currentItem
|
||||
val model = if (currentItem >= 0 && currentItem < list.size) list[currentItem] else null
|
||||
if (model != null) {
|
||||
// Never do auto media export for ephemeral messages!
|
||||
if (model.isFromEphemeralMessage) {
|
||||
Log.e("$TAG Do not export media from ephemeral message!")
|
||||
return
|
||||
}
|
||||
|
||||
val filePath = model.path
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
|
|
|
|||
|
|
@ -57,9 +57,9 @@ class MediaListViewModel
|
|||
}
|
||||
|
||||
@UiThread
|
||||
fun initTempModel(path: String, timestamp: Long, isEncrypted: Boolean, originalPath: String) {
|
||||
fun initTempModel(path: String, timestamp: Long, isEncrypted: Boolean, originalPath: String, isFromEphemeralMessage: Boolean) {
|
||||
val name = FileUtils.getNameFromFilePath(path)
|
||||
val model = FileModel(path, name, 0, timestamp, isEncrypted, originalPath)
|
||||
val model = FileModel(path, name, 0, timestamp, isEncrypted, originalPath, isFromEphemeralMessage)
|
||||
temporaryModel = model
|
||||
Log.i("$TAG Temporary model for file [$name] created, use it while other media for conversation are being loaded")
|
||||
mediaList.postValue(arrayListOf(model))
|
||||
|
|
@ -98,7 +98,10 @@ class MediaListViewModel
|
|||
val size = mediaContent.size.toLong()
|
||||
val timestamp = mediaContent.creationTimestamp
|
||||
if (path.isNotEmpty() && name.isNotEmpty()) {
|
||||
val model = FileModel(path, name, size, timestamp, isEncrypted, originalPath)
|
||||
// TODO FIXME: we don't have the ephemeral info at Content level, using the chatRoom info even if content ephemeral status may or may not be different...
|
||||
val ephemeral = chatRoom.isEphemeralEnabled
|
||||
|
||||
val model = FileModel(path, name, size, timestamp, isEncrypted, originalPath, ephemeral)
|
||||
list.add(model)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,11 @@ import androidx.navigation.NavOptions
|
|||
import androidx.navigation.findNavController
|
||||
import kotlin.math.max
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import org.linphone.R
|
||||
|
|
@ -313,6 +315,19 @@ class MainActivity : GenericActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
coreContext.filesToExportToNativeMediaGalleryEvent.observe(this) {
|
||||
it.consume { files ->
|
||||
Log.i("$TAG Found [${files.size}] files to export to native media gallery")
|
||||
for (file in files) {
|
||||
exportFileToNativeMediaGallery(file)
|
||||
}
|
||||
|
||||
coreContext.postOnCoreThread {
|
||||
coreContext.clearFilesToExportToNativeGallery()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CarConnection(this).type.observe(this) {
|
||||
val asString = when (it) {
|
||||
CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "NOT CONNECTED"
|
||||
|
|
@ -777,4 +792,18 @@ class MainActivity : GenericActivity() {
|
|||
dialog.show()
|
||||
currentlyDisplayedAuthDialog = dialog
|
||||
}
|
||||
|
||||
private fun exportFileToNativeMediaGallery(filePath: String) {
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
Log.i("$TAG Export file [$filePath] to Android's MediaStore")
|
||||
val mediaStorePath = FileUtils.addContentToMediaStore(filePath)
|
||||
if (mediaStorePath.isNotEmpty()) {
|
||||
Log.i("$TAG File [$filePath] has been successfully exported to MediaStore")
|
||||
} else {
|
||||
Log.e("$TAG Failed to export file [$filePath] to MediaStore!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ class ConversationDocumentsListFragment : SlidingPaneChildFragment() {
|
|||
putBoolean("isEncrypted", fileModel.isEncrypted)
|
||||
putLong("timestamp", fileModel.fileCreationTimestamp)
|
||||
putString("originalPath", fileModel.originalPath)
|
||||
putBoolean("isFromEphemeralMessage", fileModel.isFromEphemeralMessage)
|
||||
putBoolean("isMedia", false)
|
||||
}
|
||||
when (FileUtils.getMimeType(mime)) {
|
||||
|
|
|
|||
|
|
@ -1114,6 +1114,7 @@ open class ConversationFragment : SlidingPaneChildFragment() {
|
|||
putBoolean("isEncrypted", fileModel.isEncrypted)
|
||||
putLong("timestamp", fileModel.fileCreationTimestamp)
|
||||
putString("originalPath", fileModel.originalPath)
|
||||
putBoolean("isFromEphemeralMessage", fileModel.isFromEphemeralMessage)
|
||||
}
|
||||
when (mimeType) {
|
||||
FileUtils.MimeType.Image, FileUtils.MimeType.Video, FileUtils.MimeType.Audio -> {
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ class ConversationMediaListFragment : SlidingPaneChildFragment() {
|
|||
putBoolean("isEncrypted", fileModel.isEncrypted)
|
||||
putLong("timestamp", fileModel.fileCreationTimestamp)
|
||||
putString("originalPath", fileModel.originalPath)
|
||||
putBoolean("isFromEphemeralMessage", fileModel.isFromEphemeralMessage)
|
||||
putBoolean("isMedia", true)
|
||||
}
|
||||
when (FileUtils.getMimeType(mime)) {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ class EventLogModel
|
|||
onWebUrlClicked: ((url: String) -> Unit)? = null,
|
||||
onContactClicked: ((friendRefKey: String) -> Unit)? = null,
|
||||
onRedToastToShow: ((pair: Pair<Int, Int>) -> Unit)? = null,
|
||||
onVoiceRecordingPlaybackEnded: ((id: String) -> Unit)? = null
|
||||
onVoiceRecordingPlaybackEnded: ((id: String) -> Unit)? = null,
|
||||
onFileToExportToNativeGallery: ((path: String) -> Unit)? = null
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "[Event Log Model]"
|
||||
|
|
@ -89,7 +90,8 @@ class EventLogModel
|
|||
onWebUrlClicked,
|
||||
onContactClicked,
|
||||
onRedToastToShow,
|
||||
onVoiceRecordingPlaybackEnded
|
||||
onVoiceRecordingPlaybackEnded,
|
||||
onFileToExportToNativeGallery
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class FileModel
|
|||
val fileCreationTimestamp: Long,
|
||||
val isEncrypted: Boolean,
|
||||
val originalPath: String,
|
||||
val isFromEphemeralMessage: Boolean,
|
||||
val isWaitingToBeDownloaded: Boolean = false,
|
||||
val flexboxLayoutWrapBefore: Boolean = false,
|
||||
private val onClicked: ((model: FileModel) -> Unit)? = null
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import kotlinx.coroutines.flow.flow
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import org.linphone.R
|
||||
import org.linphone.core.Address
|
||||
import org.linphone.core.ChatMessage
|
||||
|
|
@ -82,7 +83,8 @@ class MessageModel
|
|||
private val onWebUrlClicked: ((url: String) -> Unit)? = null,
|
||||
private val onContactClicked: ((friendRefKey: String) -> Unit)? = null,
|
||||
private val onRedToastToShow: ((pair: Pair<Int, Int>) -> Unit)? = null,
|
||||
private val onVoiceRecordingPlaybackEnded: ((id: String) -> Unit)? = null
|
||||
private val onVoiceRecordingPlaybackEnded: ((id: String) -> Unit)? = null,
|
||||
private val onFileToExportToNativeGallery: ((path: String) -> Unit)? = null
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "[Message Model]"
|
||||
|
|
@ -224,6 +226,27 @@ class MessageModel
|
|||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onFileTransferTerminated(message: ChatMessage, content: Content) {
|
||||
Log.i("$TAG File [${content.name}] from message [${message.messageId}] transfer terminated")
|
||||
|
||||
// Never do auto media export for ephemeral messages!
|
||||
if (corePreferences.makePublicMediaFilesDownloaded && !message.isEphemeral) {
|
||||
val path = content.filePath
|
||||
if (path.isNullOrEmpty()) return
|
||||
|
||||
val mime = "${content.type}/${content.subtype}"
|
||||
val mimeType = FileUtils.getMimeType(mime)
|
||||
when (mimeType) {
|
||||
FileUtils.MimeType.Image, FileUtils.MimeType.Video, FileUtils.MimeType.Audio -> {
|
||||
Log.i("$TAG Exporting file path [$path] to the native media gallery")
|
||||
onFileToExportToNativeGallery?.invoke(path)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onNewMessageReaction(message: ChatMessage, reaction: ChatMessageReaction) {
|
||||
Log.i(
|
||||
|
|
@ -443,6 +466,7 @@ class MessageModel
|
|||
timestamp,
|
||||
isFileEncrypted,
|
||||
originalPath,
|
||||
chatMessage.isEphemeral,
|
||||
flexboxLayoutWrapBefore = wrapBefore
|
||||
) { model ->
|
||||
onContentClicked?.invoke(model)
|
||||
|
|
@ -470,7 +494,8 @@ class MessageModel
|
|||
content.fileSize.toLong(),
|
||||
timestamp,
|
||||
isFileEncrypted,
|
||||
path
|
||||
path,
|
||||
chatMessage.isEphemeral
|
||||
) { model ->
|
||||
onContentClicked?.invoke(model)
|
||||
}
|
||||
|
|
@ -482,6 +507,7 @@ class MessageModel
|
|||
timestamp,
|
||||
isFileEncrypted,
|
||||
name,
|
||||
chatMessage.isEphemeral,
|
||||
isWaitingToBeDownloaded = true
|
||||
) { model ->
|
||||
downloadContent(model, content)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,11 @@ class ConversationDocumentsListViewModel
|
|||
val size = documentContent.size.toLong()
|
||||
val timestamp = documentContent.creationTimestamp
|
||||
if (path.isNotEmpty() && name.isNotEmpty()) {
|
||||
val model = FileModel(path, name, size, timestamp, isEncrypted, originalPath) {
|
||||
// TODO FIXME: we don't have the ephemeral info at Content level, using the chatRoom info even if content ephemeral status may or may not be different...
|
||||
val ephemeral = chatRoom.isEphemeralEnabled
|
||||
|
||||
val model =
|
||||
FileModel(path, name, size, timestamp, isEncrypted, originalPath, ephemeral) {
|
||||
openDocumentEvent.postValue(Event(it))
|
||||
}
|
||||
list.add(model)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,8 @@ class ConversationMediaListViewModel
|
|||
val size = mediaContent.size.toLong()
|
||||
val timestamp = mediaContent.creationTimestamp
|
||||
if (path.isNotEmpty() && name.isNotEmpty()) {
|
||||
val model = FileModel(path, name, size, timestamp, isEncrypted, originalPath) {
|
||||
val model =
|
||||
FileModel(path, name, size, timestamp, isEncrypted, originalPath, chatRoom.isEphemeralEnabled) {
|
||||
openMediaEvent.postValue(Event(it))
|
||||
}
|
||||
list.add(model)
|
||||
|
|
|
|||
|
|
@ -761,6 +761,19 @@ class ConversationViewModel
|
|||
},
|
||||
{ id ->
|
||||
voiceRecordPlaybackEndedEvent.postValue(Event(id))
|
||||
},
|
||||
{ filePath ->
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
Log.i("$TAG Export file [$filePath] to Android's MediaStore")
|
||||
val mediaStorePath = FileUtils.addContentToMediaStore(filePath)
|
||||
if (mediaStorePath.isNotEmpty()) {
|
||||
Log.i("$TAG File [$filePath] has been successfully exported to MediaStore")
|
||||
} else {
|
||||
Log.e("$TAG Failed to export file [$filePath] to MediaStore!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
eventsList.add(model)
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ class SendMessageInConversationViewModel
|
|||
|
||||
val fileName = FileUtils.getNameFromFilePath(file)
|
||||
val timestamp = System.currentTimeMillis() / 1000
|
||||
val model = FileModel(file, fileName, 0, timestamp, false, file) { model ->
|
||||
val model = FileModel(file, fileName, 0, timestamp, false, file, chatRoom.isEphemeralEnabled) { model ->
|
||||
removeAttachment(model.path)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ class SettingsViewModel
|
|||
|
||||
val autoDownloadEnabled = MutableLiveData<Boolean>()
|
||||
|
||||
val autoExportMediaToNativeGallery = MutableLiveData<Boolean>()
|
||||
|
||||
val markAsReadWhenDismissingNotification = MutableLiveData<Boolean>()
|
||||
|
||||
// Contacts settings
|
||||
|
|
@ -246,7 +248,8 @@ class SettingsViewModel
|
|||
expandAudioCodecs.value = false
|
||||
expandVideoCodecs.value = false
|
||||
|
||||
isVfsEnabled.value = VFS.isEnabled(coreContext.context)
|
||||
val vfsEnabled = VFS.isEnabled(coreContext.context)
|
||||
isVfsEnabled.value = vfsEnabled
|
||||
|
||||
val vibrator = coreContext.context.getSystemService(Vibrator::class.java)
|
||||
isVibrationAvailable.value = vibrator.hasVibrator()
|
||||
|
|
@ -285,6 +288,7 @@ class SettingsViewModel
|
|||
allowIpv6.postValue(core.isIpv6Enabled)
|
||||
|
||||
autoDownloadEnabled.postValue(core.maxSizeForAutoDownloadIncomingFiles == 0)
|
||||
autoExportMediaToNativeGallery.postValue(corePreferences.makePublicMediaFilesDownloaded && !vfsEnabled)
|
||||
markAsReadWhenDismissingNotification.postValue(
|
||||
corePreferences.markConversationAsReadWhenDismissingMessageNotification
|
||||
)
|
||||
|
|
@ -439,6 +443,15 @@ class SettingsViewModel
|
|||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun toggleAutoExportMediaFilesToNativeGallery() {
|
||||
val newValue = autoExportMediaToNativeGallery.value == false
|
||||
coreContext.postOnCoreThread { core ->
|
||||
corePreferences.makePublicMediaFilesDownloaded = newValue
|
||||
autoExportMediaToNativeGallery.postValue(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun toggleMarkConversationAsReadWhenDismissingNotification() {
|
||||
val newValue = markAsReadWhenDismissingNotification.value == false
|
||||
|
|
|
|||
|
|
@ -40,10 +40,39 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:enabled="@{!viewModel.isVfsEnabled}"
|
||||
android:checked="@{viewModel.autoDownloadEnabled}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/settings_title_style"
|
||||
android:onClick="@{() -> viewModel.toggleAutoExportMediaFilesToNativeGallery()}"
|
||||
android:id="@+id/auto_export_media_to_native_gallery_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="@string/settings_conversations_auto_export_media_to_native_gallery_title"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintTop_toTopOf="@id/auto_export_media_to_native_gallery_switch"
|
||||
app:layout_constraintBottom_toBottomOf="@id/auto_export_media_to_native_gallery_switch"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/auto_export_media_to_native_gallery_switch"/>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
style="@style/material_switch_style"
|
||||
android:id="@+id/auto_export_media_to_native_gallery_switch"
|
||||
android:onClick="@{() -> viewModel.toggleAutoExportMediaFilesToNativeGallery()}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:checked="@{viewModel.autoExportMediaToNativeGallery}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/auto_download_switch" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/settings_title_style"
|
||||
android:onClick="@{() -> viewModel.toggleMarkConversationAsReadWhenDismissingNotification()}"
|
||||
|
|
@ -70,7 +99,7 @@
|
|||
android:layout_marginEnd="16dp"
|
||||
android:checked="@{viewModel.markAsReadWhenDismissingNotification}"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/auto_download_switch" />
|
||||
app:layout_constraintTop_toBottomOf="@id/auto_export_media_to_native_gallery_switch" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@
|
|||
<string name="settings_calls_change_ringtone_title">Changer de sonnerie</string>
|
||||
<string name="settings_conversations_title">Conversations</string>
|
||||
<string name="settings_conversations_auto_download_title">Télécharger automatiquement les fichiers</string>
|
||||
<string name="settings_conversations_auto_export_media_to_native_gallery_title">Rendre visible dans la galerie les médias téléchargés</string>
|
||||
<string name="settings_conversations_mark_as_read_when_dismissing_notif_title">Marquer la conversation comme lue lorsqu\'une notification de message est supprimée</string>
|
||||
<string name="settings_contacts_title">Contacts</string>
|
||||
<string name="settings_contacts_add_ldap_server_title">Ajouter un serveur LDAP</string>
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@
|
|||
<string name="settings_calls_change_ringtone_title">Change ringtone</string>
|
||||
<string name="settings_conversations_title">Conversations</string>
|
||||
<string name="settings_conversations_auto_download_title">Auto-download files</string>
|
||||
<string name="settings_conversations_auto_export_media_to_native_gallery_title">Make downloaded media public</string>
|
||||
<string name="settings_conversations_mark_as_read_when_dismissing_notif_title">Mark conversation as read when dismissing message notification</string>
|
||||
<string name="settings_contacts_title">Contacts</string>
|
||||
<string name="settings_contacts_add_ldap_server_title">Add LDAP server</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue