diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/README.md b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/README.md deleted file mode 100644 index 4cabb7a9..00000000 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/README.md +++ /dev/null @@ -1,148 +0,0 @@ -# ActionBar-PullToRefresh - -![ActionBar-PullToRefresh](https://github.com/chrisbanes/ActionBar-PullToRefresh/raw/master/header.png) - -ActionBar-PullToRefresh provides an easy way to add a modern version of the pull-to-refresh interaction to your application. - -Please note that this is __not__ an update to [Android-PullToRefresh](https://github.com/chrisbanes/Android-PullToRefresh), this has been created from new. You should think of this as Android-PullToRefresh's younger, leaner cousin. - -### This is a Preview -Please note that this is currently in a preview state. This basically means that the API is not fixed and you should expect changes between releases. - ---- - -## Sample Apps - -There are two sample applications, the stock sample which uses the standard library and is therefore has a `minSdkVersion` of 14. There is also a sample which uses the ActionBarSherlock extra so has a `minSdkVersion` of 7. - -### Stock Sample -[![Get it on Google Play](http://www.android.com/images/brand/get_it_on_play_logo_small.png)](http://play.google.com/store/apps/details?id=uk.co.senab.actionbarpulltorefresh.samples.stock) - -### ActionBarSherlock Sample -[![Get it on Google Play](http://www.android.com/images/brand/get_it_on_play_logo_small.png)](http://play.google.com/store/apps/details?id=uk.co.senab.actionbarpulltorefresh.samples.actionbarsherlock) - -## Video - -[![Sample Video](http://img.youtube.com/vi/YOYtPF-4RPg/0.jpg)](https://www.youtube.com/watch?v=YOYtPF-4RPg) - ---- - -## Supported Views - -ActionBar-PullToRefresh has in-built support for: - - * AbsListView derivatives (ListView & GridView). - * ScrollView - * WebView - -If the View you want to use is not listed above, you can easily add support in your own code by providing a `ViewDelegate`. See the `ViewDelegate` section below for more info. - ---- - -## Usage -You just need to create an instance of `PullToRefreshAttacher`, giving it the Activity and the View for which will scroll. - -``` java -private PullToRefreshAttacher mPullToRefreshAttacher; - -@Override -public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Get View for which the user will scroll… - View scrollableView = findViewById(R.id.blah); - - // Create a PullToRefreshAttacher instance - mPullToRefreshAttacher = PullToRefreshAttacher.get(this); - - // Add the Refreshable View and provide the refresh listener - mPullToRefreshAttacher.addRefreshableView(scrollableView, this); -} -``` -See the [ListView](https://github.com/chrisbanes/ActionBar-PullToRefresh/blob/master/samples/stock/src/uk/co/senab/actionbarpulltorefresh/samples/stock/ListViewActivity.java) sample for more info. - -### Fragments - -One thing to note is that the `PullToRefreshAttacher` **needs** to be created in the `onCreate()` phase of the Activity. If you plan on using this library with Fragments then the best practice is for your Activity to create the `PullToRefreshAttacher`, and then have your fragments retrieve it from the Activity. - -An example is provided in the [Fragment & Tabs](https://github.com/chrisbanes/ActionBar-PullToRefresh/blob/master/samples/stock/src/uk/co/senab/actionbarpulltorefresh/samples/stock/FragmentTabsActivity.java) sample. - ---- - -## Customisation - -There are many ways you can customise the pull-to-refresh experience to your needs. See the [GridView](https://github.com/chrisbanes/ActionBar-PullToRefresh/blob/master/samples/stock/src/uk/co/senab/actionbarpulltorefresh/samples/stock/GridViewActivity.java) sample for more info on all of these. - -### ViewDelegate - -ViewDelegates provide support for handling scrollable Views. The main use of a `ViewDelegate` is to being able to tell when a scrollable view is scrolled to the top. There is currently inbuilt support for: - - * AbsListView classes (through [AbsListViewDelegate](https://github.com/chrisbanes/ActionBar-PullToRefresh/blob/master/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/AbsListViewDelegate.java)) - * ScrollView (through [ScrollViewDelegate](https://github.com/chrisbanes/ActionBar-PullToRefresh/blob/master/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollViewDelegate.java)) - * WebView (through [WebViewDelegate](https://github.com/chrisbanes/ActionBar-PullToRefresh/blob/master/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/WebViewDelegate.java)) - -So what if you want the view you want to use a view which isn't in the list above? Well you can just provide your own `ViewDelegate`. - -``` java -// Create a PullToRefresh Attacher -mPullToRefreshAttacher = PullToRefreshAttacher.get(this); - -// Create ViewDelegate which can handle your scrollable view. -// In this case we're creating a ficticious class -PullToRefreshAttacher.ViewDelegate delegate = new XYZViewDelegate(); - -// Set the Refreshable View, along with your ViewDelegate -mPullToRefreshAttacher.setRefreshableView(xyzView, delegate, listener); -``` - -### Options -When instatiating a `PullToRefreshAttacher` you can provide an `Options` instance which contains a number of configuration elements: - - * `headerLayout`: Layout resource to be inflated as the header view (see below). - * `headerTransformer`: The HeaderTransformer for the heard view (see below). - * `headerInAnimation`: The animation resource which is used when the header view is shown. - * `headerOutAnimation`: The animation resource which is used when the header view is hidden. - * `refreshScrollDistance`: The vertical distance (percentage of the scrollable view height) that the user needs to scroll for a refresh to start. - * `refreshOnUp`: Whether to wait to start the refresh until when the user has lifted their finger. - -### HeaderTransformers -HeaderTransformers are responsible for updating the header view to match the current state. If you do not provide a HeaderTransformer, there is a default implementation created for you called `DefaultHeaderTransformer`. This default implementation is what provides the default behaviour (growing progress bar, etc). - -### Customised Header View layout -If you feel that the default header view layout does not provide what you require, you can provide your own which is inflated for you. For the majority of cases, you will probably want to provide your own `HeaderTransformer` as well, to update your custom layout. - -## Maven -For the standard library (APIv14+) add the following as a dependency in you `pom.xml`: -``` - - com.github.chrisbanes.actionbarpulltorefresh - library - 0.5 - -``` - -If you're using ActionBarSherlock (APIv7+) add the following as a dependency in you `pom.xml`: -``` - - com.github.chrisbanes.actionbarpulltorefresh - extra-abs - 0.5 - -``` ---- - -## License - - Copyright 2013 Chris Banes - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/AndroidManifest.xml b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/AndroidManifest.xml index 4b10d731..ae76ec35 100644 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/AndroidManifest.xml +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/AndroidManifest.xml @@ -1,9 +1,7 @@ + package="uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock"> - + diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/build.gradle b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/build.gradle new file mode 100644 index 00000000..24db4e23 --- /dev/null +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'android-library' + +dependencies { + compile project(':library') + compile 'com.android.support:support-v4:18.0.+' + compile ('com.actionbarsherlock:actionbarsherlock:4.4.+@aar') { + // Need to specifically exclude this as it is specified in ActionBarSherlock pom + exclude group: 'com.google.android', module: 'support-v4' + } +} + +android { + compileSdkVersion 18 + buildToolsVersion '17.0.0' + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + } + } +} + +apply from: '../../maven_push.gradle' diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/gradle.properties b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/gradle.properties new file mode 100644 index 00000000..3a29e9ee --- /dev/null +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=ActionBar-PullToRefresh Extras: ActionBarSherlock +POM_ARTIFACT_ID=extra-abs +POM_PACKAGING=aar diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/pom.xml b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/pom.xml deleted file mode 100644 index 9f2d4d8f..00000000 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/pom.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - 4.0.0 - - com.github.chrisbanes.actionbarpulltorefresh - extra-abs - apklib - ActionBar-PullToRefresh Extras: ActionBarSherlock - - - com.github.chrisbanes.actionbarpulltorefresh - extras - 0.6-SNAPSHOT - - - - - com.google.android - android - - - ${project.groupId} - library - apklib - ${project.version} - - - com.actionbarsherlock - actionbarsherlock - apklib - 4.3.1 - - - - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - - - - diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/AbsDefaultHeaderTransformer.java b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/AbsDefaultHeaderTransformer.java new file mode 100644 index 00000000..85b1c329 --- /dev/null +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/AbsDefaultHeaderTransformer.java @@ -0,0 +1,89 @@ +/* + * Copyright 2013 Chris Banes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.TypedValue; + +import uk.co.senab.actionbarpulltorefresh.library.DefaultHeaderTransformer; + +public class AbsDefaultHeaderTransformer extends DefaultHeaderTransformer { + + @Override + protected Drawable getActionBarBackground(Context context) { + // Super handles ICS+ anyway... + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return super.getActionBarBackground(context); + } + + // Need to get resource id of style pointed to from actionBarStyle + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.actionBarStyle, outValue, true); + // Now get action bar style values... + TypedArray abStyle = context.getTheme().obtainStyledAttributes(outValue.resourceId, + R.styleable.SherlockActionBar); + try { + return abStyle.getDrawable(R.styleable.SherlockActionBar_background); + } finally { + abStyle.recycle(); + } + } + + @Override + protected int getActionBarSize(Context context) { + // Super handles ICS+ anyway... + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return super.getActionBarSize(context); + } + + TypedArray values = context.getTheme() + .obtainStyledAttributes(R.styleable.SherlockTheme); + try { + return values.getDimensionPixelSize(R.styleable.SherlockTheme_actionBarSize, 0); + } finally { + values.recycle(); + } + } + + @Override + protected int getActionBarTitleStyle(Context context) { + // Super handles ICS+ anyway... + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return super.getActionBarTitleStyle(context); + } + + // Need to get resource id of style pointed to from actionBarStyle + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.actionBarStyle, outValue, true); + // Now get action bar style values... + TypedArray abStyle = context.getTheme().obtainStyledAttributes(outValue.resourceId, + R.styleable.SherlockActionBar); + try { + return abStyle.getResourceId(R.styleable.SherlockActionBar_titleTextStyle, 0); + } finally { + abStyle.recycle(); + } + } + + @Override + protected int getMinimumApiLevel() { + return Build.VERSION_CODES.ECLAIR_MR1; + } +} diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/PullToRefreshAttacher.java b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/PullToRefreshAttacher.java index 5152f539..aad995c5 100644 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/PullToRefreshAttacher.java +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/PullToRefreshAttacher.java @@ -24,30 +24,16 @@ import android.app.Activity; import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.util.TypedValue; - -import java.util.WeakHashMap; public class PullToRefreshAttacher extends uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher { - private static final WeakHashMap ATTACHERS - = new WeakHashMap(); - public static PullToRefreshAttacher get(Activity activity) { return get(activity, new Options()); } public static PullToRefreshAttacher get(Activity activity, Options options) { - PullToRefreshAttacher attacher = ATTACHERS.get(activity); - if (attacher == null) { - attacher = new PullToRefreshAttacher(activity, options); - ATTACHERS.put(activity, attacher); - } - return attacher; + return new PullToRefreshAttacher(activity, options); } protected PullToRefreshAttacher(Activity activity, Options options) { @@ -86,44 +72,4 @@ public Context getContextForInflater(Activity activity) { return super.getContextForInflater(activity); } } - - public static class AbsDefaultHeaderTransformer extends DefaultHeaderTransformer { - - @Override - protected Drawable getActionBarBackground(Context context) { - // Super handles ICS+ anyway... - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - return super.getActionBarBackground(context); - } - - // Need to get resource id of style pointed to from actionBarStyle - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.actionBarStyle, outValue, true); - // Now get action bar style values... - TypedArray abStyle = context.getTheme().obtainStyledAttributes(outValue.resourceId, - R.styleable.SherlockActionBar); - try { - return abStyle.getDrawable(R.styleable.SherlockActionBar_background); - } finally { - abStyle.recycle(); - } - } - - @Override - protected int getActionBarSize(Context context) { - // Super handles ICS+ anyway... - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - return super.getActionBarSize(context); - } - - TypedArray values = context.getTheme() - .obtainStyledAttributes(R.styleable.SherlockTheme); - try { - return values.getDimensionPixelSize(R.styleable.SherlockTheme_actionBarSize, 0); - } finally { - values.recycle(); - } - } - - } } diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/pom.xml b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/pom.xml deleted file mode 100644 index 36bd2ed1..00000000 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/extras/pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - com.github.chrisbanes.actionbarpulltorefresh - extras - pom - ActionBar-PullToRefresh Extras - - - com.github.chrisbanes.actionbarpulltorefresh - parent - 0.6-SNAPSHOT - - - - actionbarsherlock - - diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/header.png b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/header.png deleted file mode 100644 index 830412f9..00000000 Binary files a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/header.png and /dev/null differ diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/AndroidManifest.xml b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/AndroidManifest.xml index 440d8368..fc808f4f 100644 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/AndroidManifest.xml +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/AndroidManifest.xml @@ -1,9 +1,7 @@ + package="uk.co.senab.actionbarpulltorefresh.library"> - + diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/build.gradle b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/build.gradle new file mode 100644 index 00000000..625d8f23 --- /dev/null +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/build.gradle @@ -0,0 +1,16 @@ +apply plugin: 'android-library' + +android { + compileSdkVersion 18 + buildToolsVersion '17.0.0' + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + res.srcDirs = ['res'] + } + } +} + +apply from: '../maven_push.gradle' \ No newline at end of file diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/gradle.properties b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/gradle.properties new file mode 100644 index 00000000..7d783d1a --- /dev/null +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=ActionBar-PullToRefresh Library +POM_ARTIFACT_ID=library +POM_PACKAGING=aar diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/pom.xml b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/pom.xml deleted file mode 100644 index 8a3c3d74..00000000 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - 4.0.0 - - com.github.chrisbanes.actionbarpulltorefresh - library - apklib - ActionBar-PullToRefresh Library - - - com.github.chrisbanes.actionbarpulltorefresh - parent - 0.6-SNAPSHOT - - - - - com.google.android - android - - - - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - - - - diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/res/values-ru/pull_refresh_strings.xml b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/res/values-ru/pull_refresh_strings.xml index e1bfe048..7e433f66 100755 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/res/values-ru/pull_refresh_strings.xml +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/res/values-ru/pull_refresh_strings.xml @@ -15,7 +15,7 @@ --> - Потяните для обновления… - Отпустите для обновления… - Загрузка… + потяните + отпустите + обновление diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/DefaultHeaderTransformer.java b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/DefaultHeaderTransformer.java new file mode 100644 index 00000000..ba36d125 --- /dev/null +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/DefaultHeaderTransformer.java @@ -0,0 +1,282 @@ +/* + * Copyright 2013 Chris Banes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.senab.actionbarpulltorefresh.library; + +import android.app.Activity; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.widget.ProgressBar; +import android.widget.TextView; + +/** + * Default Header Transformer. + */ +public class DefaultHeaderTransformer extends PullToRefreshAttacher.HeaderTransformer { + + private ViewGroup mContentLayout; + private TextView mHeaderTextView; + private ProgressBar mHeaderProgressBar; + + private CharSequence mPullRefreshLabel, mRefreshingLabel, mReleaseLabel; + + private boolean mUseCustomProgressColor = false; + private int mProgressDrawableColor; + + private final Interpolator mInterpolator = new AccelerateInterpolator(); + + protected DefaultHeaderTransformer() { + final int min = getMinimumApiLevel(); + if (Build.VERSION.SDK_INT < min) { + throw new IllegalStateException("This HeaderTransformer is designed to run on SDK " + + min + + "+. If using ActionBarSherlock or ActionBarCompat you should use the appropriate provided extra."); + } + } + + @Override + public void onViewCreated(Activity activity, View headerView) { + // Get ProgressBar and TextView. Also set initial text on TextView + mHeaderProgressBar = (ProgressBar) headerView.findViewById(R.id.ptr_progress); + mHeaderTextView = (TextView) headerView.findViewById(R.id.ptr_text); + + // Apply any custom ProgressBar colors + applyProgressBarColor(); + + // Labels to display + mPullRefreshLabel = activity.getString(R.string.pull_to_refresh_pull_label); + mRefreshingLabel = activity.getString(R.string.pull_to_refresh_refreshing_label); + mReleaseLabel = activity.getString(R.string.pull_to_refresh_release_label); + + // Retrieve the Action Bar size from the Activity's theme + mContentLayout = (ViewGroup) headerView.findViewById(R.id.ptr_content); + if (mContentLayout != null) { + mContentLayout.getLayoutParams().height = getActionBarSize(activity); + mContentLayout.requestLayout(); + } + + // Retrieve the Action Bar background from the Activity's theme (see #93). + Drawable abBg = getActionBarBackground(activity); + if (abBg != null) { + // If we do not have a opaque background we just display a solid solid behind it + if (abBg.getOpacity() != PixelFormat.OPAQUE) { + View view = headerView.findViewById(R.id.ptr_text_opaque_bg); + if (view != null) { + view.setVisibility(View.VISIBLE); + } + } + + mHeaderTextView.setBackgroundDrawable(abBg); + } + + // Retrieve the Action Bar Title Style from the Action Bar's theme + Context abContext = headerView.getContext(); + final int titleTextStyle = getActionBarTitleStyle(abContext); + if (titleTextStyle != 0) { + mHeaderTextView.setTextAppearance(abContext, titleTextStyle); + } + + // Call onReset to make sure that the View is consistent + onReset(); + } + + @Override + public void onReset() { + // Reset Progress Bar + if (mHeaderProgressBar != null) { + mHeaderProgressBar.setVisibility(View.GONE); + mHeaderProgressBar.setProgress(0); + mHeaderProgressBar.setIndeterminate(false); + } + + // Reset Text View + if (mHeaderTextView != null) { + mHeaderTextView.setVisibility(View.VISIBLE); + mHeaderTextView.setText(mPullRefreshLabel); + } + + // Reset the Content Layout + if (mContentLayout != null) { + mContentLayout.setVisibility(View.VISIBLE); + } + } + + @Override + public void onPulled(float percentagePulled) { + if (mHeaderProgressBar != null) { + mHeaderProgressBar.setVisibility(View.VISIBLE); + final float progress = mInterpolator.getInterpolation(percentagePulled); + mHeaderProgressBar.setProgress(Math.round(mHeaderProgressBar.getMax() * progress)); + } + } + + @Override + public void onRefreshStarted() { + if (mHeaderTextView != null) { + mHeaderTextView.setText(mRefreshingLabel); + } + if (mHeaderProgressBar != null) { + mHeaderProgressBar.setVisibility(View.VISIBLE); + mHeaderProgressBar.setIndeterminate(true); + } + } + + @Override + public void onReleaseToRefresh() { + if (mHeaderTextView != null) { + mHeaderTextView.setText(mReleaseLabel); + } + if (mHeaderProgressBar != null) { + mHeaderProgressBar.setProgress(mHeaderProgressBar.getMax()); + } + } + + @Override + public void onRefreshMinimized() { + // Here we fade out most of the header, leaving just the progress bar + if (mContentLayout != null) { + mContentLayout.startAnimation(AnimationUtils + .loadAnimation(mContentLayout.getContext(), R.anim.fade_out)); + mContentLayout.setVisibility(View.INVISIBLE); + } + } + + /** + * Set color to apply to the progress bar. Automatically enables usage of the custom color. Use + * {@link #setProgressBarColorEnabled(boolean)} to disable and re-enable the custom color usage. + *

+ * The best way to apply a color is to load the color from resources: {@code + * setProgressBarColor(getResources().getColor(R.color.your_color_name))}. + * + * @param color The color to use. + */ + public void setProgressBarColor(int color) { + mProgressDrawableColor = color; + setProgressBarColorEnabled(true); + } + + /** + * Enable or disable the use of a custom progress bar color. You can set what color to use with + * {@link #setProgressBarColor(int)}, which also automatically enables custom color usage. + */ + public void setProgressBarColorEnabled(boolean enabled) { + mUseCustomProgressColor = enabled; + applyProgressBarColor(); + } + + + /** + * Set Text to show to prompt the user is pull (or keep pulling). + * + * @param pullText - Text to display. + */ + public void setPullText(CharSequence pullText) { + mPullRefreshLabel = pullText; + if (mHeaderTextView != null) { + mHeaderTextView.setText(mPullRefreshLabel); + } + } + + /** + * Set Text to show to tell the user that a refresh is currently in progress. + * + * @param refreshingText - Text to display. + */ + public void setRefreshingText(CharSequence refreshingText) { + mRefreshingLabel = refreshingText; + } + + /** + * Set Text to show to tell the user has scrolled enough to refresh. + * + * @param releaseText - Text to display. + */ + public void setReleaseText(CharSequence releaseText) { + mReleaseLabel = releaseText; + } + + private void applyProgressBarColor() { + if (mHeaderProgressBar != null) { + if (mUseCustomProgressColor) { + mHeaderProgressBar.getProgressDrawable() + .setColorFilter(mProgressDrawableColor, PorterDuff.Mode.SRC_ATOP); + mHeaderProgressBar.getIndeterminateDrawable() + .setColorFilter(mProgressDrawableColor, PorterDuff.Mode.SRC_ATOP); + } else { + mHeaderProgressBar.getProgressDrawable().clearColorFilter(); + mHeaderProgressBar.getIndeterminateDrawable().clearColorFilter(); + } + } + } + + protected Drawable getActionBarBackground(Context context) { + int[] android_styleable_ActionBar = {android.R.attr.background}; + + // Need to get resource id of style pointed to from actionBarStyle + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.actionBarStyle, outValue, true); + // Now get action bar style values... + TypedArray abStyle = context.getTheme().obtainStyledAttributes(outValue.resourceId, + android_styleable_ActionBar); + try { + // background is the first attr in the array above so it's index is 0. + return abStyle.getDrawable(0); + } finally { + abStyle.recycle(); + } + } + + protected int getActionBarSize(Context context) { + int[] attrs = {android.R.attr.actionBarSize}; + TypedArray values = context.getTheme().obtainStyledAttributes(attrs); + try { + return values.getDimensionPixelSize(0, 0); + } finally { + values.recycle(); + } + } + + protected int getActionBarTitleStyle(Context context) { + int[] android_styleable_ActionBar = {android.R.attr.titleTextStyle}; + + // Need to get resource id of style pointed to from actionBarStyle + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.actionBarStyle, outValue, true); + // Now get action bar style values... + TypedArray abStyle = context.getTheme().obtainStyledAttributes(outValue.resourceId, + android_styleable_ActionBar); + try { + // titleTextStyle is the first attr in the array above so it's index is 0. + return abStyle.getResourceId(0, 0); + } finally { + abStyle.recycle(); + } + } + + protected int getMinimumApiLevel() { + return Build.VERSION_CODES.ICE_CREAM_SANDWICH; + } +} diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/InstanceCreationUtils.java b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/InstanceCreationUtils.java index b0c9e188..77766f8a 100644 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/InstanceCreationUtils.java +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/InstanceCreationUtils.java @@ -26,7 +26,7 @@ import java.util.Set; import uk.co.senab.actionbarpulltorefresh.library.viewdelegates.AbsListViewDelegate; -import uk.co.senab.actionbarpulltorefresh.library.viewdelegates.ScrollViewDelegate; +import uk.co.senab.actionbarpulltorefresh.library.viewdelegates.ScrollYDelegate; import uk.co.senab.actionbarpulltorefresh.library.viewdelegates.WebViewDelegate; class InstanceCreationUtils { @@ -40,7 +40,6 @@ class InstanceCreationUtils { static { BUILT_IN_DELEGATES = new HashMap(); BUILT_IN_DELEGATES.put(AbsListViewDelegate.SUPPORTED_VIEW_CLASS, AbsListViewDelegate.class); - BUILT_IN_DELEGATES.put(ScrollViewDelegate.SUPPORTED_VIEW_CLASS, ScrollViewDelegate.class); BUILT_IN_DELEGATES.put(WebViewDelegate.SUPPORTED_VIEW_CLASS, WebViewDelegate.class); } @@ -52,7 +51,10 @@ static PullToRefreshAttacher.ViewDelegate getBuiltInViewDelegate(final View view entry.getValue(), VIEW_DELEGATE_CONSTRUCTOR_SIGNATURE, null); } } - return null; + + // Default is the ScrollYDelegate + return InstanceCreationUtils.newInstance(view.getContext(), + ScrollYDelegate.class, VIEW_DELEGATE_CONSTRUCTOR_SIGNATURE, null); } static T instantiateViewDelegate(Context context, String className, Object[] arguments) { diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshAttacher.java b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshAttacher.java index 5b4808a4..ea2a8144 100644 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshAttacher.java +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshAttacher.java @@ -16,953 +16,962 @@ package uk.co.senab.actionbarpulltorefresh.library; +import java.util.Set; +import java.util.WeakHashMap; + import android.app.Activity; import android.content.Context; import android.content.res.Configuration; -import android.content.res.TypedArray; -import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Handler; import android.util.Log; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; import android.widget.FrameLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import java.util.WeakHashMap; /** * FIXME */ public class PullToRefreshAttacher implements View.OnTouchListener { - /* Default configuration values */ - private static final int DEFAULT_HEADER_LAYOUT = R.layout.default_header; - private static final int DEFAULT_ANIM_HEADER_IN = R.anim.fade_in; - private static final int DEFAULT_ANIM_HEADER_OUT = R.anim.fade_out; - private static final float DEFAULT_REFRESH_SCROLL_DISTANCE = 0.5f; - private static final boolean DEFAULT_REFRESH_ON_UP = false; - private static final int DEFAULT_REFRESH_MINIMIZED_DELAY = 3 * 1000; - - private static final boolean DEBUG = false; - private static final String LOG_TAG = "PullToRefreshAttacher"; - - private static final WeakHashMap ATTACHERS - = new WeakHashMap(); - - /* Member Variables */ - - private final Activity mActivity; - - private final EnvironmentDelegate mEnvironmentDelegate; - private final HeaderTransformer mHeaderTransformer; - - private final View mHeaderView; - private final Animation mHeaderInAnimation, mHeaderOutAnimation; - - private final int mTouchSlop; - private final float mRefreshScrollDistance; - - private float mInitialMotionY, mLastMotionY, mPullBeginY; - private boolean mIsBeingDragged, mIsRefreshing, mIsHandlingTouchEvent; - - private final WeakHashMap mRefreshableViews; - - private boolean mEnabled = true; - private boolean mRefreshOnUp; - private int mRefreshMinimizeDelay; - - private final Handler mHandler = new Handler(); - - /** - * Get a PullToRefreshAttacher for this Activity. If there is already a PullToRefreshAttacher - * attached to the Activity, the existing one is returned, otherwise a new instance is created. - * This version of the method will use default configuration options for everything. - * - * @param activity Activity to attach to. - * @return PullToRefresh attached to the Activity. - */ - public static PullToRefreshAttacher get(Activity activity) { - return get(activity, new Options()); - } - - /** - * Get a PullToRefreshAttacher for this Activity. If there is already a PullToRefreshAttacher - * attached to the Activity, the existing one is returned, otherwise a new instance is created. - * - * @param activity Activity to attach to. - * @param options Options used when creating the PullToRefreshAttacher. - * @return PullToRefresh attached to the Activity. - */ - public static PullToRefreshAttacher get(Activity activity, Options options) { - PullToRefreshAttacher attacher = ATTACHERS.get(activity); - if (attacher == null) { - attacher = new PullToRefreshAttacher(activity, options); - ATTACHERS.put(activity, attacher); - } - return attacher; - } - - protected PullToRefreshAttacher(Activity activity, Options options) { - if (options == null) { - Log.i(LOG_TAG, "Given null options so using default options."); - options = new Options(); - } - - mActivity = activity; - - mRefreshableViews = new WeakHashMap(); - - // Copy necessary values from options - mRefreshScrollDistance = options.refreshScrollDistance; - mRefreshOnUp = options.refreshOnUp; - mRefreshMinimizeDelay = options.refreshMinimizeDelay; - - // EnvironmentDelegate - mEnvironmentDelegate = options.environmentDelegate != null - ? options.environmentDelegate - : createDefaultEnvironmentDelegate(); - - // Header Transformer - mHeaderTransformer = options.headerTransformer != null - ? options.headerTransformer - : createDefaultHeaderTransformer(); - - // Create animations for use later - mHeaderInAnimation = AnimationUtils.loadAnimation(activity, options.headerInAnimation); - mHeaderOutAnimation = AnimationUtils.loadAnimation(activity, options.headerOutAnimation); - if (mHeaderOutAnimation != null) { - mHeaderOutAnimation.setAnimationListener(new AnimationCallback()); - } - - // Get touch slop for use later - mTouchSlop = ViewConfiguration.get(activity).getScaledTouchSlop(); - - // Get Window Decor View - final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); - - // Check to see if there is already a Attacher view installed - if (decorView.getChildCount() == 1 && decorView.getChildAt(0) instanceof DecorChildLayout) { - throw new IllegalStateException("View already installed to DecorView. This shouldn't happen."); - } - - // Create Header view and then add to Decor View - mHeaderView = LayoutInflater.from(mEnvironmentDelegate.getContextForInflater(activity)) - .inflate(options.headerLayout, decorView, false); - if (mHeaderView == null) { - throw new IllegalArgumentException("Must supply valid layout id for header."); - } - mHeaderView.setVisibility(View.GONE); - - // Create DecorChildLayout which will move all of the system's decor view's children + the - // Header View to itself. See DecorChildLayout for more info. - DecorChildLayout decorContents = new DecorChildLayout(activity, decorView, mHeaderView); - - // Now add the DecorChildLayout to the decor view - decorView.addView(decorContents, ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - - // Notify transformer + /* Default configuration values */ + private static final int DEFAULT_HEADER_LAYOUT = R.layout.default_header; + private static final int DEFAULT_ANIM_HEADER_IN = R.anim.fade_in; + private static final int DEFAULT_ANIM_HEADER_OUT = R.anim.fade_out; + private static final float DEFAULT_REFRESH_SCROLL_DISTANCE = 0.5f; + private static final boolean DEFAULT_REFRESH_ON_UP = false; + private static final int DEFAULT_REFRESH_MINIMIZED_DELAY = 3 * 1000; + private static final boolean DEFAULT_REFRESH_MINIMIZE = true; + + private static final boolean DEBUG = false; + private static final String LOG_TAG = "PullToRefreshAttacher"; + + /* Member Variables */ + + private final EnvironmentDelegate mEnvironmentDelegate; + private final HeaderTransformer mHeaderTransformer; + + private final View mHeaderView; + private HeaderViewListener mHeaderViewListener; + private final Animation mHeaderInAnimation, mHeaderOutAnimation; + + private final int mTouchSlop; + private final float mRefreshScrollDistance; + + private int mInitialMotionY, mLastMotionY, mPullBeginY; + private boolean mIsBeingDragged, mIsRefreshing, mIsHandlingTouchEvent; + + private final WeakHashMap mRefreshableViews; + + private boolean mEnabled = true; + private final boolean mRefreshOnUp; + private final int mRefreshMinimizeDelay; + private final boolean mRefreshMinimize; + + private final Handler mHandler = new Handler(); + + /** + * Get a PullToRefreshAttacher for this Activity. If there is already a + * PullToRefreshAttacher attached to the Activity, the existing one is + * returned, otherwise a new instance is created. This version of the method + * will use default configuration options for everything. + * + * @param activity + * Activity to attach to. + * @return PullToRefresh attached to the Activity. + */ + public static PullToRefreshAttacher get(Activity activity) { + return get(activity, new Options()); + } + + /** + * Get a PullToRefreshAttacher for this Activity. If there is already a + * PullToRefreshAttacher attached to the Activity, the existing one is + * returned, otherwise a new instance is created. + * + * @param activity + * Activity to attach to. + * @param options + * Options used when creating the PullToRefreshAttacher. + * @return PullToRefresh attached to the Activity. + */ + public static PullToRefreshAttacher get(Activity activity, Options options) { + return new PullToRefreshAttacher(activity, options); + } + + protected PullToRefreshAttacher(Activity activity, Options options) { + if (options == null) { + Log.i(LOG_TAG, "Given null options so using default options."); + options = new Options(); + } + + mRefreshableViews = new WeakHashMap(); + + // Copy necessary values from options + mRefreshScrollDistance = options.refreshScrollDistance; + mRefreshOnUp = options.refreshOnUp; + mRefreshMinimizeDelay = options.refreshMinimizeDelay; + mRefreshMinimize = options.refreshMinimize; + + // EnvironmentDelegate + mEnvironmentDelegate = options.environmentDelegate != null ? options.environmentDelegate + : createDefaultEnvironmentDelegate(); + + // Header Transformer + mHeaderTransformer = options.headerTransformer != null ? options.headerTransformer + : createDefaultHeaderTransformer(); + + // Create animations for use later + mHeaderInAnimation = AnimationUtils.loadAnimation(activity, + options.headerInAnimation); + mHeaderOutAnimation = AnimationUtils.loadAnimation(activity, + options.headerOutAnimation); + if (mHeaderOutAnimation != null || mHeaderInAnimation != null) { + final AnimationCallback callback = new AnimationCallback(); + if (mHeaderInAnimation != null) + mHeaderInAnimation.setAnimationListener(callback); + if (mHeaderOutAnimation != null) + mHeaderOutAnimation.setAnimationListener(callback); + } + + // Get touch slop for use later + mTouchSlop = ViewConfiguration.get(activity).getScaledTouchSlop(); + + // Get Window Decor View + final ViewGroup decorView = (ViewGroup) activity.getWindow() + .getDecorView(); + + // Check to see if there is already a Attacher view installed + if (decorView.getChildCount() == 1 + && decorView.getChildAt(0) instanceof DecorChildLayout) { + throw new IllegalStateException( + "View already installed to DecorView. This shouldn't happen."); + } + + // Create Header view and then add to Decor View + mHeaderView = LayoutInflater.from( + mEnvironmentDelegate.getContextForInflater(activity)).inflate( + options.headerLayout, decorView, false); + if (mHeaderView == null) { + throw new IllegalArgumentException( + "Must supply valid layout id for header."); + } + mHeaderView.setVisibility(View.GONE); + + // Create DecorChildLayout which will move all of the system's decor + // view's children + the + // Header View to itself. See DecorChildLayout for more info. + DecorChildLayout decorContents = new DecorChildLayout(activity, + decorView, mHeaderView); + + // Now add the DecorChildLayout to the decor view + decorView.addView(decorContents, ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + + // Notify transformer mHeaderTransformer.onViewCreated(activity, mHeaderView); - } - - /** - * Add a view which will be used to initiate refresh requests and a listener to be invoked - * when a refresh is started. This version of the method will try to find a handler for the - * view from the built-in view delegates. - * - * @param view View which will be used to initiate refresh requests. - * @param refreshListener Listener to be invoked when a refresh is started. - */ - public void addRefreshableView(View view, OnRefreshListener refreshListener) { - addRefreshableView(view, null, refreshListener); - } - - /** - * Add a view which will be used to initiate refresh requests, along with a delegate which - * knows how to handle the given view, and a listener to be invoked when a refresh is started. - * - * @param view View which will be used to initiate refresh requests. - * @param viewDelegate delegate which knows how to handle view. - * @param refreshListener Listener to be invoked when a refresh is started. - */ - public void addRefreshableView(View view, ViewDelegate viewDelegate, - OnRefreshListener refreshListener) { - addRefreshableView(view, viewDelegate, refreshListener, true); - } - - /** - * Add a view which will be used to initiate refresh requests, along with a delegate which - * knows how to handle the given view, and a listener to be invoked when a refresh is started. - * - * @param view View which will be used to initiate refresh requests. - * @param viewDelegate delegate which knows how to handle view. - * @param refreshListener Listener to be invoked when a refresh is started. - * @param setTouchListener Whether to set this as the {@link android.view.View.OnTouchListener}. - */ - void addRefreshableView(View view, ViewDelegate viewDelegate, - OnRefreshListener refreshListener, final boolean setTouchListener) { - // Check to see if view is null - if (view == null) { - Log.i(LOG_TAG, "Refreshable View is null."); - return; - } - - if (refreshListener == null) { - throw new IllegalArgumentException("OnRefreshListener not given. Please provide one."); - } - - // ViewDelegate - if (viewDelegate == null) { - viewDelegate = InstanceCreationUtils.getBuiltInViewDelegate(view); - if (viewDelegate == null) { - throw new IllegalArgumentException("No view handler found. Please provide one."); - } - } - - // View to detect refreshes for - mRefreshableViews.put(view, new ViewParams(viewDelegate, refreshListener)); - if (setTouchListener) { - view.setOnTouchListener(this); - } - } - - /** - * Remove a view which was previously used to initiate refresh requests. - * - * @param view - View which will be used to initiate refresh requests. - */ - public void removeRefreshableView(View view) { - if (mRefreshableViews.containsKey(view)) { - mRefreshableViews.remove(view); - view.setOnTouchListener(null); - } - } - - /** - * This method should be called by your Activity's or Fragment's onConfigurationChanged method. - * @param newConfig - The new configuration - */ - public void onConfigurationChanged(Configuration newConfig) { - mHeaderTransformer.onViewCreated(mActivity, mHeaderView); - } - - /** - * Manually set this Attacher's refreshing state. The header will be displayed or hidden as - * requested. - * @param refreshing - Whether the attacher should be in a refreshing state, - */ - public final void setRefreshing(boolean refreshing) { - setRefreshingInt(null, refreshing, false); - } - - /** - * @return true if this Attacher is currently in a refreshing state. - */ - public final boolean isRefreshing() { - return mIsRefreshing; - } - - /** - * @return true if this PullToRefresh is currently enabled (defaults to true) - */ - public boolean isEnabled() { - return mEnabled; - } - - /** - * Allows the enable/disable of this PullToRefreshAttacher. If disabled when refreshing then - * the UI is automatically reset. - * - * @param enabled - Whether this PullToRefreshAttacher is enabled. - */ - public void setEnabled(boolean enabled) { - mEnabled = enabled; - - if (!enabled) { - // If we're not enabled, reset any touch handling - resetTouch(); - - // If we're currently refreshing, reset the ptr UI - if (mIsRefreshing) { - reset(false); - } - } - } - - /** - * Call this when your refresh is complete and this view should reset itself (header view - * will be hidden). - * - * This is the equivalent of calling setRefreshing(false). - */ - public final void setRefreshComplete() { - setRefreshingInt(null, false, false); - } - - /** - * @return The HeaderTransformer currently used by this Attacher. - */ - public HeaderTransformer getHeaderTransformer() { - return mHeaderTransformer; - } - - @Override - public final boolean onTouch(final View view, final MotionEvent event) { - if (!mIsHandlingTouchEvent && onInterceptTouchEvent(view, event)) { - mIsHandlingTouchEvent = true; - } - - if (mIsHandlingTouchEvent) { - onTouchEvent(view, event); - } - - // Always return false as we only want to observe events - return false; - } - - final boolean onInterceptTouchEvent(View view, MotionEvent event) { - if (DEBUG) { - Log.d(LOG_TAG, "onInterceptTouchEvent: " + event.toString()); - } - - // If we're not enabled or currently refreshing don't handle any touch events - if (!isEnabled() || isRefreshing()) { - return false; - } - - final ViewParams params = mRefreshableViews.get(view); - if (params == null) { - return false; - } - - switch (event.getAction()) { - case MotionEvent.ACTION_MOVE: { - // We're not currently being dragged so check to see if the user has scrolled enough - if (!mIsBeingDragged && mInitialMotionY > 0f) { - final float y = event.getY(); - final float yDiff = y - mInitialMotionY; - - if (yDiff > mTouchSlop) { - mIsBeingDragged = true; - onPullStarted(y); - } else if (yDiff < -mTouchSlop) { - resetTouch(); - } - } - break; - } - - case MotionEvent.ACTION_DOWN: { - // If we're already refreshing, ignore - if (canRefresh(true, params.onRefreshListener) && - params.viewDelegate.isScrolledToTop(view)) { - mInitialMotionY = event.getY(); - } - break; - } - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - resetTouch(); - break; - } - } - - return mIsBeingDragged; - } - - final boolean onTouchEvent(View view, MotionEvent event) { - if (DEBUG) { - Log.d(LOG_TAG, "onTouchEvent: " + event.toString()); - } - - // If we're not enabled or currently refreshing don't handle any touch events - if (!isEnabled()) { - return false; - } - - final ViewParams params = mRefreshableViews.get(view); - if (params == null) { - return false; - } - - switch (event.getAction()) { - case MotionEvent.ACTION_MOVE: { - // If we're already refreshing ignore it - if (isRefreshing()) { - return false; - } - - final float y = event.getY(); - - if (mIsBeingDragged) { - final float yDx = y - mLastMotionY; - - /** - * Check to see if the user is scrolling the right direction (down). - * We allow a small scroll up which is the check against negative touch slop. - */ - if (yDx >= -mTouchSlop) { - onPull(view, y); - // Only record the y motion if the user has scrolled down. - if (yDx > 0f) { - mLastMotionY = y; - } - } else { - onPullEnded(); - resetTouch(); - } - } - break; - } - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - checkScrollForRefresh(view); - if (mIsBeingDragged) { - onPullEnded(); - } - resetTouch(); - break; - } - } - - return true; - } - - private void resetTouch() { - mIsBeingDragged = false; - mIsHandlingTouchEvent = false; - mInitialMotionY = mLastMotionY = mPullBeginY = -1f; - } - - void onPullStarted(float y) { - if (DEBUG) { - Log.d(LOG_TAG, "onPullStarted"); - } - // Show Header - if (mHeaderInAnimation != null) { - mHeaderView.startAnimation(mHeaderInAnimation); - } - mHeaderView.setVisibility(View.VISIBLE); - mPullBeginY = y; - } - - void onPull(View view, float y) { - if (DEBUG) { - Log.d(LOG_TAG, "onPull"); - } - - final int pxScrollForRefresh = getScrollNeededForRefresh(view); - final float scrollLength = y - mPullBeginY; - - if (scrollLength < pxScrollForRefresh) { - mHeaderTransformer.onPulled(scrollLength / pxScrollForRefresh); - } else { - if (mRefreshOnUp) { - mHeaderTransformer.onReleaseToRefresh(); - } else { - setRefreshingInt(view, true, true); - } - } - } - - void onPullEnded() { - if (DEBUG) { - Log.d(LOG_TAG, "onPullEnded"); - } - if (!mIsRefreshing) { - reset(true); - } - } - - protected EnvironmentDelegate createDefaultEnvironmentDelegate() { - return new EnvironmentDelegate(); - } - - protected HeaderTransformer createDefaultHeaderTransformer() { - return new DefaultHeaderTransformer(); - } - - private boolean checkScrollForRefresh(View view) { - if (mIsBeingDragged && mRefreshOnUp && view != null) { - if (mLastMotionY - mPullBeginY >= getScrollNeededForRefresh(view)) { - setRefreshingInt(view, true, true); - return true; - } - } - return false; - } - - private void setRefreshingInt(View view, boolean refreshing, boolean fromTouch) { - if (DEBUG) { - Log.d(LOG_TAG, "setRefreshingInt: " + refreshing); - } - // Check to see if we need to do anything - if (mIsRefreshing == refreshing) { - return; - } - - resetTouch(); - - if (refreshing && canRefresh(fromTouch, getRefreshListenerForView(view))) { - startRefresh(view, fromTouch); - } else { - reset(fromTouch); - } - } - - private OnRefreshListener getRefreshListenerForView(View view) { - if (view != null) { - ViewParams params = mRefreshableViews.get(view); - if (params != null) { - return params.onRefreshListener; - } - } - return null; - } - - /** - * @param fromTouch - Whether this is being invoked from a touch event - * @return true if we're currently in a state where a refresh can be started. - */ - private boolean canRefresh(boolean fromTouch, OnRefreshListener listener) { - return !mIsRefreshing && (!fromTouch || listener != null); - } - - private int getScrollNeededForRefresh(View view) { - return Math.round(view.getHeight() * mRefreshScrollDistance); - } - - private void reset(boolean fromTouch) { - // Update isRefreshing state - mIsRefreshing = false; - - // Remove any minimize callbacks - mHandler.removeCallbacks(mRefreshMinimizeRunnable); - - if (mHeaderView.getVisibility() != View.GONE) { - // Hide Header - if (mHeaderOutAnimation != null) { - mHeaderView.startAnimation(mHeaderOutAnimation); - // HeaderTransformer.onReset() is called once the animation has finished - } else { - // As we're not animating, hide the header + call the header transformer now - mHeaderView.setVisibility(View.GONE); - mHeaderTransformer.onReset(); - } - } - } - - private void startRefresh(View view, boolean fromTouch) { - // Update isRefreshing state - mIsRefreshing = true; - - // Call OnRefreshListener if this call has originated from a touch event - if (fromTouch) { - OnRefreshListener listener = getRefreshListenerForView(view); - if (listener != null) { - listener.onRefreshStarted(view); - } - } - - // Call Transformer - mHeaderTransformer.onRefreshStarted(); - - // Make sure header is visible. - if (mHeaderView.getVisibility() != View.VISIBLE) { - if (mHeaderInAnimation != null) { - mHeaderView.startAnimation(mHeaderInAnimation); - } - mHeaderView.setVisibility(View.VISIBLE); - } - - // Post a delay runnable to minimize the refresh header - mHandler.postDelayed(mRefreshMinimizeRunnable, mRefreshMinimizeDelay); - } - - /** - * Simple Listener to listen for any callbacks to Refresh. - */ - public interface OnRefreshListener { - /** - * Called when the user has initiated a refresh by pulling. - * @param view - View which the user has started the refresh from. - */ - public void onRefreshStarted(View view); - } - - public static abstract class HeaderTransformer { - /** - * Called whether the header view has been inflated from the resources defined in - * {@link Options#headerLayout}. - * - * @param headerView - inflated header view. - */ - public abstract void onViewCreated(Activity activity, View headerView); - - /** - * Called when the header should be reset. You should update any child views to reflect this. + // TODO Remove the follow deprecated method call before v1.0 + mHeaderTransformer.onViewCreated(mHeaderView); + } + + /** + * Add a view which will be used to initiate refresh requests and a listener + * to be invoked when a refresh is started. This version of the method will + * try to find a handler for the view from the built-in view delegates. + * + * @param view + * View which will be used to initiate refresh requests. + * @param refreshListener + * Listener to be invoked when a refresh is started. + */ + public void addRefreshableView(View view, OnRefreshListener refreshListener) { + addRefreshableView(view, null, refreshListener); + } + + /** + * Add a view which will be used to initiate refresh requests, along with a + * delegate which knows how to handle the given view, and a listener to be + * invoked when a refresh is started. + * + * @param view + * View which will be used to initiate refresh requests. + * @param viewDelegate + * delegate which knows how to handle view. + * @param refreshListener + * Listener to be invoked when a refresh is started. + */ + public void addRefreshableView(View view, ViewDelegate viewDelegate, + OnRefreshListener refreshListener) { + addRefreshableView(view, viewDelegate, refreshListener, true); + } + + /** + * Add a view which will be used to initiate refresh requests, along with a + * delegate which knows how to handle the given view, and a listener to be + * invoked when a refresh is started. + * + * @param view + * View which will be used to initiate refresh requests. + * @param viewDelegate + * delegate which knows how to handle view. + * @param refreshListener + * Listener to be invoked when a refresh is started. + * @param setTouchListener + * Whether to set this as the + * {@link android.view.View.OnTouchListener}. + */ + void addRefreshableView(View view, ViewDelegate viewDelegate, + OnRefreshListener refreshListener, final boolean setTouchListener) { + // Check to see if view is null + if (view == null) { + Log.i(LOG_TAG, "Refreshable View is null."); + return; + } + + if (refreshListener == null) { + throw new IllegalArgumentException( + "OnRefreshListener not given. Please provide one."); + } + + // ViewDelegate + if (viewDelegate == null) { + viewDelegate = InstanceCreationUtils.getBuiltInViewDelegate(view); + if (viewDelegate == null) { + throw new IllegalArgumentException( + "No view handler found. Please provide one."); + } + } + + // View to detect refreshes for + mRefreshableViews.put(view, new ViewParams(viewDelegate, + refreshListener)); + if (setTouchListener) { + view.setOnTouchListener(this); + } + } + + /** + * Remove a view which was previously used to initiate refresh requests. + * + * @param view + * - View which will be used to initiate refresh requests. + */ + public void removeRefreshableView(View view) { + if (mRefreshableViews.containsKey(view)) { + mRefreshableViews.remove(view); + view.setOnTouchListener(null); + } + } + + /** + * Clear all views which were previously used to initiate refresh requests. + */ + public void clearRefreshableViews() { + Set views = mRefreshableViews.keySet(); + for (View view : views) { + view.setOnTouchListener(null); + } + mRefreshableViews.clear(); + } + + /** + * This method should be called by your Activity's or Fragment's + * onConfigurationChanged method. + * + * @param newConfig + * - The new configuration + */ + public void onConfigurationChanged(Configuration newConfig) { + mHeaderTransformer.onViewCreated(mHeaderView); + } + + /** + * Manually set this Attacher's refreshing state. The header will be + * displayed or hidden as requested. + * + * @param refreshing + * - Whether the attacher should be in a refreshing state, + */ + public final void setRefreshing(boolean refreshing) { + setRefreshingInt(null, refreshing, false); + } + + /** + * @return true if this Attacher is currently in a refreshing state. + */ + public final boolean isRefreshing() { + return mIsRefreshing; + } + + /** + * @return true if this PullToRefresh is currently enabled (defaults to + * true) + */ + public boolean isEnabled() { + return mEnabled; + } + + /** + * Allows the enable/disable of this PullToRefreshAttacher. If disabled when + * refreshing then the UI is automatically reset. + * + * @param enabled + * - Whether this PullToRefreshAttacher is enabled. + */ + public void setEnabled(boolean enabled) { + mEnabled = enabled; + + if (!enabled) { + // If we're not enabled, reset any touch handling + resetTouch(); + + // If we're currently refreshing, reset the ptr UI + if (mIsRefreshing) { + reset(false); + } + } + } + + /** + * Call this when your refresh is complete and this view should reset itself + * (header view will be hidden). + * + * This is the equivalent of calling setRefreshing(false). + */ + public final void setRefreshComplete() { + setRefreshingInt(null, false, false); + } + + /** + * Set a {@link HeaderViewListener} which is called when the visibility + * state of the Header View has changed. + * + * @param listener + */ + public final void setHeaderViewListener(HeaderViewListener listener) { + mHeaderViewListener = listener; + } + + /** + * @return The Header View which is displayed when the user is pulling, or + * we are refreshing. + */ + public final View getHeaderView() { + return mHeaderView; + } + + /** + * @return The HeaderTransformer currently used by this Attacher. + */ + public HeaderTransformer getHeaderTransformer() { + return mHeaderTransformer; + } + + @Override + public final boolean onTouch(final View view, final MotionEvent event) { + if (!mIsHandlingTouchEvent && onInterceptTouchEvent(view, event)) { + mIsHandlingTouchEvent = true; + } + + if (mIsHandlingTouchEvent) { + onTouchEvent(view, event); + } + + // Always return false as we only want to observe events + return false; + } + + final boolean onInterceptTouchEvent(View view, MotionEvent event) { + if (DEBUG) { + Log.d(LOG_TAG, "onInterceptTouchEvent: " + event.toString()); + } + + // If we're not enabled or currently refreshing don't handle any touch + // events + if (!isEnabled() || isRefreshing()) { + return false; + } + + final ViewParams params = mRefreshableViews.get(view); + if (params == null) { + return false; + } + + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: { + // We're not currently being dragged so check to see if the user has + // scrolled enough + if (!mIsBeingDragged && mInitialMotionY > 0) { + final int y = (int) event.getY(); + final int yDiff = y - mInitialMotionY; + + if (yDiff > mTouchSlop) { + mIsBeingDragged = true; + onPullStarted(y); + } else if (yDiff < -mTouchSlop) { + resetTouch(); + } + } + break; + } + + case MotionEvent.ACTION_DOWN: { + // If we're already refreshing, ignore + if (canRefresh(true, params.onRefreshListener) + && params.viewDelegate.isScrolledToTop(view)) { + mInitialMotionY = (int) event.getY(); + } + break; + } + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + resetTouch(); + break; + } + } + + return mIsBeingDragged; + } + + final boolean onTouchEvent(View view, MotionEvent event) { + if (DEBUG) { + Log.d(LOG_TAG, "onTouchEvent: " + event.toString()); + } + + // If we're not enabled or currently refreshing don't handle any touch + // events + if (!isEnabled()) { + return false; + } + + final ViewParams params = mRefreshableViews.get(view); + if (params == null) { + return false; + } + + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: { + // If we're already refreshing ignore it + if (isRefreshing()) { + return false; + } + + final int y = (int) event.getY(); + + if (mIsBeingDragged && y != mLastMotionY) { + final int yDx = y - mLastMotionY; + + /** + * Check to see if the user is scrolling the right direction + * (down). We allow a small scroll up which is the check against + * negative touch slop. + */ + if (yDx >= -mTouchSlop) { + onPull(view, y); + // Only record the y motion if the user has scrolled down. + if (yDx > 0) { + mLastMotionY = y; + } + } else { + onPullEnded(); + resetTouch(); + } + } + break; + } + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + checkScrollForRefresh(view); + if (mIsBeingDragged) { + onPullEnded(); + } + resetTouch(); + break; + } + } + + return true; + } + + void resetTouch() { + mIsBeingDragged = false; + mIsHandlingTouchEvent = false; + mInitialMotionY = mLastMotionY = mPullBeginY = -1; + } + + void onPullStarted(int y) { + if (DEBUG) { + Log.d(LOG_TAG, "onPullStarted"); + } + showHeaderView(); + mPullBeginY = y; + } + + void onPull(View view, int y) { + if (DEBUG) { + Log.d(LOG_TAG, "onPull"); + } + + final float pxScrollForRefresh = getScrollNeededForRefresh(view); + final int scrollLength = y - mPullBeginY; + + if (scrollLength < pxScrollForRefresh) { + mHeaderTransformer.onPulled(scrollLength / pxScrollForRefresh); + } else { + if (mRefreshOnUp) { + mHeaderTransformer.onReleaseToRefresh(); + } else { + setRefreshingInt(view, true, true); + } + } + } + + void onPullEnded() { + if (DEBUG) { + Log.d(LOG_TAG, "onPullEnded"); + } + if (!mIsRefreshing) { + reset(true); + } + } + + void showHeaderView() { + if (mHeaderView.getVisibility() != View.VISIBLE) { + // Show Header + if (mHeaderInAnimation != null) { + // AnimationListener will call HeaderViewListener + mHeaderView.startAnimation(mHeaderInAnimation); + } else { + // Call HeaderViewListener now as we have no animation + if (mHeaderViewListener != null) { + mHeaderViewListener.onStateChanged(mHeaderView, + HeaderViewListener.STATE_VISIBLE); + } + } + mHeaderView.setVisibility(View.VISIBLE); + } + } + + void hideHeaderView() { + if (mHeaderView.getVisibility() != View.GONE) { + // Hide Header + if (mHeaderOutAnimation != null) { + // AnimationListener will call HeaderTransformer and + // HeaderViewListener + mHeaderView.startAnimation(mHeaderOutAnimation); + } else { + // As we're not animating, hide the header + call the header + // transformer now + mHeaderView.setVisibility(View.GONE); + mHeaderTransformer.onReset(); + + if (mHeaderViewListener != null) { + mHeaderViewListener.onStateChanged(mHeaderView, + HeaderViewListener.STATE_HIDDEN); + } + } + } + } + + protected EnvironmentDelegate createDefaultEnvironmentDelegate() { + return new EnvironmentDelegate(); + } + + protected HeaderTransformer createDefaultHeaderTransformer() { + return new DefaultHeaderTransformer(); + } + + private boolean checkScrollForRefresh(View view) { + if (mIsBeingDragged && mRefreshOnUp && view != null) { + if (mLastMotionY - mPullBeginY >= getScrollNeededForRefresh(view)) { + setRefreshingInt(view, true, true); + return true; + } + } + return false; + } + + private void setRefreshingInt(View view, boolean refreshing, + boolean fromTouch) { + if (DEBUG) { + Log.d(LOG_TAG, "setRefreshingInt: " + refreshing); + } + // Check to see if we need to do anything + if (mIsRefreshing == refreshing) { + return; + } + + resetTouch(); + + if (refreshing + && canRefresh(fromTouch, getRefreshListenerForView(view))) { + startRefresh(view, fromTouch); + } else { + reset(fromTouch); + } + } + + private OnRefreshListener getRefreshListenerForView(View view) { + if (view != null) { + ViewParams params = mRefreshableViews.get(view); + if (params != null) { + return params.onRefreshListener; + } + } + return null; + } + + /** + * @param fromTouch + * - Whether this is being invoked from a touch event + * @return true if we're currently in a state where a refresh can be + * started. + */ + private boolean canRefresh(boolean fromTouch, OnRefreshListener listener) { + return !mIsRefreshing && (!fromTouch || listener != null); + } + + private float getScrollNeededForRefresh(View view) { + return view.getHeight() * mRefreshScrollDistance; + } + + private void reset(boolean fromTouch) { + // Update isRefreshing state + mIsRefreshing = false; + + // Remove any minimize callbacks + if (mRefreshMinimize) { + mHandler.removeCallbacks(mRefreshMinimizeRunnable); + } + + // Hide Header View + hideHeaderView(); + } + + private void startRefresh(View view, boolean fromTouch) { + // Update isRefreshing state + mIsRefreshing = true; + + // Call OnRefreshListener if this call has originated from a touch event + if (fromTouch) { + OnRefreshListener listener = getRefreshListenerForView(view); + if (listener != null) { + listener.onRefreshStarted(view); + } + } + + // Call Transformer + mHeaderTransformer.onRefreshStarted(); + + // Show Header View + showHeaderView(); + + // Post a delay runnable to minimize the refresh header + if (mRefreshMinimize) { + mHandler.postDelayed(mRefreshMinimizeRunnable, mRefreshMinimizeDelay); + } + } + + /** + * Simple Listener to listen for any callbacks to Refresh. + */ + public interface OnRefreshListener { + /** + * Called when the user has initiated a refresh by pulling. + * + * @param view + * - View which the user has started the refresh from. + */ + public void onRefreshStarted(View view); + } + + public interface HeaderViewListener { + /** + * The state when the header view is completely visible. + */ + public static int STATE_VISIBLE = 0; + + /** + * The state when the header view is minimized. By default this means + * that the progress bar is still visible, but the rest of the view is + * hidden, showing the Action Bar behind. *

- * You should not change the visibility of the header view. - */ - public abstract void onReset(); - - /** - * Called the user has pulled on the scrollable view. - * @param percentagePulled - value between 0.0f and 1.0f depending on how far the user has pulled. - */ - public abstract void onPulled(float percentagePulled); - - /** - * Called when a refresh has begun. Theoretically this call is similar to that provided - * from {@link OnRefreshListener} but is more suitable for header view updates. - */ - public abstract void onRefreshStarted(); - - /** - * Called when a refresh can be initiated when the user ends the touch event. This is only - * called when {@link Options#refreshOnUp} is set to true. - */ - public abstract void onReleaseToRefresh(); - - /** - * Called when the current refresh has taken longer than the time specified in - * {@link Options#refreshMinimizeDelay}. - */ - public abstract void onRefreshMinimized(); - } - - /** - * FIXME - */ - public static abstract class ViewDelegate { + * This will not be called in header minimization is disabled. + */ + public static int STATE_MINIMIZED = 1; + + /** + * The state when the header view is completely hidden. + */ + public static int STATE_HIDDEN = 2; + + /** + * Called when the visibility state of the Header View has changed. + * + * @param headerView + * HeaderView who's state has changed. + * @param state + * The new state. One of {@link #STATE_VISIBLE}, + * {@link #STATE_MINIMIZED} and {@link #STATE_HIDDEN} + */ + public void onStateChanged(View headerView, int state); + } + + public static abstract class HeaderTransformer { /** - * Allows you to provide support for View which do not have built-in support. In this - * method you should cast view to it's native class, and check if it is - * scrolled to the top. + * Called whether the header view has been inflated from the resources + * defined in {@link Options#headerLayout}. * - * @param view The view which has should be checked against. - * @return true if view is scrolled to the top. - */ - public abstract boolean isScrolledToTop(View view); - } - - /** - * FIXME - */ - public static class EnvironmentDelegate { - - /** - * @return Context which should be used for inflating the header layout - */ - public Context getContextForInflater(Activity activity) { - if (Build.VERSION.SDK_INT >= 14) { - return activity.getActionBar().getThemedContext(); - } else { - return activity; - } - } - } - - public static class Options { - /** - * EnvironmentDelegate instance which will be used. If null, we will create an instance of - * the default class. - */ - public EnvironmentDelegate environmentDelegate = null; - - /** - * The layout resource ID which should be inflated to be displayed above the Action Bar - */ - public int headerLayout = DEFAULT_HEADER_LAYOUT; - - /** - * The header transformer to be used to transfer the header view. If null, an instance of - * {@link DefaultHeaderTransformer} will be used. - */ - public HeaderTransformer headerTransformer = null; - - /** - * The anim resource ID which should be started when the header is being hidden. - */ - public int headerOutAnimation = DEFAULT_ANIM_HEADER_OUT; - - /** - * The anim resource ID which should be started when the header is being shown. - */ - public int headerInAnimation = DEFAULT_ANIM_HEADER_IN; - - /** - * The percentage of the refreshable view that needs to be scrolled before a refresh - * is initiated. - */ - public float refreshScrollDistance = DEFAULT_REFRESH_SCROLL_DISTANCE; - - /** - * Whether a refresh should only be initiated when the user has finished the touch event. - */ - public boolean refreshOnUp = DEFAULT_REFRESH_ON_UP; - - /** - * The delay after a refresh is started in which the header should be 'minimized'. By - * default, most of the header is faded out, leaving only the progress bar signifying that - * a refresh is taking place. - */ - public int refreshMinimizeDelay = DEFAULT_REFRESH_MINIMIZED_DELAY; - } - - private class AnimationCallback implements Animation.AnimationListener { - - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - if (animation == mHeaderOutAnimation) { - mHeaderView.setVisibility(View.GONE); - mHeaderTransformer.onReset(); - } - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - } - - /** - * Default Header Transformer. - */ - public static class DefaultHeaderTransformer extends HeaderTransformer { - private ViewGroup mContentLayout; - private TextView mHeaderTextView; - private ProgressBar mHeaderProgressBar; - - private CharSequence mPullRefreshLabel, mRefreshingLabel, mReleaseLabel; - - private final Interpolator mInterpolator = new AccelerateInterpolator(); - - @Override - public void onViewCreated(Activity activity, View headerView) { - // Get ProgressBar and TextView. Also set initial text on TextView - mHeaderProgressBar = (ProgressBar) headerView.findViewById(R.id.ptr_progress); - mHeaderTextView = (TextView) headerView.findViewById(R.id.ptr_text); - - // Labels to display - mPullRefreshLabel = activity.getString(R.string.pull_to_refresh_pull_label); - mRefreshingLabel = activity.getString(R.string.pull_to_refresh_refreshing_label); - mReleaseLabel = activity.getString(R.string.pull_to_refresh_release_label); - - mContentLayout = (ViewGroup) headerView.findViewById(R.id.ptr_content); - if (mContentLayout != null) { - mContentLayout.getLayoutParams().height = getActionBarSize(activity); - mContentLayout.requestLayout(); - } - - Drawable abBg = getActionBarBackground(activity); - if (abBg != null) { - // If we do not have a opaque background we just display a solid solid behind it - if (abBg.getOpacity() != PixelFormat.OPAQUE) { - View view = headerView.findViewById(R.id.ptr_text_opaque_bg); - if (view != null) { - view.setVisibility(View.VISIBLE); - } - } - - mHeaderTextView.setBackgroundDrawable(abBg); - } - - // Call onReset to make sure that the View is consistent - onReset(); - } - - @Override - public void onReset() { - // Reset Progress Bar - if (mHeaderProgressBar != null) { - mHeaderProgressBar.setVisibility(View.GONE); - mHeaderProgressBar.setProgress(0); - mHeaderProgressBar.setIndeterminate(false); - } - - // Reset Text View - if (mHeaderTextView != null) { - mHeaderTextView.setVisibility(View.VISIBLE); - mHeaderTextView.setText(mPullRefreshLabel); - } - - // Reset the Content Layout - if (mContentLayout != null) { - mContentLayout.setVisibility(View.VISIBLE); - } - } - - @Override - public void onPulled(float percentagePulled) { - if (mHeaderProgressBar != null) { - mHeaderProgressBar.setVisibility(View.VISIBLE); - final float progress = mInterpolator.getInterpolation(percentagePulled); - mHeaderProgressBar.setProgress(Math.round(mHeaderProgressBar.getMax() * progress)); - } - } - - @Override - public void onRefreshStarted() { - if (mHeaderTextView != null) { - mHeaderTextView.setText(mRefreshingLabel); - } - if (mHeaderProgressBar != null) { - mHeaderProgressBar.setVisibility(View.VISIBLE); - mHeaderProgressBar.setIndeterminate(true); - } - } - - @Override - public void onReleaseToRefresh() { - if (mHeaderTextView != null) { - mHeaderTextView.setText(mReleaseLabel); - } - if (mHeaderProgressBar != null) { - mHeaderProgressBar.setProgress(mHeaderProgressBar.getMax()); - } - } - - @Override - public void onRefreshMinimized() { - // Here we fade out most of the header, leaving just the progress bar - if (mContentLayout != null) { - mContentLayout.startAnimation(AnimationUtils - .loadAnimation(mContentLayout.getContext(), R.anim.fade_out)); - mContentLayout.setVisibility(View.INVISIBLE); - } - } - - /** - * Set Text to show to prompt the user is pull (or keep pulling). - * @param pullText - Text to display. - */ - public void setPullText(CharSequence pullText) { - mPullRefreshLabel = pullText; - if (mHeaderTextView != null) { - mHeaderTextView.setText(mPullRefreshLabel); - } - } - - /** - * Set Text to show to tell the user that a refresh is currently in progress. - * @param refreshingText - Text to display. - */ - public void setRefreshingText(CharSequence refreshingText) { - mRefreshingLabel = refreshingText; - } - - /** - * Set Text to show to tell the user has scrolled enough to refresh. - * @param releaseText - Text to display. + * @param activity The {@link Activity} that the header view is attached to. + * @param headerView The inflated header view. */ - public void setReleaseText(CharSequence releaseText) { - mReleaseLabel = releaseText; - } - - protected Drawable getActionBarBackground(Context context) { - int[] android_styleable_ActionBar = { android.R.attr.background }; - - // Need to get resource id of style pointed to from actionBarStyle - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(android.R.attr.actionBarStyle, outValue, true); - // Now get action bar style values... - TypedArray abStyle = context.getTheme().obtainStyledAttributes(outValue.resourceId, - android_styleable_ActionBar); - try { - // background is the first attr in the array above so it's index is 0. - return abStyle.getDrawable(0); - } finally { - abStyle.recycle(); - } - } - - protected int getActionBarSize(Context context) { - int[] attrs = { android.R.attr.actionBarSize }; - TypedArray values = context.getTheme().obtainStyledAttributes(attrs); - try { - return values.getDimensionPixelSize(0, 0); - } finally { - values.recycle(); - } - } - } - - /** - * This class allows us to insert a layer in between the system decor view and the actual decor. - * (e.g. Action Bar views). This is needed so we can receive a call to fitSystemWindows(Rect) - * so we can adjust the header view to fit the system windows too. - */ - final static class DecorChildLayout extends FrameLayout { - private ViewGroup mHeaderViewWrapper; - - DecorChildLayout(Context context, ViewGroup systemDecorView, View headerView) { - super(context); - - // Move all children from decor view to here - for (int i = 0, z = systemDecorView.getChildCount() ; i < z ; i++) { - View child = systemDecorView.getChildAt(i); - systemDecorView.removeView(child); - addView(child); - } - - /** - * Wrap the Header View in a FrameLayout and add it to this view. It is wrapped - * so any inset changes do not affect the actual header view. - */ - mHeaderViewWrapper = new FrameLayout(context); - mHeaderViewWrapper.addView(headerView); - addView(mHeaderViewWrapper, ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - } - - @Override - protected boolean fitSystemWindows(Rect insets) { - if (DEBUG) { - Log.d(LOG_TAG, "fitSystemWindows: " + insets.toString()); - } - - // Adjust the Header View's padding to take the insets into account - mHeaderViewWrapper.setPadding(insets.left, insets.top, insets.right, insets.bottom); - - // Call return super so that the rest of the - return super.fitSystemWindows(insets); - } - } - - private static final class ViewParams { - final OnRefreshListener onRefreshListener; - final ViewDelegate viewDelegate; - - ViewParams(ViewDelegate _viewDelegate, OnRefreshListener _onRefreshListener) { - onRefreshListener = _onRefreshListener; - viewDelegate = _viewDelegate; - } - } - - private final Runnable mRefreshMinimizeRunnable = new Runnable() { - @Override - public void run() { - mHeaderTransformer.onRefreshMinimized(); - } - }; + public void onViewCreated(Activity activity, View headerView) {} + + /** + * @deprecated This will be removed before v1.0. Override + * {@link #onViewCreated(android.app.Activity, android.view.View)} instead. + */ + public void onViewCreated(View headerView) {} + + /** + * Called when the header should be reset. You should update any child + * views to reflect this. + *

+ * You should not change the visibility of the header + * view. + */ + public void onReset() {} + + /** + * Called the user has pulled on the scrollable view. + * + * @param percentagePulled + * - value between 0.0f and 1.0f depending on how far the + * user has pulled. + */ + public void onPulled(float percentagePulled) {} + + /** + * Called when a refresh has begun. Theoretically this call is similar + * to that provided from {@link OnRefreshListener} but is more suitable + * for header view updates. + */ + public void onRefreshStarted() {} + + /** + * Called when a refresh can be initiated when the user ends the touch + * event. This is only called when {@link Options#refreshOnUp} is set to + * true. + */ + public void onReleaseToRefresh() {} + + /** + * Called when the current refresh has taken longer than the time + * specified in {@link Options#refreshMinimizeDelay}. + */ + public void onRefreshMinimized() {} + } + + /** + * FIXME + */ + public static abstract class ViewDelegate { + + /** + * Allows you to provide support for View which do not have built-in + * support. In this method you should cast view to it's + * native class, and check if it is scrolled to the top. + * + * @param view + * The view which has should be checked against. + * @return true if view is scrolled to the top. + */ + public abstract boolean isScrolledToTop(View view); + } + + /** + * FIXME + */ + public static class EnvironmentDelegate { + + /** + * @return Context which should be used for inflating the header layout + */ + public Context getContextForInflater(Activity activity) { + if (Build.VERSION.SDK_INT >= 14) { + return activity.getActionBar().getThemedContext(); + } else { + return activity; + } + } + } + + public static class Options { + + /** + * EnvironmentDelegate instance which will be used. If null, we will + * create an instance of the default class. + */ + public EnvironmentDelegate environmentDelegate = null; + + /** + * The layout resource ID which should be inflated to be displayed above + * the Action Bar + */ + public int headerLayout = DEFAULT_HEADER_LAYOUT; + + /** + * The header transformer to be used to transfer the header view. If + * null, an instance of {@link DefaultHeaderTransformer} will be used. + */ + public HeaderTransformer headerTransformer = null; + + /** + * The anim resource ID which should be started when the header is being + * hidden. + */ + public int headerOutAnimation = DEFAULT_ANIM_HEADER_OUT; + + /** + * The anim resource ID which should be started when the header is being + * shown. + */ + public int headerInAnimation = DEFAULT_ANIM_HEADER_IN; + + /** + * The percentage of the refreshable view that needs to be scrolled + * before a refresh is initiated. + */ + public float refreshScrollDistance = DEFAULT_REFRESH_SCROLL_DISTANCE; + + /** + * Whether a refresh should only be initiated when the user has finished + * the touch event. + */ + public boolean refreshOnUp = DEFAULT_REFRESH_ON_UP; + + /** + * The delay after a refresh is started in which the header should be + * 'minimized'. By default, most of the header is faded out, leaving + * only the progress bar signifying that a refresh is taking place. + */ + public int refreshMinimizeDelay = DEFAULT_REFRESH_MINIMIZED_DELAY; + + /** + * Enable or disable the header 'minimization', which by default means that the majority of + * the header is hidden, leaving only the progress bar still showing. + *

+ * If set to true, the header will be minimized after the delay set in + * {@link #refreshMinimizeDelay}. If set to false then the whole header will be displayed + * until the refresh is finished. + */ + public boolean refreshMinimize = DEFAULT_REFRESH_MINIMIZE; + } + + private class AnimationCallback implements Animation.AnimationListener { + + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + if (animation == mHeaderOutAnimation) { + mHeaderView.setVisibility(View.GONE); + mHeaderTransformer.onReset(); + if (mHeaderViewListener != null) { + mHeaderViewListener.onStateChanged(mHeaderView, + HeaderViewListener.STATE_HIDDEN); + } + } else if (animation == mHeaderInAnimation) { + if (mHeaderViewListener != null) { + mHeaderViewListener.onStateChanged(mHeaderView, + HeaderViewListener.STATE_VISIBLE); + } + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + } + + /** + * This class allows us to insert a layer in between the system decor view + * and the actual decor. (e.g. Action Bar views). This is needed so we can + * receive a call to fitSystemWindows(Rect) so we can adjust the header view + * to fit the system windows too. + */ + final static class DecorChildLayout extends FrameLayout { + private final ViewGroup mHeaderViewWrapper; + + DecorChildLayout(Context context, ViewGroup systemDecorView, + View headerView) { + super(context); + + // Move all children from decor view to here + for (int i = 0, z = systemDecorView.getChildCount(); i < z; i++) { + View child = systemDecorView.getChildAt(i); + systemDecorView.removeView(child); + addView(child); + } + + /** + * Wrap the Header View in a FrameLayout and add it to this view. It + * is wrapped so any inset changes do not affect the actual header + * view. + */ + mHeaderViewWrapper = new FrameLayout(context); + mHeaderViewWrapper.addView(headerView); + addView(mHeaderViewWrapper, ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + @Override + protected boolean fitSystemWindows(Rect insets) { + if (DEBUG) { + Log.d(LOG_TAG, "fitSystemWindows: " + insets.toString()); + } + + // Adjust the Header View's padding to take the insets into account + mHeaderViewWrapper.setPadding(insets.left, insets.top, + insets.right, insets.bottom); + + // Call return super so that the rest of the + return super.fitSystemWindows(insets); + } + } + + private static final class ViewParams { + final OnRefreshListener onRefreshListener; + final ViewDelegate viewDelegate; + + ViewParams(ViewDelegate _viewDelegate, + OnRefreshListener _onRefreshListener) { + onRefreshListener = _onRefreshListener; + viewDelegate = _viewDelegate; + } + } + + private final Runnable mRefreshMinimizeRunnable = new Runnable() { + @Override + public void run() { + mHeaderTransformer.onRefreshMinimized(); + + if (mHeaderViewListener != null) { + mHeaderViewListener.onStateChanged(mHeaderView, + HeaderViewListener.STATE_MINIMIZED); + } + } + }; } diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshLayout.java b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshLayout.java index b3c44d00..a368223e 100644 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshLayout.java +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshLayout.java @@ -21,7 +21,6 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; import android.widget.FrameLayout; /** @@ -30,7 +29,6 @@ public class PullToRefreshLayout extends FrameLayout { private PullToRefreshAttacher mPullToRefreshAttacher; - private View mRefreshableView; public PullToRefreshLayout(Context context) { this(context, null); @@ -44,45 +42,40 @@ public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } - @Override - public void addView(View child, int index, ViewGroup.LayoutParams params) { - if (getChildCount() == 0) { - super.addView(child, index, params); - mRefreshableView = child; - } else { - throw new IllegalArgumentException("PullToRefreshLayout can only have one child."); - } - } - /** * Set the {@link PullToRefreshAttacher} to be used with this layout. The view which is added * to this layout will automatically be added as a refreshable-view in the attacher. */ public void setPullToRefreshAttacher(PullToRefreshAttacher attacher, PullToRefreshAttacher.OnRefreshListener refreshListener) { - if (mPullToRefreshAttacher != null && mRefreshableView != null) { - mPullToRefreshAttacher.removeRefreshableView(mRefreshableView); - } + View view; + for (int i = 0, z = getChildCount(); i < z; i++) { + view = getChildAt(i); - mPullToRefreshAttacher = attacher; + if (mPullToRefreshAttacher != null) { + mPullToRefreshAttacher.removeRefreshableView(view); + } - if (attacher != null && mRefreshableView != null) { - attacher.addRefreshableView(mRefreshableView, null, refreshListener, false); + if (attacher != null) { + attacher.addRefreshableView(view, null, refreshListener, false); + } } + + mPullToRefreshAttacher = attacher; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (mPullToRefreshAttacher != null && mRefreshableView != null) { - return mPullToRefreshAttacher.onInterceptTouchEvent(mRefreshableView, event); + if (mPullToRefreshAttacher != null && getChildCount() > 0) { + return mPullToRefreshAttacher.onInterceptTouchEvent(getChildAt(0), event); } return super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { - if (mPullToRefreshAttacher != null && mRefreshableView != null) { - return mPullToRefreshAttacher.onTouchEvent(mRefreshableView, event); + if (mPullToRefreshAttacher != null && getChildCount() > 0) { + return mPullToRefreshAttacher.onTouchEvent(getChildAt(0), event); } return super.onTouchEvent(event); } @@ -91,7 +84,7 @@ public boolean onTouchEvent(MotionEvent event) { protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - if (mPullToRefreshAttacher != null && mRefreshableView != null) { + if (mPullToRefreshAttacher != null) { mPullToRefreshAttacher.onConfigurationChanged(newConfig); } } diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollViewDelegate.java b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollYDelegate.java similarity index 86% rename from dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollViewDelegate.java rename to dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollYDelegate.java index 5b4602fe..e8a9ed37 100644 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollViewDelegate.java +++ b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/library/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollYDelegate.java @@ -24,9 +24,7 @@ /** * FIXME */ -public class ScrollViewDelegate extends PullToRefreshAttacher.ViewDelegate { - - public static final Class SUPPORTED_VIEW_CLASS = ScrollView.class; +public class ScrollYDelegate extends PullToRefreshAttacher.ViewDelegate { @Override public boolean isScrolledToTop(View view) { diff --git a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/pom.xml b/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/pom.xml deleted file mode 100644 index daf477e4..00000000 --- a/dependencies/ActionBar-PullToRefresh-e8e6d2b58c/pom.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - 4.0.0 - - com.github.chrisbanes.actionbarpulltorefresh - parent - pom - 0.6-SNAPSHOT - ActionBar-PullToRefresh Project - A modern implementation of the pull-to-refresh for Android - https://github.com/chrisbanes/ActionBar-PullToRefresh - - - org.sonatype.oss - oss-parent - 7 - - - - - Apache License Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - - https://github.com/chrisbanes/Android-BitmapCache - scm:git:git://github.com/chrisbanes/ActionBar-PullToRefresh.git - scm:git:git@github.com:chrisbanes/ActionBar-PullToRefresh.git - - HEAD - - - - - Chris Banes - http://www.senab.co.uk - chrisbanes - - - - - library - samples - extras - - - - - UTF-8 - UTF-8 - 1.6 - 4.1.1.4 - 16 - 3.6.0 - 3.1 - 2.4.1 - - - - - - com.google.android - android - ${android.version} - provided - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler.version} - - ${java.version} - ${java.version} - - - - org.apache.maven.plugins - maven-release-plugin - ${maven-release.version} - - v@{project.version} - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - ${android-maven.version} - - - ${android.platform} - - true - ${sourceCompatibility} - ${sourceCompatibility} - - true - - - - src - - diff --git a/src/com/todotxt/todotxttouch/TodoTxtTouch.java b/src/com/todotxt/todotxttouch/TodoTxtTouch.java index 769b077f..ed725f14 100644 --- a/src/com/todotxt/todotxttouch/TodoTxtTouch.java +++ b/src/com/todotxt/todotxttouch/TodoTxtTouch.java @@ -33,7 +33,7 @@ import java.util.List; import uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock.PullToRefreshAttacher; -import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher.DefaultHeaderTransformer; +import uk.co.senab.actionbarpulltorefresh.library.DefaultHeaderTransformer; import android.annotation.TargetApi; import android.app.Activity;