mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Merge branch 'develop' into feature/bma/url_preview
This commit is contained in:
commit
989f1c6268
26 changed files with 261 additions and 226 deletions
|
@ -25,6 +25,7 @@
|
|||
<w>pids</w>
|
||||
<w>pkcs</w>
|
||||
<w>previewable</w>
|
||||
<w>previewables</w>
|
||||
<w>riotx</w>
|
||||
<w>signin</w>
|
||||
<w>signout</w>
|
||||
|
|
|
@ -16,6 +16,8 @@ Bugfix 🐛:
|
|||
- Fix cancellation of sending event (#2438)
|
||||
- Double bottomsheet effect after verify with passphrase
|
||||
- EditText cursor jumps to the start while typing fast (#2469)
|
||||
- Show preview when sending attachment from the keyboard (#2440)
|
||||
- Do not compress GIFs (#1616, #1254)
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.os.Parcelable
|
|||
import androidx.exifinterface.media.ExifInterface
|
||||
import com.squareup.moshi.JsonClass
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType
|
||||
|
||||
@Parcelize
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
@ -45,5 +46,5 @@ data class ContentAttachmentData(
|
|||
VIDEO
|
||||
}
|
||||
|
||||
fun getSafeMimeType() = if (mimeType == "image/jpg") "image/jpeg" else mimeType
|
||||
fun getSafeMimeType() = mimeType?.normalizeMimeType()
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.squareup.moshi.Json
|
|||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
@ -54,5 +55,5 @@ data class MessageImageContent(
|
|||
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
|
||||
) : MessageImageInfoContent {
|
||||
override val mimeType: String?
|
||||
get() = encryptedFileInfo?.mimetype ?: info?.mimeType ?: "image/*"
|
||||
get() = encryptedFileInfo?.mimetype ?: info?.mimeType ?: MimeTypes.Images
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.api.util
|
||||
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
|
||||
// The Android SDK does not provide constant for mime type, add some of them here
|
||||
object MimeTypes {
|
||||
const val Any: String = "*/*"
|
||||
const val OctetStream = "application/octet-stream"
|
||||
|
||||
const val Images = "image/*"
|
||||
|
||||
const val Png = "image/png"
|
||||
const val BadJpg = "image/jpg"
|
||||
const val Jpeg = "image/jpeg"
|
||||
const val Gif = "image/gif"
|
||||
|
||||
fun String?.normalizeMimeType() = if (this == BadJpg) Jpeg else this
|
||||
|
||||
fun String?.isMimeTypeImage() = this?.startsWith("image/").orFalse()
|
||||
fun String?.isMimeTypeVideo() = this?.startsWith("video/").orFalse()
|
||||
fun String?.isMimeTypeAudio() = this?.startsWith("audio/").orFalse()
|
||||
}
|
|
@ -20,6 +20,7 @@ import android.content.Context
|
|||
import android.graphics.Bitmap
|
||||
import android.media.MediaMetadataRetriever
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import timber.log.Timber
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
|
@ -58,7 +59,7 @@ internal object ThumbnailExtractor {
|
|||
height = thumbnailHeight,
|
||||
size = thumbnailSize.toLong(),
|
||||
bytes = outputStream.toByteArray(),
|
||||
mimeType = "image/jpeg"
|
||||
mimeType = MimeTypes.Jpeg
|
||||
)
|
||||
thumbnail.recycle()
|
||||
outputStream.reset()
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
|||
import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments
|
||||
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
|
||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||
|
@ -151,7 +152,10 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
|||
params.attachment.size
|
||||
)
|
||||
|
||||
if (attachment.type == ContentAttachmentData.Type.IMAGE && params.compressBeforeSending) {
|
||||
if (attachment.type == ContentAttachmentData.Type.IMAGE
|
||||
// Do not compress gif
|
||||
&& attachment.mimeType != MimeTypes.Gif
|
||||
&& params.compressBeforeSending) {
|
||||
fileToUpload = imageCompressor.compress(context, workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
|
||||
.also { compressedFile ->
|
||||
// Get new Bitmap size
|
||||
|
@ -191,7 +195,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
|||
Timber.v("## FileService: Uploading file")
|
||||
|
||||
fileUploader
|
||||
.uploadFile(encryptedFile, attachment.name, "application/octet-stream", progressListener)
|
||||
.uploadFile(encryptedFile, attachment.name, MimeTypes.OctetStream, progressListener)
|
||||
} else {
|
||||
Timber.v("## FileService: Clear file")
|
||||
encryptedFile = null
|
||||
|
@ -258,7 +262,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
|||
val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType)
|
||||
val contentUploadResponse = fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
|
||||
"thumb_${params.attachment.name}",
|
||||
"application/octet-stream",
|
||||
MimeTypes.OctetStream,
|
||||
thumbnailProgressListener)
|
||||
UploadThumbnailResult(
|
||||
contentUploadResponse.contentUri,
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.identity.ThreePid
|
|||
import org.matrix.android.sdk.api.session.profile.ProfileService
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity
|
||||
import org.matrix.android.sdk.internal.database.model.UserThreePidEntity
|
||||
|
@ -80,7 +81,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
|
|||
|
||||
override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback<Unit>): Cancelable {
|
||||
return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, matrixCallback) {
|
||||
val response = fileUploader.uploadFromUri(newAvatarUri, fileName, "image/jpeg")
|
||||
val response = fileUploader.uploadFromUri(newAvatarUri, fileName, MimeTypes.Jpeg)
|
||||
setAvatarUrlTask.execute(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = response.contentUri))
|
||||
userStore.updateAvatar(userId, response.contentUri)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
|||
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
|
||||
import org.matrix.android.sdk.api.session.identity.toMedium
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.internal.crypto.DeviceListManager
|
||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
|
||||
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
|
||||
|
@ -96,7 +97,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
|
|||
fileUploader.uploadFromUri(
|
||||
uri = avatarUri,
|
||||
filename = UUID.randomUUID().toString(),
|
||||
mimeType = "image/jpeg")
|
||||
mimeType = MimeTypes.Jpeg)
|
||||
}
|
||||
?.let { response ->
|
||||
Event(
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
|||
import org.matrix.android.sdk.api.session.room.state.StateService
|
||||
import org.matrix.android.sdk.api.util.Cancelable
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
import org.matrix.android.sdk.internal.session.content.FileUploader
|
||||
import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask
|
||||
|
@ -164,7 +165,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
|
|||
|
||||
override fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback<Unit>): Cancelable {
|
||||
return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) {
|
||||
val response = fileUploader.uploadFromUri(avatarUri, fileName, "image/jpeg")
|
||||
val response = fileUploader.uploadFromUri(avatarUri, fileName, MimeTypes.Jpeg)
|
||||
awaitCallback<Unit> {
|
||||
sendStateEvent(
|
||||
eventType = EventType.STATE_ROOM_AVATAR,
|
||||
|
|
|
@ -20,17 +20,11 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import android.webkit.MimeTypeMap
|
||||
import im.vector.app.core.utils.getFileExtension
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType
|
||||
import timber.log.Timber
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
* Mime types
|
||||
*/
|
||||
const val MIME_TYPE_JPEG = "image/jpeg"
|
||||
const val MIME_TYPE_JPG = "image/jpg"
|
||||
const val MIME_TYPE_IMAGE_ALL = "image/*"
|
||||
const val MIME_TYPE_ALL_CONTENT = "*/*"
|
||||
|
||||
data class Resource(
|
||||
var mContentStream: InputStream? = null,
|
||||
var mMimeType: String? = null
|
||||
|
@ -55,7 +49,7 @@ data class Resource(
|
|||
* @return true if the opened resource is a jpeg one.
|
||||
*/
|
||||
fun isJpegResource(): Boolean {
|
||||
return MIME_TYPE_JPEG == mMimeType || MIME_TYPE_JPG == mMimeType
|
||||
return mMimeType.normalizeMimeType() == MimeTypes.Jpeg
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,10 @@ import okio.buffer
|
|||
import okio.sink
|
||||
import okio.source
|
||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeAudio
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeImage
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeVideo
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
@ -138,7 +142,7 @@ fun openFileSelection(activity: Activity,
|
|||
fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultipleSelection)
|
||||
|
||||
fileIntent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
fileIntent.type = "*/*"
|
||||
fileIntent.type = MimeTypes.Any
|
||||
|
||||
try {
|
||||
activityResultLauncher
|
||||
|
@ -182,7 +186,7 @@ fun openCamera(activity: Activity, titlePrefix: String, requestCode: Int): Strin
|
|||
// The Galaxy S not only requires the name of the file to output the image to, but will also not
|
||||
// set the mime type of the picture it just took (!!!). We assume that the Galaxy S takes image/jpegs
|
||||
// so the attachment uploader doesn't freak out about there being no mimetype in the content database.
|
||||
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
||||
values.put(MediaStore.Images.Media.MIME_TYPE, MimeTypes.Jpeg)
|
||||
var dummyUri: Uri? = null
|
||||
try {
|
||||
dummyUri = activity.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
|
||||
|
@ -344,9 +348,9 @@ fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String
|
|||
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
||||
}
|
||||
val externalContentUri = when {
|
||||
mediaMimeType?.startsWith("image/") == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.startsWith("video/") == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.startsWith("audio/") == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.isMimeTypeVideo() == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
||||
mediaMimeType?.isMimeTypeAudio() == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||
else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
|
||||
}
|
||||
|
||||
|
@ -365,7 +369,7 @@ fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String
|
|||
notificationUtils.buildDownloadFileNotification(
|
||||
uri,
|
||||
filename,
|
||||
mediaMimeType ?: "application/octet-stream"
|
||||
mediaMimeType ?: MimeTypes.OctetStream
|
||||
).let { notification ->
|
||||
notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification)
|
||||
}
|
||||
|
@ -385,9 +389,9 @@ private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: Str
|
|||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
val dest = when {
|
||||
mediaMimeType?.startsWith("image/") == true -> Environment.DIRECTORY_PICTURES
|
||||
mediaMimeType?.startsWith("video/") == true -> Environment.DIRECTORY_MOVIES
|
||||
mediaMimeType?.startsWith("audio/") == true -> Environment.DIRECTORY_MUSIC
|
||||
mediaMimeType?.isMimeTypeImage() == true -> Environment.DIRECTORY_PICTURES
|
||||
mediaMimeType?.isMimeTypeVideo() == true -> Environment.DIRECTORY_MOVIES
|
||||
mediaMimeType?.isMimeTypeAudio() == true -> Environment.DIRECTORY_MUSIC
|
||||
else -> Environment.DIRECTORY_DOWNLOADS
|
||||
}
|
||||
val downloadDir = Environment.getExternalStoragePublicDirectory(dest)
|
||||
|
@ -405,7 +409,7 @@ private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: Str
|
|||
savedFile.name,
|
||||
title,
|
||||
true,
|
||||
mediaMimeType ?: "application/octet-stream",
|
||||
mediaMimeType ?: MimeTypes.OctetStream,
|
||||
savedFile.absolutePath,
|
||||
savedFile.length(),
|
||||
true)
|
||||
|
|
|
@ -23,6 +23,9 @@ import im.vector.lib.multipicker.entity.MultiPickerFileType
|
|||
import im.vector.lib.multipicker.entity.MultiPickerImageType
|
||||
import im.vector.lib.multipicker.entity.MultiPickerVideoType
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeAudio
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeImage
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeVideo
|
||||
import timber.log.Timber
|
||||
|
||||
fun MultiPickerContactType.toContactAttachment(): ContactAttachment {
|
||||
|
@ -59,9 +62,9 @@ fun MultiPickerAudioType.toContentAttachmentData(): ContentAttachmentData {
|
|||
|
||||
private fun MultiPickerBaseType.mapType(): ContentAttachmentData.Type {
|
||||
return when {
|
||||
mimeType?.startsWith("image/") == true -> ContentAttachmentData.Type.IMAGE
|
||||
mimeType?.startsWith("video/") == true -> ContentAttachmentData.Type.VIDEO
|
||||
mimeType?.startsWith("audio/") == true -> ContentAttachmentData.Type.AUDIO
|
||||
mimeType?.isMimeTypeImage() == true -> ContentAttachmentData.Type.IMAGE
|
||||
mimeType?.isMimeTypeVideo() == true -> ContentAttachmentData.Type.VIDEO
|
||||
mimeType?.isMimeTypeAudio() == true -> ContentAttachmentData.Type.AUDIO
|
||||
else -> ContentAttachmentData.Type.FILE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,19 @@
|
|||
package im.vector.app.features.attachments
|
||||
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
|
||||
private val listOfPreviewableMimeTypes = listOf(
|
||||
MimeTypes.Jpeg,
|
||||
MimeTypes.BadJpg,
|
||||
MimeTypes.Png,
|
||||
MimeTypes.Gif
|
||||
)
|
||||
|
||||
fun ContentAttachmentData.isPreviewable(): Boolean {
|
||||
// For now the preview only supports still image
|
||||
return type == ContentAttachmentData.Type.IMAGE
|
||||
&& listOf("image/jpeg", "image/png", "image/jpg").contains(getSafeMimeType() ?: "")
|
||||
&& listOfPreviewableMimeTypes.contains(getSafeMimeType() ?: "")
|
||||
}
|
||||
|
||||
data class GroupedContentAttachmentData(
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
package im.vector.app.features.attachments.preview
|
||||
|
||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeImage
|
||||
|
||||
/**
|
||||
* All images are editable, expect Gif
|
||||
*/
|
||||
fun ContentAttachmentData.isEditable(): Boolean {
|
||||
return type == ContentAttachmentData.Type.IMAGE
|
||||
&& getSafeMimeType()?.startsWith("image/") == true
|
||||
&& getSafeMimeType() != "image/gif"
|
||||
&& getSafeMimeType()?.isMimeTypeImage() == true
|
||||
&& getSafeMimeType() != MimeTypes.Gif
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
|
|||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
|
||||
import kotlinx.android.synthetic.main.composer_layout.view.*
|
||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||
import org.billcarsonfr.jsonviewer.JSonViewerDialog
|
||||
import org.commonmark.parser.Parser
|
||||
|
@ -1101,18 +1101,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private val writingFileActivityResultLauncher = registerForPermissionsResult { allGranted ->
|
||||
if (allGranted) {
|
||||
val pendingUri = roomDetailViewModel.pendingUri
|
||||
if (pendingUri != null) {
|
||||
roomDetailViewModel.pendingUri = null
|
||||
sendUri(pendingUri)
|
||||
}
|
||||
} else {
|
||||
cleanUpAfterPermissionNotGranted()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupComposer() {
|
||||
val composerEditText = composerLayout.composerEditText
|
||||
autoCompleter.setup(composerEditText)
|
||||
|
@ -1158,14 +1146,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
||||
// We need WRITE_EXTERNAL permission
|
||||
return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, requireActivity(), writingFileActivityResultLauncher)) {
|
||||
sendUri(contentUri)
|
||||
} else {
|
||||
roomDetailViewModel.pendingUri = contentUri
|
||||
// Always intercept when we request some permission
|
||||
true
|
||||
}
|
||||
return sendUri(contentUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1196,11 +1177,9 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun sendUri(uri: Uri): Boolean {
|
||||
roomDetailViewModel.preventAttachmentPreview = true
|
||||
val shareIntent = Intent(Intent.ACTION_SEND, uri)
|
||||
val isHandled = attachmentsHelper.handleShareIntent(requireContext(), shareIntent)
|
||||
if (!isHandled) {
|
||||
roomDetailViewModel.preventAttachmentPreview = false
|
||||
Toast.makeText(requireContext(), R.string.error_handling_incoming_share, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
return isHandled
|
||||
|
@ -1562,7 +1541,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
private fun cleanUpAfterPermissionNotGranted() {
|
||||
// Reset all pending data
|
||||
roomDetailViewModel.pendingAction = null
|
||||
roomDetailViewModel.pendingUri = null
|
||||
attachmentsHelper.pendingType = null
|
||||
}
|
||||
|
||||
|
@ -1969,10 +1947,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
// AttachmentsHelper.Callback
|
||||
|
||||
override fun onContentAttachmentsReady(attachments: List<ContentAttachmentData>) {
|
||||
if (roomDetailViewModel.preventAttachmentPreview) {
|
||||
roomDetailViewModel.preventAttachmentPreview = false
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(attachments, false))
|
||||
} else {
|
||||
val grouped = attachments.toGroupedContentAttachmentData()
|
||||
if (grouped.notPreviewables.isNotEmpty()) {
|
||||
// Send the not previewable attachments right now (?)
|
||||
|
@ -1983,10 +1957,8 @@ class RoomDetailFragment @Inject constructor(
|
|||
contentAttachmentActivityResultLauncher.launch(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachmentsProcessFailed() {
|
||||
roomDetailViewModel.preventAttachmentPreview = false
|
||||
Toast.makeText(requireContext(), R.string.error_attachment, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
|
|
@ -132,12 +132,6 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
// Slot to keep a pending action during permission request
|
||||
var pendingAction: RoomDetailAction? = null
|
||||
|
||||
// Slot to keep a pending uri during permission request
|
||||
var pendingUri: Uri? = null
|
||||
|
||||
// Slot to store if we want to prevent preview of attachment
|
||||
var preventAttachmentPreview = false
|
||||
|
||||
private var trackUnreadMessages = AtomicBoolean(false)
|
||||
private var mostRecentDisplayedEvent: TimelineEvent? = null
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ import androidx.transition.TransitionSet
|
|||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import im.vector.app.R
|
||||
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
|
||||
import kotlinx.android.synthetic.main.composer_layout.view.*
|
||||
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
|
||||
|
||||
/**
|
||||
|
@ -86,7 +86,7 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
|||
get() = composerEditText.text
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.merge_composer_layout, this)
|
||||
inflate(context, R.layout.composer_layout, this)
|
||||
ButterKnife.bind(this)
|
||||
collapse(false)
|
||||
composerEditText.callback = object : ComposerEditText.Callback {
|
||||
|
@ -110,20 +110,20 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
|||
}
|
||||
|
||||
fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {
|
||||
if (currentConstraintSetId == R.layout.constraint_set_composer_layout_compact) {
|
||||
if (currentConstraintSetId == R.layout.composer_layout_constraint_set_compact) {
|
||||
// ignore we good
|
||||
return
|
||||
}
|
||||
currentConstraintSetId = R.layout.constraint_set_composer_layout_compact
|
||||
currentConstraintSetId = R.layout.composer_layout_constraint_set_compact
|
||||
applyNewConstraintSet(animate, transitionComplete)
|
||||
}
|
||||
|
||||
fun expand(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {
|
||||
if (currentConstraintSetId == R.layout.constraint_set_composer_layout_expanded) {
|
||||
if (currentConstraintSetId == R.layout.composer_layout_constraint_set_expanded) {
|
||||
// ignore we good
|
||||
return
|
||||
}
|
||||
currentConstraintSetId = R.layout.constraint_set_composer_layout_expanded
|
||||
currentConstraintSetId = R.layout.composer_layout_constraint_set_expanded
|
||||
applyNewConstraintSet(animate, transitionComplete)
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ import org.matrix.android.sdk.api.session.room.model.message.getFileName
|
|||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
|
||||
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
|
||||
import javax.inject.Inject
|
||||
|
@ -311,7 +312,7 @@ class MessageItemFactory @Inject constructor(
|
|||
.leftGuideline(avatarSizeProvider.leftGuideline)
|
||||
.imageContentRenderer(imageContentRenderer)
|
||||
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
|
||||
.playable(messageContent.info?.mimeType == "image/gif")
|
||||
.playable(messageContent.info?.mimeType == MimeTypes.Gif)
|
||||
.highlighted(highlight)
|
||||
.mediaData(data)
|
||||
.apply {
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.MatrixCallback
|
|||
import org.matrix.android.sdk.api.session.file.FileService
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import java.io.File
|
||||
|
||||
class DataAttachmentRoomProvider(
|
||||
|
@ -38,7 +39,7 @@ class DataAttachmentRoomProvider(
|
|||
return getItem(position).let {
|
||||
when (it) {
|
||||
is ImageContentRenderer.Data -> {
|
||||
if (it.mimeType == "image/gif") {
|
||||
if (it.mimeType == MimeTypes.Gif) {
|
||||
AttachmentInfo.AnimatedImage(
|
||||
uid = it.eventId,
|
||||
url = it.url ?: "",
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
|||
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
|
||||
import java.io.File
|
||||
|
||||
|
@ -56,7 +57,7 @@ class RoomEventsAttachmentProvider(
|
|||
allowNonMxcUrls = it.root.sendState.isSending()
|
||||
|
||||
)
|
||||
if (content.mimeType == "image/gif") {
|
||||
if (content.mimeType == MimeTypes.Gif) {
|
||||
AttachmentInfo.AnimatedImage(
|
||||
uid = it.eventId,
|
||||
url = content.url ?: "",
|
||||
|
|
|
@ -46,6 +46,7 @@ import okhttp3.Response
|
|||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.matrix.android.sdk.api.Matrix
|
||||
import org.matrix.android.sdk.api.util.MimeTypes
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
@ -274,7 +275,7 @@ class BugReporter @Inject constructor(
|
|||
|
||||
// add the gzipped files
|
||||
for (file in gzippedFiles) {
|
||||
builder.addFormDataPart("compressed-log", file.name, file.asRequestBody("application/octet-stream".toMediaTypeOrNull()))
|
||||
builder.addFormDataPart("compressed-log", file.name, file.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()))
|
||||
}
|
||||
|
||||
mBugReportFiles.addAll(gzippedFiles)
|
||||
|
@ -295,7 +296,7 @@ class BugReporter @Inject constructor(
|
|||
}
|
||||
|
||||
builder.addFormDataPart("file",
|
||||
logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody("application/octet-stream".toMediaTypeOrNull()))
|
||||
logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()))
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "## sendBugReport() : fail to write screenshot$e")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<item
|
||||
android:bottom="10dp"
|
||||
android:left="10dp"
|
||||
android:right="10dp"
|
||||
android:top="10dp">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/riotx_accent" />
|
||||
</shape>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:constraintSet="@layout/constraint_set_composer_layout_compact"
|
||||
tools:constraintSet="@layout/composer_layout_constraint_set_compact"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<!-- ========================
|
||||
|
@ -12,7 +12,7 @@
|
|||
/!\ These 3 files must be modified to stay coherent!
|
||||
======================== -->
|
||||
<View
|
||||
android:id="@+id/related_message_backround"
|
||||
android:id="@+id/related_message_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?riotx_bottom_nav_background_color"
|
||||
|
@ -39,13 +39,6 @@
|
|||
tools:ignore="MissingConstraints"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composer_shield"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:src="@drawable/ic_shield_black" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/composer_related_message_sender"
|
||||
android:layout_width="0dp"
|
||||
|
@ -83,23 +76,6 @@
|
|||
android:tint="@color/riotx_notice"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composer_emoji"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/attachmentButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/option_send_files"
|
||||
android:src="@drawable/ic_attachment"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/composer_preview_barrier"
|
||||
android:layout_width="0dp"
|
||||
|
@ -111,14 +87,21 @@
|
|||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:id="@+id/attachmentButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:contentDescription="@string/send"
|
||||
android:src="@drawable/ic_send"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="@string/option_send_files"
|
||||
android:src="@drawable/ic_attachment"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composer_shield"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
tools:ignore="MissingConstraints"
|
||||
tools:src="@drawable/ic_shield_black" />
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.ComposerEditText
|
||||
android:id="@+id/composerEditText"
|
||||
style="@style/ComposerEditTextStyle"
|
||||
|
@ -129,4 +112,21 @@
|
|||
tools:hint="@string/room_message_placeholder_not_encrypted"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composer_emoji"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:contentDescription="@string/send"
|
||||
android:src="@drawable/ic_send"
|
||||
tools:ignore="MissingConstraints" />
|
||||
|
||||
</merge>
|
|
@ -10,7 +10,7 @@
|
|||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<View
|
||||
android:id="@+id/related_message_backround"
|
||||
android:id="@+id/related_message_background"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?riotx_bottom_nav_background_color"
|
||||
|
@ -95,44 +95,6 @@
|
|||
tools:ignore="MissingPrefix"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/attachmentButton"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_margin="12dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_attachment"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/composer_shield"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composer_shield"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/attachmentButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/attachmentButton"
|
||||
app:layout_constraintStart_toEndOf="@+id/attachmentButton"
|
||||
app:layout_constraintTop_toTopOf="@id/attachmentButton"
|
||||
tools:src="@drawable/ic_shield_black"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composer_emoji"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sendButton"
|
||||
app:layout_constraintStart_toEndOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
app:layout_goneMarginEnd="8dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/composer_preview_barrier"
|
||||
android:layout_width="0dp"
|
||||
|
@ -144,18 +106,29 @@
|
|||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:src="@drawable/ic_send"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/composer_emoji"
|
||||
android:id="@+id/attachmentButton"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_margin="1dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_attachment"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/composer_shield"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composer_shield"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/composerEditText"
|
||||
app:layout_constraintStart_toEndOf="@+id/attachmentButton"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
tools:src="@drawable/ic_shield_black"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.ComposerEditText
|
||||
android:id="@+id/composerEditText"
|
||||
style="@style/ComposerEditTextStyle"
|
||||
|
@ -170,4 +143,30 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composer_emoji"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_margin="1dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sendButton"
|
||||
app:layout_constraintStart_toEndOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
app:layout_goneMarginEnd="8dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_send"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/composer_emoji"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -10,7 +10,7 @@
|
|||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<View
|
||||
android:id="@+id/related_message_backround"
|
||||
android:id="@+id/related_message_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="?riotx_bottom_nav_background_color"
|
||||
|
@ -22,18 +22,18 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:background="?riotx_bottom_nav_background_border_color"
|
||||
app:layout_constraintEnd_toEndOf="@id/related_message_backround"
|
||||
app:layout_constraintStart_toStartOf="@+id/related_message_backround"
|
||||
app:layout_constraintTop_toTopOf="@id/related_message_backround" />
|
||||
app:layout_constraintEnd_toEndOf="@id/related_message_background"
|
||||
app:layout_constraintStart_toStartOf="@+id/related_message_background"
|
||||
app:layout_constraintTop_toTopOf="@id/related_message_background" />
|
||||
|
||||
<View
|
||||
android:id="@+id/related_message_background_bottom_separator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:background="?riotx_bottom_nav_background_border_color"
|
||||
app:layout_constraintBottom_toBottomOf="@id/related_message_backround"
|
||||
app:layout_constraintEnd_toEndOf="@id/related_message_backround"
|
||||
app:layout_constraintStart_toStartOf="@+id/related_message_backround" />
|
||||
app:layout_constraintBottom_toBottomOf="@id/related_message_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/related_message_background"
|
||||
app:layout_constraintStart_toStartOf="@+id/related_message_background" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composer_related_message_avatar_view"
|
||||
|
@ -100,41 +100,6 @@
|
|||
app:tint="@color/riotx_notice"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/attachmentButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_attachment"
|
||||
app:layout_constraintStart_toStartOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toBottomOf="parent"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composer_shield"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/composer_emoji"
|
||||
app:layout_constraintEnd_toStartOf="@+id/composerEditText"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/composer_emoji"
|
||||
tools:src="@drawable/ic_shield_black" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composer_emoji"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sendButton"
|
||||
app:layout_constraintStart_toEndOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
app:layout_goneMarginEnd="8dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/composer_preview_barrier"
|
||||
android:layout_width="0dp"
|
||||
|
@ -146,20 +111,28 @@
|
|||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:src="@drawable/ic_send"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier"
|
||||
app:layout_constraintVertical_bias="1"
|
||||
android:id="@+id/attachmentButton"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_margin="1dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_attachment"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/sendButton"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/composer_shield"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/composerEditText"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/sendButton"
|
||||
tools:src="@drawable/ic_shield_black" />
|
||||
|
||||
<im.vector.app.features.home.room.detail.composer.ComposerEditText
|
||||
android:id="@+id/composerEditText"
|
||||
style="@style/ComposerEditTextStyle"
|
||||
|
@ -173,4 +146,31 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/composer_emoji"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:layout_margin="1dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_insert_emoji"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sendButton"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sendButton"
|
||||
app:layout_constraintStart_toEndOf="@id/composerEditText"
|
||||
app:layout_constraintTop_toTopOf="@id/sendButton"
|
||||
app:layout_goneMarginEnd="8dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/sendButton"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:background="@drawable/bg_send"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_send"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/composer_preview_barrier"
|
||||
app:layout_constraintVertical_bias="1"
|
||||
tools:ignore="MissingPrefix" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in a new issue