fixed #429
close #691 trying to improve #692 tweaked media viewer swipe
This commit is contained in:
parent
857ba24bb0
commit
e7e37caff8
|
@ -6,10 +6,10 @@ import org.mariotaku.twidere.model.UserKey;
|
|||
* Created by mariotaku on 16/1/28.
|
||||
*/
|
||||
public class MediaExtra {
|
||||
UserKey accountKey;
|
||||
boolean useThumbor = true;
|
||||
String fallbackUrl;
|
||||
boolean skipUrlReplacing;
|
||||
private UserKey accountKey;
|
||||
private boolean useThumbor = true;
|
||||
private String fallbackUrl;
|
||||
private boolean skipUrlReplacing;
|
||||
|
||||
public UserKey getAccountKey() {
|
||||
return accountKey;
|
||||
|
|
|
@ -48,37 +48,37 @@ import java.io.InputStream;
|
|||
*/
|
||||
public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
||||
|
||||
private final Context mContext;
|
||||
private final SharedPreferencesWrapper mPreferences;
|
||||
private final RestHttpClient mClient;
|
||||
private final String mUserAgent;
|
||||
private final Context context;
|
||||
private final SharedPreferencesWrapper preferences;
|
||||
private final RestHttpClient client;
|
||||
private final String userAgent;
|
||||
|
||||
private Thumbor mThumbor;
|
||||
private Thumbor thumbor;
|
||||
|
||||
public TwidereMediaDownloader(final Context context, SharedPreferencesWrapper preferences,
|
||||
RestHttpClient client) {
|
||||
mContext = context;
|
||||
mPreferences = preferences;
|
||||
mClient = client;
|
||||
mUserAgent = UserAgentUtils.getDefaultUserAgentStringSafe(context);
|
||||
this.context = context;
|
||||
this.preferences = preferences;
|
||||
this.client = client;
|
||||
userAgent = UserAgentUtils.getDefaultUserAgentStringSafe(context);
|
||||
reloadConnectivitySettings();
|
||||
}
|
||||
|
||||
public void reloadConnectivitySettings() {
|
||||
if (mPreferences.getBoolean(KEY_THUMBOR_ENABLED)) {
|
||||
final String address = mPreferences.getString(KEY_THUMBOR_ADDRESS, null);
|
||||
final String securityKey = mPreferences.getString(KEY_THUMBOR_SECURITY_KEY, null);
|
||||
if (preferences.getBoolean(KEY_THUMBOR_ENABLED)) {
|
||||
final String address = preferences.getString(KEY_THUMBOR_ADDRESS, null);
|
||||
final String securityKey = preferences.getString(KEY_THUMBOR_SECURITY_KEY, null);
|
||||
if (address != null && URLUtil.isValidUrl(address)) {
|
||||
if (TextUtils.isEmpty(securityKey)) {
|
||||
mThumbor = Thumbor.create(address);
|
||||
thumbor = Thumbor.create(address);
|
||||
} else {
|
||||
mThumbor = Thumbor.create(address, securityKey);
|
||||
thumbor = Thumbor.create(address, securityKey);
|
||||
}
|
||||
} else {
|
||||
mThumbor = null;
|
||||
thumbor = null;
|
||||
}
|
||||
} else {
|
||||
mThumbor = null;
|
||||
thumbor = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
skipUrlReplacing = ((MediaExtra) extra).isSkipUrlReplacing();
|
||||
}
|
||||
if (!skipUrlReplacing) {
|
||||
final ParcelableMedia media = PreviewMediaExtractor.fromLink(url, mClient, extra);
|
||||
final ParcelableMedia media = PreviewMediaExtractor.fromLink(url, client, extra);
|
||||
if (media != null && media.media_url != null) {
|
||||
return getInternal(media.media_url, extra);
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
final String fallbackUrl = ((MediaExtra) extra).getFallbackUrl();
|
||||
if (fallbackUrl != null) {
|
||||
final ParcelableMedia media = PreviewMediaExtractor.fromLink(fallbackUrl,
|
||||
mClient, extra);
|
||||
client, extra);
|
||||
if (media != null && media.media_url != null) {
|
||||
return getInternal(media.media_url, extra);
|
||||
} else {
|
||||
|
@ -124,7 +124,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
useThumbor = ((MediaExtra) extra).isUseThumbor();
|
||||
UserKey accountKey = ((MediaExtra) extra).getAccountKey();
|
||||
if (accountKey != null) {
|
||||
account = AccountUtils.getAccountDetails(AccountManager.get(mContext), accountKey, true);
|
||||
account = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true);
|
||||
if (account != null) {
|
||||
auth = CredentialsExtensionsKt.getAuthorization(account.credentials);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
}
|
||||
final Uri modifiedUri = getReplacedUri(uri, account != null ? account.credentials.api_url_format : null);
|
||||
final MultiValueMap<String> additionalHeaders = new MultiValueMap<>();
|
||||
additionalHeaders.add("User-Agent", mUserAgent);
|
||||
additionalHeaders.add("User-Agent", userAgent);
|
||||
final String method = GET.METHOD;
|
||||
final String requestUri;
|
||||
if (isAuthRequired(uri, account) && auth != null && auth.hasAuthorization()) {
|
||||
|
@ -152,8 +152,8 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
queries, null, null, null, null);
|
||||
additionalHeaders.add("Authorization", auth.getHeader(endpoint, info));
|
||||
requestUri = modifiedUri.toString();
|
||||
} else if (mThumbor != null && useThumbor) {
|
||||
requestUri = mThumbor.buildImage(modifiedUri.toString()).filter(ThumborUrlBuilder.quality(85)).toUrl();
|
||||
} else if (thumbor != null && useThumbor) {
|
||||
requestUri = thumbor.buildImage(Uri.encode(modifiedUri.toString())).filter(ThumborUrlBuilder.quality(85)).toUrl();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
additionalHeaders.add("Accept", "image/webp, */*");
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
builder.url(requestUri);
|
||||
builder.headers(additionalHeaders);
|
||||
builder.tag(NoIntercept.INSTANCE);
|
||||
final HttpResponse resp = mClient.newCall(builder.build()).execute();
|
||||
final HttpResponse resp = client.newCall(builder.build()).execute();
|
||||
if (!resp.isSuccessful()) {
|
||||
final String detailMessage = "Unable to get " + requestUri + ", response code: "
|
||||
+ resp.getStatus();
|
||||
|
|
|
@ -338,6 +338,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher, APIEditorDi
|
|||
setSignInButton()
|
||||
if (result.alreadyLoggedIn) {
|
||||
result.updateAccount(am)
|
||||
deleteAccountData(contentResolver, result.user.key)
|
||||
Toast.makeText(this, R.string.message_toast_already_logged_in, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
result.addAccount(am, preferences[randomizeAccountNameKey])
|
||||
|
|
|
@ -29,7 +29,7 @@ interface IControlBarActivity {
|
|||
fun notifyControlBarOffsetChanged() {}
|
||||
|
||||
interface ControlBarOffsetListener {
|
||||
fun onControlBarOffsetChanged(activity: IControlBarActivity, offset: Float) {}
|
||||
fun onControlBarOffsetChanged(activity: IControlBarActivity, offset: Float)
|
||||
}
|
||||
|
||||
class ControlBarShowHideHelper(private val activity: IControlBarActivity) {
|
||||
|
|
|
@ -16,4 +16,6 @@ fun parcelableMediaTypeString(@ParcelableMedia.Type type: Int): String? {
|
|||
ParcelableMedia.Type.VARIABLE_TYPE -> "variable"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ParcelableMedia.aspect_ratio: Double get() = this.width / this.height.toDouble()
|
|
@ -350,6 +350,8 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
|||
val color = ContextCompat.getColor(context, R.color.material_red)
|
||||
val size = resources.getDimensionPixelSize(R.dimen.element_spacing_msmall)
|
||||
menu.setMenuItemIcon(R.id.premium_features, BadgeDrawable(icon, color, size))
|
||||
} else {
|
||||
menu.setMenuItemIcon(R.id.premium_features, R.drawable.ic_action_infinity)
|
||||
}
|
||||
var hasLists = false
|
||||
var hasGroups = false
|
||||
|
|
|
@ -38,11 +38,11 @@ import org.mariotaku.twidere.extension.model.setPosition
|
|||
import org.mariotaku.twidere.loader.AccountDetailsLoader
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Inbox
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Outbox
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import org.mariotaku.twidere.util.IntentUtils
|
||||
import org.mariotaku.twidere.util.deleteAccountData
|
||||
import org.mariotaku.twidere.util.support.removeAccountSupport
|
||||
|
||||
/**
|
||||
|
@ -206,6 +206,9 @@ class AccountsManagerFragment : BaseFragment(), LoaderManager.LoaderCallbacks<Li
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE YOUR ACCOUNT
|
||||
*/
|
||||
class AccountDeletionDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
|
||||
|
||||
override fun onClick(dialog: DialogInterface, which: Int) {
|
||||
|
@ -215,19 +218,13 @@ class AccountsManagerFragment : BaseFragment(), LoaderManager.LoaderCallbacks<Li
|
|||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
val accountKey = account.getAccountKey(am)
|
||||
deleteAccountData(resolver, accountKey)
|
||||
am.removeAccountSupport(account)
|
||||
val where = Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY).sql
|
||||
val whereArgs = arrayOf(accountKey.toString())
|
||||
// Also delete tweets related to the account we previously
|
||||
// deleted.
|
||||
resolver.delete(Statuses.CONTENT_URI, where, whereArgs)
|
||||
resolver.delete(Mentions.CONTENT_URI, where, whereArgs)
|
||||
resolver.delete(Inbox.CONTENT_URI, where, whereArgs)
|
||||
resolver.delete(Outbox.CONTENT_URI, where, whereArgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val context = context
|
||||
val builder = AlertDialog.Builder(context)
|
||||
|
|
|
@ -14,7 +14,9 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.MediaController
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.SeekBar
|
||||
import android.widget.TextView
|
||||
import com.commonsware.cwac.layouts.AspectLockedFrameLayout.AspectRatioSource
|
||||
import edu.tsinghua.hotmobi.HotMobiLogger
|
||||
import edu.tsinghua.hotmobi.model.MediaDownloadEvent
|
||||
import kotlinx.android.synthetic.main.layout_media_viewer_texture_video_view.*
|
||||
|
@ -25,6 +27,7 @@ import org.mariotaku.twidere.R
|
|||
import org.mariotaku.twidere.TwidereConstants.EXTRA_ACCOUNT_KEY
|
||||
import org.mariotaku.twidere.TwidereConstants.EXTRA_MEDIA
|
||||
import org.mariotaku.twidere.activity.MediaViewerActivity
|
||||
import org.mariotaku.twidere.activity.iface.IControlBarActivity
|
||||
import org.mariotaku.twidere.model.ParcelableMedia
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.util.media.MediaExtra
|
||||
|
@ -32,14 +35,105 @@ import java.util.*
|
|||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPreparedListener,
|
||||
MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, View.OnClickListener {
|
||||
MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, View.OnClickListener, IControlBarActivity.ControlBarOffsetListener {
|
||||
|
||||
private var mPlayAudio: Boolean = false
|
||||
private var mVideoProgressRunnable: VideoPlayProgressRunnable? = null
|
||||
private var playAudio: Boolean = false
|
||||
private var mediaPlayer: MediaPlayer? = null
|
||||
private var mMediaPlayerError: Int = 0
|
||||
private var mediaPlayerError: Int = 0
|
||||
private var videoProgressRunnable: VideoPlayProgressRunnable? = null
|
||||
private var mediaDownloadEvent: MediaDownloadEvent? = null
|
||||
|
||||
private val isLoopEnabled: Boolean get() = arguments.getBoolean(EXTRA_LOOP, false)
|
||||
|
||||
private val media: ParcelableMedia? get() = arguments.getParcelable<ParcelableMedia>(EXTRA_MEDIA)
|
||||
|
||||
private val accountKey: UserKey get() = arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
|
||||
|
||||
private var aspectRatioSource = object : AspectRatioSource {
|
||||
override fun getHeight(): Int {
|
||||
val height = media?.height ?: 0
|
||||
if (height <= 0) return view!!.measuredHeight
|
||||
return height
|
||||
}
|
||||
|
||||
override fun getWidth(): Int {
|
||||
val width = media?.width ?: 0
|
||||
if (width <= 0) return view!!.measuredWidth
|
||||
return width
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
var handler: Handler? = videoViewProgress.handler
|
||||
if (handler == null) {
|
||||
handler = Handler(activity.mainLooper)
|
||||
}
|
||||
|
||||
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
|
||||
// Play audio by default if ringer mode on
|
||||
playAudio = am.ringerMode == AudioManager.RINGER_MODE_NORMAL
|
||||
|
||||
videoProgressRunnable = VideoPlayProgressRunnable(handler, videoViewProgress,
|
||||
durationLabel, positionLabel, videoView)
|
||||
|
||||
|
||||
videoViewOverlay.setOnClickListener(this)
|
||||
videoView.setOnPreparedListener(this)
|
||||
videoView.setOnErrorListener(this)
|
||||
videoView.setOnCompletionListener(this)
|
||||
|
||||
playPauseButton.setOnClickListener(this)
|
||||
volumeButton.setOnClickListener(this)
|
||||
videoControl.visibility = View.GONE
|
||||
videoContainer.setAspectRatioSource(aspectRatioSource)
|
||||
videoViewProgress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
private var paused: Boolean = false
|
||||
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
if (!fromUser) return
|
||||
val mp = mediaPlayer ?: return
|
||||
val duration = mp.duration
|
||||
if (duration <= 0) return
|
||||
mp.seekTo(Math.round(duration * (progress.toFloat() / seekBar.max)))
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {
|
||||
paused = pauseVideo()
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||
if (paused) {
|
||||
resumeVideo()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
startLoading(false)
|
||||
setMediaViewVisible(false)
|
||||
updateVolume()
|
||||
}
|
||||
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
super.onAttach(context)
|
||||
if (context is IControlBarActivity) {
|
||||
context.registerControlBarOffsetListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
val activity = activity
|
||||
if (activity is IControlBarActivity) {
|
||||
activity.unregisterControlBarOffsetListener(this)
|
||||
}
|
||||
super.onDetach()
|
||||
}
|
||||
|
||||
override fun getDownloadExtra(): Any? {
|
||||
val extra = MediaExtra()
|
||||
extra.isUseThumbor = false
|
||||
|
@ -50,29 +144,24 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPrep
|
|||
return extra
|
||||
}
|
||||
|
||||
val isLoopEnabled: Boolean
|
||||
get() = arguments.getBoolean(EXTRA_LOOP, false)
|
||||
|
||||
override fun isAbleToLoad(): Boolean {
|
||||
return downloadUri != null
|
||||
}
|
||||
|
||||
|
||||
override fun getDownloadUri(): Uri? {
|
||||
val bestVideoUrlAndType = getBestVideoUrlAndType(media,
|
||||
SUPPORTED_VIDEO_TYPES)
|
||||
val bestVideoUrlAndType = getBestVideoUrlAndType(media, SUPPORTED_VIDEO_TYPES)
|
||||
if (bestVideoUrlAndType != null && bestVideoUrlAndType.first != null) {
|
||||
return Uri.parse(bestVideoUrlAndType.first)
|
||||
}
|
||||
return arguments.getParcelable<Uri>(SubsampleImageViewerFragment.EXTRA_MEDIA_URI)
|
||||
}
|
||||
|
||||
|
||||
override fun displayMedia(result: CacheDownloadLoader.Result) {
|
||||
videoView.setVideoURI(result.cacheUri)
|
||||
videoControl.visibility = View.GONE
|
||||
setMediaViewVisible(true)
|
||||
val activity = activity
|
||||
activity?.supportInvalidateOptionsMenu()
|
||||
activity.supportInvalidateOptionsMenu()
|
||||
}
|
||||
|
||||
override fun recycleMedia() {
|
||||
|
@ -81,29 +170,31 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPrep
|
|||
|
||||
override fun onCompletion(mp: MediaPlayer) {
|
||||
updatePlayerState()
|
||||
// mVideoViewProgress.removeCallbacks(mVideoProgressRunnable);
|
||||
// mVideoViewProgress.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
override fun onControlBarOffsetChanged(activity: IControlBarActivity, offset: Float) {
|
||||
videoControl.translationY = (1 - offset) * videoControl.height
|
||||
}
|
||||
|
||||
override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
|
||||
mediaPlayer = null
|
||||
videoViewProgress.removeCallbacks(mVideoProgressRunnable)
|
||||
videoViewProgress.removeCallbacks(videoProgressRunnable)
|
||||
videoViewProgress.visibility = View.GONE
|
||||
videoControl.visibility = View.GONE
|
||||
mMediaPlayerError = what
|
||||
mediaPlayerError = what
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepared(mp: MediaPlayer) {
|
||||
if (userVisibleHint) {
|
||||
mediaPlayer = mp
|
||||
mMediaPlayerError = 0
|
||||
mediaPlayerError = 0
|
||||
mp.setScreenOnWhilePlaying(true)
|
||||
updateVolume()
|
||||
mp.isLooping = isLoopEnabled
|
||||
mp.start()
|
||||
videoViewProgress.visibility = View.VISIBLE
|
||||
videoViewProgress.post(mVideoProgressRunnable)
|
||||
videoViewProgress.post(videoProgressRunnable)
|
||||
updatePlayerState()
|
||||
videoControl.visibility = View.VISIBLE
|
||||
}
|
||||
|
@ -111,10 +202,10 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPrep
|
|||
|
||||
private fun updateVolume() {
|
||||
|
||||
volumeButton.setImageResource(if (mPlayAudio) R.drawable.ic_action_speaker_max else R.drawable.ic_action_speaker_muted)
|
||||
volumeButton.setImageResource(if (playAudio) R.drawable.ic_action_speaker_max else R.drawable.ic_action_speaker_muted)
|
||||
val mp = mediaPlayer ?: return
|
||||
try {
|
||||
if (mPlayAudio) {
|
||||
if (playAudio) {
|
||||
mp.setVolume(1f, 1f)
|
||||
} else {
|
||||
mp.setVolume(0f, 0f)
|
||||
|
@ -136,103 +227,28 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPrep
|
|||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
|
||||
var handler: Handler? = videoViewProgress.handler
|
||||
if (handler == null) {
|
||||
handler = Handler(activity.mainLooper)
|
||||
}
|
||||
|
||||
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
|
||||
// Play audio by default if ringer mode on
|
||||
mPlayAudio = am.ringerMode == AudioManager.RINGER_MODE_NORMAL
|
||||
|
||||
mVideoProgressRunnable = VideoPlayProgressRunnable(handler, videoViewProgress,
|
||||
durationLabel, positionLabel, videoView)
|
||||
|
||||
|
||||
videoViewOverlay.setOnClickListener(this)
|
||||
videoView.setOnPreparedListener(this)
|
||||
videoView.setOnErrorListener(this)
|
||||
videoView.setOnCompletionListener(this)
|
||||
|
||||
playPauseButton.setOnClickListener(this)
|
||||
volumeButton.setOnClickListener(this)
|
||||
videoControl.visibility = View.GONE
|
||||
startLoading(false)
|
||||
setMediaViewVisible(false)
|
||||
updateVolume()
|
||||
}
|
||||
|
||||
@SuppressLint("SwitchIntDef")
|
||||
private fun getBestVideoUrlAndType(media: ParcelableMedia?,
|
||||
supportedTypes: Array<String>): Pair<String, String>? {
|
||||
if (media == null) return null
|
||||
when (media.type) {
|
||||
ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF -> {
|
||||
if (media.video_info == null) {
|
||||
return Pair.create<String, String>(media.media_url, null)
|
||||
}
|
||||
val firstMatch = media.video_info.variants.first { variant ->
|
||||
supportedTypes.any { it.equals(variant.content_type, ignoreCase = true) }
|
||||
} ?: return null
|
||||
return Pair.create(firstMatch.url, firstMatch.content_type)
|
||||
}
|
||||
ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
||||
return Pair.create<String, String>(media.media_url, "video/mp4")
|
||||
}
|
||||
else -> {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.volumeButton -> {
|
||||
mPlayAudio = !mPlayAudio
|
||||
playAudio = !playAudio
|
||||
updateVolume()
|
||||
}
|
||||
R.id.playPauseButton -> {
|
||||
val mp = mediaPlayer
|
||||
if (mp != null) {
|
||||
if (mp.isPlaying) {
|
||||
mp.pause()
|
||||
} else {
|
||||
mp.start()
|
||||
}
|
||||
val mp = mediaPlayer ?: return
|
||||
if (mp.isPlaying) {
|
||||
mp.pause()
|
||||
} else {
|
||||
mp.start()
|
||||
}
|
||||
updatePlayerState()
|
||||
}
|
||||
R.id.videoViewOverlay -> {
|
||||
val activity = activity as MediaViewerActivity
|
||||
if (videoControl.visibility == View.VISIBLE) {
|
||||
videoControl.visibility = View.GONE
|
||||
activity.setBarVisibility(false)
|
||||
} else {
|
||||
videoControl.visibility = View.VISIBLE
|
||||
activity.setBarVisibility(true)
|
||||
}
|
||||
activity.setBarVisibility(!activity.isBarShowing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePlayerState() {
|
||||
val mp = mediaPlayer
|
||||
if (mp != null) {
|
||||
val playing = mp.isPlaying
|
||||
playPauseButton.contentDescription = getString(if (playing) R.string.pause else R.string.play)
|
||||
playPauseButton.setImageResource(if (playing) R.drawable.ic_action_pause else R.drawable.ic_action_play_arrow)
|
||||
} else {
|
||||
playPauseButton.contentDescription = getString(R.string.play)
|
||||
playPauseButton.setImageResource(R.drawable.ic_action_play_arrow)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateMediaView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return inflater.inflate(R.layout.layout_media_viewer_texture_video_view, container, false)
|
||||
}
|
||||
|
@ -267,11 +283,62 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPrep
|
|||
}
|
||||
}
|
||||
|
||||
private val media: ParcelableMedia?
|
||||
get() = arguments.getParcelable<ParcelableMedia>(EXTRA_MEDIA)
|
||||
|
||||
private val accountKey: UserKey
|
||||
get() = arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
|
||||
@SuppressLint("SwitchIntDef")
|
||||
private fun getBestVideoUrlAndType(media: ParcelableMedia?, supportedTypes: Array<String>): Pair<String, String>? {
|
||||
if (media == null) return null
|
||||
when (media.type) {
|
||||
ParcelableMedia.Type.VIDEO, ParcelableMedia.Type.ANIMATED_GIF -> {
|
||||
if (media.video_info == null) {
|
||||
return Pair.create<String, String>(media.media_url, null)
|
||||
}
|
||||
val firstMatch = media.video_info.variants.first { variant ->
|
||||
supportedTypes.any { it.equals(variant.content_type, ignoreCase = true) }
|
||||
} ?: return null
|
||||
return Pair.create(firstMatch.url, firstMatch.content_type)
|
||||
}
|
||||
ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
||||
return Pair.create<String, String>(media.media_url, "video/mp4")
|
||||
}
|
||||
else -> {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePlayerState() {
|
||||
val mp = mediaPlayer
|
||||
if (mp != null) {
|
||||
val playing = mp.isPlaying
|
||||
playPauseButton.contentDescription = getString(if (playing) R.string.pause else R.string.play)
|
||||
playPauseButton.setImageResource(if (playing) R.drawable.ic_action_pause else R.drawable.ic_action_play_arrow)
|
||||
} else {
|
||||
playPauseButton.contentDescription = getString(R.string.play)
|
||||
playPauseButton.setImageResource(R.drawable.ic_action_play_arrow)
|
||||
}
|
||||
}
|
||||
|
||||
private fun pauseVideo(): Boolean {
|
||||
val mp = mediaPlayer ?: return false
|
||||
var result = false
|
||||
if (mp.isPlaying) {
|
||||
mp.pause()
|
||||
result = true
|
||||
}
|
||||
updatePlayerState()
|
||||
return result
|
||||
}
|
||||
|
||||
private fun resumeVideo(): Boolean {
|
||||
val mp = mediaPlayer ?: return false
|
||||
var result = false
|
||||
if (!mp.isPlaying) {
|
||||
mp.start()
|
||||
result = true
|
||||
}
|
||||
updatePlayerState()
|
||||
return result
|
||||
}
|
||||
|
||||
private class VideoPlayProgressRunnable internal constructor(
|
||||
private val handler: Handler,
|
||||
|
@ -302,7 +369,7 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPrep
|
|||
|
||||
const val EXTRA_LOOP = "loop"
|
||||
private val SUPPORTED_VIDEO_TYPES: Array<String>
|
||||
private val FALLBACK_VIDEO_TYPES: Array<String>
|
||||
private val FALLBACK_VIDEO_TYPES: Array<String> = arrayOf("video/mp4")
|
||||
|
||||
init {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
|
@ -310,7 +377,6 @@ class VideoPageFragment : CacheDownloadMediaViewerFragment(), MediaPlayer.OnPrep
|
|||
} else {
|
||||
SUPPORTED_VIDEO_TYPES = arrayOf("video/webm", "video/mp4")
|
||||
}
|
||||
FALLBACK_VIDEO_TYPES = arrayOf("video/mp4")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package org.mariotaku.twidere.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
|
@ -11,6 +12,7 @@ import org.mariotaku.twidere.constant.filterPossibilitySensitiveStatusesKey
|
|||
import org.mariotaku.twidere.constant.filterUnavailableQuoteStatusesKey
|
||||
import org.mariotaku.twidere.model.DraftCursorIndices
|
||||
import org.mariotaku.twidere.model.ParcelableStatus.FilterFlags
|
||||
import org.mariotaku.twidere.model.UserKey
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
||||
|
||||
/**
|
||||
|
@ -100,3 +102,14 @@ fun deleteDrafts(context: Context, draftIds: LongArray): Int {
|
|||
}
|
||||
return context.contentResolver.delete(Drafts.CONTENT_URI, where, whereArgs)
|
||||
}
|
||||
|
||||
fun deleteAccountData(resolver: ContentResolver, accountKey: UserKey) {
|
||||
val where = Expression.equalsArgs(AccountSupportColumns.ACCOUNT_KEY).sql
|
||||
val whereArgs = arrayOf(accountKey.toString())
|
||||
// Also delete tweets related to the account we previously
|
||||
// deleted.
|
||||
resolver.delete(Statuses.CONTENT_URI, where, whereArgs)
|
||||
resolver.delete(Mentions.CONTENT_URI, where, whereArgs)
|
||||
resolver.delete(DirectMessages.Inbox.CONTENT_URI, where, whereArgs)
|
||||
resolver.delete(DirectMessages.Outbox.CONTENT_URI, where, whereArgs)
|
||||
}
|
|
@ -69,7 +69,7 @@ class ReadStateManager(context: Context) {
|
|||
preferences.unregisterOnSharedPreferenceChangeListener(listener)
|
||||
}
|
||||
|
||||
@JvmOverloads fun setPosition(key: String, keyId: String, position: Long, acceptOlder: Boolean = false): Boolean {
|
||||
fun setPosition(key: String, keyId: String, position: Long, acceptOlder: Boolean = false): Boolean {
|
||||
if (TextUtils.isEmpty(key)) return false
|
||||
val set: MutableSet<String> = preferences.getStringSet(key, null) ?: CompactHashSet<String>()
|
||||
val prefix = keyId + ":"
|
||||
|
|
|
@ -46,25 +46,22 @@ class MediaSwipeCloseContainer(context: Context, attrs: AttributeSet? = null) :
|
|||
val container = this@MediaSwipeCloseContainer
|
||||
val minVel = ViewConfiguration.get(context).scaledMinimumFlingVelocity
|
||||
when {
|
||||
yvel > minVel -> {
|
||||
yvel > minVel && childTop > 0 -> {
|
||||
// Settle downward
|
||||
container.dragHelper.settleCapturedViewAt(0, container.height)
|
||||
}
|
||||
yvel < -minVel -> {
|
||||
yvel < -minVel && childTop < 0 -> {
|
||||
// Settle upward
|
||||
container.dragHelper.settleCapturedViewAt(0, -container.height)
|
||||
|
||||
}
|
||||
else -> when {
|
||||
childTop < -container.height / 4 -> {
|
||||
container.dragHelper.smoothSlideViewTo(releasedChild, 0, -container.height)
|
||||
}
|
||||
childTop > container.height / 4 -> {
|
||||
container.dragHelper.smoothSlideViewTo(releasedChild, 0, container.height)
|
||||
}
|
||||
else -> {
|
||||
container.dragHelper.smoothSlideViewTo(releasedChild, 0, 0)
|
||||
}
|
||||
yvel <= 0 && childTop < -container.height / 4 -> {
|
||||
container.dragHelper.smoothSlideViewTo(releasedChild, 0, -container.height)
|
||||
}
|
||||
yvel >= 0 && childTop > container.height / 4 -> {
|
||||
container.dragHelper.smoothSlideViewTo(releasedChild, 0, container.height)
|
||||
}
|
||||
else -> {
|
||||
container.dragHelper.smoothSlideViewTo(releasedChild, 0, 0)
|
||||
}
|
||||
}
|
||||
ViewCompat.postInvalidateOnAnimation(container)
|
||||
|
|
|
@ -26,11 +26,18 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<com.sprylab.android.widget.TextureVideoView
|
||||
android:id="@+id/videoView"
|
||||
<com.commonsware.cwac.layouts.AspectLockedFrameLayout
|
||||
android:id="@+id/videoContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"/>
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerInParent="true">
|
||||
|
||||
<com.sprylab.android.widget.TextureVideoView
|
||||
android:id="@+id/videoView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</com.commonsware.cwac.layouts.AspectLockedFrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/videoViewOverlay"
|
||||
|
@ -72,7 +79,7 @@
|
|||
android:textSize="@dimen/text_size_extra_small"
|
||||
tools:text="--:--"/>
|
||||
|
||||
<ProgressBar
|
||||
<SeekBar
|
||||
android:id="@+id/videoViewProgress"
|
||||
style="?android:progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
|
@ -81,8 +88,7 @@
|
|||
android:layout_toEndOf="@+id/playPauseButton"
|
||||
android:layout_toLeftOf="@+id/volumeButton"
|
||||
android:layout_toRightOf="@+id/playPauseButton"
|
||||
android:layout_toStartOf="@+id/volumeButton"
|
||||
android:indeterminate="false"/>
|
||||
android:layout_toStartOf="@+id/volumeButton"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/durationLabel"
|
||||
|
|
Loading…
Reference in New Issue