Merge with upstream

This commit is contained in:
Alibek Omarov 2020-01-20 13:56:18 +03:00
commit 565f7f5788
15 changed files with 150 additions and 26 deletions

View File

@ -89,6 +89,13 @@
<data android:mimeType="video/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="audio/*" />
</intent-filter>
<meta-data
android:name="android.service.chooser.chooser_target_service"

View File

@ -186,8 +186,14 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
for (listener in toolbarVisibilityListeners) {
listener(isToolbarVisible)
}
val visibility = if (isToolbarVisible) View.VISIBLE else View.INVISIBLE
val alpha = if (isToolbarVisible) 1.0f else 0.0f
if (isToolbarVisible) {
// If to be visible, need to make visible immediately and animate alpha
toolbar.alpha = 0.0f
toolbar.visibility = visibility
}
toolbar.animate().alpha(alpha)
.setListener(object : AnimatorListenerAdapter() {
@ -248,8 +254,9 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
val attachment = attachments!![viewPager.currentItem].attachment
when (attachment.type) {
Attachment.Type.IMAGE -> shareImage(directory, attachment.url)
Attachment.Type.AUDIO,
Attachment.Type.VIDEO,
Attachment.Type.GIFV -> shareVideo(directory, attachment.url)
Attachment.Type.GIFV -> shareMediaFile(directory, attachment.url)
else -> Log.e(TAG, "Unknown media format for sharing.")
}
}
@ -313,7 +320,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
}
private fun shareVideo(directory: File, url: String) {
private fun shareMediaFile(directory: File, url: String) {
val uri = Uri.parse(url)
val mimeTypeMap = MimeTypeMap.getSingleton()
val extension = MimeTypeMap.getFileExtensionFromUrl(url)

View File

@ -495,6 +495,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText());
contentWarningDescriptionTextView.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE);
contentWarningButton.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE);
if (statusViewData.isExpanded()) {
contentWarningButton.setText(R.string.status_content_warning_show_less);
} else {
contentWarningButton.setText(R.string.status_content_warning_show_more);
}
contentWarningButton.setOnClickListener(view -> {
if (getAdapterPosition() != RecyclerView.NO_POSITION) {

View File

@ -209,7 +209,7 @@ class ComposeActivity : BaseActivity(),
* instance state will be re-queued. */
val type = intent.type
if (type != null) {
if (type.startsWith("image/") || type.startsWith("video/")) {
if (type.startsWith("image/") || type.startsWith("video/") || type.startsWith("audio/")) {
val uriList = ArrayList<Uri>()
if (intent.action != null) {
when (intent.action) {
@ -368,8 +368,8 @@ class ComposeActivity : BaseActivity(),
}
combineOptionalLiveData(viewModel.media, viewModel.poll) { media, poll ->
if(!viewModel.hasNoAttachmentLimits) {
val active = (poll == null && media!!.size != 4
&& media.firstOrNull()?.type != QueuedMedia.Type.VIDEO)
val active = poll == null && media!!.size != 4
&& (media.isEmpty() || media.first().type == QueuedMedia.Type.IMAGE)
enableButton(composeAddMediaButton, active, active)
enablePollButton(media.isNullOrEmpty())
}
@ -913,7 +913,7 @@ class ComposeActivity : BaseActivity(),
intent.addCategory(Intent.CATEGORY_OPENABLE)
if(!viewModel.hasNoAttachmentLimits) {
val mimeTypes = arrayOf("image/*", "video/*")
val mimeTypes = arrayOf("image/*", "video/*", "audio/*")
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
}
intent.type = "*/*"
@ -960,6 +960,9 @@ class ComposeActivity : BaseActivity(),
is MediaSizeException -> {
R.string.error_media_upload_size
}
is AudioSizeException -> {
R.string.error_audio_upload_size
}
is VideoOrImageException -> {
R.string.error_media_upload_image_or_video
}
@ -1088,7 +1091,8 @@ class ComposeActivity : BaseActivity(),
companion object Type {
public const val IMAGE: Int = 0
public const val VIDEO: Int = 1
public const val UNKNOWN: Int = 2
public const val AUDIO: Int = 2
public const val UNKNOWN: Int = 3
}
}
@ -1145,7 +1149,7 @@ class ComposeActivity : BaseActivity(),
@JvmStatic
fun canHandleMimeType(mimeType: String?): Boolean {
return mimeType != null && (mimeType.startsWith("image/") || mimeType.startsWith("video/") || mimeType == "text/plain")
return mimeType != null && (mimeType.startsWith("image/") || mimeType.startsWith("video/") || mimeType.startsWith("audio/") || mimeType == "text/plain")
}
}
}

View File

@ -181,7 +181,7 @@ class ComposeViewModel
.map { (type, uri, size) ->
val mediaItems = media.value!!
if (!hasNoAttachmentLimits
&& type == QueuedMedia.Type.VIDEO
&& type != QueuedMedia.Type.IMAGE
&& mediaItems.isNotEmpty()
&& mediaItems[0].type == QueuedMedia.Type.IMAGE) {
throw VideoOrImageException()
@ -449,6 +449,7 @@ class ComposeViewModel
val mediaType = when (a.type) {
Attachment.Type.VIDEO, Attachment.Type.GIFV -> QueuedMedia.Type.VIDEO
Attachment.Type.UNKNOWN, Attachment.Type.IMAGE -> QueuedMedia.Type.IMAGE
Attachment.Type.AUDIO -> QueuedMedia.Type.AUDIO
else -> QueuedMedia.Type.IMAGE
}
addUploadedMedia(a.id, mediaType, a.url.toUri(), a.description)

View File

@ -89,6 +89,11 @@ class MediaPreviewAdapter(
holder.view.setChecked(!item.description.isNullOrEmpty())
holder.view.setProgress(item.uploadPercent)
}
ComposeActivity.QueuedMedia.Type.AUDIO -> {
(holder as PreviewViewHolder).view.setChecked(!item.description.isNullOrEmpty())
holder.view.setProgress(item.uploadPercent)
holder.view.setImageResource(R.drawable.ic_music_box_preview_24dp)
}
else -> {
(holder as PreviewViewHolder).view.setChecked(!item.description.isNullOrEmpty())
holder.view.setProgress(item.uploadPercent)

View File

@ -63,6 +63,7 @@ interface MediaUploader {
fun uploadMedia(media: QueuedMedia, videoLimit: Int, imageLimit: Int): Observable<UploadEvent>
}
class AudioSizeException : Exception()
class VideoSizeException : Exception()
class MediaSizeException : Exception()
class MediaTypeException : Exception()
@ -129,6 +130,12 @@ class MediaUploaderImpl(
"image" -> {
PreparedMedia(QueuedMedia.Type.IMAGE, uri, mediaSize)
}
"audio" -> {
if (mediaSize > videoLimit) { // TODO: CHANGE!!11
throw AudioSizeException()
}
PreparedMedia(QueuedMedia.Type.AUDIO, uri, mediaSize)
}
else -> {
if (mediaSize > videoLimit) {
throw MediaSizeException()

View File

@ -24,7 +24,6 @@ import android.text.InputType
import android.util.DisplayMetrics
import android.view.WindowManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
@ -34,6 +33,7 @@ import at.connyduck.sparkbutton.helpers.Utils
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.github.chrisbanes.photoview.PhotoView
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.util.withLifecycleContext
@ -50,7 +50,7 @@ fun <T> T.makeCaptionDialog(existingDescription: String?,
dialogLayout.setPadding(padding, padding, padding, padding)
dialogLayout.orientation = LinearLayout.VERTICAL
val imageView = ImageView(this)
val imageView = PhotoView(this)
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)

View File

@ -21,6 +21,7 @@ import android.annotation.SuppressLint
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -31,6 +32,7 @@ import com.keylesspalace.tusky.ViewMediaActivity
import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.visible
import com.keylesspalace.tusky.view.ExposedPlayPauseVideoView
import kotlinx.android.synthetic.main.activity_view_media.*
import kotlinx.android.synthetic.main.fragment_view_video.*
@ -41,11 +43,13 @@ class ViewVideoFragment : ViewMediaFragment() {
// Hoist toolbar hiding to activity so it can track state across different fragments
// This is explicitly stored as runnable so that we pass it to the handler later for cancellation
mediaActivity.onPhotoTap()
mediaController.hide()
}
private lateinit var mediaActivity: ViewMediaActivity
private val TOOLBAR_HIDE_DELAY_MS = 3000L
override lateinit var descriptionView : TextView
private lateinit var mediaController : MediaController
private var isAudio = false
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
// Start/pause/resume video playback as fragment is shown/hidden
@ -72,14 +76,43 @@ class ViewVideoFragment : ViewMediaFragment() {
videoView.transitionName = url
videoView.setVideoPath(url)
mediaController = MediaController(mediaActivity)
mediaController = object : MediaController(mediaActivity) {
override fun show(timeout: Int) {
// We're doing manual auto-close management.
// Also, take focus back from the pause button so we can use the back button.
super.show(0)
mediaController.requestFocus()
}
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
if (event?.keyCode == KeyEvent.KEYCODE_BACK) {
if (event.action == KeyEvent.ACTION_UP) {
hide()
activity?.supportFinishAfterTransition()
}
return true
}
return super.dispatchKeyEvent(event)
}
}
mediaController.setMediaPlayer(videoView)
videoView.setMediaController(mediaController)
videoView.requestFocus()
videoView.setOnTouchListener { _, _ ->
mediaActivity.onPhotoTap()
false
}
videoView.setPlayPauseListener(object: ExposedPlayPauseVideoView.PlayPauseListener {
override fun onPause() {
handler.removeCallbacks(hideToolbar)
}
override fun onPlay() {
// Audio doesn't cause the controller to show automatically,
// and we only want to hide the toolbar if it's a video.
if (isAudio) {
mediaController.show()
} else {
hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS)
}
}
})
videoView.setOnPreparedListener { mp ->
val containerWidth = videoContainer.measuredWidth.toFloat()
val containerHeight = videoContainer.measuredHeight.toFloat()
@ -94,10 +127,16 @@ class ViewVideoFragment : ViewMediaFragment() {
videoView.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
}
// Wait until the media is loaded before accepting taps as we don't want toolbar to
// be hidden until then.
videoView.setOnTouchListener { _, _ ->
mediaActivity.onPhotoTap()
false
}
progressBar.hide()
mp.isLooping = true
if (arguments!!.getBoolean(ARG_START_POSTPONED_TRANSITION)) {
hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS)
videoView.start()
}
}
@ -126,6 +165,7 @@ class ViewVideoFragment : ViewMediaFragment() {
throw IllegalArgumentException("attachment has to be set")
}
url = attachment.url
isAudio = attachment.type == Attachment.Type.AUDIO
finalizeViewSetup(url, attachment.previewUrl, attachment.description)
}
@ -136,6 +176,12 @@ class ViewVideoFragment : ViewMediaFragment() {
isDescriptionVisible = showingDescription && visible
val alpha = if (isDescriptionVisible) 1.0f else 0.0f
if (isDescriptionVisible) {
// If to be visible, need to make visible immediately and animate alpha
descriptionView.alpha = 0.0f
descriptionView.visible(isDescriptionVisible)
}
descriptionView.animate().alpha(alpha)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
@ -145,7 +191,7 @@ class ViewVideoFragment : ViewMediaFragment() {
})
.start()
if (visible) {
if (visible && videoView.isPlaying && !isAudio) {
hideToolbarAfterDelay(TOOLBAR_HIDE_DELAY_MS)
} else {
handler.removeCallbacks(hideToolbar)

View File

@ -0,0 +1,33 @@
package com.keylesspalace.tusky.view
import android.content.Context
import android.util.AttributeSet
import android.widget.VideoView
class ExposedPlayPauseVideoView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0)
: VideoView(context, attrs, defStyleAttr) {
private var listener: PlayPauseListener? = null
fun setPlayPauseListener(listener: PlayPauseListener) {
this.listener = listener
}
override fun start() {
super.start()
listener?.onPlay()
}
override fun pause() {
super.pause()
listener?.onPause()
}
interface PlayPauseListener {
fun onPlay()
fun onPause()
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="?android:textColorTertiary" android:pathData="M16,9H13V14.5A2.5,2.5 0 0,1 10.5,17A2.5,2.5 0 0,1 8,14.5A2.5,2.5 0 0,1 10.5,12C11.07,12 11.58,12.19 12,12.5V7H16M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3Z" />
</vector>

View File

@ -225,7 +225,7 @@
<TextView
android:id="@+id/actionPhotoTake"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:padding="8dp"
@ -234,7 +234,7 @@
<TextView
android:id="@+id/actionPhotoPick"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:padding="8dp"
@ -243,7 +243,7 @@
<TextView
android:id="@+id/addPollTextActionTextView"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:padding="8dp"

View File

@ -23,7 +23,7 @@
app:layout_constraintTop_toTopOf="parent"
tools:text="Some media description" />
<VideoView
<com.keylesspalace.tusky.view.ExposedPlayPauseVideoView
android:id="@+id/videoView"
android:layout_width="wrap_content"
android:layout_height="match_parent"

View File

@ -15,7 +15,7 @@
<RadioButton
android:id="@+id/publicRadioButton"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_weight="1"
@ -27,7 +27,7 @@
<RadioButton
android:id="@+id/unlistedRadioButton"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
@ -40,7 +40,7 @@
<RadioButton
android:id="@+id/privateRadioButton"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
@ -53,7 +53,7 @@
<RadioButton
android:id="@+id/directRadioButton"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_weight="1"

View File

@ -12,6 +12,7 @@
<string name="error_compose_character_limit">The status is too long!</string>
<string name="error_image_upload_size">The file must be less than 8MB.</string>
<string name="error_video_upload_size">Video files must be less than 40MB.</string>
<string name="error_audio_upload_size">Audio files must be less than 40MB.</string>
<string name="error_media_upload_type">That type of file cannot be uploaded.</string>
<string name="error_media_upload_opening">That file could not be opened.</string>
<string name="error_media_upload_permission">Permission to read media is required.</string>