parent
30a54cfdbc
commit
d9ffce7e0d
|
@ -10,6 +10,7 @@ Improvements 🙌:
|
||||||
- Compress video before sending (#442)
|
- Compress video before sending (#442)
|
||||||
- Improve file too big error detection (#3245)
|
- Improve file too big error detection (#3245)
|
||||||
- User can now select video when selecting Gallery to send attachments to a room
|
- User can now select video when selecting Gallery to send attachments to a room
|
||||||
|
- Add option to record a video from the camera
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
- Message states cosmetic changes (#3007)
|
- Message states cosmetic changes (#3007)
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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.lib.multipicker
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.MediaMetadataRetriever
|
||||||
|
import android.net.Uri
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import im.vector.lib.multipicker.entity.MultiPickerVideoType
|
||||||
|
import java.io.File
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of taking a video with Camera
|
||||||
|
*/
|
||||||
|
class CameraVideoPicker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start camera by using a ActivityResultLauncher
|
||||||
|
* @return Uri of taken photo or null if the operation is cancelled.
|
||||||
|
*/
|
||||||
|
fun startWithExpectingFile(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>): Uri? {
|
||||||
|
val videoUri = createVideoUri(context)
|
||||||
|
val intent = createIntent().apply {
|
||||||
|
putExtra(MediaStore.EXTRA_OUTPUT, videoUri)
|
||||||
|
}
|
||||||
|
activityResultLauncher.launch(intent)
|
||||||
|
return videoUri
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function from onActivityResult(int, int, Intent).
|
||||||
|
* @return Taken photo or null if request code is wrong
|
||||||
|
* or result code is not Activity.RESULT_OK
|
||||||
|
* or user cancelled the operation.
|
||||||
|
*/
|
||||||
|
fun getTakenVideo(context: Context, videoUri: Uri): MultiPickerVideoType? {
|
||||||
|
val projection = arrayOf(
|
||||||
|
MediaStore.Images.Media.DISPLAY_NAME,
|
||||||
|
MediaStore.Images.Media.SIZE,
|
||||||
|
MediaStore.Images.Media.MIME_TYPE
|
||||||
|
)
|
||||||
|
|
||||||
|
context.contentResolver.query(
|
||||||
|
videoUri,
|
||||||
|
projection,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)?.use { cursor ->
|
||||||
|
val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
|
||||||
|
val sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
|
||||||
|
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
val name = cursor.getString(nameColumn)
|
||||||
|
val size = cursor.getLong(sizeColumn)
|
||||||
|
var duration = 0L
|
||||||
|
var width = 0
|
||||||
|
var height = 0
|
||||||
|
var orientation = 0
|
||||||
|
|
||||||
|
context.contentResolver.openFileDescriptor(videoUri, "r")?.use { pfd ->
|
||||||
|
val mediaMetadataRetriever = MediaMetadataRetriever()
|
||||||
|
mediaMetadataRetriever.setDataSource(pfd.fileDescriptor)
|
||||||
|
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
|
||||||
|
width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: 0
|
||||||
|
height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: 0
|
||||||
|
orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)?.toInt() ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiPickerVideoType(
|
||||||
|
name,
|
||||||
|
size,
|
||||||
|
context.contentResolver.getType(videoUri),
|
||||||
|
videoUri,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
orientation,
|
||||||
|
duration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createIntent(): Intent {
|
||||||
|
return Intent(MediaStore.ACTION_VIDEO_CAPTURE)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun createVideoUri(context: Context): Uri {
|
||||||
|
val file = createVideoFile(context)
|
||||||
|
val authority = context.packageName + ".multipicker.fileprovider"
|
||||||
|
return FileProvider.getUriForFile(context, authority, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createVideoFile(context: Context): File {
|
||||||
|
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
||||||
|
val storageDir: File = context.filesDir
|
||||||
|
return File.createTempFile(
|
||||||
|
"${timeStamp}_", /* prefix */
|
||||||
|
".mp4", /* suffix */
|
||||||
|
storageDir /* directory */
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ class MultiPicker<T> {
|
||||||
val AUDIO by lazy { MultiPicker<AudioPicker>() }
|
val AUDIO by lazy { MultiPicker<AudioPicker>() }
|
||||||
val CONTACT by lazy { MultiPicker<ContactPicker>() }
|
val CONTACT by lazy { MultiPicker<ContactPicker>() }
|
||||||
val CAMERA by lazy { MultiPicker<CameraPicker>() }
|
val CAMERA by lazy { MultiPicker<CameraPicker>() }
|
||||||
|
val CAMERA_VIDEO by lazy { MultiPicker<CameraVideoPicker>() }
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T> get(type: MultiPicker<T>): T {
|
fun <T> get(type: MultiPicker<T>): T {
|
||||||
|
@ -37,6 +38,7 @@ class MultiPicker<T> {
|
||||||
AUDIO -> AudioPicker() as T
|
AUDIO -> AudioPicker() as T
|
||||||
CONTACT -> ContactPicker() as T
|
CONTACT -> ContactPicker() as T
|
||||||
CAMERA -> CameraPicker() as T
|
CAMERA -> CameraPicker() as T
|
||||||
|
CAMERA_VIDEO -> CameraVideoPicker() as T
|
||||||
else -> throw IllegalArgumentException("Unsupported type $type")
|
else -> throw IllegalArgumentException("Unsupported type $type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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.app.core.dialogs
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.DialogPhotoOrVideoBinding
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
|
||||||
|
class PhotoOrVideoDialog(
|
||||||
|
private val activity: Activity,
|
||||||
|
private val vectorPreferences: VectorPreferences
|
||||||
|
) {
|
||||||
|
|
||||||
|
interface PhotoOrVideoDialogListener {
|
||||||
|
fun takePhoto()
|
||||||
|
fun takeVideo()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PhotoOrVideoDialogSettingsListener {
|
||||||
|
fun onUpdated()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show(listener: PhotoOrVideoDialogListener) {
|
||||||
|
when (vectorPreferences.getTakePhotoVideoMode()) {
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_PHOTO -> listener.takePhoto()
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_VIDEO -> listener.takeVideo()
|
||||||
|
/* VectorPreferences.TAKE_PHOTO_VIDEO_MODE_ALWAYS_ASK */
|
||||||
|
else -> {
|
||||||
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_photo_or_video, null)
|
||||||
|
val views = DialogPhotoOrVideoBinding.bind(dialogLayout)
|
||||||
|
|
||||||
|
// Show option to set as default in this case
|
||||||
|
views.dialogPhotoOrVideoAsDefault.isVisible = true
|
||||||
|
// Always default to photo
|
||||||
|
views.dialogPhotoOrVideoPhoto.isChecked = true
|
||||||
|
|
||||||
|
AlertDialog.Builder(activity)
|
||||||
|
.setTitle(R.string.option_take_photo_video)
|
||||||
|
.setView(dialogLayout)
|
||||||
|
.setPositiveButton(R.string._continue) { _, _ ->
|
||||||
|
submit(views, vectorPreferences, listener)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun submit(views: DialogPhotoOrVideoBinding,
|
||||||
|
vectorPreferences: VectorPreferences,
|
||||||
|
listener: PhotoOrVideoDialogListener) {
|
||||||
|
val mode = if (views.dialogPhotoOrVideoPhoto.isChecked) {
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_PHOTO
|
||||||
|
} else {
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_VIDEO
|
||||||
|
}
|
||||||
|
|
||||||
|
if (views.dialogPhotoOrVideoAsDefault.isChecked) {
|
||||||
|
vectorPreferences.setTakePhotoVideoMode(mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
when (mode) {
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_PHOTO -> listener.takePhoto()
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_VIDEO -> listener.takeVideo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showForSettings(listener: PhotoOrVideoDialogSettingsListener) {
|
||||||
|
val currentMode = vectorPreferences.getTakePhotoVideoMode()
|
||||||
|
|
||||||
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_photo_or_video, null)
|
||||||
|
val views = DialogPhotoOrVideoBinding.bind(dialogLayout)
|
||||||
|
|
||||||
|
// Show option for always ask in this case
|
||||||
|
views.dialogPhotoOrVideoAlwaysAsk.isVisible = true
|
||||||
|
// Always default to photo
|
||||||
|
views.dialogPhotoOrVideoPhoto.isChecked = currentMode == VectorPreferences.TAKE_PHOTO_VIDEO_MODE_PHOTO
|
||||||
|
views.dialogPhotoOrVideoVideo.isChecked = currentMode == VectorPreferences.TAKE_PHOTO_VIDEO_MODE_VIDEO
|
||||||
|
views.dialogPhotoOrVideoAlwaysAsk.isChecked = currentMode == VectorPreferences.TAKE_PHOTO_VIDEO_MODE_ALWAYS_ASK
|
||||||
|
|
||||||
|
AlertDialog.Builder(activity)
|
||||||
|
.setTitle(R.string.option_take_photo_video)
|
||||||
|
.setView(dialogLayout)
|
||||||
|
.setPositiveButton(R.string.save) { _, _ ->
|
||||||
|
submitSettings(views)
|
||||||
|
listener.onUpdated()
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun submitSettings(views: DialogPhotoOrVideoBinding) {
|
||||||
|
vectorPreferences.setTakePhotoVideoMode(
|
||||||
|
when {
|
||||||
|
views.dialogPhotoOrVideoPhoto.isChecked -> VectorPreferences.TAKE_PHOTO_VIDEO_MODE_PHOTO
|
||||||
|
views.dialogPhotoOrVideoVideo.isChecked -> VectorPreferences.TAKE_PHOTO_VIDEO_MODE_VIDEO
|
||||||
|
else -> VectorPreferences.TAKE_PHOTO_VIDEO_MODE_ALWAYS_ASK
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,12 +15,15 @@
|
||||||
*/
|
*/
|
||||||
package im.vector.app.features.attachments
|
package im.vector.app.features.attachments
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import im.vector.app.core.dialogs.PhotoOrVideoDialog
|
||||||
import im.vector.app.core.platform.Restorable
|
import im.vector.app.core.platform.Restorable
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.lib.multipicker.MultiPicker
|
import im.vector.lib.multipicker.MultiPicker
|
||||||
import org.matrix.android.sdk.BuildConfig
|
import org.matrix.android.sdk.BuildConfig
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
|
@ -91,10 +94,21 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the process for handling capture image picking
|
* Starts the process for handling image/video capture. Can open a dialog
|
||||||
*/
|
*/
|
||||||
fun openCamera(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>) {
|
fun openCamera(activity: Activity,
|
||||||
captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(context, activityResultLauncher)
|
vectorPreferences: VectorPreferences,
|
||||||
|
cameraActivityResultLauncher: ActivityResultLauncher<Intent>,
|
||||||
|
cameraVideoActivityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
|
PhotoOrVideoDialog(activity, vectorPreferences).show(object : PhotoOrVideoDialog.PhotoOrVideoDialogListener {
|
||||||
|
override fun takePhoto() {
|
||||||
|
captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(context, cameraActivityResultLauncher)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun takeVideo() {
|
||||||
|
captureUri = MultiPicker.get(MultiPicker.CAMERA_VIDEO).startWithExpectingFile(context, cameraVideoActivityResultLauncher)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -141,7 +155,7 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onPhotoResult() {
|
fun onCameraResult() {
|
||||||
captureUri?.let { captureUri ->
|
captureUri?.let { captureUri ->
|
||||||
MultiPicker.get(MultiPicker.CAMERA)
|
MultiPicker.get(MultiPicker.CAMERA)
|
||||||
.getTakenPhoto(context, captureUri)
|
.getTakenPhoto(context, captureUri)
|
||||||
|
@ -153,6 +167,18 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onCameraVideoResult() {
|
||||||
|
captureUri?.let { captureUri ->
|
||||||
|
MultiPicker.get(MultiPicker.CAMERA_VIDEO)
|
||||||
|
.getTakenVideo(context, captureUri)
|
||||||
|
?.let {
|
||||||
|
callback.onContentAttachmentsReady(
|
||||||
|
listOf(it).map { it.toContentAttachmentData() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onVideoResult(data: Intent?) {
|
fun onVideoResult(data: Intent?) {
|
||||||
callback.onContentAttachmentsReady(
|
callback.onContentAttachmentsReady(
|
||||||
MultiPicker.get(MultiPicker.VIDEO)
|
MultiPicker.get(MultiPicker.VIDEO)
|
||||||
|
|
|
@ -994,9 +994,15 @@ class RoomDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val attachmentPhotoActivityResultLauncher = registerStartForActivityResult {
|
private val attachmentCameraActivityResultLauncher = registerStartForActivityResult {
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
attachmentsHelper.onPhotoResult()
|
attachmentsHelper.onCameraResult()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val attachmentCameraVideoActivityResultLauncher = registerStartForActivityResult {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
|
attachmentsHelper.onCameraVideoResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1989,7 +1995,12 @@ class RoomDetailFragment @Inject constructor(
|
||||||
|
|
||||||
private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) {
|
private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) {
|
||||||
when (type) {
|
when (type) {
|
||||||
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(requireContext(), attachmentPhotoActivityResultLauncher)
|
AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(
|
||||||
|
activity = requireActivity(),
|
||||||
|
vectorPreferences = vectorPreferences,
|
||||||
|
cameraActivityResultLauncher = attachmentCameraActivityResultLauncher,
|
||||||
|
cameraVideoActivityResultLauncher = attachmentCameraVideoActivityResultLauncher
|
||||||
|
)
|
||||||
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
|
AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher)
|
||||||
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentMediaActivityResultLauncher)
|
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentMediaActivityResultLauncher)
|
||||||
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
|
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher)
|
||||||
|
|
|
@ -193,6 +193,13 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||||
|
|
||||||
private const val SETTINGS_UNKNOWN_DEVICE_DISMISSED_LIST = "SETTINGS_UNKNWON_DEVICE_DISMISSED_LIST"
|
private const val SETTINGS_UNKNOWN_DEVICE_DISMISSED_LIST = "SETTINGS_UNKNWON_DEVICE_DISMISSED_LIST"
|
||||||
|
|
||||||
|
private const val TAKE_PHOTO_VIDEO_MODE = "TAKE_PHOTO_VIDEO_MODE"
|
||||||
|
|
||||||
|
// Possible values for TAKE_PHOTO_VIDEO_MODE
|
||||||
|
const val TAKE_PHOTO_VIDEO_MODE_ALWAYS_ASK = 0
|
||||||
|
const val TAKE_PHOTO_VIDEO_MODE_PHOTO = 1
|
||||||
|
const val TAKE_PHOTO_VIDEO_MODE_VIDEO = 2
|
||||||
|
|
||||||
// Background sync modes
|
// Background sync modes
|
||||||
|
|
||||||
// some preferences keys must be kept after a logout
|
// some preferences keys must be kept after a logout
|
||||||
|
@ -948,4 +955,17 @@ class VectorPreferences @Inject constructor(private val context: Context) {
|
||||||
fun labsUseExperimentalRestricted(): Boolean {
|
fun labsUseExperimentalRestricted(): Boolean {
|
||||||
return defaultPrefs.getBoolean(SETTINGS_LABS_USE_RESTRICTED_JOIN_RULE, false)
|
return defaultPrefs.getBoolean(SETTINGS_LABS_USE_RESTRICTED_JOIN_RULE, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Photo / video picker
|
||||||
|
*/
|
||||||
|
fun getTakePhotoVideoMode(): Int {
|
||||||
|
return defaultPrefs.getInt(TAKE_PHOTO_VIDEO_MODE, TAKE_PHOTO_VIDEO_MODE_ALWAYS_ASK)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTakePhotoVideoMode(mode: Int) {
|
||||||
|
return defaultPrefs.edit {
|
||||||
|
putInt(TAKE_PHOTO_VIDEO_MODE, mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.children
|
import androidx.core.view.children
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.dialogs.PhotoOrVideoDialog
|
||||||
import im.vector.app.core.extensions.restart
|
import im.vector.app.core.extensions.restart
|
||||||
import im.vector.app.core.preference.VectorListPreference
|
import im.vector.app.core.preference.VectorListPreference
|
||||||
import im.vector.app.core.preference.VectorPreference
|
import im.vector.app.core.preference.VectorPreference
|
||||||
|
@ -45,6 +46,9 @@ class VectorSettingsPreferencesFragment @Inject constructor(
|
||||||
private val textSizePreference by lazy {
|
private val textSizePreference by lazy {
|
||||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_INTERFACE_TEXT_SIZE_KEY)!!
|
findPreference<VectorPreference>(VectorPreferences.SETTINGS_INTERFACE_TEXT_SIZE_KEY)!!
|
||||||
}
|
}
|
||||||
|
private val takePhotoOrVideoPreference by lazy {
|
||||||
|
findPreference<VectorPreference>("SETTINGS_INTERFACE_TAKE_PHOTO_VIDEO")!!
|
||||||
|
}
|
||||||
|
|
||||||
override fun bindPref() {
|
override fun bindPref() {
|
||||||
// user interface preferences
|
// user interface preferences
|
||||||
|
@ -123,6 +127,28 @@ class VectorSettingsPreferencesFragment @Inject constructor(
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take photo or video
|
||||||
|
updateTakePhotoOrVideoPreferenceSummary()
|
||||||
|
takePhotoOrVideoPreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
|
PhotoOrVideoDialog(requireActivity(), vectorPreferences).showForSettings(object: PhotoOrVideoDialog.PhotoOrVideoDialogSettingsListener {
|
||||||
|
override fun onUpdated() {
|
||||||
|
updateTakePhotoOrVideoPreferenceSummary()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateTakePhotoOrVideoPreferenceSummary() {
|
||||||
|
takePhotoOrVideoPreference.summary = getString(
|
||||||
|
when (vectorPreferences.getTakePhotoVideoMode()) {
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_PHOTO -> R.string.option_take_photo
|
||||||
|
VectorPreferences.TAKE_PHOTO_VIDEO_MODE_VIDEO -> R.string.option_take_video
|
||||||
|
/* VectorPreferences.TAKE_PHOTO_VIDEO_MODE_ALWAYS_ASK */
|
||||||
|
else -> R.string.option_always_ask
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/layout_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="?dialogPreferredPadding"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingEnd="?dialogPreferredPadding"
|
||||||
|
android:paddingBottom="12dp">
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/dialog_photo_or_video_photo"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/option_take_photo"
|
||||||
|
tools:checked="true" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/dialog_photo_or_video_video"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="180dp"
|
||||||
|
android:text="@string/option_take_video" />
|
||||||
|
|
||||||
|
<!-- Displayed only form the settings -->
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/dialog_photo_or_video_always_ask"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minWidth="180dp"
|
||||||
|
android:text="@string/option_always_ask"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
|
<!-- Displayed only form the timeline -->
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/dialog_photo_or_video_as_default"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/use_as_default_and_do_not_ask_again"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -575,6 +575,9 @@
|
||||||
<string name="option_take_photo_video">Take photo or video</string>
|
<string name="option_take_photo_video">Take photo or video</string>
|
||||||
<string name="option_take_photo">Take photo</string>
|
<string name="option_take_photo">Take photo</string>
|
||||||
<string name="option_take_video">Take video</string>
|
<string name="option_take_video">Take video</string>
|
||||||
|
<string name="option_always_ask">Always ask</string>
|
||||||
|
|
||||||
|
<string name="use_as_default_and_do_not_ask_again">Use as default and do not ask again</string>
|
||||||
|
|
||||||
<!-- No sticker application dialog -->
|
<!-- No sticker application dialog -->
|
||||||
<string name="no_sticker_application_dialog_content">You don’t currently have any stickerpacks enabled.\n\nAdd some now?</string>
|
<string name="no_sticker_application_dialog_content">You don’t currently have any stickerpacks enabled.\n\nAdd some now?</string>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.preference.PreferenceScreen 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">
|
||||||
|
|
||||||
<im.vector.app.core.preference.VectorPreferenceCategory
|
<im.vector.app.core.preference.VectorPreferenceCategory
|
||||||
android:key="SETTINGS_USER_INTERFACE_KEY"
|
android:key="SETTINGS_USER_INTERFACE_KEY"
|
||||||
|
@ -55,6 +56,12 @@
|
||||||
android:summary="@string/settings_show_emoji_keyboard_summary"
|
android:summary="@string/settings_show_emoji_keyboard_summary"
|
||||||
android:title="@string/settings_show_emoji_keyboard" />
|
android:title="@string/settings_show_emoji_keyboard" />
|
||||||
|
|
||||||
|
<im.vector.app.core.preference.VectorPreference
|
||||||
|
android:key="SETTINGS_INTERFACE_TAKE_PHOTO_VIDEO"
|
||||||
|
android:persistent="false"
|
||||||
|
android:title="@string/option_take_photo_video"
|
||||||
|
tools:summary="@string/option_always_ask" />
|
||||||
|
|
||||||
</im.vector.app.core.preference.VectorPreferenceCategory>
|
</im.vector.app.core.preference.VectorPreferenceCategory>
|
||||||
|
|
||||||
<im.vector.app.core.preference.VectorPreferenceCategory android:title="@string/settings_category_timeline">
|
<im.vector.app.core.preference.VectorPreferenceCategory android:title="@string/settings_category_timeline">
|
||||||
|
@ -185,10 +192,10 @@
|
||||||
|
|
||||||
<im.vector.app.core.preference.VectorPreferenceCategory android:title="@string/settings_category_room_directory">
|
<im.vector.app.core.preference.VectorPreferenceCategory android:title="@string/settings_category_room_directory">
|
||||||
|
|
||||||
<im.vector.app.core.preference.VectorSwitchPreference
|
<im.vector.app.core.preference.VectorSwitchPreference
|
||||||
android:key="SETTINGS_ROOM_DIRECTORY_SHOW_ALL_PUBLIC_ROOMS"
|
android:key="SETTINGS_ROOM_DIRECTORY_SHOW_ALL_PUBLIC_ROOMS"
|
||||||
android:summary="@string/settings_room_directory_show_all_rooms_summary"
|
android:summary="@string/settings_room_directory_show_all_rooms_summary"
|
||||||
android:title="@string/settings_room_directory_show_all_rooms" />
|
android:title="@string/settings_room_directory_show_all_rooms" />
|
||||||
|
|
||||||
</im.vector.app.core.preference.VectorPreferenceCategory>
|
</im.vector.app.core.preference.VectorPreferenceCategory>
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue