Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/activity/MediaViewerActivity.kt

652 lines
26 KiB
Kotlin
Raw Normal View History

2016-07-07 09:39:32 +02:00
/*
* Copyright (C) 2009 The Android Open Source Project
*
* 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.mariotaku.twidere.activity
import android.annotation.SuppressLint
import android.app.Activity
2016-07-07 09:39:32 +02:00
import android.content.ActivityNotFoundException
import android.content.Intent
import android.graphics.Color
2016-07-07 09:39:32 +02:00
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
2016-07-07 09:39:32 +02:00
import android.os.Parcelable
2020-01-26 08:35:15 +01:00
import androidx.annotation.RequiresApi
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.viewpager.widget.ViewPager
import androidx.core.view.WindowInsetsCompat
import androidx.customview.widget.ViewDragHelper
import androidx.appcompat.app.WindowDecorActionBar
import androidx.appcompat.app.decorToolbar
import android.view.*
2016-07-07 09:39:32 +02:00
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_media_viewer.*
import nl.komponents.kovenant.combine.and
import nl.komponents.kovenant.task
import nl.komponents.kovenant.ui.alwaysUi
import nl.komponents.kovenant.ui.successUi
2016-12-24 05:30:43 +01:00
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.ktextension.*
2016-07-07 09:39:32 +02:00
import org.mariotaku.mediaviewer.library.*
import org.mariotaku.mediaviewer.library.subsampleimageview.SubsampleImageViewerFragment.EXTRA_MEDIA_URI
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper
2017-02-04 07:13:08 +01:00
import org.mariotaku.twidere.annotation.CacheFileType
2017-04-17 18:10:29 +02:00
import org.mariotaku.twidere.extension.addSystemUiVisibility
import org.mariotaku.twidere.extension.dismissProgressDialog
2017-04-17 18:10:29 +02:00
import org.mariotaku.twidere.extension.removeSystemUiVisibility
import org.mariotaku.twidere.extension.showProgressDialog
import org.mariotaku.twidere.fragment.PermissionRequestDialog
import org.mariotaku.twidere.fragment.ProgressDialogFragment
2017-02-02 15:08:04 +01:00
import org.mariotaku.twidere.fragment.iface.IBaseFragment
import org.mariotaku.twidere.fragment.media.*
2016-07-07 09:39:32 +02:00
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.provider.CacheProvider
import org.mariotaku.twidere.provider.ShareProvider
import org.mariotaku.twidere.task.SaveFileTask
import org.mariotaku.twidere.task.SaveMediaToGalleryTask
2017-04-12 10:17:20 +02:00
import org.mariotaku.twidere.util.IntentUtils
import org.mariotaku.twidere.util.PermissionUtils
import org.mariotaku.twidere.util.ThemeUtils
2017-04-16 15:09:56 +02:00
import org.mariotaku.twidere.util.dagger.GeneralComponent
import org.mariotaku.twidere.util.support.WindowSupport
import org.mariotaku.twidere.view.viewer.MediaSwipeCloseContainer
2016-07-07 09:39:32 +02:00
import java.io.File
import javax.inject.Inject
2020-04-01 10:03:35 +02:00
import kotlin.concurrent.thread
2020-06-09 00:50:51 +02:00
import kotlin.math.abs
import kotlin.math.roundToInt
2016-12-13 04:06:07 +01:00
import android.Manifest.permission as AndroidPermissions
2016-07-07 09:39:32 +02:00
class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeCloseContainer.Listener,
PermissionRequestDialog.PermissionRequestCancelCallback {
2016-07-07 09:39:32 +02:00
@Inject
2017-02-08 05:12:25 +01:00
internal lateinit var mediaFileCache: FileCache
@Inject
2017-02-08 05:12:25 +01:00
internal lateinit var mediaDownloader: MediaDownloader
2016-12-06 06:15:22 +01:00
private var saveToStoragePosition = -1
2016-07-07 09:39:32 +02:00
private var shareMediaPosition = -1
private var wasBarShowing = 0
private var hideOffsetNotSupported = false
2016-12-24 05:30:43 +01:00
private lateinit var mediaViewerHelper: IMediaViewerActivity.Helper
private lateinit var controlBarShowHideHelper: ControlBarShowHideHelper
2016-07-07 09:39:32 +02:00
2016-12-24 05:30:43 +01:00
private val status: ParcelableStatus?
get() = intent.getParcelableExtra<ParcelableStatus>(EXTRA_STATUS)
private val initialMedia: ParcelableMedia?
get() = intent.getParcelableExtra<ParcelableMedia>(EXTRA_CURRENT_MEDIA)
2017-05-24 07:34:33 +02:00
private val media: Array<ParcelableMedia> by lazy {
return@lazy intent.getNullableTypedArrayExtra<ParcelableMedia>(EXTRA_MEDIA) ?: emptyArray()
2016-12-24 05:30:43 +01:00
}
2016-07-07 09:39:32 +02:00
private val currentFragment: MediaViewerFragment?
get() {
val viewPager = findViewPager()
2020-01-26 08:35:15 +01:00
val adapter = viewPager.adapter ?: return null
val currentItem = viewPager.currentItem
if (currentItem < 0 || currentItem >= adapter.count) return null
return adapter.instantiateItem(viewPager, currentItem) as? MediaViewerFragment
}
2017-04-17 18:10:29 +02:00
private fun getCurrentCacheFileInfo(position: Int): SaveFileTask.FileInfo? {
if (position == -1) return null
val viewPager = findViewPager()
2020-01-26 08:35:15 +01:00
val adapter = viewPager.adapter ?: return null
val f = adapter.instantiateItem(viewPager, position) as? MediaViewerFragment ?:
return null
return f.cacheFileInfo()
}
2017-02-08 05:12:25 +01:00
override val shouldApplyWindowBackground: Boolean = false
override val controlBarHeight: Int
get() {
return supportActionBar?.height ?: 0
}
override var controlBarOffset: Float
get() {
val actionBar = supportActionBar
if (actionBar != null) {
return 1 - actionBar.hideOffset / controlBarHeight.toFloat()
}
return 0f
}
@SuppressLint("RestrictedApi")
2017-02-08 05:12:25 +01:00
set(offset) {
val actionBar = supportActionBar
if (actionBar != null && !hideOffsetNotSupported) {
if (actionBar is WindowDecorActionBar) {
2017-04-17 18:10:29 +02:00
val toolbar = actionBar.decorToolbar.viewGroup
2017-02-08 05:12:25 +01:00
toolbar.alpha = offset
2017-09-13 11:52:09 +02:00
activityLayout.statusBarAlpha = offset
2017-02-08 05:12:25 +01:00
}
try {
2020-06-09 00:50:51 +02:00
actionBar.hideOffset = (controlBarHeight * (1f - offset)).roundToInt()
2017-02-08 05:12:25 +01:00
} catch (e: UnsupportedOperationException) {
// Some device will throw this exception
hideOffsetNotSupported = true
}
}
notifyControlBarOffsetChanged()
}
2016-07-07 09:39:32 +02:00
override fun onCreate(savedInstanceState: Bundle?) {
2017-02-02 15:08:04 +01:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
}
2016-07-07 09:39:32 +02:00
super.onCreate(savedInstanceState)
2017-04-16 15:09:56 +02:00
GeneralComponent.get(this).inject(this)
2016-12-24 05:30:43 +01:00
mediaViewerHelper = IMediaViewerActivity.Helper(this)
controlBarShowHideHelper = ControlBarShowHideHelper(this)
2016-12-24 05:30:43 +01:00
mediaViewerHelper.onCreate(savedInstanceState)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
2017-02-02 15:08:04 +01:00
supportActionBar?.elevation = 0f
swipeContainer.listener = this
swipeContainer.backgroundAlpha = 1f
WindowSupport.setStatusBarColor(window, Color.TRANSPARENT)
2017-09-13 11:52:09 +02:00
activityLayout.statusBarColor = overrideTheme.colorToolbar
2017-06-25 17:01:33 +02:00
ViewCompat.setOnApplyWindowInsetsListener(activityLayout) { view, insets ->
val statusBarHeight = insets.systemWindowInsetTop - ThemeUtils.getActionBarHeight(this)
2017-09-13 11:52:09 +02:00
activityLayout.statusBarHeight = statusBarHeight
2017-06-25 17:01:33 +02:00
onApplyWindowInsets(view, insets)
2017-01-29 13:46:52 +01:00
}
2017-09-16 19:32:26 +02:00
window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
activityLayout.statusBarAlpha = if (View.SYSTEM_UI_FLAG_FULLSCREEN in visibility) 0f else 1f
}
2016-07-07 09:39:32 +02:00
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
2020-05-31 08:02:32 +02:00
super.onActivityResult(requestCode, resultCode, data)
2016-07-07 09:39:32 +02:00
when (requestCode) {
REQUEST_SHARE_MEDIA -> {
ShareProvider.clearTempFiles(this)
}
REQUEST_SELECT_SAVE_MEDIA -> {
if (resultCode != Activity.RESULT_OK || data == null) return
val uri = data.data ?: return
saveMediaToContentUri(uri)
}
2016-07-07 09:39:32 +02:00
}
}
2016-07-07 09:39:32 +02:00
override fun onContentChanged() {
super.onContentChanged()
2016-12-24 05:30:43 +01:00
mediaViewerHelper.onContentChanged()
2016-07-07 09:39:32 +02:00
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
2016-12-24 05:30:43 +01:00
super.onCreateOptionsMenu(menu)
2016-07-07 09:39:32 +02:00
menuInflater.inflate(R.menu.menu_media_viewer, menu)
return true
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
2016-12-24 05:30:43 +01:00
super.onPrepareOptionsMenu(menu)
2017-04-17 18:10:29 +02:00
val obj = currentFragment ?: return false
if (obj.isDetached || obj.host == null) return false
2017-03-01 07:13:10 +01:00
val running = obj.isMediaLoading
val downloaded = obj.isMediaLoaded
val supportedSaveTo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.refresh, !running && !downloaded)
menu.setItemAvailability(R.id.share, !running && downloaded)
menu.setItemAvailability(R.id.save, !running && downloaded)
menu.setItemAvailability(R.id.save_to, supportedSaveTo && !running && downloaded)
2016-07-07 09:39:32 +02:00
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val viewPager = findViewPager()
2020-01-26 08:35:15 +01:00
val adapter = viewPager.adapter ?: return false
2016-07-07 09:39:32 +02:00
val currentItem = viewPager.currentItem
if (currentItem < 0 || currentItem >= adapter.count) return false
2016-12-06 06:15:22 +01:00
val obj = adapter.instantiateItem(viewPager, currentItem) as? MediaViewerFragment ?: return false
2016-07-07 09:39:32 +02:00
when (item.itemId) {
R.id.refresh -> {
if (obj is CacheDownloadMediaViewerFragment) {
obj.startLoading(true)
obj.showProgress(true, 0f)
obj.setMediaViewVisible(false)
}
return true
}
R.id.share -> {
val fileInfo = obj.cacheFileInfo()
if (fileInfo != null) {
2016-07-07 09:39:32 +02:00
requestAndShareMedia(currentItem)
} else {
val media = media[currentItem]
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, media.url)
2016-12-26 17:26:09 +01:00
startActivity(Intent.createChooser(intent, getString(R.string.action_share)))
2016-07-07 09:39:32 +02:00
}
return true
}
R.id.save -> {
requestAndSaveToStorage(currentItem)
return true
}
R.id.save_to -> {
openSaveToDocumentChooser()
return true
}
2016-07-07 09:39:32 +02:00
R.id.open_in_browser -> {
val media = media[currentItem]
try {
val uri = Uri.parse(media.url)
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.addCategory(Intent.CATEGORY_BROWSABLE)
intent.`package` = IntentUtils.getDefaultBrowserPackage(this, uri, true)
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// TODO show error, or improve app url
}
return true
}
android.R.id.home -> {
finish()
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onRequestPermissionCancelled(requestCode: Int) {
when (requestCode) {
REQUEST_PERMISSION_SHARE_MEDIA -> {
shareMedia()
}
}
}
2016-07-07 09:39:32 +02:00
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
REQUEST_PERMISSION_SAVE_MEDIA -> {
2016-12-13 04:06:07 +01:00
if (PermissionUtils.hasPermission(permissions, grantResults, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
2016-07-07 09:39:32 +02:00
saveToStorage()
} else {
2017-01-26 14:28:43 +01:00
Toast.makeText(this, R.string.message_toast_save_media_no_storage_permission, Toast.LENGTH_LONG).show()
2016-07-07 09:39:32 +02:00
}
return
}
REQUEST_PERMISSION_SHARE_MEDIA -> {
2016-12-13 04:06:07 +01:00
if (!PermissionUtils.hasPermission(permissions, grantResults, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
2017-01-26 14:28:43 +01:00
Toast.makeText(this, R.string.message_toast_share_media_no_storage_permission, Toast.LENGTH_LONG).show()
2016-07-07 09:39:32 +02:00
}
shareMedia()
return
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
currentFragment
return super.onKeyUp(keyCode, event)
}
2016-07-07 09:39:32 +02:00
override fun toggleBar() {
setBarVisibility(!isBarShowing)
}
override fun getInitialPosition(): Int {
2016-08-17 15:46:18 +02:00
return media.indexOf(initialMedia)
2016-07-07 09:39:32 +02:00
}
override fun getLayoutRes(): Int {
return R.layout.activity_media_viewer
}
override fun findViewPager(): ViewPager {
return viewPager
}
override fun isBarShowing(): Boolean {
2017-04-17 18:10:29 +02:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return FLAG_SYSTEM_UI_HIDE_BARS !in window.decorView.systemUiVisibility
}
return controlBarOffset >= 1
2016-07-07 09:39:32 +02:00
}
override fun setBarVisibility(visible: Boolean) {
2017-02-02 15:08:04 +01:00
if (isBarShowing == visible) return
2017-04-17 18:10:29 +02:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (visible) {
window.decorView.removeSystemUiVisibility(FLAG_SYSTEM_UI_HIDE_BARS)
} else {
window.decorView.addSystemUiVisibility(FLAG_SYSTEM_UI_HIDE_BARS)
}
} else {
setControlBarVisibleAnimate(visible)
}
2016-07-07 09:39:32 +02:00
}
override fun getDownloader(): MediaDownloader {
return mediaDownloader
2016-07-07 09:39:32 +02:00
}
override fun getFileCache(): FileCache {
return mediaFileCache
2016-07-07 09:39:32 +02:00
}
@SuppressLint("SwitchIntDef")
override fun instantiateMediaFragment(position: Int): MediaViewerFragment {
val media = media[position]
val args = Bundle()
val intent = intent
args.putParcelable(EXTRA_ACCOUNT_KEY, intent.getParcelableExtra<Parcelable>(EXTRA_ACCOUNT_KEY))
args.putParcelable(EXTRA_MEDIA, media)
args.putParcelable(EXTRA_STATUS, intent.getParcelableExtra<Parcelable>(EXTRA_STATUS))
when (media.type) {
ParcelableMedia.Type.IMAGE -> {
val mediaUrl = media.media_url ?: return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment
args.putParcelable(EXTRA_MEDIA_URI, Uri.parse(mediaUrl))
2020-06-08 23:19:10 +02:00
return if (mediaUrl.endsWith(".gif")) {
Fragment.instantiate(this, GifPageFragment::class.java.name, args) as MediaViewerFragment
2016-07-07 09:39:32 +02:00
} else {
2020-06-08 23:19:10 +02:00
Fragment.instantiate(this, ImagePageFragment::class.java.name, args) as MediaViewerFragment
2016-07-07 09:39:32 +02:00
}
}
ParcelableMedia.Type.ANIMATED_GIF, ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
args.putBoolean(VideoPageFragment.EXTRA_LOOP, true)
2017-02-02 15:08:04 +01:00
args.putBoolean(VideoPageFragment.EXTRA_DISABLE_CONTROL, true)
args.putBoolean(VideoPageFragment.EXTRA_DEFAULT_MUTE, true)
return instantiateMediaViewerFragment(args)
2016-07-07 09:39:32 +02:00
}
ParcelableMedia.Type.VIDEO -> {
return instantiateMediaViewerFragment(args)
2016-07-07 09:39:32 +02:00
}
ParcelableMedia.Type.EXTERNAL_PLAYER -> {
return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment
}
2017-05-05 17:49:46 +02:00
else -> {
return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment
}
2016-07-07 09:39:32 +02:00
}
}
override fun getMediaCount(): Int {
return media.size
}
2016-12-24 05:30:43 +01:00
override fun getOverrideTheme(): Chameleon.Theme {
2016-12-25 04:56:34 +01:00
val theme = super.getOverrideTheme()
theme.colorToolbar = ContextCompat.getColor(this, R.color.ab_bg_color_media_viewer)
theme.isToolbarColored = false
return theme
2016-07-07 09:39:32 +02:00
}
override fun onSwipeCloseFinished() {
finish()
overridePendingTransition(0, 0)
}
override fun onSwipeOffsetChanged(offset: Int) {
2020-06-09 00:50:51 +02:00
val offsetFactor = 1 - (abs(offset).toFloat() / swipeContainer.height)
swipeContainer.backgroundAlpha = offsetFactor
val colorToolbar = overrideTheme.colorToolbar
2020-06-09 00:50:51 +02:00
val alpha = (Color.alpha(colorToolbar) * offsetFactor).roundToInt().coerceIn(0..255)
2017-09-13 11:52:09 +02:00
activityLayout.statusBarAlpha = alpha / 255f
}
override fun onSwipeStateChanged(state: Int) {
supportActionBar?.let {
2017-04-17 18:10:29 +02:00
val barShowing = controlBarOffset >= 1
if (state == ViewDragHelper.STATE_IDLE) {
2017-04-17 18:10:29 +02:00
if (wasBarShowing == 1 && !barShowing) {
setControlBarVisibleAnimate(true)
}
wasBarShowing = 0
} else {
if (wasBarShowing == 0) {
2017-04-17 18:10:29 +02:00
wasBarShowing = if (barShowing) 1 else -1
}
2017-04-17 18:10:29 +02:00
if (barShowing) {
setControlBarVisibleAnimate(false)
}
}
}
}
override fun setControlBarVisibleAnimate(visible: Boolean, listener: ControlBarShowHideHelper.ControlBarAnimationListener?) {
controlBarShowHideHelper.setControlBarVisibleAnimate(visible, listener)
}
2017-06-25 17:01:33 +02:00
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
val result = super.onApplyWindowInsets(v, insets)
2020-01-26 08:35:15 +01:00
val adapter = viewPager.adapter ?: return insets
2017-06-25 17:01:33 +02:00
if (adapter.count == 0) return insets
2017-02-02 15:08:04 +01:00
val fragment = adapter.instantiateItem(viewPager, viewPager.currentItem)
if (fragment is IBaseFragment<*>) {
fragment.requestApplyInsets()
2017-02-02 15:08:04 +01:00
}
return result
2017-02-02 15:08:04 +01:00
}
private fun instantiateMediaViewerFragment(args: Bundle): MediaViewerFragment {
2020-05-31 08:15:53 +02:00
return Fragment.instantiate(this, ExoPlayerPageFragment::class.java.name, args) as MediaViewerFragment
}
2016-12-06 06:15:22 +01:00
private fun processShareIntent(intent: Intent) {
2016-07-18 04:14:51 +02:00
val status = status ?: return
2016-07-07 09:39:32 +02:00
intent.putExtra(Intent.EXTRA_SUBJECT, IntentUtils.getStatusShareSubject(this, status))
intent.putExtra(Intent.EXTRA_TEXT, IntentUtils.getStatusShareText(this, status))
}
2016-12-06 06:15:22 +01:00
private fun requestAndSaveToStorage(position: Int) {
saveToStoragePosition = position
2016-12-13 04:06:07 +01:00
if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
2016-07-07 09:39:32 +02:00
saveToStorage()
} else {
2020-06-09 01:09:31 +02:00
val permissions: Array<String> = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
2020-06-08 23:19:10 +02:00
arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
2016-07-07 09:39:32 +02:00
} else {
2020-06-08 23:19:10 +02:00
arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE)
2016-07-07 09:39:32 +02:00
}
2016-12-13 04:06:07 +01:00
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_save_media),
permissions, REQUEST_PERMISSION_SAVE_MEDIA)
2016-07-07 09:39:32 +02:00
}
}
2016-12-06 06:15:22 +01:00
private fun requestAndShareMedia(position: Int) {
2016-12-13 04:06:07 +01:00
shareMediaPosition = position
if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
2016-07-07 09:39:32 +02:00
shareMedia()
} else {
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
2016-07-07 09:39:32 +02:00
} else {
arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE)
2016-07-07 09:39:32 +02:00
}
2016-12-13 04:06:07 +01:00
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_share_media),
permissions, REQUEST_PERMISSION_SHARE_MEDIA)
2016-07-07 09:39:32 +02:00
}
}
2016-12-06 06:15:22 +01:00
private fun shareMedia() {
val fileInfo = getCurrentCacheFileInfo(shareMediaPosition) ?: return
2016-07-07 09:39:32 +02:00
val destination = ShareProvider.getFilesDir(this) ?: return
val task = SaveMediaTask(this, destination, fileInfo)
2017-05-19 17:08:23 +02:00
task.execute()
2016-07-07 09:39:32 +02:00
}
2016-12-06 06:15:22 +01:00
private fun saveToStorage() {
val fileInfo = getCurrentCacheFileInfo(saveToStoragePosition) ?: return
2020-06-08 23:09:07 +02:00
val pubDir = when ((fileInfo as? CacheProvider.CacheFileTypeSupport)?.cacheFileType) {
CacheFileType.VIDEO -> {
2020-04-02 09:04:31 +02:00
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
} else {
getExternalFilesDir(Environment.DIRECTORY_MOVIES)
}
}
CacheFileType.IMAGE -> {
2020-04-02 09:04:31 +02:00
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
} else {
getExternalFilesDir(Environment.DIRECTORY_PICTURES)
}
}
else -> {
2020-04-02 09:04:31 +02:00
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
} else {
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
}
}
2016-07-07 09:39:32 +02:00
}
val saveDir = File(pubDir, "Twidere")
val task = SaveMediaToGalleryTask(this, fileInfo, saveDir)
2017-05-19 17:08:23 +02:00
task.execute()
2016-07-07 09:39:32 +02:00
}
private fun openSaveToDocumentChooser() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
val fileInfo = getCurrentCacheFileInfo(viewPager.currentItem) ?: return
2020-04-01 10:03:35 +02:00
thread {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.type = fileInfo.mimeType ?: "*/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
val extension = fileInfo.fileExtension
val saveFileName = if (extension != null) {
"${fileInfo.fileName?.removeSuffix("_$extension")}.$extension"
} else {
fileInfo.fileName
}
intent.putExtra(Intent.EXTRA_TITLE, saveFileName)
startActivityForResult(intent, REQUEST_SELECT_SAVE_MEDIA)
}
}
private fun saveMediaToContentUri(data: Uri) {
val fileInfo = getCurrentCacheFileInfo(viewPager.currentItem) ?: return
val weakThis = weak()
(showProgressDialog("save_media_to_progress") and task {
val a = weakThis.get() ?: throw InterruptedException()
fileInfo.inputStream().use { st ->
2019-10-25 10:50:10 +02:00
a.contentResolver.openOutputStream(data)?.use {
st.copyTo(it)
}
}
}).successUi {
val a = weakThis.get() ?: return@successUi
Toast.makeText(a, R.string.message_toast_media_saved, Toast.LENGTH_SHORT).show()
}.alwaysUi {
val a = weakThis.get() ?: return@alwaysUi
a.dismissProgressDialog("save_media_to_progress")
}
}
private fun MediaViewerFragment.cacheFileInfo(): SaveFileTask.FileInfo? {
2020-01-26 08:35:15 +01:00
when (this) {
is CacheDownloadMediaViewerFragment -> {
val cacheUri = downloadResult?.cacheUri ?: return null
val type = when (this) {
is ImagePageFragment -> CacheFileType.IMAGE
is VideoPageFragment -> CacheFileType.VIDEO
is GifPageFragment -> CacheFileType.IMAGE
else -> return null
}
2020-01-26 08:35:15 +01:00
return activity?.let {
CacheProvider.ContentUriFileInfo(it, cacheUri, type)
}
}
is ExoPlayerPageFragment -> {
return getRequestFileInfo()
}
else -> return null
}
}
class SaveMediaTask(activity: MediaViewerActivity, destination: File, fileInfo: FileInfo) :
SaveFileTask(activity, destination, fileInfo) {
private val PROGRESS_FRAGMENT_TAG = "progress"
override fun dismissProgress() {
val activity = context as? MediaViewerActivity ?: return
activity.executeAfterFragmentResumed {
val fm = it.supportFragmentManager
val fragment = fm.findFragmentByTag(PROGRESS_FRAGMENT_TAG) as? DialogFragment
fragment?.dismiss()
}
}
override fun showProgress() {
val activity = context as? MediaViewerActivity ?: return
activity.executeAfterFragmentResumed {
val fragment = ProgressDialogFragment()
fragment.isCancelable = false
fragment.show(it.supportFragmentManager, PROGRESS_FRAGMENT_TAG)
}
}
override fun onFileSaved(savedFile: File, mimeType: String?) {
val activity = context as? MediaViewerActivity ?: return
val fileUri = ShareProvider.getUriForFile(activity, AUTHORITY_TWIDERE_SHARE,
savedFile)
val intent = Intent(Intent.ACTION_SEND)
intent.setDataAndType(fileUri, mimeType)
intent.putExtra(Intent.EXTRA_STREAM, fileUri)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
}
activity.processShareIntent(intent)
activity.startActivityForResult(Intent.createChooser(intent, activity.getString(R.string.action_share)),
REQUEST_SHARE_MEDIA)
}
override fun onFileSaveFailed() {
val activity = context as? MediaViewerActivity ?: return
Toast.makeText(activity, R.string.message_toast_error_occurred, Toast.LENGTH_SHORT).show()
}
}
2017-09-13 11:52:09 +02:00
2016-07-07 09:39:32 +02:00
companion object {
2020-06-08 23:11:06 +02:00
private const val REQUEST_SHARE_MEDIA = 201
private const val REQUEST_PERMISSION_SAVE_MEDIA = 202
private const val REQUEST_PERMISSION_SHARE_MEDIA = 203
private const val REQUEST_SELECT_SAVE_MEDIA = 204
2017-04-17 18:10:29 +02:00
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
const val FLAG_SYSTEM_UI_HIDE_BARS = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN
2016-07-07 09:39:32 +02:00
}
interface Media
2016-07-07 09:39:32 +02:00
}