From 5d7765b6d3f6271705dbe1f03eb0614045ed0747 Mon Sep 17 00:00:00 2001 From: Mariotaku Lee Date: Tue, 21 Apr 2015 15:11:14 +0800 Subject: [PATCH] added load progress for video improved keyboard shortcut --- settings.gradle | 3 +- .../mariotaku/twidere/TwidereConstants.java | 10 +- twidere.extension.launcher.compose/.gitignore | 1 + .../build.gradle | 42 +++ .../proguard-rules.pro | 17 + .../launcher/compose/ApplicationTest.java | 32 ++ .../src/main/AndroidManifest.xml | 38 +++ .../launcher/compose/MainActivity.java | 47 +++ .../src/main/res/values/strings.xml | 22 ++ .../support/BaseActionBarActivity.java | 4 +- .../activity/support/HomeActivity.java | 11 +- .../activity/support/LinkHandlerActivity.java | 10 +- .../activity/support/MediaViewerActivity.java | 206 ++++++------ .../fragment/support/AbsStatusesFragment.java | 49 +-- .../fragment/support/AbsUsersFragment.java | 33 +- .../support/DirectMessagesFragment.java | 307 +++++++++--------- .../util/KeyboardShortcutsHandler.java | 2 +- .../util/RecyclerViewNavigationHelper.java | 80 +++++ .../org/mariotaku/twidere/util/Utils.java | 6 +- .../mariotaku/twidere/util/VideoLoader.java | 4 + .../res/layout/fragment_media_page_image.xml | 6 +- .../res/layout/fragment_media_page_video.xml | 12 +- 22 files changed, 634 insertions(+), 308 deletions(-) create mode 100644 twidere.extension.launcher.compose/.gitignore create mode 100644 twidere.extension.launcher.compose/build.gradle create mode 100644 twidere.extension.launcher.compose/proguard-rules.pro create mode 100644 twidere.extension.launcher.compose/src/androidTest/java/org/mariotaku/twidere/extension/launcher/compose/ApplicationTest.java create mode 100644 twidere.extension.launcher.compose/src/main/AndroidManifest.xml create mode 100644 twidere.extension.launcher.compose/src/main/java/org/mariotaku/twidere/extension/launcher/compose/MainActivity.java create mode 100644 twidere.extension.launcher.compose/src/main/res/values/strings.xml create mode 100644 twidere/src/main/java/org/mariotaku/twidere/util/RecyclerViewNavigationHelper.java diff --git a/settings.gradle b/settings.gradle index dbfc82df5..6b9249062 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,4 +11,5 @@ include ':twidere.donate.nyanwp.wear' include ':twidere.component.nyan' include ':twidere.extension.streaming' include ':twidere.extension.twitlonger' -include ':twidere.extension.push.xiaomi' \ No newline at end of file +include ':twidere.extension.push.xiaomi' +include ':twidere.extension.launcher.compose' \ No newline at end of file diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/TwidereConstants.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/TwidereConstants.java index cb118f9b3..2fa5574ce 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/TwidereConstants.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/TwidereConstants.java @@ -29,12 +29,12 @@ import org.mariotaku.twidere.constant.SharedPreferenceConstants; */ public interface TwidereConstants extends SharedPreferenceConstants, IntentConstants { - public static final String APP_NAME = "Twidere"; - public static final String APP_PACKAGE_NAME = "org.mariotaku.twidere"; - public static final String APP_PROJECT_URL = "https://github.com/mariotaku/twidere"; - public static final String APP_PROJECT_EMAIL = "twidere.project@gmail.com"; + public static final String TWIDERE_APP_NAME = "Twidere"; + public static final String TWIDERE_PACKAGE_NAME = "org.mariotaku.twidere"; + public static final String TWIDERE_PROJECT_URL = "https://github.com/mariotaku/twidere"; + public static final String TWIDERE_PROJECT_EMAIL = "twidere.project@gmail.com"; - public static final String LOGTAG = APP_NAME; + public static final String LOGTAG = TWIDERE_APP_NAME; public static final String USER_NICKNAME_PREFERENCES_NAME = "user_nicknames"; public static final String USER_COLOR_PREFERENCES_NAME = "user_colors"; diff --git a/twidere.extension.launcher.compose/.gitignore b/twidere.extension.launcher.compose/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/twidere.extension.launcher.compose/.gitignore @@ -0,0 +1 @@ +/build diff --git a/twidere.extension.launcher.compose/build.gradle b/twidere.extension.launcher.compose/build.gradle new file mode 100644 index 000000000..4833c4036 --- /dev/null +++ b/twidere.extension.launcher.compose/build.gradle @@ -0,0 +1,42 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +apply plugin: 'com.android.application' +apply from: rootProject.file('global.gradle') + +android { + defaultConfig { + applicationId "org.mariotaku.twidere.extension.launcher.compose" + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile project(':twidere.library.extension') + compile fileTree(dir: 'libs', include: ['*.jar']) +} diff --git a/twidere.extension.launcher.compose/proguard-rules.pro b/twidere.extension.launcher.compose/proguard-rules.pro new file mode 100644 index 000000000..a3abb5fc4 --- /dev/null +++ b/twidere.extension.launcher.compose/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/mariotaku/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/twidere.extension.launcher.compose/src/androidTest/java/org/mariotaku/twidere/extension/launcher/compose/ApplicationTest.java b/twidere.extension.launcher.compose/src/androidTest/java/org/mariotaku/twidere/extension/launcher/compose/ApplicationTest.java new file mode 100644 index 000000000..61253dfe4 --- /dev/null +++ b/twidere.extension.launcher.compose/src/androidTest/java/org/mariotaku/twidere/extension/launcher/compose/ApplicationTest.java @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.extension.launcher.compose; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/twidere.extension.launcher.compose/src/main/AndroidManifest.xml b/twidere.extension.launcher.compose/src/main/AndroidManifest.xml new file mode 100644 index 000000000..3e02160e2 --- /dev/null +++ b/twidere.extension.launcher.compose/src/main/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + diff --git a/twidere.extension.launcher.compose/src/main/java/org/mariotaku/twidere/extension/launcher/compose/MainActivity.java b/twidere.extension.launcher.compose/src/main/java/org/mariotaku/twidere/extension/launcher/compose/MainActivity.java new file mode 100644 index 000000000..807e9c66c --- /dev/null +++ b/twidere.extension.launcher.compose/src/main/java/org/mariotaku/twidere/extension/launcher/compose/MainActivity.java @@ -0,0 +1,47 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.extension.launcher.compose; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.os.Bundle; + +import org.mariotaku.twidere.TwidereConstants; + +/** + * Created by mariotaku on 15/4/21. + */ +public class MainActivity extends Activity implements TwidereConstants { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Intent intent = new Intent(INTENT_ACTION_COMPOSE); + intent.setPackage(TWIDERE_PACKAGE_NAME); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + try { + startActivity(intent); + } catch (ActivityNotFoundException ignored) { + } + finish(); + + } +} diff --git a/twidere.extension.launcher.compose/src/main/res/values/strings.xml b/twidere.extension.launcher.compose/src/main/res/values/strings.xml new file mode 100644 index 000000000..087375c34 --- /dev/null +++ b/twidere.extension.launcher.compose/src/main/res/values/strings.xml @@ -0,0 +1,22 @@ + + + + Twidere Compose Launcher + diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/BaseActionBarActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/BaseActionBarActivity.java index 073c3f2ae..a64e5af3f 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/BaseActionBarActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/BaseActionBarActivity.java @@ -32,7 +32,7 @@ import org.mariotaku.twidere.activity.iface.IControlBarActivity; import org.mariotaku.twidere.app.TwidereApplication; import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback; import org.mariotaku.twidere.util.AsyncTwitterWrapper; -import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback; +import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback; import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.view.iface.IExtendedView.OnFitSystemWindowsListener; @@ -41,7 +41,7 @@ import java.util.ArrayList; @SuppressLint("Registered") public class BaseActionBarActivity extends ThemedActionBarActivity implements Constants, OnFitSystemWindowsListener, SystemWindowsInsetsCallback, IControlBarActivity, - ShortcutCallback { + KeyboardShortcutCallback { private boolean mInstanceStateSaved; private boolean mIsVisible; diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java index 688e96f0f..abc3f4b02 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/HomeActivity.java @@ -91,7 +91,7 @@ import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.ColorUtils; import org.mariotaku.twidere.util.CustomTabUtils; import org.mariotaku.twidere.util.KeyboardShortcutsHandler; -import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback; +import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback; import org.mariotaku.twidere.util.MathUtils; import org.mariotaku.twidere.util.MultiSelectEventHandler; import org.mariotaku.twidere.util.ParseUtils; @@ -287,6 +287,7 @@ public class HomeActivity extends BaseActionBarActivity implements OnClickListen mSlidingMenu.showContent(true); } else { mSlidingMenu.showMenu(true); + setControlBarVisibleAnimate(true); } return true; } @@ -684,16 +685,16 @@ public class HomeActivity extends BaseActionBarActivity implements OnClickListen private boolean handleFragmentKeyboardShortcutSingle(int keyCode, @NonNull KeyEvent event) { final Fragment fragment = getCurrentVisibleFragment(); - if (fragment instanceof ShortcutCallback) { - return ((ShortcutCallback) fragment).handleKeyboardShortcutSingle(keyCode, event); + if (fragment instanceof KeyboardShortcutCallback) { + return ((KeyboardShortcutCallback) fragment).handleKeyboardShortcutSingle(keyCode, event); } return false; } private boolean handleFragmentKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event) { final Fragment fragment = getCurrentVisibleFragment(); - if (fragment instanceof ShortcutCallback) { - return ((ShortcutCallback) fragment).handleKeyboardShortcutRepeat(keyCode, repeatCount, event); + if (fragment instanceof KeyboardShortcutCallback) { + return ((KeyboardShortcutCallback) fragment).handleKeyboardShortcutRepeat(keyCode, repeatCount, event); } return false; } diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/LinkHandlerActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/LinkHandlerActivity.java index 5ee678dad..7d870722f 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/LinkHandlerActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/LinkHandlerActivity.java @@ -50,7 +50,7 @@ import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback; import org.mariotaku.twidere.fragment.support.SearchFragment; import org.mariotaku.twidere.fragment.support.UserFragment; import org.mariotaku.twidere.util.KeyboardShortcutsHandler; -import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback; +import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback; import org.mariotaku.twidere.util.MultiSelectEventHandler; import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.Utils; @@ -221,16 +221,16 @@ public class LinkHandlerActivity extends BaseActionBarActivity implements System private boolean handleFragmentKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event) { final Fragment fragment = getCurrentVisibleFragment(); - if (fragment instanceof ShortcutCallback) { - return ((ShortcutCallback) fragment).handleKeyboardShortcutRepeat(keyCode, repeatCount, event); + if (fragment instanceof KeyboardShortcutCallback) { + return ((KeyboardShortcutCallback) fragment).handleKeyboardShortcutRepeat(keyCode, repeatCount, event); } return false; } private boolean handleFragmentKeyboardShortcutSingle(int keyCode, @NonNull KeyEvent event) { final Fragment fragment = getCurrentVisibleFragment(); - if (fragment instanceof ShortcutCallback) { - return ((ShortcutCallback) fragment).handleKeyboardShortcutSingle(keyCode, event); + if (fragment instanceof KeyboardShortcutCallback) { + return ((KeyboardShortcutCallback) fragment).handleKeyboardShortcutSingle(keyCode, event); } return false; } diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java index 515980423..3822aa519 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java @@ -228,7 +228,7 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement super.onBaseViewCreated(view, savedInstanceState); mImageView = (SubsamplingScaleImageView) view.findViewById(R.id.image_view); mGifImageView = (GifTextureView) view.findViewById(R.id.gif_image_view); - mProgressBar = (ProgressWheel) view.findViewById(R.id.progress); + mProgressBar = (ProgressWheel) view.findViewById(R.id.load_progress); } @Override @@ -324,6 +324,11 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement activity.setBarVisibility(false); } + public void onZoomOut() { + final MediaViewerActivity activity = (MediaViewerActivity) getActivity(); + activity.setBarVisibility(true); + } + @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); @@ -349,21 +354,11 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement shareProvider.setShareIntent(intent); } - public void onZoomOut() { - final MediaViewerActivity activity = (MediaViewerActivity) getActivity(); - activity.setBarVisibility(true); - } - private ParcelableMedia getMedia() { final Bundle args = getArguments(); return args.getParcelable(EXTRA_MEDIA); } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.menu_media_viewer_image_page, menu); - } - private void loadImage() { getLoaderManager().destroyLoader(0); if (!mLoaderInitialized) { @@ -387,22 +382,8 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement } @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case MENU_OPEN_IN_BROWSER: { - openInBrowser(); - return true; - } - case MENU_SAVE: { - saveToGallery(); - return true; - } - case MENU_REFRESH: { - loadImage(); - return true; - } - } - return super.onOptionsItemSelected(item); + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.menu_media_viewer_image_page, menu); } private void saveToGallery() { @@ -427,6 +408,25 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement // mImageView.resetScale(); } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_OPEN_IN_BROWSER: { + openInBrowser(); + return true; + } + case MENU_SAVE: { + saveToGallery(); + return true; + } + case MENU_REFRESH: { + loadImage(); + return true; + } + } + return super.onOptionsItemSelected(item); + } + @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { @@ -526,6 +526,7 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement private SaveFileTask mSaveFileTask; private File mVideoFile; private Pair mVideoUrlAndType; + private ProgressWheel mProgressBar; public boolean isLoopEnabled() { return getArguments().getBoolean(EXTRA_LOOP, false); @@ -544,13 +545,6 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement // mVideoViewProgress.setVisibility(View.GONE); } - @Override - public void onBaseViewCreated(View view, Bundle savedInstanceState) { - super.onBaseViewCreated(view, savedInstanceState); - mVideoView = (TextureVideoView) view.findViewById(R.id.video_view); - mVideoViewProgress = (ProgressBar) view.findViewById(R.id.video_view_progress); - } - @Override public boolean onError(MediaPlayer mp, int what, int extra) { mVideoViewProgress.removeCallbacks(mVideoProgressRunnable); @@ -558,6 +552,14 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement return true; } + @Override + public void onBaseViewCreated(View view, Bundle savedInstanceState) { + super.onBaseViewCreated(view, savedInstanceState); + mVideoView = (TextureVideoView) view.findViewById(R.id.video_view); + mVideoViewProgress = (ProgressBar) view.findViewById(R.id.video_view_progress); + mProgressBar = (ProgressWheel) view.findViewById(R.id.load_progress); + } + @Override public void onPrepared(MediaPlayer mp) { if (getUserVisibleHint()) { @@ -574,6 +576,22 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement } } + @Override + public void onVideoLoadingCancelled(String uri, VideoLoadingListener listener) { + mProgressBar.setVisibility(View.GONE); + mProgressBar.setProgress(0); + invalidateOptionsMenu(); + } + + @Override + public void onVideoLoadingComplete(String uri, VideoLoadingListener listener, File file) { + mVideoView.setVideoURI(Uri.fromFile(file)); + mVideoFile = file; + mProgressBar.setVisibility(View.GONE); + mProgressBar.setProgress(0); + invalidateOptionsMenu(); + } + @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); @@ -590,60 +608,32 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement } @Override - public void onVideoLoadingCancelled(String uri, VideoLoadingListener listener) { + public void onVideoLoadingFailed(String uri, VideoLoadingListener listener, Exception e) { + mProgressBar.setVisibility(View.GONE); + mProgressBar.setProgress(0); invalidateOptionsMenu(); } + @Override + public void onVideoLoadingProgressUpdate(String uri, VideoLoadingListener listener, int current, int total) { + if (total <= 0) { + if (!mProgressBar.isSpinning()) { + mProgressBar.spin(); + } + return; + } + mProgressBar.setProgress(current / (float) total); + } + @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_media_page_video, container, false); } - @Override - public void onVideoLoadingComplete(String uri, VideoLoadingListener listener, File file) { - mVideoView.setVideoURI(Uri.fromFile(file)); - mVideoFile = file; - invalidateOptionsMenu(); - } - - @Override - public void onVideoLoadingFailed(String uri, VideoLoadingListener listener, Exception e) { - invalidateOptionsMenu(); - } - - @Override - public void onVideoLoadingProgressUpdate(String uri, VideoLoadingListener listener, int current, int total) { - - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - final File file = mVideoFile; - final Pair linkAndType = mVideoUrlAndType; - final boolean isLoading = getLoaderManager().hasRunningLoaders(); - final boolean hasVideo = file != null && file.exists() && linkAndType != null; - MenuUtils.setMenuItemAvailability(menu, R.id.refresh, !hasVideo && !isLoading); - MenuUtils.setMenuItemAvailability(menu, R.id.share, hasVideo && !isLoading); - MenuUtils.setMenuItemAvailability(menu, R.id.save, hasVideo && !isLoading); - if (!hasVideo) return; - final MenuItem shareItem = menu.findItem(R.id.share); - final ShareActionProvider shareProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem); - final Intent intent = new Intent(Intent.ACTION_SEND); - final Uri fileUri = Uri.fromFile(file); - intent.setDataAndType(fileUri, linkAndType.second); - intent.putExtra(Intent.EXTRA_STREAM, fileUri); - final MediaViewerActivity activity = (MediaViewerActivity) getActivity(); - if (activity.hasStatus()) { - final ParcelableStatus status = activity.getStatus(); - intent.putExtra(Intent.EXTRA_TEXT, Utils.getStatusShareText(activity, status)); - intent.putExtra(Intent.EXTRA_SUBJECT, Utils.getStatusShareSubject(activity, status)); - } - shareProvider.setShareIntent(intent); - } - @Override public void onVideoLoadingStarted(String uri, VideoLoadingListener listener) { + mProgressBar.setVisibility(View.VISIBLE); + mProgressBar.spin(); invalidateOptionsMenu(); } @@ -670,11 +660,6 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement } } - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.menu_media_viewer_video_page, menu); - } - private ParcelableMedia getMedia() { final Bundle args = getArguments(); return args.getParcelable(EXTRA_MEDIA); @@ -696,18 +681,29 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement } @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case MENU_SAVE: { - saveToGallery(); - return true; - } - case MENU_REFRESH: { - loadVideo(); - return true; - } + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + final File file = mVideoFile; + final Pair linkAndType = mVideoUrlAndType; + final boolean isLoading = linkAndType != null && mVideoLoader.isLoading(linkAndType.first); + final boolean hasVideo = file != null && file.exists() && linkAndType != null; + MenuUtils.setMenuItemAvailability(menu, R.id.refresh, !hasVideo && !isLoading); + MenuUtils.setMenuItemAvailability(menu, R.id.share, hasVideo && !isLoading); + MenuUtils.setMenuItemAvailability(menu, R.id.save, hasVideo && !isLoading); + if (!hasVideo) return; + final MenuItem shareItem = menu.findItem(R.id.share); + final ShareActionProvider shareProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem); + final Intent intent = new Intent(Intent.ACTION_SEND); + final Uri fileUri = Uri.fromFile(file); + intent.setDataAndType(fileUri, linkAndType.second); + intent.putExtra(Intent.EXTRA_STREAM, fileUri); + final MediaViewerActivity activity = (MediaViewerActivity) getActivity(); + if (activity.hasStatus()) { + final ParcelableStatus status = activity.getStatus(); + intent.putExtra(Intent.EXTRA_TEXT, Utils.getStatusShareText(activity, status)); + intent.putExtra(Intent.EXTRA_SUBJECT, Utils.getStatusShareSubject(activity, status)); } - return super.onOptionsItemSelected(item); + shareProvider.setShareIntent(intent); } private static class VideoPlayProgressRunnable implements Runnable { @@ -735,6 +731,28 @@ public final class MediaViewerActivity extends ThemedActionBarActivity implement } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.menu_media_viewer_video_page, menu); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_SAVE: { + saveToGallery(); + return true; + } + case MENU_REFRESH: { + loadVideo(); + return true; + } + } + return super.onOptionsItemSelected(item); + } + + @Override public void onResume() { super.onResume(); diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsStatusesFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsStatusesFragment.java index cfa5fe207..defc87a43 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsStatusesFragment.java +++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/AbsStatusesFragment.java @@ -32,8 +32,9 @@ import org.mariotaku.twidere.model.ParcelableMedia; import org.mariotaku.twidere.model.ParcelableStatus; import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.KeyboardShortcutsHandler; -import org.mariotaku.twidere.util.KeyboardShortcutsHandler.ShortcutCallback; +import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback; import org.mariotaku.twidere.util.ReadStateManager; +import org.mariotaku.twidere.util.RecyclerViewNavigationHelper; import org.mariotaku.twidere.util.RecyclerViewUtils; import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.message.StatusListChangedEvent; @@ -49,7 +50,7 @@ import static org.mariotaku.twidere.util.Utils.setMenuForStatus; * Created by mariotaku on 14/11/5. */ public abstract class AbsStatusesFragment extends AbsContentListFragment> - implements LoaderCallbacks, StatusAdapterListener, ShortcutCallback { + implements LoaderCallbacks, StatusAdapterListener, KeyboardShortcutCallback { private final Object mStatusesBusCallback; private SharedPreferences mPreferences; @@ -71,7 +72,7 @@ public abstract class AbsStatusesFragment extends AbsContentListFragment extends AbsContentListFragment extends AbsContentListFragment adapter = getAdapter(); + final RecyclerView recyclerView = getRecyclerView(); + final LinearLayoutManager layoutManager = getLayoutManager(); + adapter.setListener(this); getScrollListener().setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { @@ -383,6 +357,7 @@ public abstract class AbsStatusesFragment extends AbsContentListFragment extends AbsContentListFragment> implements LoaderCallbacks, UserAdapterListener { +abstract class AbsUsersFragment extends AbsContentListFragment> + implements LoaderCallbacks, UserAdapterListener, KeyboardShortcutCallback { + + private KeyboardShortcutsHandler mKeyboardShortcutsHandler; + private RecyclerViewNavigationHelper mRecyclerViewNavigationHelper; public final Data getData() { return getAdapter().getData(); } + @Override + public boolean handleKeyboardShortcutSingle(int keyCode, @NonNull KeyEvent event) { + return false; + } + + @Override + public boolean handleKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event) { + return mRecyclerViewNavigationHelper.handleKeyboardShortcutRepeat(keyCode, repeatCount, event); + } + @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - getAdapter().setListener(this); + final FragmentActivity activity = getActivity(); + final TwidereApplication application = TwidereApplication.getInstance(activity); + mKeyboardShortcutsHandler = application.getKeyboardShortcutsHandler(); + final AbsUsersAdapter adapter = getAdapter(); + final RecyclerView recyclerView = getRecyclerView(); + final LinearLayoutManager layoutManager = getLayoutManager(); + adapter.setListener(this); + mRecyclerViewNavigationHelper = new RecyclerViewNavigationHelper(mKeyboardShortcutsHandler, recyclerView, layoutManager, adapter); final Bundle loaderArgs = new Bundle(getArguments()); loaderArgs.putBoolean(EXTRA_FROM_USER, true); getLoaderManager().initLoader(0, loaderArgs, this); diff --git a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java index 4894b8926..0f57beefe 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java +++ b/twidere/src/main/java/org/mariotaku/twidere/fragment/support/DirectMessagesFragment.java @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager.LoaderCallbacks; @@ -40,6 +41,7 @@ import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; import android.support.v7.widget.FixedLinearLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -70,7 +72,10 @@ import org.mariotaku.twidere.util.AsyncTaskUtils; import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.ContentListScrollListener; import org.mariotaku.twidere.util.ContentListScrollListener.ContentListSupport; +import org.mariotaku.twidere.util.KeyboardShortcutsHandler; +import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback; import org.mariotaku.twidere.util.MultiSelectManager; +import org.mariotaku.twidere.util.RecyclerViewNavigationHelper; import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver; @@ -85,7 +90,7 @@ import static org.mariotaku.twidere.util.Utils.openMessageConversation; public class DirectMessagesFragment extends BaseSupportFragment implements LoaderCallbacks, RefreshScrollTopInterface, OnRefreshListener, MessageEntriesAdapterListener, - ControlBarOffsetListener, ContentListSupport { + ControlBarOffsetListener, ContentListSupport, KeyboardShortcutCallback { private final SupportFragmentReloadCursorObserver mReloadContentObserver = new SupportFragmentReloadCursorObserver( this, 0, this); @@ -100,11 +105,54 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade private SwipeRefreshLayout mSwipeRefreshLayout; private View mProgressContainer; private LinearLayoutManager mLayoutManager; + private KeyboardShortcutsHandler mKeyboardShortcutsHandler; + private RecyclerViewNavigationHelper mRecyclerViewNavigationHelper; + private Rect mSystemWindowsInsets = new Rect(); + private int mControlBarOffsetPixels; + + @Override + public MessageEntriesAdapter getAdapter() { + return mAdapter; + } + + @Override + public boolean isRefreshing() { + if (mSwipeRefreshLayout == null || mAdapter == null) return false; + return mSwipeRefreshLayout.isRefreshing() || mAdapter.isLoadMoreIndicatorVisible(); + } + + public void setRefreshing(boolean refreshing) { + if (mAdapter == null || refreshing == mSwipeRefreshLayout.isRefreshing()) return; + mSwipeRefreshLayout.setRefreshing(refreshing && !mAdapter.isLoadMoreIndicatorVisible()); + } + + @Override + public void onLoadMoreContents() { + loadMoreMessages(); + } + + @Override + public void setControlVisible(boolean visible) { + final FragmentActivity activity = getActivity(); + if (activity instanceof BaseActionBarActivity) { + ((BaseActionBarActivity) activity).setControlBarVisibleAnimate(visible); + } + } public final LongSparseArray> getUnreadCountsToRemove() { return mUnreadCountsToRemove; } + @Override + public boolean handleKeyboardShortcutSingle(int keyCode, @NonNull KeyEvent event) { + return false; + } + + @Override + public boolean handleKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event) { + return mRecyclerViewNavigationHelper.handleKeyboardShortcutRepeat(keyCode, repeatCount, event); + } + @Override public void onAttach(Activity activity) { super.onAttach(activity); @@ -113,9 +161,98 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade } } + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_recycler_view, container, false); + } - private Rect mSystemWindowsInsets = new Rect(); - private int mControlBarOffsetPixels; + @Override + public void onActivityCreated(final Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + final View view = getView(); + if (view == null) throw new AssertionError(); + final TwidereApplication application = TwidereApplication.getInstance(getActivity()); + mKeyboardShortcutsHandler = application.getKeyboardShortcutsHandler(); + mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); + final Context viewContext = view.getContext(); + mMultiSelectManager = getMultiSelectManager(); + mAdapter = new MessageEntriesAdapter(viewContext); + mAdapter.setListener(this); + mLayoutManager = new FixedLinearLayoutManager(viewContext); + mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); + mSwipeRefreshLayout.setOnRefreshListener(this); + mSwipeRefreshLayout.setColorSchemeColors(ThemeUtils.getUserAccentColor(viewContext)); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mAdapter); + mRecyclerViewNavigationHelper = new RecyclerViewNavigationHelper(mKeyboardShortcutsHandler, mRecyclerView, mLayoutManager, mAdapter); + + final ContentListScrollListener scrollListener = new ContentListScrollListener(this); + scrollListener.setTouchSlop(ViewConfiguration.get(viewContext).getScaledTouchSlop()); + mRecyclerView.setOnScrollListener(scrollListener); + + final DividerItemDecoration itemDecoration = new DividerItemDecoration(viewContext, mLayoutManager.getOrientation()); + final Resources res = viewContext.getResources(); + final int decorPaddingLeft = res.getDimensionPixelSize(R.dimen.element_spacing_normal) * 3 + + res.getDimensionPixelSize(R.dimen.icon_size_status_profile_image); + itemDecoration.setPadding(decorPaddingLeft, 0, 0, 0); + itemDecoration.setDecorationEndOffset(1); + mRecyclerView.addItemDecoration(itemDecoration); + getLoaderManager().initLoader(0, null, this); + setListShown(false); + } + + @Override + public void onStart() { + super.onStart(); + final ContentResolver resolver = getContentResolver(); + resolver.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver); + final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus(); + bus.register(this); + mAdapter.updateReadState(); + updateRefreshState(); + } + + @Override + public void onStop() { + final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus(); + bus.unregister(this); + final ContentResolver resolver = getContentResolver(); + resolver.unregisterContentObserver(mReloadContentObserver); + super.onStop(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case MENU_COMPOSE: { + openMessageConversation(getActivity(), -1, -1); + break; + } + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onBaseViewCreated(view, savedInstanceState); + mProgressContainer = view.findViewById(R.id.progress_container); + mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_layout); + mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); + } + + @Override + public void onDetach() { + final FragmentActivity activity = getActivity(); + if (activity instanceof IControlBarActivity) { + ((IControlBarActivity) activity).unregisterControlBarOffsetListener(this); + } + super.onDetach(); + } + + @Override + public void setUserVisibleHint(final boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + } @Override protected void fitSystemWindows(Rect insets) { @@ -131,54 +268,6 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade updateRefreshProgressOffset(); } - - private void updateRefreshProgressOffset() { - if (mSystemWindowsInsets.top == 0 || mSwipeRefreshLayout == null || isRefreshing()) return; - final float density = getResources().getDisplayMetrics().density; - final int progressCircleDiameter = mSwipeRefreshLayout.getProgressCircleDiameter(); - final int swipeStart = (mSystemWindowsInsets.top - mControlBarOffsetPixels) - progressCircleDiameter; - // 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET - final int swipeDistance = Math.round(64 * density); - mSwipeRefreshLayout.setProgressViewOffset(true, swipeStart, swipeStart + swipeDistance); - } - - @Override - public void onDetach() { - final FragmentActivity activity = getActivity(); - if (activity instanceof IControlBarActivity) { - ((IControlBarActivity) activity).unregisterControlBarOffsetListener(this); - } - super.onDetach(); - } - - @Override - public void onEntryClick(int position, DirectMessageEntry entry) { - Utils.openMessageConversation(getActivity(), entry.account_id, entry.conversation_id); - } - - @Override - public void onUserClick(int position, DirectMessageEntry entry) { - Utils.openUserProfile(getActivity(), entry.account_id, entry.conversation_id, entry.screen_name, null); - } - - @Override - public void onRefresh() { - triggerRefresh(); - } - - private void setListShown(boolean shown) { - mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE); - mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE); - } - - @Override - public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onBaseViewCreated(view, savedInstanceState); - mProgressContainer = view.findViewById(R.id.progress_container); - mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_layout); - mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - } - @Override public Loader onCreateLoader(final int id, final Bundle args) { final Uri uri = DirectMessages.ConversationEntries.CONTENT_URI; @@ -211,54 +300,15 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade } @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_recycler_view, container, false); + public void onEntryClick(int position, DirectMessageEntry entry) { + Utils.openMessageConversation(getActivity(), entry.account_id, entry.conversation_id); } @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - final View view = getView(); - if (view == null) throw new AssertionError(); - mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); - final Context viewContext = view.getContext(); - mMultiSelectManager = getMultiSelectManager(); - mAdapter = new MessageEntriesAdapter(viewContext); - mAdapter.setListener(this); - mLayoutManager = new FixedLinearLayoutManager(viewContext); - mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); - mSwipeRefreshLayout.setOnRefreshListener(this); - mSwipeRefreshLayout.setColorSchemeColors(ThemeUtils.getUserAccentColor(viewContext)); - mRecyclerView.setLayoutManager(mLayoutManager); - mRecyclerView.setAdapter(mAdapter); - - final ContentListScrollListener scrollListener = new ContentListScrollListener(this); - scrollListener.setTouchSlop(ViewConfiguration.get(viewContext).getScaledTouchSlop()); - mRecyclerView.setOnScrollListener(scrollListener); - - final DividerItemDecoration itemDecoration = new DividerItemDecoration(viewContext, mLayoutManager.getOrientation()); - final Resources res = viewContext.getResources(); - final int decorPaddingLeft = res.getDimensionPixelSize(R.dimen.element_spacing_normal) * 3 - + res.getDimensionPixelSize(R.dimen.icon_size_status_profile_image); - itemDecoration.setPadding(decorPaddingLeft, 0, 0, 0); - itemDecoration.setDecorationEndOffset(1); - mRecyclerView.addItemDecoration(itemDecoration); - getLoaderManager().initLoader(0, null, this); - setListShown(false); + public void onUserClick(int position, DirectMessageEntry entry) { + Utils.openUserProfile(getActivity(), entry.account_id, entry.conversation_id, entry.screen_name, null); } - @Override - public void onStart() { - super.onStart(); - final ContentResolver resolver = getContentResolver(); - resolver.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver); - final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus(); - bus.register(this); - mAdapter.updateReadState(); - updateRefreshState(); - } - - @Subscribe public void onGetMessagesTaskChanged(GetMessagesTaskEvent event) { if (event.uri.equals(Inbox.CONTENT_URI) && !event.running) { @@ -269,23 +319,8 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade } @Override - public void onStop() { - final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus(); - bus.unregister(this); - final ContentResolver resolver = getContentResolver(); - resolver.unregisterContentObserver(mReloadContentObserver); - super.onStop(); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case MENU_COMPOSE: { - openMessageConversation(getActivity(), -1, -1); - break; - } - } - return super.onOptionsItemSelected(item); + public void onRefresh() { + triggerRefresh(); } @Override @@ -323,12 +358,6 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade return true; } - @Override - public void setUserVisibleHint(final boolean isVisibleToUser) { - super.setUserVisibleHint(isVisibleToUser); - } - - protected long getAccountId() { final Bundle args = getArguments(); return args != null ? args.getLong(EXTRA_ACCOUNT_ID, -1) : -1; @@ -339,17 +368,6 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade setRefreshing(twitter != null && (twitter.isReceivedDirectMessagesRefreshing() || twitter.isSentDirectMessagesRefreshing())); } - public void setRefreshing(boolean refreshing) { - if (mAdapter == null || refreshing == mSwipeRefreshLayout.isRefreshing()) return; - mSwipeRefreshLayout.setRefreshing(refreshing && !mAdapter.isLoadMoreIndicatorVisible()); - } - - @Override - public boolean isRefreshing() { - if (mSwipeRefreshLayout == null || mAdapter == null) return false; - return mSwipeRefreshLayout.isRefreshing() || mAdapter.isLoadMoreIndicatorVisible(); - } - private void addReadPosition(final int firstVisibleItem) { if (mFirstVisibleItem != firstVisibleItem) { mReadPositions.add(firstVisibleItem); @@ -395,24 +413,6 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade }); } - @Override - public MessageEntriesAdapter getAdapter() { - return mAdapter; - } - - @Override - public void setControlVisible(boolean visible) { - final FragmentActivity activity = getActivity(); - if (activity instanceof BaseActionBarActivity) { - ((BaseActionBarActivity) activity).setControlBarVisibleAnimate(visible); - } - } - - @Override - public void onLoadMoreContents() { - loadMoreMessages(); - } - private void removeUnreadCounts() { if (mRemoveUnreadCountsTask != null && mRemoveUnreadCountsTask.getStatus() == AsyncTask.Status.RUNNING) return; @@ -420,6 +420,21 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade AsyncTaskUtils.executeTask(mRemoveUnreadCountsTask); } + private void setListShown(boolean shown) { + mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE); + mSwipeRefreshLayout.setVisibility(shown ? View.VISIBLE : View.GONE); + } + + private void updateRefreshProgressOffset() { + if (mSystemWindowsInsets.top == 0 || mSwipeRefreshLayout == null || isRefreshing()) return; + final float density = getResources().getDisplayMetrics().density; + final int progressCircleDiameter = mSwipeRefreshLayout.getProgressCircleDiameter(); + final int swipeStart = (mSystemWindowsInsets.top - mControlBarOffsetPixels) - progressCircleDiameter; + // 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET + final int swipeDistance = Math.round(64 * density); + mSwipeRefreshLayout.setProgressViewOffset(true, swipeStart, swipeStart + swipeDistance); + } + static class RemoveUnreadCountsTask extends AsyncTask { private final Set read_positions; private final MessageEntriesAdapter adapter; diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/KeyboardShortcutsHandler.java b/twidere/src/main/java/org/mariotaku/twidere/util/KeyboardShortcutsHandler.java index 332368047..2ea614d45 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/KeyboardShortcutsHandler.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/KeyboardShortcutsHandler.java @@ -249,7 +249,7 @@ public class KeyboardShortcutsHandler implements Constants { editor.apply(); } - public static interface ShortcutCallback { + public static interface KeyboardShortcutCallback { boolean handleKeyboardShortcutSingle(int keyCode, @NonNull KeyEvent event); boolean handleKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event); diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/RecyclerViewNavigationHelper.java b/twidere/src/main/java/org/mariotaku/twidere/util/RecyclerViewNavigationHelper.java new file mode 100644 index 000000000..f53f2ff6e --- /dev/null +++ b/twidere/src/main/java/org/mariotaku/twidere/util/RecyclerViewNavigationHelper.java @@ -0,0 +1,80 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.util; + +import android.support.annotation.NonNull; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.Adapter; +import android.support.v7.widget.RecyclerView.ViewHolder; +import android.view.KeyEvent; +import android.view.View; + +/** +* Created by mariotaku on 15/4/21. +*/ +public class RecyclerViewNavigationHelper { + + private int positionBackup; + private final KeyboardShortcutsHandler handler; + private final RecyclerView view; + private final LinearLayoutManager manager; + private final Adapter adapter; + + public RecyclerViewNavigationHelper(KeyboardShortcutsHandler handler, RecyclerView view, + LinearLayoutManager manager, Adapter adapter) { + this.handler = handler; + this.view = view; + this.manager = manager; + this.adapter = adapter; + } + + public boolean handleKeyboardShortcutRepeat(int keyCode, int repeatCount, @NonNull KeyEvent event) { + final String action = handler.getKeyAction("navigation", keyCode, event); + if (action == null) return false; + final LinearLayoutManager layoutManager = this.manager; + final View focusedChild = RecyclerViewUtils.findRecyclerViewChild(view, layoutManager.getFocusedChild()); + final int position; + if (focusedChild != null) { + position = view.getChildLayoutPosition(focusedChild); + } else if (layoutManager.findFirstVisibleItemPosition() == 0) { + position = -1; + } else { + final int itemCount = adapter.getItemCount(); + if (layoutManager.findLastVisibleItemPosition() == itemCount - 1) { + position = itemCount; + } else { + position = positionBackup; + } + } + positionBackup = position; + switch (action) { + case "navigation.previous": { + RecyclerViewUtils.focusNavigate(view, layoutManager, position, -1); + return true; + } + case "navigation.next": { + RecyclerViewUtils.focusNavigate(view, layoutManager, position, 1); + return true; + } + } + return false; + } +} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java index c6e22d3d3..dc39b8efa 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java @@ -3576,9 +3576,9 @@ public final class Utils implements Constants, TwitterConstants { final PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0); final String version_name = pi.versionName; cb.setClientVersion(pi.versionName); - cb.setClientName(APP_NAME); - cb.setClientURL(APP_PROJECT_URL); - cb.setHttpUserAgent(APP_NAME + " " + APP_PROJECT_URL + " / " + version_name + cb.setClientName(TWIDERE_APP_NAME); + cb.setClientURL(TWIDERE_PROJECT_URL); + cb.setHttpUserAgent(TWIDERE_APP_NAME + " " + TWIDERE_PROJECT_URL + " / " + version_name + (gzipCompressing ? " (gzip)" : "")); } catch (final PackageManager.NameNotFoundException e) { throw new AssertionError(e); diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/VideoLoader.java b/twidere/src/main/java/org/mariotaku/twidere/util/VideoLoader.java index 448d91d27..e5916b13d 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/VideoLoader.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/VideoLoader.java @@ -69,6 +69,10 @@ public class VideoLoader { return null; } + public boolean isLoading(String url) { + return mTaskManager.hasRunningTasksForTag(url); + } + public int loadVideo(String uri, VideoLoadingListener listener) { if (mTaskManager.hasRunningTasksForTag(uri)) { diff --git a/twidere/src/main/res/layout/fragment_media_page_image.xml b/twidere/src/main/res/layout/fragment_media_page_image.xml index d0b5e0e23..327ba9a23 100644 --- a/twidere/src/main/res/layout/fragment_media_page_image.xml +++ b/twidere/src/main/res/layout/fragment_media_page_image.xml @@ -21,7 +21,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:animateLayoutChanges="true"> diff --git a/twidere/src/main/res/layout/fragment_media_page_video.xml b/twidere/src/main/res/layout/fragment_media_page_video.xml index 144334467..f0dd0418f 100644 --- a/twidere/src/main/res/layout/fragment_media_page_video.xml +++ b/twidere/src/main/res/layout/fragment_media_page_video.xml @@ -20,8 +20,10 @@ --> + android:layout_height="match_parent" + android:animateLayoutChanges="true"> - - + android:visibility="gone" + app:matProg_barColor="@color/branding_color"/> \ No newline at end of file