mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-02 17:56:56 +01:00
updated media viewer library
This commit is contained in:
parent
b10a5019cc
commit
d89ce3bfbd
@ -57,7 +57,7 @@ cache:
|
||||
- $HOME/.m2/
|
||||
|
||||
before_install:
|
||||
- openssl aes-256-cbc -K $encrypted_9b8203f9524d_key -iv $encrypted_9b8203f9524d_iv -in twidere_private_config.tar.gz.enc -out travis/configs/twidere_private_config.tar.gz -d
|
||||
- openssl aes-256-cbc -K $encrypted_9b8203f9524d_key -iv $encrypted_9b8203f9524d_iv -in travis/configs/twidere_private_config.tar.gz.enc -out travis/configs/twidere_private_config.tar.gz -d
|
||||
|
||||
install:
|
||||
# Extracts build configs into source tree
|
||||
|
@ -171,8 +171,8 @@ dependencies {
|
||||
compile "com.google.android.exoplayer:exoplayer:$exoplayer_version"
|
||||
compile "com.google.android.exoplayer:extension-okhttp:$exoplayer_version"
|
||||
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:base:0.9.17'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:subsample-image-view:0.9.17'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:base:0.9.20'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:subsample-image-view:0.9.20'
|
||||
compile 'com.github.mariotaku:SQLiteQB:0.9.10'
|
||||
compile "com.github.mariotaku.ObjectCursor:core:$mariotaku_object_cursor_version"
|
||||
compile 'com.github.mariotaku:MultiValueSwitch:0.9.7'
|
||||
|
@ -139,7 +139,7 @@ public class TwidereMediaDownloader implements MediaDownloader {
|
||||
additionalHeaders.add("User-Agent", userAgent);
|
||||
final String method = GET.METHOD;
|
||||
final String requestUri;
|
||||
if (isAuthRequired(uri, account) && auth != null && auth.hasAuthorization()) {
|
||||
if (isAuthRequired(account, uri) && auth != null && auth.hasAuthorization()) {
|
||||
final Endpoint endpoint;
|
||||
if (auth instanceof OAuthAuthorization) {
|
||||
endpoint = new OAuthEndpoint(getEndpoint(modifiedUri), getEndpoint(uri));
|
||||
@ -184,7 +184,7 @@ public class TwidereMediaDownloader implements MediaDownloader {
|
||||
return new TwidereDownloadResult(body, metadata);
|
||||
}
|
||||
|
||||
private String getEndpoint(Uri uri) {
|
||||
public static String getEndpoint(Uri uri) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(uri.getScheme());
|
||||
sb.append("://");
|
||||
@ -197,7 +197,7 @@ public class TwidereMediaDownloader implements MediaDownloader {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private boolean isAuthRequired(final Uri uri, @Nullable final AccountDetails details) {
|
||||
public static boolean isAuthRequired(@Nullable final AccountDetails details, @NonNull final Uri uri) {
|
||||
if (details == null) return false;
|
||||
final String host = uri.getHost();
|
||||
if (details.credentials.api_url_format != null && details.credentials.api_url_format.contains(host)) {
|
||||
@ -206,11 +206,11 @@ public class TwidereMediaDownloader implements MediaDownloader {
|
||||
return "ton.twitter.com".equalsIgnoreCase(host);
|
||||
}
|
||||
|
||||
private boolean isTwitterUri(final Uri uri) {
|
||||
private static boolean isTwitterUri(final Uri uri) {
|
||||
return uri != null && "ton.twitter.com".equalsIgnoreCase(uri.getHost());
|
||||
}
|
||||
|
||||
private Uri getReplacedUri(@NonNull final Uri uri, final String apiUrlFormat) {
|
||||
public static Uri getReplacedUri(@NonNull final Uri uri, final String apiUrlFormat) {
|
||||
if (apiUrlFormat == null) return uri;
|
||||
if (isTwitterUri(uri)) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
@ -173,17 +173,11 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||
if (currentItem < 0 || currentItem >= adapter.count) return false
|
||||
val obj = adapter.instantiateItem(viewPager, currentItem) as? MediaViewerFragment ?: return false
|
||||
if (obj.isDetached || obj.host == null) return false
|
||||
if (obj is CacheDownloadMediaViewerFragment) {
|
||||
val running = obj.loaderManager.hasRunningLoadersSafe()
|
||||
val downloaded = obj.hasDownloadedData()
|
||||
MenuUtils.setItemAvailability(menu, R.id.refresh, !running && !downloaded)
|
||||
MenuUtils.setItemAvailability(menu, R.id.share, !running && downloaded)
|
||||
MenuUtils.setItemAvailability(menu, R.id.save, !running && downloaded)
|
||||
} else {
|
||||
MenuUtils.setItemAvailability(menu, R.id.refresh, false)
|
||||
MenuUtils.setItemAvailability(menu, R.id.share, true)
|
||||
MenuUtils.setItemAvailability(menu, R.id.save, false)
|
||||
}
|
||||
val running = obj.isMediaLoading
|
||||
val downloaded = obj.isMediaLoaded
|
||||
MenuUtils.setItemAvailability(menu, R.id.refresh, !running && !downloaded)
|
||||
MenuUtils.setItemAvailability(menu, R.id.share, !running && downloaded)
|
||||
MenuUtils.setItemAvailability(menu, R.id.save, !running && downloaded)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package org.mariotaku.twidere.fragment.media
|
||||
|
||||
import android.accounts.AccountManager
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
@ -31,7 +32,7 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.exoplayer2.*
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource
|
||||
import com.google.android.exoplayer2.source.LoopingMediaSource
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray
|
||||
@ -40,20 +41,33 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_exo_player_view.*
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_video_overlay.*
|
||||
import org.mariotaku.mediaviewer.library.MediaViewerFragment
|
||||
import org.mariotaku.mediaviewer.library.subsampleimageview.SubsampleImageViewerFragment
|
||||
import org.mariotaku.restfu.RestRequest
|
||||
import org.mariotaku.restfu.http.Endpoint
|
||||
import org.mariotaku.restfu.http.MultiValueMap
|
||||
import org.mariotaku.restfu.oauth.OAuthAuthorization
|
||||
import org.mariotaku.restfu.oauth.OAuthEndpoint
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_POSITION
|
||||
import org.mariotaku.twidere.extension.model.getAuthorization
|
||||
import org.mariotaku.twidere.fragment.iface.IBaseFragment
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.EXTRA_PAUSED_BY_USER
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.EXTRA_PLAY_AUDIO
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.SUPPORTED_VIDEO_TYPES
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.accountKey
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.isControlDisabled
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.isLoopEnabled
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.isMutedByDefault
|
||||
import org.mariotaku.twidere.fragment.media.VideoPageFragment.Companion.media
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import org.mariotaku.twidere.util.media.TwidereMediaDownloader
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@ -65,7 +79,10 @@ import javax.inject.Inject
|
||||
class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPageFragment> {
|
||||
|
||||
@Inject
|
||||
lateinit var dataSourceFactory: DataSource.Factory
|
||||
internal lateinit var dataSourceFactory: DataSource.Factory
|
||||
|
||||
@Inject
|
||||
internal lateinit var extractorsFactory: ExtractorsFactory
|
||||
|
||||
private lateinit var mainHandler: Handler
|
||||
|
||||
@ -80,6 +97,7 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
}
|
||||
|
||||
override fun onPlayerError(error: ExoPlaybackException) {
|
||||
|
||||
}
|
||||
|
||||
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
|
||||
@ -212,13 +230,20 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
requestFitSystemWindows()
|
||||
}
|
||||
|
||||
override fun recycleMedia() {
|
||||
}
|
||||
|
||||
override fun executeAfterFragmentResumed(useHandler: Boolean, action: (ExoPlayerPageFragment) -> Unit) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun isMediaLoaded(): Boolean {
|
||||
val player = playerView.player ?: return false
|
||||
return player.playbackState != ExoPlayer.STATE_IDLE
|
||||
}
|
||||
|
||||
override fun isMediaLoading(): Boolean {
|
||||
val player = playerView.player ?: return false
|
||||
return player.isLoading
|
||||
}
|
||||
|
||||
private fun releasePlayer() {
|
||||
val player = playerView.player ?: return
|
||||
positionBackup = player.currentPosition
|
||||
@ -243,9 +268,10 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
return@run player
|
||||
}
|
||||
|
||||
val uri = getDownloadUri() ?: return
|
||||
val uriSource = ExtractorMediaSource(uri, dataSourceFactory, DefaultExtractorsFactory(),
|
||||
null, null)
|
||||
val uri = media?.getDownloadUri() ?: return
|
||||
val am = AccountManager.get(context)
|
||||
val factory = AuthDelegatingDataSourceFactory(uri, accountKey, am, dataSourceFactory)
|
||||
val uriSource = ExtractorMediaSource(uri, factory, extractorsFactory, null, null)
|
||||
if (isLoopEnabled) {
|
||||
playerView.player.prepare(LoopingMediaSource(uriSource))
|
||||
} else {
|
||||
@ -264,11 +290,51 @@ class ExoPlayerPageFragment : MediaViewerFragment(), IBaseFragment<ExoPlayerPage
|
||||
}
|
||||
}
|
||||
|
||||
fun getDownloadUri(): Uri? {
|
||||
val bestVideoUrlAndType = VideoPageFragment.getBestVideoUrlAndType(media, VideoPageFragment.SUPPORTED_VIDEO_TYPES)
|
||||
fun ParcelableMedia.getDownloadUri(): Uri? {
|
||||
val bestVideoUrlAndType = VideoPageFragment.getBestVideoUrlAndType(this, SUPPORTED_VIDEO_TYPES)
|
||||
if (bestVideoUrlAndType != null && bestVideoUrlAndType.first != null) {
|
||||
return Uri.parse(bestVideoUrlAndType.first)
|
||||
}
|
||||
return arguments.getParcelable<Uri>(SubsampleImageViewerFragment.EXTRA_MEDIA_URI)
|
||||
}
|
||||
|
||||
class AuthDelegatingDataSourceFactory(
|
||||
val uri: Uri,
|
||||
val accountKey: UserKey,
|
||||
val am: AccountManager,
|
||||
val delegate: DataSource.Factory
|
||||
) : DataSource.Factory {
|
||||
override fun createDataSource(): DataSource {
|
||||
val source = delegate.createDataSource()
|
||||
if (source is HttpDataSource) {
|
||||
setAuthorizationHeader(source)
|
||||
}
|
||||
return source
|
||||
}
|
||||
|
||||
private fun setAuthorizationHeader(dataSource: HttpDataSource) {
|
||||
val account = AccountUtils.getAccountDetails(am, accountKey, true) ?: return
|
||||
val modifiedUri = TwidereMediaDownloader.getReplacedUri(uri, account.credentials.api_url_format) ?: uri
|
||||
if (TwidereMediaDownloader.isAuthRequired(account, uri)) {
|
||||
val auth = account.credentials.getAuthorization()
|
||||
val endpoint: Endpoint
|
||||
if (auth is OAuthAuthorization) {
|
||||
endpoint = OAuthEndpoint(TwidereMediaDownloader.getEndpoint(modifiedUri),
|
||||
TwidereMediaDownloader.getEndpoint(uri))
|
||||
} else {
|
||||
endpoint = Endpoint(TwidereMediaDownloader.getEndpoint(modifiedUri))
|
||||
}
|
||||
val queries = MultiValueMap<String>()
|
||||
for (name in uri.queryParameterNames) {
|
||||
for (value in uri.getQueryParameters(name)) {
|
||||
queries.add(name, value)
|
||||
}
|
||||
}
|
||||
val info = RestRequest("GET", false, uri.path, null, queries, null, null, null, null)
|
||||
dataSource.setRequestProperty("Authorization", auth.getHeader(endpoint, info))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -67,8 +67,12 @@ class ExternalBrowserPageFragment : MediaViewerFragment() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun recycleMedia() {
|
||||
override fun isMediaLoaded(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun isMediaLoading(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
|
||||
|
@ -80,7 +80,7 @@ class GifPageFragment : CacheDownloadMediaViewerFragment() {
|
||||
return inflater.inflate(R.layout.layout_media_viewer_gif, parent, false)
|
||||
}
|
||||
|
||||
override fun recycleMedia() {
|
||||
override fun releaseMediaResources() {
|
||||
gifView?.setInputSource(null)
|
||||
}
|
||||
|
||||
|
@ -203,8 +203,7 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), IBaseFragment<Vide
|
||||
activity.supportInvalidateOptionsMenu()
|
||||
}
|
||||
|
||||
override fun recycleMedia() {
|
||||
|
||||
override fun releaseMediaResources() {
|
||||
}
|
||||
|
||||
override fun onCompletion(mp: MediaPlayer) {
|
||||
|
@ -48,7 +48,8 @@ import org.mariotaku.twidere.task.twitter.message.GetMessagesTask.Companion.addL
|
||||
*/
|
||||
class SendMessageTask(
|
||||
context: Context
|
||||
) : ExceptionHandlingAbstractTask<ParcelableNewMessage, SendMessageTask.SendMessageResult, MicroBlogException, Unit>(context) {
|
||||
) : ExceptionHandlingAbstractTask<ParcelableNewMessage, SendMessageTask.SendMessageResult,
|
||||
MicroBlogException, Unit>(context) {
|
||||
|
||||
override fun onExecute(params: ParcelableNewMessage): SendMessageResult {
|
||||
val account = params.account
|
||||
@ -118,11 +119,11 @@ class SendMessageTask(
|
||||
e.deleteAlways?.forEach {
|
||||
it.delete(context)
|
||||
}
|
||||
throw e
|
||||
throw MicroBlogException(e)
|
||||
} finally {
|
||||
deleteOnSuccess?.forEach { it.delete(context) }
|
||||
deleteAlways?.forEach { it.delete(context) }
|
||||
}
|
||||
deleteAlways?.forEach { it.delete(context) }
|
||||
deleteOnSuccess?.forEach { it.delete(context) }
|
||||
val conversationId = sendResponse.entries?.firstOrNull {
|
||||
it.message != null
|
||||
}?.message?.conversationId
|
||||
@ -137,8 +138,33 @@ class SendMessageTask(
|
||||
}
|
||||
|
||||
private fun sendDefaultDM(microBlog: MicroBlog, account: AccountDetails, message: ParcelableNewMessage): GetMessagesTask.DatabaseUpdateData {
|
||||
var deleteOnSuccess: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
var deleteAlways: List<UpdateStatusTask.MediaDeletionItem>? = null
|
||||
val recipientId = message.recipient_ids.singleOrNull() ?: throw MicroBlogException("No recipient")
|
||||
val response = microBlog.sendDirectMessage(recipientId, message.text)
|
||||
val response = try {
|
||||
var mediaId: String? = null
|
||||
if (message.media.isNotNullOrEmpty()) {
|
||||
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
|
||||
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
|
||||
mediaLoader, upload, account, message.media, null, true, null)
|
||||
mediaId = uploadResult.ids[0]
|
||||
deleteAlways = uploadResult.deleteAlways
|
||||
deleteOnSuccess = uploadResult.deleteOnSuccess
|
||||
}
|
||||
if (mediaId != null) {
|
||||
microBlog.sendDirectMessage(recipientId, message.text, mediaId)
|
||||
} else {
|
||||
microBlog.sendDirectMessage(recipientId, message.text)
|
||||
}
|
||||
} catch (e: UpdateStatusTask.UploadException) {
|
||||
e.deleteAlways?.forEach {
|
||||
it.delete(context)
|
||||
}
|
||||
throw MicroBlogException(e)
|
||||
} finally {
|
||||
deleteAlways?.forEach { it.delete(context) }
|
||||
}
|
||||
deleteOnSuccess?.forEach { it.delete(context) }
|
||||
return createDatabaseUpdateData(account, response)
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@ import android.os.Looper
|
||||
import android.support.v4.net.ConnectivityManagerCompat
|
||||
import android.support.v4.text.BidiFormatter
|
||||
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.nostra13.universalimageloader.cache.disc.DiskCache
|
||||
import com.nostra13.universalimageloader.cache.disc.impl.ext.LruDiskCache
|
||||
@ -330,6 +332,12 @@ class ApplicationModule(private val application: Application) {
|
||||
return OkHttpDataSourceFactory(builder.build(), userAgent, null)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun extractorsFactory(): ExtractorsFactory {
|
||||
return DefaultExtractorsFactory()
|
||||
}
|
||||
|
||||
private fun createDiskCache(dirName: String, preferences: SharedPreferencesWrapper): DiskCache {
|
||||
val cacheDir = Utils.getExternalCacheDir(application, dirName)
|
||||
val fallbackCacheDir = Utils.getInternalCacheDir(application, dirName)
|
||||
|
Loading…
x
Reference in New Issue
Block a user