diff --git a/README.md b/README.md index e52a4f8a..69f4a51c 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,9 @@ Some code/libraries/resources are used in the project: * [AndroidAnnotations](http://androidannotations.org/) Pierre-Yves Ricau (eBusinessInformations) et al. Apache License, Version 2.0 +* [ActionBar-PullToRefresh](https://github.com/chrisbanes/ActionBar-PullToRefresh) + Chris Banes + Apache License, Version 2.0 * [Crouton](https://github.com/keyboardsurfer/Crouton) Code: Benjamin Weiss (Neofonie Mobile Gmbh) et al. Idea: Cyril Mottier diff --git a/core/project.properties b/core/project.properties index 0ca2ebd5..054f960b 100644 --- a/core/project.properties +++ b/core/project.properties @@ -16,3 +16,5 @@ android.library.reference.1=../external/JakeWharton-ActionBarSherlock/library android.library.reference.2=../external/ColorPickerPreference android.library=true android.library.reference.3=../external/Crouton/library +android.library.reference.4=../external/ActionBar-PullToRefresh-actionbarsherlock +android.library.reference.5=../external/ActionBar-PullToRefresh diff --git a/core/res/values/changelog.xml b/core/res/values/changelog.xml index a12c9d53..82213298 100644 --- a/core/res/values/changelog.xml +++ b/core/res/values/changelog.xml @@ -18,6 +18,7 @@ Transdroid 2.0.1\n +- Support for pull to refresh\n - First Google Play release of the lite version as Transdrone\n - First release as auto-update (now checked only once a day)\n \n diff --git a/core/res/values/strings.xml b/core/res/values/strings.xml index af4e4c31..6d9e7a67 100644 --- a/core/res/values/strings.xml +++ b/core/res/values/strings.xml @@ -374,7 +374,7 @@ \u00A9 Eric Kok, 2312 development Published under GNU General Public License v3 Some code/libraries are used in the project: - ActionBarSherlock\n \u00A0 http://actionbarsherlock.com/\n \u00A0 Jake Wharton \n \u00A0 Apache License, Version 2.0\nAndroidAnnotations\n \u00A0 http://androidannotations.org/\n \u00A0 Pierre-Yves Ricau (eBusinessInformations) et al. \n \u00A0 Apache License, Version 2.0\nCrouton\n \u00A0 https://github.com/keyboardsurfer/Crouton\n \u00A0 Code: Benjamin Weiss (Neofonie Mobile Gmbh) et al. \n \u00A0 Idea: Cyril Mottier \n \u00A0 Apache License, Version 2.0\nBase16Encoder\n \u00A0 http://openjpa.apache.org/\n \u00A0 Marc Prud\'hommeaux \n \u00A0 Apache OpenJPA\n MultipartEntity \n \u00A0 Apache Software Foundation \n \u00A0 Apache License, Version 2.0\nRssParser (learning-android)\n \u00A0 http://github.com/digitalspaghetti/learning-android\n \u00A0 Tane Piper \n \u00A0 Public Domain\nBase64\n \u00A0 http://iharder.net/base64\n \u00A0 Robert Harder \n \u00A0 Public Domain\nandroid-xmlrpc\n \u00A0 http://code.google.com/p/android-xmlrpc/\n \u00A0 pskink et al. \n \u00A0 Apache License, Version 2.0\nandroid-ColorPickerPreference\n \u00A0 https://github.com/attenzione/android-ColorPickerPreference\n \u00A0 Daniel Nilsson and Sergey Margaritov \n \u00A0 Apache License, Version 2.0\nCheckableRelativeLayout\n \u00A0 http://www.marvinlabs.com/2010/10/custom-listview-ability-check-items/\n \u00A0 Cédric Caron (MarvinLabs)\n \u00A0 Public Domain\nFunnel icon\n \u00A0 http://thenounproject.com/noun/funnel/#icon-No5608\n \u00A0 Naomi Atkinson from The Noun Project\n \u00A0 Creative Commons Attribution 3.0 + ActionBarSherlock\n \u00A0 http://actionbarsherlock.com/\n \u00A0 Jake Wharton \n \u00A0 Apache License, Version 2.0\nAndroidAnnotations\n \u00A0 http://androidannotations.org/\n \u00A0 Pierre-Yves Ricau (eBusinessInformations) et al. \n \u00A0 Apache License, Version 2.0\nActionBar-PullToRefresh\n \u00A0 https://github.com/chrisbanes/ActionBar-PullToRefresh\n \u00A0 Chris Banes \n \u00A0 Apache License, Version 2.0\nCrouton\n \u00A0 https://github.com/keyboardsurfer/Crouton\n \u00A0 Code: Benjamin Weiss (Neofonie Mobile Gmbh) et al. \n \u00A0 Idea: Cyril Mottier \n \u00A0 Apache License, Version 2.0\nBase16Encoder\n \u00A0 http://openjpa.apache.org/\n \u00A0 Marc Prud\'hommeaux \n \u00A0 Apache OpenJPA\n MultipartEntity \n \u00A0 Apache Software Foundation \n \u00A0 Apache License, Version 2.0\nRssParser (learning-android)\n \u00A0 http://github.com/digitalspaghetti/learning-android\n \u00A0 Tane Piper \n \u00A0 Public Domain\nBase64\n \u00A0 http://iharder.net/base64\n \u00A0 Robert Harder \n \u00A0 Public Domain\nandroid-xmlrpc\n \u00A0 http://code.google.com/p/android-xmlrpc/\n \u00A0 pskink et al. \n \u00A0 Apache License, Version 2.0\nandroid-ColorPickerPreference\n \u00A0 https://github.com/attenzione/android-ColorPickerPreference\n \u00A0 Daniel Nilsson and Sergey Margaritov \n \u00A0 Apache License, Version 2.0\nCheckableRelativeLayout\n \u00A0 http://www.marvinlabs.com/2010/10/custom-listview-ability-check-items/\n \u00A0 Cédric Caron (MarvinLabs)\n \u00A0 Public Domain\nFunnel icon\n \u00A0 http://thenounproject.com/noun/funnel/#icon-No5608\n \u00A0 Naomi Atkinson from The Noun Project\n \u00A0 Creative Commons Attribution 3.0 Manage your torrents from your Android device diff --git a/core/src/org/transdroid/core/gui/DetailsActivity.java b/core/src/org/transdroid/core/gui/DetailsActivity.java index 0f3c816d..50a5dcde 100644 --- a/core/src/org/transdroid/core/gui/DetailsActivity.java +++ b/core/src/org/transdroid/core/gui/DetailsActivity.java @@ -32,6 +32,7 @@ import org.androidannotations.annotations.UiThread; import org.transdroid.core.R; import org.transdroid.core.app.settings.*; import org.transdroid.core.gui.lists.LocalTorrent; +import org.transdroid.core.gui.lists.NoProgressHeaderTransformer; import org.transdroid.core.gui.log.Log; import org.transdroid.core.gui.navigation.Label; import org.transdroid.core.gui.navigation.NavigationHelper; @@ -62,10 +63,15 @@ import org.transdroid.daemon.task.SetTrackersTask; import org.transdroid.daemon.task.StartTask; import org.transdroid.daemon.task.StopTask; +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher; +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher.OnRefreshListener; +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher.Options; + import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import android.view.View; import android.widget.Toast; import com.actionbarsherlock.app.SherlockFragmentActivity; @@ -97,6 +103,7 @@ public class DetailsActivity extends SherlockFragmentActivity implements Torrent @Bean protected ApplicationSettings applicationSettings; private IDaemonAdapter currentConnection = null; + private PullToRefreshAttacher pullToRefreshAttacher = null; // Details view components @FragmentById(resName = "torrent_details") @@ -148,6 +155,28 @@ public class DetailsActivity extends SherlockFragmentActivity implements Torrent TorrentsActivity_.intent(this).flags(Intent.FLAG_ACTIVITY_CLEAR_TOP).start(); } + /** + * Attaches some view (perhaps contained in a fragment) to this activity's pull to refresh support + * @param view The view to attach + */ + @Override + public void addRefreshableView(View view) { + if (pullToRefreshAttacher == null) { + // Still need to initialise the PullToRefreshAttacher + Options options = new PullToRefreshAttacher.Options(); + options.headerTransformer = new NoProgressHeaderTransformer(); + pullToRefreshAttacher = PullToRefreshAttacher.get(this, options); + } + pullToRefreshAttacher.addRefreshableView(view, new OnRefreshListener() { + @Override + public void onRefreshStarted(View view) { + // Just refresh the full screen, now that the user has pulled to refresh + pullToRefreshAttacher.setRefreshComplete(); + refreshScreen(); + } + }); + } + @OptionsItem(resName = "action_refresh") public void refreshScreen() { fragmentDetails.updateIsLoading(true, null); @@ -330,7 +359,7 @@ public class DetailsActivity extends SherlockFragmentActivity implements Torrent protected void onCommunicationError(DaemonTaskFailureResult result, boolean isCritical) { Log.i(this, result.getException().toString()); String error = getString(LocalTorrent.getResourceForDaemonException(result.getException())); - fragmentDetails.updateIsLoading(false, isCritical? error: null); + fragmentDetails.updateIsLoading(false, isCritical ? error : null); Crouton.showText(this, getString(LocalTorrent.getResourceForDaemonException(result.getException())), NavigationHelper.CROUTON_ERROR_STYLE); } diff --git a/core/src/org/transdroid/core/gui/DetailsFragment.java b/core/src/org/transdroid/core/gui/DetailsFragment.java index d38c26d2..29de8d05 100644 --- a/core/src/org/transdroid/core/gui/DetailsFragment.java +++ b/core/src/org/transdroid/core/gui/DetailsFragment.java @@ -119,6 +119,11 @@ public class DetailsFragment extends SherlockFragment implements OnTrackersUpdat detailsList.setAdapter(new DetailsAdapter(getActivity())); detailsList.setMultiChoiceModeListener(onDetailsSelected); detailsList.setFastScrollEnabled(true); + if (getActivity() != null && getActivity() instanceof RefreshableActivity) { + ((RefreshableActivity) getActivity()).addRefreshableView(detailsList); + } + + // Restore the fragment state (on orientation changes et al.) if (torrent != null) updateTorrent(torrent); if (torrentDetails != null) diff --git a/core/src/org/transdroid/core/gui/TorrentsActivity.java b/core/src/org/transdroid/core/gui/TorrentsActivity.java index 11499432..01cc2eee 100644 --- a/core/src/org/transdroid/core/gui/TorrentsActivity.java +++ b/core/src/org/transdroid/core/gui/TorrentsActivity.java @@ -46,6 +46,7 @@ import org.apache.http.impl.cookie.BasicClientCookie; import org.transdroid.core.R; import org.transdroid.core.app.settings.*; import org.transdroid.core.gui.lists.LocalTorrent; +import org.transdroid.core.gui.lists.NoProgressHeaderTransformer; import org.transdroid.core.gui.lists.SimpleListItem; import org.transdroid.core.gui.log.*; import org.transdroid.core.gui.navigation.*; @@ -92,6 +93,10 @@ import org.transdroid.daemon.task.StopTask; import org.transdroid.daemon.util.DLog; import org.transdroid.daemon.util.HttpHelper; +import uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock.PullToRefreshAttacher; +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher.OnRefreshListener; +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher.Options; + import android.annotation.TargetApi; import android.app.SearchManager; import android.content.ContentResolver; @@ -138,6 +143,7 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi @SystemService protected SearchManager searchManager; private MenuItem searchMenu = null; + private PullToRefreshAttacher pullToRefreshAttacher = null; // Settings @Bean @@ -571,6 +577,28 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi startSearch(query, false, null, false); } + /** + * Attaches some view (perhaps contained in a fragment) to this activity's pull to refresh support + * @param view The view to attach + */ + @Override + public void addRefreshableView(View view) { + if (pullToRefreshAttacher == null) { + // Still need to initialise the PullToRefreshAttacher + Options options = new PullToRefreshAttacher.Options(); + options.headerTransformer = new NoProgressHeaderTransformer(); + pullToRefreshAttacher = PullToRefreshAttacher.get(this, options); + } + pullToRefreshAttacher.addRefreshableView(view, new OnRefreshListener() { + @Override + public void onRefreshStarted(View view) { + // Just refresh the full screen, now that the user has pulled to refresh + pullToRefreshAttacher.setRefreshComplete(); + refreshScreen(); + } + }); + } + @OptionsItem(resName = "action_refresh") public void refreshScreen() { fragmentTorrents.updateIsLoading(true); diff --git a/core/src/org/transdroid/core/gui/TorrentsFragment.java b/core/src/org/transdroid/core/gui/TorrentsFragment.java index 5a9333a0..680b4068 100644 --- a/core/src/org/transdroid/core/gui/TorrentsFragment.java +++ b/core/src/org/transdroid/core/gui/TorrentsFragment.java @@ -114,6 +114,10 @@ public class TorrentsFragment extends SherlockFragment implements OnLabelPickedL torrentsList.setFastScrollEnabled(true); if (torrents != null) updateTorrents(torrents, currentLabels); + // Allow pulls on the list view to refresh the torrents + if (getActivity() != null && getActivity() instanceof RefreshableActivity) { + ((RefreshableActivity) getActivity()).addRefreshableView(torrentsList); + } nosettingsText.setText(getString(R.string.navigation_nosettings, getString(R.string.app_name))); } diff --git a/core/src/org/transdroid/core/gui/lists/NoProgressHeaderTransformer.java b/core/src/org/transdroid/core/gui/lists/NoProgressHeaderTransformer.java new file mode 100644 index 00000000..a9abcee2 --- /dev/null +++ b/core/src/org/transdroid/core/gui/lists/NoProgressHeaderTransformer.java @@ -0,0 +1,17 @@ +package org.transdroid.core.gui.lists; + +import org.transdroid.core.R; + +import android.app.Activity; +import android.view.View; +import uk.co.senab.actionbarpulltorefresh.extras.actionbarsherlock.AbsDefaultHeaderTransformer; + +public class NoProgressHeaderTransformer extends AbsDefaultHeaderTransformer { + + @Override + public void onViewCreated(Activity activity, View headerView) { + super.onViewCreated(activity, headerView); + setProgressBarColor(activity.getResources().getColor(R.color.green)); + } + +} diff --git a/core/src/org/transdroid/core/gui/navigation/RefreshableActivity.java b/core/src/org/transdroid/core/gui/navigation/RefreshableActivity.java index b5df126a..37ab45af 100644 --- a/core/src/org/transdroid/core/gui/navigation/RefreshableActivity.java +++ b/core/src/org/transdroid/core/gui/navigation/RefreshableActivity.java @@ -16,6 +16,8 @@ */ package org.transdroid.core.gui.navigation; +import android.view.View; + /** * Interface to be implemented by any activity that allows its content to be refreshed; fragments can ask for * user-initiated refreshes. @@ -25,4 +27,6 @@ public interface RefreshableActivity { public void refreshScreen(); + public void addRefreshableView(View view); + } diff --git a/core/src/org/transdroid/core/service/AppUpdateService.java b/core/src/org/transdroid/core/service/AppUpdateService.java index 7cdf6975..ef7a29e1 100644 --- a/core/src/org/transdroid/core/service/AppUpdateService.java +++ b/core/src/org/transdroid/core/service/AppUpdateService.java @@ -79,7 +79,7 @@ public class AppUpdateService extends IntentService { Date lastChecked = systemSettings.getLastCheckedForAppUpdates(); Calendar lastDay = Calendar.getInstance(); lastDay.add(Calendar.DAY_OF_MONTH, -1); - if (lastChecked == null || lastChecked.after(lastDay.getTime())) { + if (lastChecked != null && lastChecked.after(lastDay.getTime())) { Log.d(this, "Ship the update service, as we already checked the last 24 hours (or to be exact at " + lastChecked.toString() + ")."); return; diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/AndroidManifest.xml b/external/ActionBar-PullToRefresh-actionbarsherlock/AndroidManifest.xml new file mode 100644 index 00000000..ae76ec35 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/build.gradle b/external/ActionBar-PullToRefresh-actionbarsherlock/build.gradle new file mode 100644 index 00000000..2ca4be69 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/build.gradle @@ -0,0 +1,25 @@ +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'] + res.srcDirs = ['res'] + } + } +} + +apply from: '../../maven_push.gradle' diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/build.xml b/external/ActionBar-PullToRefresh-actionbarsherlock/build.xml new file mode 100644 index 00000000..390ff5f3 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/gradle.properties b/external/ActionBar-PullToRefresh-actionbarsherlock/gradle.properties new file mode 100644 index 00000000..3a29e9ee --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=ActionBar-PullToRefresh Extras: ActionBarSherlock +POM_ARTIFACT_ID=extra-abs +POM_PACKAGING=aar diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/proguard-project.txt b/external/ActionBar-PullToRefresh-actionbarsherlock/proguard-project.txt new file mode 100644 index 00000000..f2fe1559 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/project.properties b/external/ActionBar-PullToRefresh-actionbarsherlock/project.properties new file mode 100644 index 00000000..367cb5d5 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/project.properties @@ -0,0 +1,17 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-18 +android.library=true +android.library.reference.1=../ActionBar-PullToRefresh +android.library.reference.2=../JakeWharton-ActionBarSherlock/library diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/res/anim/fade_in.xml b/external/ActionBar-PullToRefresh-actionbarsherlock/res/anim/fade_in.xml new file mode 100644 index 00000000..fd820b3a --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/res/anim/fade_in.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/res/anim/fade_out.xml b/external/ActionBar-PullToRefresh-actionbarsherlock/res/anim/fade_out.xml new file mode 100644 index 00000000..aad49484 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/res/anim/fade_out.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/AbsDefaultHeaderTransformer.java b/external/ActionBar-PullToRefresh-actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/AbsDefaultHeaderTransformer.java new file mode 100644 index 00000000..3fd83be8 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/AbsDefaultHeaderTransformer.java @@ -0,0 +1,187 @@ +/* + * 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.app.Activity; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; + +import uk.co.senab.actionbarpulltorefresh.library.DefaultHeaderTransformer; + +public class AbsDefaultHeaderTransformer extends DefaultHeaderTransformer { + + private Animation mHeaderInAnimation, mHeaderOutAnimation; + + @Override + public void onViewCreated(Activity activity, View headerView) { + super.onViewCreated(activity, headerView); + + // Create animations for use later + mHeaderInAnimation = AnimationUtils.loadAnimation(activity, R.anim.fade_in); + mHeaderOutAnimation = AnimationUtils.loadAnimation(activity, R.anim.fade_out); + + if (mHeaderOutAnimation != null || mHeaderInAnimation != null) { + final AnimationCallback callback = new AnimationCallback(); + if (mHeaderOutAnimation != null) { + mHeaderOutAnimation.setAnimationListener(callback); + } + } + } + + @Override + protected Drawable getActionBarBackground(Context context) { + // Super handles ICS+ anyway... + if (Build.VERSION.SDK_INT >= super.getMinimumApiLevel()) { + return super.getActionBarBackground(context); + } + + // Get action bar style values... + TypedArray abStyle = obtainStyledAttrsFromThemeAttr(context, R.attr.actionBarStyle, + 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 >= super.getMinimumApiLevel()) { + return super.getActionBarSize(context); + } + + TypedArray values = context.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 >= super.getMinimumApiLevel()) { + return super.getActionBarTitleStyle(context); + } + + // Get action bar style values... + TypedArray abStyle = obtainStyledAttrsFromThemeAttr(context, R.attr.actionBarStyle, + R.styleable.SherlockActionBar); + try { + return abStyle.getResourceId(R.styleable.SherlockActionBar_titleTextStyle, 0); + } finally { + abStyle.recycle(); + } + } + + @Override + public boolean showHeaderView() { + // Super handles ICS+ anyway... + if (Build.VERSION.SDK_INT >= super.getMinimumApiLevel()) { + return super.showHeaderView(); + } + + final View headerView = getHeaderView(); + final boolean changeVis = headerView != null && headerView.getVisibility() != View.VISIBLE; + if (changeVis) { + // Show Header + if (mHeaderInAnimation != null) { + // AnimationListener will call HeaderViewListener + headerView.startAnimation(mHeaderInAnimation); + } + headerView.setVisibility(View.VISIBLE); + } + return changeVis; + } + + @Override + public boolean hideHeaderView() { + // Super handles ICS+ anyway... + if (Build.VERSION.SDK_INT >= super.getMinimumApiLevel()) { + return super.hideHeaderView(); + } + + final View headerView = getHeaderView(); + final boolean changeVis = headerView != null && headerView.getVisibility() != View.GONE; + if (changeVis) { + // Hide Header + if (mHeaderOutAnimation != null) { + // AnimationListener will call HeaderTransformer and + // HeaderViewListener + headerView.startAnimation(mHeaderOutAnimation); + } else { + // As we're not animating, hide the header + call the header + // transformer now + headerView.setVisibility(View.GONE); + onReset(); + } + } + return changeVis; + } + + @Override + public void onRefreshMinimized() { + // Super handles ICS+ anyway... + if (Build.VERSION.SDK_INT >= super.getMinimumApiLevel()) { + super.onRefreshMinimized(); + return; + } + + // Here we fade out most of the header, leaving just the progress bar + View contentLayout = getHeaderView().findViewById(R.id.ptr_content); + if (contentLayout != null) { + contentLayout.startAnimation(AnimationUtils + .loadAnimation(contentLayout.getContext(), R.anim.fade_out)); + contentLayout.setVisibility(View.INVISIBLE); + } + } + + @Override + protected int getMinimumApiLevel() { + return Build.VERSION_CODES.ECLAIR_MR1; + } + + class AnimationCallback implements Animation.AnimationListener { + + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + if (animation == mHeaderOutAnimation) { + View headerView = getHeaderView(); + if (headerView != null) { + headerView.setVisibility(View.GONE); + } + onReset(); + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + } +} diff --git a/external/ActionBar-PullToRefresh-actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/PullToRefreshAttacher.java b/external/ActionBar-PullToRefresh-actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/PullToRefreshAttacher.java new file mode 100644 index 00000000..aad995c5 --- /dev/null +++ b/external/ActionBar-PullToRefresh-actionbarsherlock/src/uk/co/senab/actionbarpulltorefresh/extras/actionbarsherlock/PullToRefreshAttacher.java @@ -0,0 +1,75 @@ +/* + * 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 com.actionbarsherlock.app.SherlockActivity; +import com.actionbarsherlock.app.SherlockExpandableListActivity; +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.app.SherlockListActivity; +import com.actionbarsherlock.app.SherlockPreferenceActivity; + +import android.app.Activity; +import android.content.Context; + +public class PullToRefreshAttacher extends + uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher { + + public static PullToRefreshAttacher get(Activity activity) { + return get(activity, new Options()); + } + + public static PullToRefreshAttacher get(Activity activity, Options options) { + return new PullToRefreshAttacher(activity, options); + } + + protected PullToRefreshAttacher(Activity activity, Options options) { + super(activity, options); + } + + @Override + protected EnvironmentDelegate createDefaultEnvironmentDelegate() { + return new AbsEnvironmentDelegate(); + } + + @Override + protected HeaderTransformer createDefaultHeaderTransformer() { + return new AbsDefaultHeaderTransformer(); + } + + public static class AbsEnvironmentDelegate extends EnvironmentDelegate { + /** + * @return Context which should be used for inflating the header layout + */ + public Context getContextForInflater(Activity activity) { + if (activity instanceof SherlockActivity) { + return ((SherlockActivity) activity).getSupportActionBar().getThemedContext(); + } else if (activity instanceof SherlockListActivity) { + return ((SherlockListActivity) activity).getSupportActionBar().getThemedContext(); + } else if (activity instanceof SherlockFragmentActivity) { + return ((SherlockFragmentActivity) activity).getSupportActionBar() + .getThemedContext(); + } else if (activity instanceof SherlockExpandableListActivity) { + return ((SherlockExpandableListActivity) activity).getSupportActionBar() + .getThemedContext(); + } else if (activity instanceof SherlockPreferenceActivity) { + return ((SherlockPreferenceActivity) activity).getSupportActionBar() + .getThemedContext(); + } + return super.getContextForInflater(activity); + } + } +} diff --git a/external/ActionBar-PullToRefresh/AndroidManifest.xml b/external/ActionBar-PullToRefresh/AndroidManifest.xml new file mode 100644 index 00000000..fc808f4f --- /dev/null +++ b/external/ActionBar-PullToRefresh/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/external/ActionBar-PullToRefresh/build.gradle b/external/ActionBar-PullToRefresh/build.gradle new file mode 100644 index 00000000..625d8f23 --- /dev/null +++ b/external/ActionBar-PullToRefresh/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/external/ActionBar-PullToRefresh/build.xml b/external/ActionBar-PullToRefresh/build.xml new file mode 100644 index 00000000..1b4d11f9 --- /dev/null +++ b/external/ActionBar-PullToRefresh/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/ActionBar-PullToRefresh/gradle.properties b/external/ActionBar-PullToRefresh/gradle.properties new file mode 100644 index 00000000..7d783d1a --- /dev/null +++ b/external/ActionBar-PullToRefresh/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=ActionBar-PullToRefresh Library +POM_ARTIFACT_ID=library +POM_PACKAGING=aar diff --git a/external/ActionBar-PullToRefresh/proguard-project.txt b/external/ActionBar-PullToRefresh/proguard-project.txt new file mode 100644 index 00000000..f2fe1559 --- /dev/null +++ b/external/ActionBar-PullToRefresh/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/external/ActionBar-PullToRefresh/project.properties b/external/ActionBar-PullToRefresh/project.properties new file mode 100644 index 00000000..1b8c5a34 --- /dev/null +++ b/external/ActionBar-PullToRefresh/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-18 +android.library=true diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progress_primary_holo.9.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progress_primary_holo.9.png new file mode 100644 index 00000000..cc547884 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progress_primary_holo.9.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo1.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo1.png new file mode 100644 index 00000000..9436297d Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo1.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo2.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo2.png new file mode 100644 index 00000000..a7155975 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo2.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo3.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo3.png new file mode 100644 index 00000000..d2c6e88d Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo3.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo4.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo4.png new file mode 100644 index 00000000..06204753 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo4.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo5.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo5.png new file mode 100644 index 00000000..8b2f09a8 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo5.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo6.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo6.png new file mode 100644 index 00000000..48ba1b4d Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo6.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo7.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo7.png new file mode 100644 index 00000000..34f15ce4 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo7.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo8.png b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo8.png new file mode 100644 index 00000000..7c943e3c Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-hdpi/ptr_progressbar_indeterminate_holo8.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progress_primary_holo.9.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progress_primary_holo.9.png new file mode 100644 index 00000000..0f542a32 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progress_primary_holo.9.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo1.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo1.png new file mode 100644 index 00000000..c59fb19b Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo1.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo2.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo2.png new file mode 100644 index 00000000..59681cb5 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo2.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo3.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo3.png new file mode 100644 index 00000000..74fe49f2 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo3.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo4.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo4.png new file mode 100644 index 00000000..143d63c4 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo4.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo5.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo5.png new file mode 100644 index 00000000..8db70e74 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo5.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo6.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo6.png new file mode 100644 index 00000000..fab55fa5 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo6.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo7.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo7.png new file mode 100644 index 00000000..feec26b9 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo7.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo8.png b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo8.png new file mode 100644 index 00000000..88432428 Binary files /dev/null and b/external/ActionBar-PullToRefresh/res/drawable-xhdpi/ptr_progressbar_indeterminate_holo8.png differ diff --git a/external/ActionBar-PullToRefresh/res/drawable/ptr_progress_horizontal_holo_center.xml b/external/ActionBar-PullToRefresh/res/drawable/ptr_progress_horizontal_holo_center.xml new file mode 100644 index 00000000..ed1d0c7a --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/drawable/ptr_progress_horizontal_holo_center.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/external/ActionBar-PullToRefresh/res/drawable/ptr_progress_indeterminate_horizontal_holo.xml b/external/ActionBar-PullToRefresh/res/drawable/ptr_progress_indeterminate_horizontal_holo.xml new file mode 100644 index 00000000..b55003e6 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/drawable/ptr_progress_indeterminate_horizontal_holo.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + diff --git a/external/ActionBar-PullToRefresh/res/layout/default_header.xml b/external/ActionBar-PullToRefresh/res/layout/default_header.xml new file mode 100644 index 00000000..4a3619e2 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/layout/default_header.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + diff --git a/external/ActionBar-PullToRefresh/res/values-ar/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-ar/pull_refresh_strings.xml new file mode 100644 index 00000000..c7de7f8c --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-ar/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + اسحب للتحديث… + اترك للتحديث… + تحميل… + diff --git a/external/ActionBar-PullToRefresh/res/values-cs/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-cs/pull_refresh_strings.xml new file mode 100755 index 00000000..97240bec --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-cs/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Tažením aktualizujete… + Uvolněním aktualizujete… + Načítání… + diff --git a/external/ActionBar-PullToRefresh/res/values-de/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-de/pull_refresh_strings.xml new file mode 100755 index 00000000..c5ac00bc --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-de/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Ziehen zum Aktualisieren… + Loslassen zum Aktualisieren… + Laden… + diff --git a/external/ActionBar-PullToRefresh/res/values-es/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-es/pull_refresh_strings.xml new file mode 100755 index 00000000..04894df2 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-es/pull_refresh_strings.xml @@ -0,0 +1,22 @@ + + + + + Desliza el dedo hacia abajo para actualizar. + Soltar para actualizar… + Cargando… + diff --git a/external/ActionBar-PullToRefresh/res/values-fi/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-fi/pull_refresh_strings.xml new file mode 100755 index 00000000..bc8d32a5 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-fi/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Päivitä vetämällä alas… + Päivitä vapauttamalla… + Päivitetään… + \ No newline at end of file diff --git a/external/ActionBar-PullToRefresh/res/values-fr/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-fr/pull_refresh_strings.xml new file mode 100755 index 00000000..0005f8cf --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-fr/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Tirez pour rafraîchir… + Relâcher pour rafraîchir… + Chargement… + diff --git a/external/ActionBar-PullToRefresh/res/values-he/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-he/pull_refresh_strings.xml new file mode 100644 index 00000000..a6a13281 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-he/pull_refresh_strings.xml @@ -0,0 +1,22 @@ + + + + + משוך לרענון… + שחרר לרענון… + טוען… + diff --git a/external/ActionBar-PullToRefresh/res/values-it/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-it/pull_refresh_strings.xml new file mode 100755 index 00000000..9476c787 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-it/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Tira per aggiornare… + Rilascia per aggionare… + Caricamento… + diff --git a/external/ActionBar-PullToRefresh/res/values-iw/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-iw/pull_refresh_strings.xml new file mode 100644 index 00000000..539b7aaa --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-iw/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + משוך לרענון… + שחרר לרענון… + טוען… + diff --git a/external/ActionBar-PullToRefresh/res/values-ja/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-ja/pull_refresh_strings.xml new file mode 100644 index 00000000..5c400234 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-ja/pull_refresh_strings.xml @@ -0,0 +1,22 @@ + + + + + 画面を引っ張って… + 指を離して更新… + 読み込み中… + diff --git a/external/ActionBar-PullToRefresh/res/values-ko/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-ko/pull_refresh_strings.xml new file mode 100755 index 00000000..7f642cb4 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-ko/pull_refresh_strings.xml @@ -0,0 +1,22 @@ + + + + + 당겨서 새로 고침… + 놓아서 새로 고침… + 로드 중… + diff --git a/external/ActionBar-PullToRefresh/res/values-nl/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-nl/pull_refresh_strings.xml new file mode 100755 index 00000000..016e7bd4 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-nl/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Sleep om te vernieuwen… + Loslaten om te vernieuwen… + Laden… + diff --git a/external/ActionBar-PullToRefresh/res/values-pl/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-pl/pull_refresh_strings.xml new file mode 100755 index 00000000..be33a27e --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-pl/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Pociągnij, aby odświeżyć… + Puść, aby odświeżyć… + Wczytywanie… + diff --git a/external/ActionBar-PullToRefresh/res/values-pt-rBR/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-pt-rBR/pull_refresh_strings.xml new file mode 100755 index 00000000..d12ab0c8 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-pt-rBR/pull_refresh_strings.xml @@ -0,0 +1,22 @@ + + + + + Puxe para atualizar… + Libere para atualizar… + Carregando… + diff --git a/external/ActionBar-PullToRefresh/res/values-pt/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-pt/pull_refresh_strings.xml new file mode 100755 index 00000000..a49e011f --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-pt/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Puxe para atualizar… + Liberação para atualizar… + A carregar… + diff --git a/external/ActionBar-PullToRefresh/res/values-ro/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-ro/pull_refresh_strings.xml new file mode 100644 index 00000000..7bc25483 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-ro/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + Trage pentru a reîmprospăta… + Eliberează pentru a reîmprospăta… + Încărcare… + diff --git a/external/ActionBar-PullToRefresh/res/values-ru/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-ru/pull_refresh_strings.xml new file mode 100755 index 00000000..7e433f66 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-ru/pull_refresh_strings.xml @@ -0,0 +1,21 @@ + + + + потяните + отпустите + обновление + diff --git a/external/ActionBar-PullToRefresh/res/values-sv/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-sv/pull_refresh_strings.xml new file mode 100755 index 00000000..14d6def5 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-sv/pull_refresh_strings.xml @@ -0,0 +1,23 @@ + + + + + Dra nedåt om du vill uppdatera + Släpp om du vill uppdatera + Uppdaterar… + + diff --git a/external/ActionBar-PullToRefresh/res/values-zh/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values-zh/pull_refresh_strings.xml new file mode 100755 index 00000000..73d787a5 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values-zh/pull_refresh_strings.xml @@ -0,0 +1,22 @@ + + + + + 下拉刷新… + 放开以刷新… + 正在载入… + diff --git a/external/ActionBar-PullToRefresh/res/values/attrs.xml b/external/ActionBar-PullToRefresh/res/values/attrs.xml new file mode 100644 index 00000000..83cc026d --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values/attrs.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/external/ActionBar-PullToRefresh/res/values/ids.xml b/external/ActionBar-PullToRefresh/res/values/ids.xml new file mode 100644 index 00000000..df504085 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values/ids.xml @@ -0,0 +1,24 @@ + + + + + + + + + + \ No newline at end of file diff --git a/external/ActionBar-PullToRefresh/res/values/pull_refresh_strings.xml b/external/ActionBar-PullToRefresh/res/values/pull_refresh_strings.xml new file mode 100755 index 00000000..d5f8714c --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values/pull_refresh_strings.xml @@ -0,0 +1,23 @@ + + + + + Pull to refresh… + Release to refresh… + Loading… + + diff --git a/external/ActionBar-PullToRefresh/res/values/styles.xml b/external/ActionBar-PullToRefresh/res/values/styles.xml new file mode 100644 index 00000000..35d7cbb4 --- /dev/null +++ b/external/ActionBar-PullToRefresh/res/values/styles.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/DefaultHeaderTransformer.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/DefaultHeaderTransformer.java new file mode 100644 index 00000000..d5989de4 --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/DefaultHeaderTransformer.java @@ -0,0 +1,397 @@ +/* + * 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.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +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.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.Interpolator; +import android.widget.ProgressBar; +import android.widget.TextView; + +import uk.co.senab.actionbarpulltorefresh.library.platform.SDK11; + +/** + * Default Header Transformer. + */ +public class DefaultHeaderTransformer extends PullToRefreshAttacher.HeaderTransformer { + + private View mHeaderView; + private ViewGroup mContentLayout; + private TextView mHeaderTextView; + private ProgressBar mHeaderProgressBar; + + private CharSequence mPullRefreshLabel, mRefreshingLabel, mReleaseLabel; + + private boolean mUseCustomProgressColor = false; + private int mProgressDrawableColor; + private long mAnimationDuration; + + 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) { + mHeaderView = headerView; + + // Get ProgressBar and TextView + mHeaderProgressBar = (ProgressBar) headerView.findViewById(R.id.ptr_progress); + mHeaderTextView = (TextView) headerView.findViewById(R.id.ptr_text); + mContentLayout = (ViewGroup) headerView.findViewById(R.id.ptr_content); + + // Default 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); + + mAnimationDuration = activity.getResources() + .getInteger(android.R.integer.config_shortAnimTime); + + // Setup the View styles + setupViewsFromStyles(activity, headerView); + + // Apply any custom ProgressBar colors + applyProgressBarColor(); + + // FIXME: I do not like this call here + onReset(); + } + + @Override + public void onConfigurationChanged(Activity activity, Configuration newConfig) { + setupViewsFromStyles(activity, getHeaderView()); + } + + @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); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + SDK11.setAlpha(mContentLayout, 1f); + } + } + } + + @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) { + ObjectAnimator.ofFloat(mContentLayout, "alpha", 1f, 0f).start(); + } + } + + public View getHeaderView() { + return mHeaderView; + } + + @Override + public boolean showHeaderView() { + final boolean changeVis = mHeaderView.getVisibility() != View.VISIBLE; + + if (changeVis) { + mHeaderView.setVisibility(View.VISIBLE); + AnimatorSet animSet = new AnimatorSet(); + ObjectAnimator transAnim = ObjectAnimator.ofFloat(mContentLayout, "translationY", + -mContentLayout.getHeight(), 0f); + ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mHeaderView, "alpha", 0f, 1f); + animSet.playTogether(transAnim, alphaAnim); + animSet.setDuration(mAnimationDuration); + animSet.start(); + } + + return changeVis; + } + + @Override + public boolean hideHeaderView() { + final boolean changeVis = mHeaderView.getVisibility() != View.GONE; + + if (changeVis) { + Animator animator; + if (mContentLayout.getAlpha() >= 0.5f) { + // If the content layout is showing, translate and fade out + animator = new AnimatorSet(); + ObjectAnimator transAnim = ObjectAnimator.ofFloat(mContentLayout, "translationY", + 0f, -mContentLayout.getHeight()); + ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mHeaderView, "alpha", 1f, 0f); + ((AnimatorSet) animator).playTogether(transAnim, alphaAnim); + } else { + // If the content layout isn't showing (minimized), just fade out + animator = ObjectAnimator.ofFloat(mHeaderView, "alpha", 1f, 0f); + } + animator.setDuration(mAnimationDuration); + animator.addListener(new HideAnimationCallback()); + animator.start(); + } + + return changeVis; + } + + /** + * 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 setupViewsFromStyles(Activity activity, View headerView) { + final TypedArray styleAttrs = obtainStyledAttrsFromThemeAttr(activity, + R.attr.ptrHeaderStyle, R.styleable.PullToRefreshHeader); + + // Retrieve the Action Bar size from the app theme or the Action Bar's style + if (mContentLayout != null) { + final int height = styleAttrs + .getDimensionPixelSize(R.styleable.PullToRefreshHeader_ptrHeaderHeight, + getActionBarSize(activity)); + mContentLayout.getLayoutParams().height = height; + mContentLayout.requestLayout(); + } + + // Retrieve the Action Bar background from the app theme or the Action Bar's style (see #93) + Drawable bg = styleAttrs.hasValue(R.styleable.PullToRefreshHeader_ptrHeaderBackground) + ? styleAttrs.getDrawable(R.styleable.PullToRefreshHeader_ptrHeaderBackground) + : getActionBarBackground(activity); + if (bg != null) { + mHeaderTextView.setBackgroundDrawable(bg); + + // If we have an opaque background we can remove the background from the content layout + if (mContentLayout != null && bg.getOpacity() == PixelFormat.OPAQUE) { + mContentLayout.setBackgroundResource(0); + } + } + + // Retrieve the Action Bar Title Style from the app theme or the Action Bar's style + Context abContext = headerView.getContext(); + final int titleTextStyle = styleAttrs + .getResourceId(R.styleable.PullToRefreshHeader_ptrHeaderTitleTextAppearance, + getActionBarTitleStyle(abContext)); + if (titleTextStyle != 0) { + mHeaderTextView.setTextAppearance(abContext, titleTextStyle); + } + + // Retrieve the Progress Bar Color the style + if (styleAttrs.hasValue(R.styleable.PullToRefreshHeader_ptrProgressBarColor)) { + mUseCustomProgressColor = true; + mProgressDrawableColor = styleAttrs + .getColor(R.styleable.PullToRefreshHeader_ptrProgressBarColor, 0); + } + + // Retrieve the text strings from the style (if they're set) + if (styleAttrs.hasValue(R.styleable.PullToRefreshHeader_ptrPullText)) { + mPullRefreshLabel = styleAttrs.getString(R.styleable.PullToRefreshHeader_ptrPullText); + } + if (styleAttrs.hasValue(R.styleable.PullToRefreshHeader_ptrRefreshingText)) { + mRefreshingLabel = styleAttrs + .getString(R.styleable.PullToRefreshHeader_ptrRefreshingText); + } + if (styleAttrs.hasValue(R.styleable.PullToRefreshHeader_ptrReleaseText)) { + mReleaseLabel = styleAttrs.getString(R.styleable.PullToRefreshHeader_ptrReleaseText); + } + + styleAttrs.recycle(); + } + + 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}; + + // Now get the action bar style values... + TypedArray abStyle = obtainStyledAttrsFromThemeAttr(context, android.R.attr.actionBarStyle, + 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}; + + // Now get the action bar style values... + TypedArray abStyle = obtainStyledAttrsFromThemeAttr(context, android.R.attr.actionBarStyle, + 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; + } + + class HideAnimationCallback extends AnimatorListenerAdapter { + @Override + public void onAnimationEnd(Animator animation) { + View headerView = getHeaderView(); + if (headerView != null) { + headerView.setVisibility(View.GONE); + } + onReset(); + } + } + + protected static TypedArray obtainStyledAttrsFromThemeAttr(Context context, int themeAttr, + int[] styleAttrs) { + // Need to get resource id of style pointed to from the theme attr + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(themeAttr, outValue, true); + final int styleResId = outValue.resourceId; + + // Now return the values (from styleAttrs) from the style + return context.obtainStyledAttributes(styleResId, styleAttrs); + } +} diff --git a/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/InstanceCreationUtils.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/InstanceCreationUtils.java new file mode 100644 index 00000000..77766f8a --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/InstanceCreationUtils.java @@ -0,0 +1,91 @@ +/* + * 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.content.Context; +import android.util.Log; +import android.view.View; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import uk.co.senab.actionbarpulltorefresh.library.viewdelegates.AbsListViewDelegate; +import uk.co.senab.actionbarpulltorefresh.library.viewdelegates.ScrollYDelegate; +import uk.co.senab.actionbarpulltorefresh.library.viewdelegates.WebViewDelegate; + +class InstanceCreationUtils { + + private static final String LOG_TAG = "InstanceCreationUtils"; + + private static final Class[] VIEW_DELEGATE_CONSTRUCTOR_SIGNATURE = new Class[]{}; + private static final Class[] TRANSFORMER_CONSTRUCTOR_SIGNATURE = new Class[]{}; + + private static final HashMap BUILT_IN_DELEGATES; + static { + BUILT_IN_DELEGATES = new HashMap(); + BUILT_IN_DELEGATES.put(AbsListViewDelegate.SUPPORTED_VIEW_CLASS, AbsListViewDelegate.class); + BUILT_IN_DELEGATES.put(WebViewDelegate.SUPPORTED_VIEW_CLASS, WebViewDelegate.class); + } + + static PullToRefreshAttacher.ViewDelegate getBuiltInViewDelegate(final View view) { + final Set> entries = BUILT_IN_DELEGATES.entrySet(); + for (final Map.Entry entry : entries) { + if (entry.getKey().isInstance(view)) { + return InstanceCreationUtils.newInstance(view.getContext(), + entry.getValue(), VIEW_DELEGATE_CONSTRUCTOR_SIGNATURE, 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) { + try { + Class clazz = context.getClassLoader().loadClass(className); + return newInstance(context, clazz, VIEW_DELEGATE_CONSTRUCTOR_SIGNATURE, arguments); + } catch (Exception e) { + Log.w(LOG_TAG, "Cannot instantiate class: " + className, e); + } + return null; + } + + static T instantiateTransformer(Context context, String className, Object[] arguments) { + try { + Class clazz = context.getClassLoader().loadClass(className); + return newInstance(context, clazz, TRANSFORMER_CONSTRUCTOR_SIGNATURE, arguments); + } catch (Exception e) { + Log.w(LOG_TAG, "Cannot instantiate class: " + className, e); + } + return null; + } + + private static T newInstance(Context context, Class clazz, Class[] constructorSig, + Object[] arguments) { + try { + Constructor constructor = clazz.getConstructor(constructorSig); + return (T) constructor.newInstance(arguments); + } catch (Exception e) { + Log.w(LOG_TAG, "Cannot instantiate class: " + clazz.getName(), e); + } + return null; + } + +} diff --git a/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshAttacher.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshAttacher.java new file mode 100644 index 00000000..5b344be1 --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshAttacher.java @@ -0,0 +1,948 @@ +/* + * 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.Configuration; +import android.graphics.Rect; +import android.os.Build; +import android.os.Handler; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import java.util.Set; +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 float DEFAULT_REFRESH_SCROLL_DISTANCE = 0.5f; + private static final boolean DEFAULT_REFRESH_ON_UP = false; + private static final int DEFAULT_REFRESH_MINIMIZED_DELAY = 1 * 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 Activity mActivity; + private final View mHeaderView; + private HeaderViewListener mHeaderViewListener; + + private final int mTouchSlop; + private final float mRefreshScrollDistance; + + private int mInitialMotionY, mLastMotionY, mPullBeginY; + private boolean mIsBeingDragged, mIsRefreshing, mHandlingTouchEventFromDown; + + 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(); + } + + mActivity = activity; + 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(); + + // 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( + "You should only create one PullToRefreshAttacher per Activity"); + } + + // 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."); + } + // Make Header View invisible so it still gets a layout pass + mHeaderView.setVisibility(View.INVISIBLE); + + // 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); + // 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.onConfigurationChanged(mActivity, newConfig); + } + + /** + * 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) { + // Just call onTouchEvent. It now handles the proper calling of onInterceptTouchEvent + 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; + } + + if (DEBUG) Log.d(LOG_TAG, "onInterceptTouchEvent. Got ViewParams. " + view.toString()); + + 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.isReadyForPull(view, event.getX(), event.getY())) { + mInitialMotionY = (int) event.getY(); + } + break; + } + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + resetTouch(); + break; + } + } + + if (DEBUG) Log.d(LOG_TAG, "onInterceptTouchEvent. Returning " + mIsBeingDragged); + + 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) { + Log.i(LOG_TAG, "View does not have ViewParams"); + return false; + } + + // Record whether our handling is started from ACTION_DOWN + if (event.getAction() == MotionEvent.ACTION_DOWN) { + mHandlingTouchEventFromDown = true; + } + + // If we're being called from ACTION_DOWN then we must call through to + // onInterceptTouchEvent until it sets mIsBeingDragged + if (mHandlingTouchEventFromDown && !mIsBeingDragged) { + onInterceptTouchEvent(view, event); + return true; + } + + 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; + mHandlingTouchEventFromDown = 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 (mHeaderTransformer.showHeaderView()) { + if (mHeaderViewListener != null) { + mHeaderViewListener.onStateChanged(mHeaderView, + HeaderViewListener.STATE_VISIBLE); + } + } + } + + void hideHeaderView() { + if (mHeaderTransformer.hideHeaderView()) { + 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 runnable to minimize the refresh header + if (mRefreshMinimize) { + if (mRefreshMinimizeDelay > 0) { + mHandler.postDelayed(mRefreshMinimizeRunnable, mRefreshMinimizeDelay); + } else { + mHandler.post(mRefreshMinimizeRunnable); + } + } + } + + /** + * 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. + *

+ * 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); + } + + /** + * HeaderTransformers are what controls and update the Header View to reflect the current state + * of the pull-to-refresh interaction. They are responsible for showing and hiding the header + * view, as well as update the state. + */ + public static abstract class HeaderTransformer { + + /** + * Called whether the header view has been inflated from the resources + * defined in {@link Options#headerLayout}. + * + * @param activity The {@link Activity} that the header view is attached to. + * @param headerView The inflated header view. + */ + 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() {} + + /** + * Called when the Header View should be made visible, usually with an animation. + * + * @return true if the visibility has changed. + */ + public abstract boolean showHeaderView(); + + /** + * Called when the Header View should be made invisible, usually with an animation. + * + * @return true if the visibility has changed. + */ + public abstract boolean hideHeaderView(); + + /** + * Called when the Activity's configuration has changed. + * + * @param activity The {@link Activity} that the header view is attached to. + * @param newConfig New configuration. + * + * @see android.app.Activity#onConfigurationChanged(android.content.res.Configuration) + */ + public void onConfigurationChanged(Activity activity, Configuration newConfig) {} + } + + /** + * ViewDelegates are what are used to de-couple the Attacher from the different types of + * scrollable views. + */ + 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. + * @param x The X co-ordinate of the touch event + * @param y The Y co-ordinate of the touch event + * @return true if view is scrolled to the top. + */ + public abstract boolean isReadyForPull(View view, float x, float y); + } + + /** + * This is used to provide platform and environment specific functionality for the Attacher. + */ + 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; + } + } + } + + /** + * Allows you to specify a number of configuration options when instantiating a + * {@link PullToRefreshAttacher}. Used with {@link #get(Activity, Options) get()}. + */ + 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 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; + } + + /** + * 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/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshLayout.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshLayout.java new file mode 100644 index 00000000..296a44f0 --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/PullToRefreshLayout.java @@ -0,0 +1,133 @@ +/* + * 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.content.Context; +import android.content.res.Configuration; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; + +/** + * FIXME + */ +public class PullToRefreshLayout extends FrameLayout { + + private static final boolean DEBUG = false; + private static final String LOG_TAG = "PullToRefreshLayout"; + + private PullToRefreshAttacher mPullToRefreshAttacher; + private View mCurrentTouchTarget; + + public PullToRefreshLayout(Context context) { + this(context, null); + } + + public PullToRefreshLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * 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) { + View view; + for (int i = 0, z = getChildCount(); i < z; i++) { + view = getChildAt(i); + + if (mPullToRefreshAttacher != null) { + mPullToRefreshAttacher.removeRefreshableView(view); + } + + if (attacher != null) { + if (DEBUG) Log.d(LOG_TAG, "Adding View to Attacher: " + view); + attacher.addRefreshableView(view, null, refreshListener, false); + } + } + + mPullToRefreshAttacher = attacher; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + if (DEBUG) Log.d(LOG_TAG, "onInterceptTouchEvent. " + event.toString()); + + if (mPullToRefreshAttacher != null && getChildCount() > 0) { + View target = getChildForTouchEvent(event); + if (target != null && mPullToRefreshAttacher.onInterceptTouchEvent(target, event)) { + mCurrentTouchTarget = target; + return true; + } + } + // Reset Current Touch Target + mCurrentTouchTarget = null; + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (DEBUG) Log.d(LOG_TAG, "onTouchEvent. " + event.toString()); + + if (mPullToRefreshAttacher != null) { + // This is an edge-case. If the ViewGroup does not contain a valid touch target then + // Android calls onTouchEvent after onInterceptTouchEvent with ACTION_DOWN event. + // If that happens then we need to find the visible view and pass it to the attacher as + // usual. + if (mCurrentTouchTarget == null && event.getAction() == MotionEvent.ACTION_DOWN) { + mCurrentTouchTarget = getChildForTouchEvent(event); + } + + if (mCurrentTouchTarget != null) { + return mPullToRefreshAttacher.onTouchEvent(mCurrentTouchTarget, event); + } + } + // Reset Current Touch Target + mCurrentTouchTarget = null; + return super.onTouchEvent(event); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + if (mPullToRefreshAttacher != null) { + mPullToRefreshAttacher.onConfigurationChanged(newConfig); + } + } + + private View getChildForTouchEvent(MotionEvent event) { + final float x = event.getX(), y = event.getY(); + View child; + for (int z = getChildCount() - 1; z >= 0 ; z--) { + child = getChildAt(z); + if (child.isShown() && x >= child.getLeft() && x <= child.getRight() + && y >= child.getTop() && y <= child.getBottom()) { + if (DEBUG) Log.d(LOG_TAG, "Got Child for Touch Event: " + child); + return child; + } + } + return null; + } +} diff --git a/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/platform/SDK11.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/platform/SDK11.java new file mode 100644 index 00000000..da55ebb6 --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/platform/SDK11.java @@ -0,0 +1,27 @@ +/* + * 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.platform; + +import android.view.View; + +public class SDK11 { + + public static void setAlpha(View view, float alpha) { + view.setAlpha(alpha); + } + +} diff --git a/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/AbsListViewDelegate.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/AbsListViewDelegate.java new file mode 100644 index 00000000..8276e146 --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/AbsListViewDelegate.java @@ -0,0 +1,93 @@ +/* + * 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.viewdelegates; + +import android.annotation.TargetApi; +import android.os.Build; +import android.view.View; +import android.widget.AbsListView; + +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher; + +/** + * FIXME + */ +public class AbsListViewDelegate + extends PullToRefreshAttacher.ViewDelegate { + + public static final Class SUPPORTED_VIEW_CLASS = AbsListView.class; + + @Override + public boolean isReadyForPull(View view, final float x, final float y) { + boolean ready = false; + + // First we check whether we're scrolled to the top + AbsListView absListView = (AbsListView) view; + if (absListView.getCount() == 0) { + ready = true; + } else if (absListView.getFirstVisiblePosition() == 0) { + final View firstVisibleChild = absListView.getChildAt(0); + ready = firstVisibleChild != null && firstVisibleChild.getTop() >= 0; + } + + // Then we have to check whether the fas scroller is enabled, and check we're not starting + // the gesture from the scroller + if (ready && absListView.isFastScrollEnabled() && isFastScrollAlwaysVisible(absListView)) { + switch (getVerticalScrollbarPosition(absListView)) { + case View.SCROLLBAR_POSITION_RIGHT: + ready = x < absListView.getRight() - absListView.getVerticalScrollbarWidth(); + break; + case View.SCROLLBAR_POSITION_LEFT: + ready = x > absListView.getVerticalScrollbarWidth(); + break; + } + } + + return ready; + } + + int getVerticalScrollbarPosition(AbsListView absListView) { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? + CompatV11.getVerticalScrollbarPosition(absListView) : + Compat.getVerticalScrollbarPosition(absListView); + } + + boolean isFastScrollAlwaysVisible(AbsListView absListView) { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? + CompatV11.isFastScrollAlwaysVisible(absListView) : + Compat.isFastScrollAlwaysVisible(absListView); + } + + static class Compat { + static int getVerticalScrollbarPosition(AbsListView absListView) { + return View.SCROLLBAR_POSITION_RIGHT; + } + static boolean isFastScrollAlwaysVisible(AbsListView absListView) { + return false; + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + static class CompatV11 { + static int getVerticalScrollbarPosition(AbsListView absListView) { + return absListView.getVerticalScrollbarPosition(); + } + static boolean isFastScrollAlwaysVisible(AbsListView absListView) { + return absListView.isFastScrollAlwaysVisible(); + } + } +} diff --git a/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollYDelegate.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollYDelegate.java new file mode 100644 index 00000000..a38885d0 --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/ScrollYDelegate.java @@ -0,0 +1,32 @@ +/* + * 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.viewdelegates; + +import android.view.View; + +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher; + +/** + * FIXME + */ +public class ScrollYDelegate extends PullToRefreshAttacher.ViewDelegate { + + @Override + public boolean isReadyForPull(View view, float x, float y) { + return view.getScrollY() <= 0; + } +} diff --git a/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/WebViewDelegate.java b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/WebViewDelegate.java new file mode 100644 index 00000000..80c6a83d --- /dev/null +++ b/external/ActionBar-PullToRefresh/src/uk/co/senab/actionbarpulltorefresh/library/viewdelegates/WebViewDelegate.java @@ -0,0 +1,35 @@ +/* + * 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.viewdelegates; + +import android.view.View; +import android.webkit.WebView; + +import uk.co.senab.actionbarpulltorefresh.library.PullToRefreshAttacher; + +/** + * FIXME + */ +public class WebViewDelegate extends PullToRefreshAttacher.ViewDelegate { + + public static final Class SUPPORTED_VIEW_CLASS = WebView.class; + + @Override + public boolean isReadyForPull(View view, float x, float y) { + return view.getScrollY() <= 0; + } +} diff --git a/external/ColorPickerPreference/build.xml b/external/ColorPickerPreference/build.xml index c575c550..1b4d11f9 100644 --- a/external/ColorPickerPreference/build.xml +++ b/external/ColorPickerPreference/build.xml @@ -1,5 +1,5 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + +