mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 18:35:40 +03:00
Attachment: continue working on preview screen
This commit is contained in:
parent
6471787232
commit
b7a7aa2f15
17 changed files with 385 additions and 46 deletions
|
@ -29,6 +29,7 @@ data class ContentAttachmentData(
|
|||
val width: Long? = 0,
|
||||
val exifOrientation: Int = ExifInterface.ORIENTATION_UNDEFINED,
|
||||
val name: String? = null,
|
||||
val queryUri: String,
|
||||
val path: String,
|
||||
val mimeType: String?,
|
||||
val type: Type
|
||||
|
|
|
@ -143,7 +143,10 @@
|
|||
<activity
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity android:name=".features.attachments.preview.AttachmentsPreviewActivity" />
|
||||
|
||||
<activity
|
||||
android:name=".features.attachments.preview.AttachmentsPreviewActivity"
|
||||
android:theme="@style/AppTheme.AttachmentsPreview" />
|
||||
|
||||
<!-- Services -->
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.riotx.core.utils
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.SnapHelper
|
||||
|
||||
interface OnSnapPositionChangeListener {
|
||||
|
||||
fun onSnapPositionChange(position: Int)
|
||||
}
|
||||
|
||||
fun RecyclerView.attachSnapHelperWithListener(
|
||||
snapHelper: SnapHelper,
|
||||
behavior: SnapOnScrollListener.Behavior = SnapOnScrollListener.Behavior.NOTIFY_ON_SCROLL_STATE_IDLE,
|
||||
onSnapPositionChangeListener: OnSnapPositionChangeListener) {
|
||||
snapHelper.attachToRecyclerView(this)
|
||||
val snapOnScrollListener = SnapOnScrollListener(snapHelper, behavior, onSnapPositionChangeListener)
|
||||
addOnScrollListener(snapOnScrollListener)
|
||||
}
|
||||
|
||||
fun SnapHelper.getSnapPosition(recyclerView: RecyclerView): Int {
|
||||
val layoutManager = recyclerView.layoutManager ?: return RecyclerView.NO_POSITION
|
||||
val snapView = findSnapView(layoutManager) ?: return RecyclerView.NO_POSITION
|
||||
return layoutManager.getPosition(snapView)
|
||||
}
|
||||
|
||||
class SnapOnScrollListener(
|
||||
private val snapHelper: SnapHelper,
|
||||
var behavior: Behavior = Behavior.NOTIFY_ON_SCROLL,
|
||||
var onSnapPositionChangeListener: OnSnapPositionChangeListener? = null
|
||||
) : RecyclerView.OnScrollListener() {
|
||||
|
||||
enum class Behavior {
|
||||
NOTIFY_ON_SCROLL,
|
||||
NOTIFY_ON_SCROLL_STATE_IDLE
|
||||
}
|
||||
|
||||
private var snapPosition = RecyclerView.NO_POSITION
|
||||
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
if (behavior == Behavior.NOTIFY_ON_SCROLL) {
|
||||
maybeNotifySnapPositionChange(recyclerView)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
if (behavior == Behavior.NOTIFY_ON_SCROLL_STATE_IDLE
|
||||
&& newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
maybeNotifySnapPositionChange(recyclerView)
|
||||
}
|
||||
}
|
||||
|
||||
private fun maybeNotifySnapPositionChange(recyclerView: RecyclerView) {
|
||||
val snapPosition = snapHelper.getSnapPosition(recyclerView)
|
||||
val snapPositionChanged = this.snapPosition != snapPosition
|
||||
if (snapPositionChanged) {
|
||||
onSnapPositionChangeListener?.onSnapPositionChange(snapPosition)
|
||||
this.snapPosition = snapPosition
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,8 @@ fun ChosenFile.toContentAttachmentData(): ContentAttachmentData {
|
|||
type = mapType(),
|
||||
size = size,
|
||||
date = createdAt?.time ?: System.currentTimeMillis(),
|
||||
name = displayName
|
||||
name = displayName,
|
||||
queryUri = queryUri
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -50,7 +51,8 @@ fun ChosenAudio.toContentAttachmentData(): ContentAttachmentData {
|
|||
size = size,
|
||||
date = createdAt?.time ?: System.currentTimeMillis(),
|
||||
name = displayName,
|
||||
duration = duration
|
||||
duration = duration,
|
||||
queryUri = queryUri
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -74,7 +76,8 @@ fun ChosenImage.toContentAttachmentData(): ContentAttachmentData {
|
|||
height = height.toLong(),
|
||||
width = width.toLong(),
|
||||
exifOrientation = orientation,
|
||||
date = createdAt?.time ?: System.currentTimeMillis()
|
||||
date = createdAt?.time ?: System.currentTimeMillis(),
|
||||
queryUri = queryUri
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -89,6 +92,7 @@ fun ChosenVideo.toContentAttachmentData(): ContentAttachmentData {
|
|||
height = height.toLong(),
|
||||
width = width.toLong(),
|
||||
duration = duration,
|
||||
name = displayName
|
||||
name = displayName,
|
||||
queryUri = queryUri
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2020 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.riotx.features.attachments
|
||||
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
|
||||
fun ContentAttachmentData.isPreviewable(): Boolean {
|
||||
return type == ContentAttachmentData.Type.IMAGE || type == ContentAttachmentData.Type.VIDEO
|
||||
}
|
||||
|
||||
fun List<ContentAttachmentData>.filterPreviewables(): List<ContentAttachmentData> {
|
||||
return filter { it.isPreviewable() }
|
||||
}
|
||||
|
||||
fun List<ContentAttachmentData>.filterNonPreviewables(): List<ContentAttachmentData> {
|
||||
return filter { it.isPreviewable().not() }
|
||||
}
|
||||
|
|
@ -35,18 +35,18 @@ class AttachmentBigPreviewController @Inject constructor() : TypedEpoxyControlle
|
|||
class AttachmentMiniaturePreviewController @Inject constructor() : TypedEpoxyController<AttachmentsPreviewViewState>() {
|
||||
|
||||
interface Callback {
|
||||
fun onAttachmentClicked(contentAttachmentData: ContentAttachmentData)
|
||||
fun onAttachmentClicked(position: Int, contentAttachmentData: ContentAttachmentData)
|
||||
}
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
override fun buildModels(data: AttachmentsPreviewViewState) {
|
||||
data.attachments.forEach {
|
||||
data.attachments.forEachIndexed { index, contentAttachmentData ->
|
||||
attachmentMiniaturePreviewItem {
|
||||
id(it.path)
|
||||
attachment(it)
|
||||
id(contentAttachmentData.path)
|
||||
attachment(contentAttachmentData)
|
||||
clickListener { _ ->
|
||||
callback?.onAttachmentClicked(it)
|
||||
callback?.onAttachmentClicked(index, contentAttachmentData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,4 +19,10 @@ package im.vector.riotx.features.attachments.preview
|
|||
|
||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class AttachmentsPreviewAction : VectorViewModelAction
|
||||
sealed class AttachmentsPreviewAction : VectorViewModelAction {
|
||||
object RemoveCurrentAttachment : AttachmentsPreviewAction()
|
||||
data class SetCurrentAttachment(val index: Int): AttachmentsPreviewAction()
|
||||
data class UpdatePathOfCurrentAttachment(val newPath: String): AttachmentsPreviewAction()
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -19,19 +19,20 @@ package im.vector.riotx.features.attachments.preview
|
|||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.features.themes.ActivityOtherThemes
|
||||
|
||||
class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
|
||||
const val RESULT_NAME = "ATTACHMENTS_PREVIEW_RESULT"
|
||||
const val REQUEST_CODE = 55
|
||||
|
||||
fun newIntent(context: Context, args: AttachmentsPreviewArgs): Intent {
|
||||
|
@ -39,15 +40,16 @@ class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
putExtra(EXTRA_FRAGMENT_ARGS, args)
|
||||
}
|
||||
}
|
||||
|
||||
fun getOutput(intent: Intent): List<ContentAttachmentData> {
|
||||
return intent.getParcelableArrayListExtra(RESULT_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOtherThemes() = ActivityOtherThemes.AttachmentsPreview
|
||||
|
||||
override fun getLayoutRes() = R.layout.activity_simple
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun initUiAndData() {
|
||||
if (isFirstCreation()) {
|
||||
val fragmentArgs: AttachmentsPreviewArgs = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS)
|
||||
|
|
|
@ -17,24 +17,41 @@
|
|||
|
||||
package im.vector.riotx.features.attachments.preview
|
||||
|
||||
import android.app.Activity.RESULT_CANCELED
|
||||
import android.app.Activity.RESULT_OK
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.PagerSnapHelper
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.yalantis.ucrop.UCrop
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.cleanup
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.core.utils.OnSnapPositionChangeListener
|
||||
import im.vector.riotx.core.utils.SnapOnScrollListener
|
||||
import im.vector.riotx.core.utils.attachSnapHelperWithListener
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_attachments_preview.*
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
@Parcelize
|
||||
data class AttachmentsPreviewArgs(
|
||||
val roomId: String,
|
||||
val attachments: List<ContentAttachmentData>
|
||||
) : Parcelable
|
||||
|
||||
|
@ -51,13 +68,107 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
applyInsets()
|
||||
setupRecyclerViews()
|
||||
setupToolbar(attachmentPreviewerToolbar)
|
||||
attachmentPreviewerSendButton.setOnClickListener {
|
||||
setResultAndFinish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (requestCode == UCrop.REQUEST_CROP && data != null) {
|
||||
Timber.v("Crop success")
|
||||
handleCropResult(data)
|
||||
}
|
||||
}
|
||||
if (resultCode == UCrop.RESULT_ERROR) {
|
||||
Timber.v("Crop error")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.attachmentsPreviewRemoveAction -> {
|
||||
handleRemoveAction()
|
||||
true
|
||||
}
|
||||
R.id.attachmentsPreviewEditAction -> {
|
||||
handleEditAction()
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMenuRes() = R.menu.vector_attachments_preview
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
attachmentPreviewerMiniatureList.cleanup()
|
||||
attachmentPreviewerBigList.cleanup()
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
if (state.attachments.isEmpty()) {
|
||||
requireActivity().setResult(RESULT_CANCELED)
|
||||
requireActivity().finish()
|
||||
} else {
|
||||
attachmentMiniaturePreviewController.setData(state)
|
||||
attachmentBigPreviewController.setData(state)
|
||||
attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
|
||||
attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachmentClicked(position: Int, contentAttachmentData: ContentAttachmentData) {
|
||||
viewModel.handle(AttachmentsPreviewAction.SetCurrentAttachment(position))
|
||||
}
|
||||
|
||||
private fun setResultAndFinish() = withState(viewModel) {
|
||||
val resultIntent = Intent().apply {
|
||||
putParcelableArrayListExtra(AttachmentsPreviewActivity.RESULT_NAME, ArrayList(it.attachments))
|
||||
}
|
||||
requireActivity().setResult(RESULT_OK, resultIntent)
|
||||
requireActivity().finish()
|
||||
}
|
||||
|
||||
private fun applyInsets() {
|
||||
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerBottomContainer) { v, insets ->
|
||||
v.updatePadding(bottom = insets.systemWindowInsetBottom)
|
||||
insets
|
||||
}
|
||||
ViewCompat.setOnApplyWindowInsetsListener(attachmentPreviewerToolbar) { v, insets ->
|
||||
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = insets.systemWindowInsetTop
|
||||
}
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCropResult(result: Intent) {
|
||||
val resultPath = UCrop.getOutput(result)?.path
|
||||
if (resultPath != null) {
|
||||
viewModel.handle(AttachmentsPreviewAction.UpdatePathOfCurrentAttachment(resultPath))
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Cannot retrieve cropped value", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRemoveAction() {
|
||||
viewModel.handle(AttachmentsPreviewAction.RemoveCurrentAttachment)
|
||||
}
|
||||
|
||||
private fun handleEditAction() = withState(viewModel) {
|
||||
val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState
|
||||
val destinationFile = File(requireContext().cacheDir, "${currentAttachment.name}_edited_image_${System.currentTimeMillis()}")
|
||||
UCrop.of(currentAttachment.queryUri.toUri(), destinationFile.toUri())
|
||||
.withOptions(UCrop.Options())
|
||||
.start(requireContext(), this)
|
||||
}
|
||||
|
||||
private fun setupRecyclerViews() {
|
||||
|
@ -67,20 +178,12 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
attachmentMiniaturePreviewController.callback = this
|
||||
|
||||
attachmentPreviewerBigList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
val snapHelper = PagerSnapHelper()
|
||||
snapHelper.attachToRecyclerView(attachmentPreviewerBigList)
|
||||
attachmentPreviewerBigList.attachSnapHelperWithListener(PagerSnapHelper(), SnapOnScrollListener.Behavior.NOTIFY_ON_SCROLL_STATE_IDLE, object : OnSnapPositionChangeListener {
|
||||
override fun onSnapPositionChange(position: Int) {
|
||||
viewModel.handle(AttachmentsPreviewAction.SetCurrentAttachment(position))
|
||||
}
|
||||
})
|
||||
attachmentPreviewerBigList.setHasFixedSize(true)
|
||||
attachmentPreviewerBigList.adapter = attachmentBigPreviewController.adapter
|
||||
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
attachmentMiniaturePreviewController.setData(state)
|
||||
attachmentBigPreviewController.setData(state)
|
||||
}
|
||||
|
||||
override fun onAttachmentClicked(contentAttachmentData: ContentAttachmentData) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,12 +17,15 @@
|
|||
|
||||
package im.vector.riotx.features.attachments.preview
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.riotx.core.extensions.exhaustive
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class AttachmentsPreviewViewModel @AssistedInject constructor(@Assisted initialState: AttachmentsPreviewViewState)
|
||||
: VectorViewModel<AttachmentsPreviewViewState, AttachmentsPreviewAction, AttachmentsPreviewViewEvents>(initialState) {
|
||||
|
@ -42,6 +45,36 @@ class AttachmentsPreviewViewModel @AssistedInject constructor(@Assisted initialS
|
|||
}
|
||||
|
||||
override fun handle(action: AttachmentsPreviewAction) {
|
||||
//TODO
|
||||
when (action) {
|
||||
is AttachmentsPreviewAction.SetCurrentAttachment -> handleSetCurrentAttachment(action)
|
||||
is AttachmentsPreviewAction.UpdatePathOfCurrentAttachment -> handleUpdatePathOfCurrentAttachment(action)
|
||||
AttachmentsPreviewAction.RemoveCurrentAttachment -> handleRemoveCurrentAttachment()
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun handleRemoveCurrentAttachment() = withState {
|
||||
val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState
|
||||
val attachments = it.attachments.minusElement(currentAttachment)
|
||||
val newAttachmentIndex = it.currentAttachmentIndex.coerceAtMost(attachments.size - 1)
|
||||
setState {
|
||||
copy(attachments = attachments, currentAttachmentIndex = newAttachmentIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUpdatePathOfCurrentAttachment(action: AttachmentsPreviewAction.UpdatePathOfCurrentAttachment) = withState {
|
||||
val attachments = it.attachments.mapIndexed { index, contentAttachmentData ->
|
||||
if (index == it.currentAttachmentIndex) {
|
||||
contentAttachmentData.copy(path = action.newPath)
|
||||
} else {
|
||||
contentAttachmentData
|
||||
}
|
||||
}
|
||||
setState {
|
||||
copy(attachments = attachments)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSetCurrentAttachment(action: AttachmentsPreviewAction.SetCurrentAttachment) = setState {
|
||||
copy(currentAttachmentIndex = action.index)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ import com.airbnb.mvrx.MvRxState
|
|||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
|
||||
data class AttachmentsPreviewViewState(
|
||||
val attachments: List<ContentAttachmentData>
|
||||
val attachments: List<ContentAttachmentData>,
|
||||
val currentAttachmentIndex: Int = 0
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: AttachmentsPreviewArgs) : this(attachments = args.attachments)
|
||||
|
|
|
@ -116,6 +116,8 @@ import im.vector.riotx.core.utils.toast
|
|||
import im.vector.riotx.features.attachments.AttachmentTypeSelectorView
|
||||
import im.vector.riotx.features.attachments.AttachmentsHelper
|
||||
import im.vector.riotx.features.attachments.ContactAttachment
|
||||
import im.vector.riotx.features.attachments.filterNonPreviewables
|
||||
import im.vector.riotx.features.attachments.filterPreviewables
|
||||
import im.vector.riotx.features.attachments.preview.AttachmentsPreviewActivity
|
||||
import im.vector.riotx.features.attachments.preview.AttachmentsPreviewArgs
|
||||
import im.vector.riotx.features.command.Command
|
||||
|
@ -502,6 +504,10 @@ class RoomDetailFragment @Inject constructor(
|
|||
val hasBeenHandled = attachmentsHelper.onActivityResult(requestCode, resultCode, data)
|
||||
if (!hasBeenHandled && resultCode == RESULT_OK && data != null) {
|
||||
when (requestCode) {
|
||||
AttachmentsPreviewActivity.REQUEST_CODE -> {
|
||||
val sendData = AttachmentsPreviewActivity.getOutput(data)
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(sendData))
|
||||
}
|
||||
REACTION_SELECT_REQUEST_CODE -> {
|
||||
val (eventId, reaction) = EmojiReactionPickerActivity.getOutput(data) ?: return
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendReaction(eventId, reaction))
|
||||
|
@ -1342,9 +1348,16 @@ class RoomDetailFragment @Inject constructor(
|
|||
// AttachmentsHelper.Callback
|
||||
|
||||
override fun onContentAttachmentsReady(attachments: List<ContentAttachmentData>) {
|
||||
val intent = AttachmentsPreviewActivity.newIntent(requireContext(), AttachmentsPreviewArgs(attachments))
|
||||
val previewable = attachments.filterPreviewables()
|
||||
val nonPreviewable = attachments.filterNonPreviewables()
|
||||
if (nonPreviewable.isNotEmpty()) {
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(nonPreviewable))
|
||||
}
|
||||
if (previewable.isNotEmpty()) {
|
||||
val intent = AttachmentsPreviewActivity.newIntent(requireContext(), AttachmentsPreviewArgs(roomDetailArgs.roomId, previewable))
|
||||
startActivityForResult(intent, AttachmentsPreviewActivity.REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachmentsProcessFailed() {
|
||||
Toast.makeText(requireContext(), R.string.error_attachment, Toast.LENGTH_SHORT).show()
|
||||
|
|
|
@ -32,4 +32,10 @@ sealed class ActivityOtherThemes(@StyleRes val dark: Int,
|
|||
R.style.AppTheme_Black,
|
||||
R.style.AppTheme_Status
|
||||
)
|
||||
|
||||
object AttachmentsPreview : ActivityOtherThemes(
|
||||
R.style.AppTheme_AttachmentsPreview,
|
||||
R.style.AppTheme_AttachmentsPreview,
|
||||
R.style.AppTheme_AttachmentsPreview
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,37 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/attachmentPreviewerBigList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/item_attachment_big_preview"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:listitem="@layout/item_attachment_big_preview" />
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/attachmentPreviewerToolbar"
|
||||
style="@style/VectorToolbarStyle"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@android:color/transparent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/attachmentPreviewerBottomContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:background="#80000000"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/attachmentPreviewerMiniatureList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/attachmentPreviewerSendButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_send"
|
||||
app:layout_constraintTop_toTopOf="@id/attachmentPreviewerBottomContainer"
|
||||
app:layout_constraintBottom_toTopOf="@id/attachmentPreviewerBottomContainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
19
vector/src/main/res/menu/vector_attachments_preview.xml
Executable file
19
vector/src/main/res/menu/vector_attachments_preview.xml
Executable file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".features.attachments.preview.AttachmentsPreviewActivity">
|
||||
|
||||
<item
|
||||
android:id="@+id/attachmentsPreviewRemoveAction"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="Delete"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/attachmentsPreviewEditAction"
|
||||
android:icon="@drawable/ic_edit"
|
||||
android:title="Edit"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
16
vector/src/main/res/values-v21/theme_common.xml
Normal file
16
vector/src/main/res/values-v21/theme_common.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Launcher Theme, only used for VectorLauncherActivity (will be use even before the Activity is started) -->
|
||||
<style name="AppTheme.Launcher" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@drawable/splash</item>
|
||||
|
||||
<item name="colorPrimaryDark">@color/primary_color_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AttachmentsPreview" parent="AppTheme.Base.Black">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -8,4 +8,6 @@
|
|||
<item name="colorPrimaryDark">@color/primary_color_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AttachmentsPreview" parent="AppTheme.Base.Black"/>
|
||||
|
||||
</resources>
|
Loading…
Reference in a new issue