close #691
trying to improve #692
tweaked media viewer swipe
This commit is contained in:
Mariotaku Lee 2017-02-01 22:00:55 +08:00
parent 857ba24bb0
commit e7e37caff8
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
12 changed files with 253 additions and 169 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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])

View File

@ -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) {

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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")
}
}
}

View File

@ -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)
}

View File

@ -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 + ":"

View File

@ -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)

View File

@ -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"