parent
59db5254ce
commit
e0e3da072a
|
@ -3,3 +3,4 @@
|
|||
/.idea/workspace.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/signing.properties
|
|
@ -0,0 +1,10 @@
|
|||
<component name="libraryTable">
|
||||
<library name="android-easing-1.0.3">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/build/intermediates/exploded-aar/it.sephiroth.android.library.easing/android-easing/1.0.3/classes.jar!/" />
|
||||
<root url="file://$PROJECT_DIR$/build/intermediates/exploded-aar/it.sephiroth.android.library.easing/android-easing/1.0.3/res" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
|
@ -0,0 +1,10 @@
|
|||
<component name="libraryTable">
|
||||
<library name="imagezoom-1.0.5">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/build/intermediates/exploded-aar/it.sephiroth.android.library.imagezoom/imagezoom/1.0.5/res" />
|
||||
<root url="jar://$PROJECT_DIR$/build/intermediates/exploded-aar/it.sephiroth.android.library.imagezoom/imagezoom/1.0.5/classes.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
|
@ -57,8 +57,8 @@ Thanks to their excellent design!
|
|||
* [HttpMime](http://hc.apache.org/httpcomponents-client-ga/httpmime/), Copyright 1999-2013 The Apache Software Foundation
|
||||
* [ACRA](http://github.com/ACRA/acra), Copyright 2013 Kevin Gaudin
|
||||
* [drag-sort-listview](https://github.com/bauerca/drag-sort-listview), Copyright 2012 Carl Bauer
|
||||
* [Android-MenuComponent](https://github.com/mariotaku/Android-MenuComponent), Copyright 2013 Mariotaku Lee
|
||||
* [RefreshNow](https://github.com/mariotaku/RefreshNow), Copyright 2014 Mariotaku Lee
|
||||
* [MenuComponent-Android](https://github.com/mariotaku/MenuComponent-Android), Copyright 2014 Mariotaku Lee
|
||||
* [RefreshNow-Android](https://github.com/mariotaku/RefreshNow-Android), Copyright 2014 Mariotaku Lee
|
||||
* [AndroidStaggeredGrid](https://github.com/etsy/AndroidStaggeredGrid), Copyright 2013 Etsy
|
||||
* [cwac-merge](https://github.com/commonsguy/cwac-merge), Copyright 2013 CommonsWare
|
||||
* [cwac-sacklist](https://github.com/commonsguy/cwac-sacklist), Copyright 2013 CommonsWare
|
||||
|
@ -78,9 +78,7 @@ I started a crowdin project, so anyone can do something for Twidere. Visit this
|
|||
|
||||
**Donation methods**
|
||||
|
||||
PayPal: "mariotaku.lee#gmail.com".replace("#", "@");
|
||||
|
||||
AliPay: http://me.alipay.com/mariotaku
|
||||
PayPal & AliPay: "mariotaku.lee#gmail.com".replace("#", "@");
|
||||
|
||||
Bitcoin: 1FHAVAzge7cj1LfCTMfnLL49DgA3mVUCuW
|
||||
|
||||
|
|
|
@ -11,6 +11,30 @@ android {
|
|||
versionCode 95
|
||||
versionName "0.2.9.14"
|
||||
}
|
||||
signingConfigs {
|
||||
debug {
|
||||
File signingPropFile = project.rootProject.file('signing.properties')
|
||||
if (signingPropFile.exists()) {
|
||||
Properties signingProp = new Properties()
|
||||
signingProp.load(signingPropFile.newDataInputStream())
|
||||
storeFile file(signingProp.get("twidere.debug.storeFile"))
|
||||
storePassword signingProp.get("twidere.debug.storePassword")
|
||||
keyAlias signingProp.get("twidere.debug.keyAlias")
|
||||
keyPassword signingProp.get("twidere.debug.keyPassword")
|
||||
}
|
||||
}
|
||||
release {
|
||||
File signingPropFile = project.rootProject.file('signing.properties')
|
||||
if (signingPropFile.exists()) {
|
||||
Properties signingProp = new Properties()
|
||||
signingProp.load(signingPropFile.newDataInputStream())
|
||||
storeFile file(signingProp.get("twidere.release.storeFile"))
|
||||
storePassword signingProp.get("twidere.release.storePassword")
|
||||
keyAlias signingProp.get("twidere.release.keyAlias")
|
||||
keyPassword signingProp.get("twidere.release.keyPassword")
|
||||
}
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
exclude 'META-INF/LICENSE'
|
||||
|
@ -22,8 +46,15 @@ android {
|
|||
exclude 'META-INF/ASL2.0'
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +64,7 @@ dependencies {
|
|||
compile 'com.negusoft.holoaccent:library:+'
|
||||
compile 'com.etsy.android.grid:library:1.0.5'
|
||||
compile 'com.sothree.slidinguppanel:library:2.0.0'
|
||||
compile 'it.sephiroth.android.library.imagezoom:imagezoom:+'
|
||||
compile 'com.twitter:twitter-text:1.9.5'
|
||||
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.2'
|
||||
compile 'org.apache.httpcomponents:httpclient-android:4.3.3'
|
||||
|
|
|
@ -1,249 +0,0 @@
|
|||
package it.sephiroth.android.library.imagezoom;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.OnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import it.sephiroth.android.library.imagezoom.ScaleGestureDetector.OnScaleGestureListener;
|
||||
|
||||
import org.mariotaku.twidere.BuildConfig;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
|
||||
public class ImageViewTouch extends ImageViewTouchBase implements Constants {
|
||||
|
||||
private static final float SCROLL_DELTA_THRESHOLD = 1.0f;
|
||||
static final float MIN_ZOOM = 0.9f;
|
||||
protected int mTouchSlop;
|
||||
protected float mCurrentScaleFactor;
|
||||
protected float mScaleFactor;
|
||||
protected int mDoubleTapDirection;
|
||||
protected GestureDetector mGestureDetector;
|
||||
protected OnGestureListener mGestureListener;
|
||||
protected OnScaleGestureListener mScaleListener;
|
||||
protected ScaleGestureDetector mScaleDetector;
|
||||
protected boolean mDoubleTapToZoomEnabled = true;
|
||||
protected boolean mScaleEnabled = true;
|
||||
protected boolean mScrollEnabled = true;
|
||||
|
||||
private OnImageViewTouchDoubleTapListener doubleTapListener;
|
||||
|
||||
public ImageViewTouch(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this ImageViewTouch can be scrolled.
|
||||
*
|
||||
* @param direction - positive direction value means scroll from right to
|
||||
* left, negative value means scroll from left to right
|
||||
* @return true if there is some more place to scroll, false - otherwise.
|
||||
*/
|
||||
public boolean canScroll(final int direction) {
|
||||
final RectF bitmapRect = getBitmapRect();
|
||||
updateRect(bitmapRect, mScrollRect);
|
||||
final Rect imageViewRect = new Rect();
|
||||
getGlobalVisibleRect(imageViewRect);
|
||||
|
||||
if (bitmapRect.right >= imageViewRect.right) {
|
||||
if (direction < 0) return Math.abs(bitmapRect.right - imageViewRect.right) > SCROLL_DELTA_THRESHOLD;
|
||||
}
|
||||
|
||||
final double bitmapScrollRectDelta = Math.abs(bitmapRect.left - mScrollRect.left);
|
||||
return bitmapScrollRectDelta > SCROLL_DELTA_THRESHOLD;
|
||||
}
|
||||
|
||||
public boolean getDoubleTapEnabled() {
|
||||
return mDoubleTapToZoomEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(final MotionEvent event) {
|
||||
if (mScaleDetector != null) {
|
||||
mScaleDetector.onTouchEvent(event);
|
||||
}
|
||||
if (mScaleDetector != null && !mScaleDetector.isInProgress()) {
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
final int action = event.getAction();
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (getScale() < 1f) {
|
||||
zoomTo(1f, 50);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setDoubleTapListener(final OnImageViewTouchDoubleTapListener doubleTapListener) {
|
||||
this.doubleTapListener = doubleTapListener;
|
||||
}
|
||||
|
||||
public void setDoubleTapToZoomEnabled(final boolean value) {
|
||||
mDoubleTapToZoomEnabled = value;
|
||||
}
|
||||
|
||||
public void setScaleEnabled(final boolean value) {
|
||||
mScaleEnabled = value;
|
||||
}
|
||||
|
||||
public void setScrollEnabled(final boolean value) {
|
||||
mScrollEnabled = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _setImageDrawable(final Drawable drawable, final boolean reset, final Matrix initial_matrix,
|
||||
final float maxZoom) {
|
||||
super._setImageDrawable(drawable, reset, initial_matrix, maxZoom);
|
||||
mScaleFactor = getMaxZoom() / 3;
|
||||
}
|
||||
|
||||
protected OnGestureListener getGestureListener() {
|
||||
return new GestureListener();
|
||||
}
|
||||
|
||||
protected OnScaleGestureListener getScaleListener() {
|
||||
return new ScaleListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
|
||||
mGestureListener = getGestureListener();
|
||||
mGestureDetector = new GestureDetector(getContext(), mGestureListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
|
||||
mScaleListener = getScaleListener();
|
||||
mScaleDetector = new ScaleGestureDetector(getContext(), mScaleListener);
|
||||
}
|
||||
mCurrentScaleFactor = 1f;
|
||||
mDoubleTapDirection = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBitmapChanged(final Drawable drawable) {
|
||||
super.onBitmapChanged(drawable);
|
||||
|
||||
final float v[] = new float[9];
|
||||
mSuppMatrix.getValues(v);
|
||||
mCurrentScaleFactor = v[Matrix.MSCALE_X];
|
||||
}
|
||||
|
||||
protected float onDoubleTapPost(final float scale, final float maxZoom) {
|
||||
if (mDoubleTapDirection == 1) {
|
||||
if (scale + mScaleFactor * 2 <= maxZoom)
|
||||
return scale + mScaleFactor;
|
||||
else {
|
||||
mDoubleTapDirection = -1;
|
||||
return maxZoom;
|
||||
}
|
||||
} else {
|
||||
mDoubleTapDirection = 1;
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onZoom(final float scale) {
|
||||
super.onZoom(scale);
|
||||
if (mScaleDetector != null && !mScaleDetector.isInProgress()) {
|
||||
mCurrentScaleFactor = scale;
|
||||
}
|
||||
}
|
||||
|
||||
public class GestureListener extends GestureDetector.SimpleOnGestureListener {
|
||||
|
||||
@Override
|
||||
public boolean onDoubleTap(final MotionEvent e) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.i(LOG_TAG, "onDoubleTap. double tap enabled? " + mDoubleTapToZoomEnabled);
|
||||
}
|
||||
if (mDoubleTapToZoomEnabled) {
|
||||
final float scale = getScale();
|
||||
float targetScale = scale;
|
||||
targetScale = onDoubleTapPost(scale, getMaxZoom());
|
||||
targetScale = Math.min(getMaxZoom(), Math.max(targetScale, MIN_ZOOM));
|
||||
mCurrentScaleFactor = targetScale;
|
||||
zoomTo(targetScale, e.getX(), e.getY(), 200);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
if (null != doubleTapListener) {
|
||||
doubleTapListener.onDoubleTap();
|
||||
}
|
||||
|
||||
return super.onDoubleTap(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float velocityX, final float velocityY) {
|
||||
if (!mScrollEnabled) return false;
|
||||
|
||||
// if (e1.getPointerCount() > 1 || e2.getPointerCount() > 1) return
|
||||
// false;
|
||||
if (mScaleDetector != null && mScaleDetector.isInProgress()) return false;
|
||||
|
||||
final float diffX = e2.getX() - e1.getX();
|
||||
final float diffY = e2.getY() - e1.getY();
|
||||
|
||||
if (Math.abs(velocityX) > 800 || Math.abs(velocityY) > 800) {
|
||||
scrollBy(diffX / 2, diffY / 2, 300);
|
||||
invalidate();
|
||||
}
|
||||
return super.onFling(e1, e2, velocityX, velocityY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(final MotionEvent e) {
|
||||
if (isLongClickable()) {
|
||||
if (mScaleDetector != null && !mScaleDetector.isInProgress()) {
|
||||
setPressed(true);
|
||||
performLongClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX, final float distanceY) {
|
||||
if (!mScrollEnabled) return false;
|
||||
if (e1 == null || e2 == null) return false;
|
||||
// if (e1.getPointerCount() > 1 || e2.getPointerCount() > 1) return
|
||||
// false;
|
||||
if (mScaleDetector != null && mScaleDetector.isInProgress()) return false;
|
||||
if (getScale() == 1f) return false;
|
||||
scrollBy(-distanceX, -distanceY);
|
||||
invalidate();
|
||||
return super.onScroll(e1, e2, distanceX, distanceY);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnImageViewTouchDoubleTapListener {
|
||||
void onDoubleTap();
|
||||
}
|
||||
|
||||
public class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
|
||||
|
||||
@Override
|
||||
public boolean onScale(final ScaleGestureDetector detector) {
|
||||
float targetScale = mCurrentScaleFactor * detector.getScaleFactor();
|
||||
if (mScaleEnabled) {
|
||||
targetScale = Math.min(getMaxZoom(), Math.max(targetScale, MIN_ZOOM));
|
||||
zoomTo(targetScale, detector.getFocusX(), detector.getFocusY());
|
||||
mCurrentScaleFactor = Math.min(getMaxZoom(), Math.max(targetScale, MIN_ZOOM));
|
||||
mDoubleTapDirection = 1;
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,504 +0,0 @@
|
|||
package it.sephiroth.android.library.imagezoom;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import it.sephiroth.android.library.imagezoom.easing.Cubic;
|
||||
import it.sephiroth.android.library.imagezoom.easing.Easing;
|
||||
import it.sephiroth.android.library.imagezoom.graphics.FastBitmapDrawable;
|
||||
import it.sephiroth.android.library.imagezoom.utils.IDisposable;
|
||||
|
||||
/**
|
||||
* Base View to manage image zoom/scrool/pinch operations
|
||||
*
|
||||
* @author alessandro
|
||||
*/
|
||||
public class ImageViewTouchBase extends ImageView implements IDisposable {
|
||||
|
||||
public static final String LOG_TAG = "image";
|
||||
|
||||
protected Easing mEasing = new Cubic();
|
||||
|
||||
protected Matrix mBaseMatrix = new Matrix();
|
||||
protected Matrix mSuppMatrix = new Matrix();
|
||||
protected Handler mHandler = new Handler();
|
||||
protected Runnable mOnLayoutRunnable = null;
|
||||
protected float mMaxZoom;
|
||||
protected final Matrix mDisplayMatrix = new Matrix();
|
||||
protected final float[] mMatrixValues = new float[9];
|
||||
protected int mThisWidth = -1, mThisHeight = -1;
|
||||
protected boolean mFitToScreen = false;
|
||||
final protected float MAX_ZOOM = 2.0f;
|
||||
protected RectF mBitmapRect = new RectF();
|
||||
|
||||
protected RectF mCenterRect = new RectF();
|
||||
protected RectF mScrollRect = new RectF();
|
||||
private OnBitmapChangedListener mListener;
|
||||
|
||||
public ImageViewTouchBase(final Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public ImageViewTouchBase(final Context context, final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
setImageBitmap(null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current image display matrix. This matrix can be used in the
|
||||
* next call to the {@link #setImageBitmap(Bitmap, boolean, Matrix)} to
|
||||
* restore the same view state of the previous {@link Bitmap}
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Matrix getDisplayMatrix() {
|
||||
return new Matrix(mSuppMatrix);
|
||||
}
|
||||
|
||||
public Matrix getImageViewMatrix() {
|
||||
mDisplayMatrix.set(mBaseMatrix);
|
||||
mDisplayMatrix.postConcat(mSuppMatrix);
|
||||
return mDisplayMatrix;
|
||||
}
|
||||
|
||||
public float getMaxZoom() {
|
||||
return mMaxZoom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getRotation() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getScale() {
|
||||
return getScale(mSuppMatrix);
|
||||
}
|
||||
|
||||
public void scrollBy(final float x, final float y) {
|
||||
panBy(x, y);
|
||||
}
|
||||
|
||||
public void setFitToScreen(final boolean value) {
|
||||
if (value != mFitToScreen) {
|
||||
mFitToScreen = value;
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageBitmap(final Bitmap bm) {
|
||||
setImageBitmap(bm, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new image to display and reset the internal matrix.
|
||||
*
|
||||
* @param bitmap - the {@link Bitmap} to display
|
||||
* @param reset - if true the image bounds will be recreated, otherwise the
|
||||
* old {@link Matrix} is used to display the new bitmap
|
||||
* @see #setImageBitmap(Bitmap)
|
||||
*/
|
||||
public void setImageBitmap(final Bitmap bitmap, final boolean reset) {
|
||||
setImageBitmap(bitmap, reset, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #setImageBitmap(Bitmap, boolean)} but an optional view
|
||||
* {@link Matrix} can be passed to determine the new bitmap view matrix.<br />
|
||||
* This method is useful if you need to restore a Bitmap with the same
|
||||
* zoom/pan values from a previous state
|
||||
*
|
||||
* @param bitmap - the {@link Bitmap} to display
|
||||
* @param reset
|
||||
* @param matrix - the {@link Matrix} to be used to display the new bitmap
|
||||
* @see #setImageBitmap(Bitmap, boolean)
|
||||
* @see #setImageBitmap(Bitmap)
|
||||
* @see #getImageViewMatrix()
|
||||
* @see #getDisplayMatrix()
|
||||
*/
|
||||
public void setImageBitmap(final Bitmap bitmap, final boolean reset, final Matrix matrix) {
|
||||
setImageBitmap(bitmap, reset, matrix, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bitmap
|
||||
* @param reset
|
||||
* @param matrix
|
||||
* @param maxZoom - maximum zoom allowd during zoom gestures
|
||||
* @see #setImageBitmap(Bitmap, boolean, Matrix)
|
||||
*/
|
||||
public void setImageBitmap(final Bitmap bitmap, final boolean reset, final Matrix matrix, final float maxZoom) {
|
||||
|
||||
Log.i(LOG_TAG, "setImageBitmap: " + bitmap);
|
||||
|
||||
if (bitmap != null) {
|
||||
setImageDrawable(new FastBitmapDrawable(bitmap), reset, matrix, maxZoom);
|
||||
} else {
|
||||
setImageDrawable(null, reset, matrix, maxZoom);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageDrawable(final Drawable drawable) {
|
||||
setImageDrawable(drawable, true, null, -1);
|
||||
}
|
||||
|
||||
public void setImageDrawable(final Drawable drawable, final boolean reset, final Matrix initial_matrix,
|
||||
final float maxZoom) {
|
||||
|
||||
final int viewWidth = getWidth();
|
||||
|
||||
if (viewWidth <= 0) {
|
||||
mOnLayoutRunnable = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
setImageDrawable(drawable, reset, initial_matrix, maxZoom);
|
||||
}
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
_setImageDrawable(drawable, reset, initial_matrix, maxZoom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageResource(final int resId) {
|
||||
setImageDrawable(getContext().getResources().getDrawable(resId));
|
||||
}
|
||||
|
||||
public void setOnBitmapChangedListener(final OnBitmapChangedListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void zoomTo(final float scale, final float durationMs) {
|
||||
final float cx = getWidth() / 2F;
|
||||
final float cy = getHeight() / 2F;
|
||||
zoomTo(scale, cx, cy, durationMs);
|
||||
}
|
||||
|
||||
protected void _setImageDrawable(final Drawable drawable, final boolean reset, final Matrix initial_matrix,
|
||||
final float maxZoom) {
|
||||
|
||||
if (drawable != null) {
|
||||
if (mFitToScreen) {
|
||||
getProperBaseMatrix2(drawable, mBaseMatrix);
|
||||
} else {
|
||||
getProperBaseMatrix(drawable, mBaseMatrix);
|
||||
}
|
||||
super.setImageDrawable(drawable);
|
||||
} else {
|
||||
mBaseMatrix.reset();
|
||||
super.setImageDrawable(null);
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
mSuppMatrix.reset();
|
||||
if (initial_matrix != null) {
|
||||
mSuppMatrix = new Matrix(initial_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
setImageMatrix(getImageViewMatrix());
|
||||
|
||||
if (maxZoom < 1) {
|
||||
mMaxZoom = maxZoom();
|
||||
} else {
|
||||
mMaxZoom = maxZoom;
|
||||
}
|
||||
|
||||
onBitmapChanged(drawable);
|
||||
}
|
||||
|
||||
protected void center(final boolean horizontal, final boolean vertical) {
|
||||
// Log.i(LOG_TAG, "center");
|
||||
final Drawable drawable = getDrawable();
|
||||
|
||||
if (drawable == null) return;
|
||||
final RectF rect = getCenter(horizontal, vertical);
|
||||
if (rect.left != 0 || rect.top != 0) {
|
||||
postTranslate(rect.left, rect.top);
|
||||
}
|
||||
}
|
||||
|
||||
protected RectF getBitmapRect() {
|
||||
final Drawable drawable = getDrawable();
|
||||
|
||||
if (drawable == null) return null;
|
||||
final Matrix m = getImageViewMatrix();
|
||||
mBitmapRect.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
|
||||
m.mapRect(mBitmapRect);
|
||||
return mBitmapRect;
|
||||
}
|
||||
|
||||
protected RectF getCenter(final boolean horizontal, final boolean vertical) {
|
||||
final Drawable drawable = getDrawable();
|
||||
|
||||
if (drawable == null) return new RectF(0, 0, 0, 0);
|
||||
|
||||
final RectF rect = getBitmapRect();
|
||||
final float height = rect.height();
|
||||
final float width = rect.width();
|
||||
float deltaX = 0, deltaY = 0;
|
||||
if (vertical) {
|
||||
final int viewHeight = getHeight();
|
||||
if (height < viewHeight) {
|
||||
deltaY = (viewHeight - height) / 2 - rect.top;
|
||||
} else if (rect.top > 0) {
|
||||
deltaY = -rect.top;
|
||||
} else if (rect.bottom < viewHeight) {
|
||||
deltaY = getHeight() - rect.bottom;
|
||||
}
|
||||
}
|
||||
if (horizontal) {
|
||||
final int viewWidth = getWidth();
|
||||
if (width < viewWidth) {
|
||||
deltaX = (viewWidth - width) / 2 - rect.left;
|
||||
} else if (rect.left > 0) {
|
||||
deltaX = -rect.left;
|
||||
} else if (rect.right < viewWidth) {
|
||||
deltaX = viewWidth - rect.right;
|
||||
}
|
||||
}
|
||||
mCenterRect.set(deltaX, deltaY, 0, 0);
|
||||
return mCenterRect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the base matrix so that the image is centered and scaled properly.
|
||||
*
|
||||
* @param bitmap
|
||||
* @param matrix
|
||||
*/
|
||||
protected void getProperBaseMatrix(final Drawable drawable, final Matrix matrix) {
|
||||
final float viewWidth = getWidth();
|
||||
final float viewHeight = getHeight();
|
||||
final float w = drawable.getIntrinsicWidth();
|
||||
final float h = drawable.getIntrinsicHeight();
|
||||
matrix.reset();
|
||||
|
||||
if (w > viewWidth || h > viewHeight) {
|
||||
final float widthScale = Math.min(viewWidth / w, 2.0f);
|
||||
final float heightScale = Math.min(viewHeight / h, 2.0f);
|
||||
final float scale = Math.min(widthScale, heightScale);
|
||||
matrix.postScale(scale, scale);
|
||||
final float tw = (viewWidth - w * scale) / 2.0f;
|
||||
final float th = (viewHeight - h * scale) / 2.0f;
|
||||
matrix.postTranslate(tw, th);
|
||||
} else {
|
||||
final float tw = (viewWidth - w) / 2.0f;
|
||||
final float th = (viewHeight - h) / 2.0f;
|
||||
matrix.postTranslate(tw, th);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the base matrix so that the image is centered and scaled properly.
|
||||
*
|
||||
* @param bitmap
|
||||
* @param matrix
|
||||
*/
|
||||
protected void getProperBaseMatrix2(final Drawable bitmap, final Matrix matrix) {
|
||||
final float viewWidth = getWidth();
|
||||
final float viewHeight = getHeight();
|
||||
final float w = bitmap.getIntrinsicWidth();
|
||||
final float h = bitmap.getIntrinsicHeight();
|
||||
matrix.reset();
|
||||
final float widthScale = Math.min(viewWidth / w, MAX_ZOOM);
|
||||
final float heightScale = Math.min(viewHeight / h, MAX_ZOOM);
|
||||
final float scale = Math.min(widthScale, heightScale);
|
||||
matrix.postScale(scale, scale);
|
||||
matrix.postTranslate((viewWidth - w * scale) / MAX_ZOOM, (viewHeight - h * scale) / MAX_ZOOM);
|
||||
}
|
||||
|
||||
protected float getScale(final Matrix matrix) {
|
||||
return getValue(matrix, Matrix.MSCALE_X);
|
||||
}
|
||||
|
||||
protected float getValue(final Matrix matrix, final int whichValue) {
|
||||
matrix.getValues(mMatrixValues);
|
||||
return mMatrixValues[whichValue];
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
setScaleType(ImageView.ScaleType.MATRIX);
|
||||
}
|
||||
|
||||
protected float maxZoom() {
|
||||
final Drawable drawable = getDrawable();
|
||||
|
||||
if (drawable == null) return 1F;
|
||||
|
||||
final float fw = (float) drawable.getIntrinsicWidth() / (float) mThisWidth;
|
||||
final float fh = (float) drawable.getIntrinsicHeight() / (float) mThisHeight;
|
||||
final float max = Math.max(fw, fh) * 4;
|
||||
return max;
|
||||
}
|
||||
|
||||
protected void onBitmapChanged(final Drawable bitmap) {
|
||||
if (mListener != null) {
|
||||
mListener.onBitmapChanged(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(final boolean changed, final int left, final int top, final int right, final int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
mThisWidth = right - left;
|
||||
mThisHeight = bottom - top;
|
||||
final Runnable r = mOnLayoutRunnable;
|
||||
if (r != null) {
|
||||
mOnLayoutRunnable = null;
|
||||
r.run();
|
||||
}
|
||||
if (getDrawable() != null) {
|
||||
if (mFitToScreen) {
|
||||
getProperBaseMatrix2(getDrawable(), mBaseMatrix);
|
||||
} else {
|
||||
getProperBaseMatrix(getDrawable(), mBaseMatrix);
|
||||
}
|
||||
setImageMatrix(getImageViewMatrix());
|
||||
}
|
||||
}
|
||||
|
||||
protected void onZoom(final float scale) {
|
||||
}
|
||||
|
||||
protected void panBy(final double dx, final double dy) {
|
||||
final RectF rect = getBitmapRect();
|
||||
mScrollRect.set((float) dx, (float) dy, 0, 0);
|
||||
updateRect(rect, mScrollRect);
|
||||
postTranslate(mScrollRect.left, mScrollRect.top);
|
||||
center(true, true);
|
||||
}
|
||||
|
||||
protected void postScale(final float scale, final float centerX, final float centerY) {
|
||||
mSuppMatrix.postScale(scale, scale, centerX, centerY);
|
||||
setImageMatrix(getImageViewMatrix());
|
||||
}
|
||||
|
||||
protected void postTranslate(final float deltaX, final float deltaY) {
|
||||
mSuppMatrix.postTranslate(deltaX, deltaY);
|
||||
setImageMatrix(getImageViewMatrix());
|
||||
}
|
||||
|
||||
protected void scrollBy(final float distanceX, final float distanceY, final double durationMs) {
|
||||
final double dx = distanceX;
|
||||
final double dy = distanceY;
|
||||
final long startTime = System.currentTimeMillis();
|
||||
mHandler.post(new Runnable() {
|
||||
|
||||
double old_x = 0;
|
||||
double old_y = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final long now = System.currentTimeMillis();
|
||||
final double currentMs = Math.min(durationMs, now - startTime);
|
||||
final double x = mEasing.easeOut(currentMs, 0, dx, durationMs);
|
||||
final double y = mEasing.easeOut(currentMs, 0, dy, durationMs);
|
||||
panBy(x - old_x, y - old_y);
|
||||
old_x = x;
|
||||
old_y = y;
|
||||
if (currentMs < durationMs) {
|
||||
mHandler.post(this);
|
||||
} else {
|
||||
final RectF centerRect = getCenter(true, true);
|
||||
if (centerRect.left != 0 || centerRect.top != 0) {
|
||||
scrollBy(centerRect.left, centerRect.top);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void updateRect(final RectF bitmapRect, final RectF scrollRect) {
|
||||
if (bitmapRect == null || scrollRect == null) return;
|
||||
final float width = getWidth();
|
||||
final float height = getHeight();
|
||||
|
||||
if (bitmapRect.top >= 0 && bitmapRect.bottom <= height) {
|
||||
scrollRect.top = 0;
|
||||
}
|
||||
if (bitmapRect.left >= 0 && bitmapRect.right <= width) {
|
||||
scrollRect.left = 0;
|
||||
}
|
||||
if (bitmapRect.top + scrollRect.top >= 0 && bitmapRect.bottom > height) {
|
||||
scrollRect.top = (int) (0 - bitmapRect.top);
|
||||
}
|
||||
if (bitmapRect.bottom + scrollRect.top <= height - 0 && bitmapRect.top < 0) {
|
||||
scrollRect.top = (int) (height - 0 - bitmapRect.bottom);
|
||||
}
|
||||
if (bitmapRect.left + scrollRect.left >= 0) {
|
||||
scrollRect.left = (int) (0 - bitmapRect.left);
|
||||
}
|
||||
if (bitmapRect.right + scrollRect.left <= width - 0) {
|
||||
scrollRect.left = (int) (width - 0 - bitmapRect.right);
|
||||
// Log.d( LOG_TAG, "scrollRect(2): " + scrollRect.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
protected void zoomTo(final float scale) {
|
||||
final float cx = getWidth() / 2F;
|
||||
final float cy = getHeight() / 2F;
|
||||
zoomTo(scale, cx, cy);
|
||||
}
|
||||
|
||||
protected void zoomTo(float scale, final float centerX, final float centerY) {
|
||||
// Log.i(LOG_TAG, "zoomTo");
|
||||
|
||||
if (scale > mMaxZoom) {
|
||||
scale = mMaxZoom;
|
||||
}
|
||||
final float oldScale = getScale();
|
||||
final float deltaScale = scale / oldScale;
|
||||
postScale(deltaScale, centerX, centerY);
|
||||
onZoom(getScale());
|
||||
center(true, true);
|
||||
}
|
||||
|
||||
protected void zoomTo(final float scale, final float centerX, final float centerY, final float durationMs) {
|
||||
// Log.i( LOG_TAG, "zoomTo: " + scale + ", " + centerX + ": " + centerY
|
||||
// );
|
||||
final long startTime = System.currentTimeMillis();
|
||||
final float incrementPerMs = (scale - getScale()) / durationMs;
|
||||
final float oldScale = getScale();
|
||||
mHandler.post(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final long now = System.currentTimeMillis();
|
||||
final float currentMs = Math.min(durationMs, now - startTime);
|
||||
final float target = oldScale + incrementPerMs * currentMs;
|
||||
zoomTo(target, centerX, centerY);
|
||||
if (currentMs < durationMs) {
|
||||
mHandler.post(this);
|
||||
} else {
|
||||
// if ( getScale() < 1f ) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface OnBitmapChangedListener {
|
||||
|
||||
void onBitmapChanged(Drawable drawable);
|
||||
}
|
||||
}
|
|
@ -1,487 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* 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 it.sephiroth.android.library.imagezoom;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.FloatMath;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/**
|
||||
* Detects transformation gestures involving more than one pointer
|
||||
* ("multitouch") using the supplied {@link MotionEvent}s. The
|
||||
* {@link OnScaleGestureListener} callback will notify users when a particular
|
||||
* gesture event has occurred. This class should only be used with
|
||||
* {@link MotionEvent}s reported via touch. To use this class:
|
||||
* <ul>
|
||||
* <li>Create an instance of the {@code ScaleGestureDetector} for your
|
||||
* {@link View}
|
||||
* <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call
|
||||
* {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback will
|
||||
* be executed when the events occur.
|
||||
* </ul>
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.ECLAIR)
|
||||
public class ScaleGestureDetector {
|
||||
/**
|
||||
* This value is the threshold ratio between our previous combined pressure
|
||||
* and the current combined pressure. We will only fire an onScale event if
|
||||
* the computed ratio between the current and previous event pressures is
|
||||
* greater than this value. When pressure decreases rapidly between events
|
||||
* the position values can often be imprecise, as it usually indicates that
|
||||
* the user is in the process of lifting a pointer off of the device. Its
|
||||
* value was tuned experimentally.
|
||||
*/
|
||||
private static final float PRESSURE_THRESHOLD = 0.67f;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private final OnScaleGestureListener mListener;
|
||||
|
||||
private boolean mGestureInProgress;
|
||||
private MotionEvent mPrevEvent;
|
||||
private MotionEvent mCurrEvent;
|
||||
|
||||
private float mFocusX;
|
||||
private float mFocusY;
|
||||
|
||||
private float mPrevFingerDiffX;
|
||||
private float mPrevFingerDiffY;
|
||||
private float mCurrFingerDiffX;
|
||||
private float mCurrFingerDiffY;
|
||||
private float mCurrLen;
|
||||
private float mPrevLen;
|
||||
private float mScaleFactor;
|
||||
private float mCurrPressure;
|
||||
private float mPrevPressure;
|
||||
private long mTimeDelta;
|
||||
private final float mEdgeSlop;
|
||||
private float mRightSlopEdge;
|
||||
|
||||
private float mBottomSlopEdge;
|
||||
private boolean mSloppyGesture;
|
||||
|
||||
public ScaleGestureDetector(final Context context, final OnScaleGestureListener listener) {
|
||||
final ViewConfiguration config = ViewConfiguration.get(context);
|
||||
mContext = context;
|
||||
mListener = listener;
|
||||
mEdgeSlop = config.getScaledEdgeSlop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current distance between the two pointers forming the gesture
|
||||
* in progress.
|
||||
*
|
||||
* @return Distance between pointers in pixels.
|
||||
*/
|
||||
public float getCurrentSpan() {
|
||||
if (mCurrLen == -1) {
|
||||
final float cvx = mCurrFingerDiffX;
|
||||
final float cvy = mCurrFingerDiffY;
|
||||
mCurrLen = FloatMath.sqrt(cvx * cvx + cvy * cvy);
|
||||
}
|
||||
return mCurrLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event time of the current event being processed.
|
||||
*
|
||||
* @return Current event time in milliseconds.
|
||||
*/
|
||||
public long getEventTime() {
|
||||
return mCurrEvent.getEventTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X coordinate of the current gesture's focal point. If a gesture
|
||||
* is in progress, the focal point is directly between the two pointers
|
||||
* forming the gesture. If a gesture is ending, the focal point is the
|
||||
* location of the remaining pointer on the screen. If
|
||||
* {@link #isInProgress()} would return false, the result of this function
|
||||
* is undefined.
|
||||
*
|
||||
* @return X coordinate of the focal point in pixels.
|
||||
*/
|
||||
public float getFocusX() {
|
||||
return mFocusX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y coordinate of the current gesture's focal point. If a gesture
|
||||
* is in progress, the focal point is directly between the two pointers
|
||||
* forming the gesture. If a gesture is ending, the focal point is the
|
||||
* location of the remaining pointer on the screen. If
|
||||
* {@link #isInProgress()} would return false, the result of this function
|
||||
* is undefined.
|
||||
*
|
||||
* @return Y coordinate of the focal point in pixels.
|
||||
*/
|
||||
public float getFocusY() {
|
||||
return mFocusY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the previous distance between the two pointers forming the gesture
|
||||
* in progress.
|
||||
*
|
||||
* @return Previous distance between pointers in pixels.
|
||||
*/
|
||||
public float getPreviousSpan() {
|
||||
if (mPrevLen == -1) {
|
||||
final float pvx = mPrevFingerDiffX;
|
||||
final float pvy = mPrevFingerDiffY;
|
||||
mPrevLen = FloatMath.sqrt(pvx * pvx + pvy * pvy);
|
||||
}
|
||||
return mPrevLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scaling factor from the previous scale event to the current
|
||||
* event. This value is defined as ({@link #getCurrentSpan()} /
|
||||
* {@link #getPreviousSpan()}).
|
||||
*
|
||||
* @return The current scaling factor.
|
||||
*/
|
||||
public float getScaleFactor() {
|
||||
if (mScaleFactor == -1) {
|
||||
mScaleFactor = getCurrentSpan() / getPreviousSpan();
|
||||
}
|
||||
return mScaleFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time difference in milliseconds between the previous accepted
|
||||
* scaling event and the current scaling event.
|
||||
*
|
||||
* @return Time difference since the last scaling event in milliseconds.
|
||||
*/
|
||||
public long getTimeDelta() {
|
||||
return mTimeDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a two-finger scale gesture is in progress.
|
||||
*
|
||||
* @return {@code true} if a scale gesture is in progress, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isInProgress() {
|
||||
return mGestureInProgress;
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(final MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
final boolean handled = true;
|
||||
|
||||
if (!mGestureInProgress) {
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN: {
|
||||
// We have a new multi-finger gesture
|
||||
|
||||
// as orientation can change, query the metrics in touch
|
||||
// down
|
||||
final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
|
||||
mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
|
||||
mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
|
||||
|
||||
// Be paranoid in case we missed an event
|
||||
reset();
|
||||
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
mTimeDelta = 0;
|
||||
|
||||
setContext(event);
|
||||
|
||||
// Check if we have a sloppy gesture. If so, delay
|
||||
// the beginning of the gesture until we're sure that's
|
||||
// what the user wanted. Sloppy gestures can happen if the
|
||||
// edge of the user's hand is touching the screen, for
|
||||
// example.
|
||||
final float edgeSlop = mEdgeSlop;
|
||||
final float rightSlop = mRightSlopEdge;
|
||||
final float bottomSlop = mBottomSlopEdge;
|
||||
final float x0 = event.getRawX();
|
||||
final float y0 = event.getRawY();
|
||||
final float x1 = getRawX(event, 1);
|
||||
final float y1 = getRawY(event, 1);
|
||||
|
||||
final boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop;
|
||||
final boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop;
|
||||
|
||||
if (p0sloppy && p1sloppy) {
|
||||
mFocusX = -1;
|
||||
mFocusY = -1;
|
||||
mSloppyGesture = true;
|
||||
} else if (p0sloppy) {
|
||||
mFocusX = MotionEventCompat.getX(event, 1);
|
||||
mFocusY = MotionEventCompat.getY(event, 1);
|
||||
mSloppyGesture = true;
|
||||
} else if (p1sloppy) {
|
||||
mFocusX = MotionEventCompat.getX(event, 0);
|
||||
mFocusY = MotionEventCompat.getY(event, 0);
|
||||
mSloppyGesture = true;
|
||||
} else {
|
||||
mGestureInProgress = mListener.onScaleBegin(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mSloppyGesture) {
|
||||
// Initiate sloppy gestures if we've moved outside of
|
||||
// the slop area.
|
||||
final float edgeSlop = mEdgeSlop;
|
||||
final float rightSlop = mRightSlopEdge;
|
||||
final float bottomSlop = mBottomSlopEdge;
|
||||
final float x0 = event.getRawX();
|
||||
final float y0 = event.getRawY();
|
||||
final float x1 = getRawX(event, 1);
|
||||
final float y1 = getRawY(event, 1);
|
||||
|
||||
final boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop;
|
||||
final boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop;
|
||||
|
||||
if (p0sloppy && p1sloppy) {
|
||||
mFocusX = -1;
|
||||
mFocusY = -1;
|
||||
} else if (p0sloppy) {
|
||||
mFocusX = MotionEventCompat.getX(event, 1);
|
||||
mFocusY = MotionEventCompat.getY(event, 1);
|
||||
} else if (p1sloppy) {
|
||||
mFocusX = MotionEventCompat.getX(event, 0);
|
||||
mFocusY = MotionEventCompat.getY(event, 0);
|
||||
} else {
|
||||
mSloppyGesture = false;
|
||||
mGestureInProgress = mListener.onScaleBegin(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (mSloppyGesture) {
|
||||
// Set focus point to the remaining finger
|
||||
final int id = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT == 0 ? 1
|
||||
: 0;
|
||||
mFocusX = event.getX(id);
|
||||
mFocusY = event.getY(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Transform gesture in progress - attempt to handle it
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
// Gesture ended
|
||||
setContext(event);
|
||||
|
||||
// Set focus point to the remaining finger
|
||||
final int id = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT == 0 ? 1
|
||||
: 0;
|
||||
mFocusX = event.getX(id);
|
||||
mFocusY = event.getY(id);
|
||||
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onScaleEnd(this);
|
||||
}
|
||||
|
||||
reset();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onScaleEnd(this);
|
||||
}
|
||||
|
||||
reset();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
setContext(event);
|
||||
|
||||
// Only accept the event if our relative pressure is within
|
||||
// a certain limit - this can help filter shaky data as a
|
||||
// finger is lifted.
|
||||
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
|
||||
final boolean updatePrevious = mListener.onScale(this);
|
||||
|
||||
if (updatePrevious) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
if (mPrevEvent != null) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = null;
|
||||
}
|
||||
if (mCurrEvent != null) {
|
||||
mCurrEvent.recycle();
|
||||
mCurrEvent = null;
|
||||
}
|
||||
mSloppyGesture = false;
|
||||
mGestureInProgress = false;
|
||||
}
|
||||
|
||||
private void setContext(final MotionEvent curr) {
|
||||
if (mCurrEvent != null) {
|
||||
mCurrEvent.recycle();
|
||||
}
|
||||
mCurrEvent = MotionEvent.obtain(curr);
|
||||
|
||||
mCurrLen = -1;
|
||||
mPrevLen = -1;
|
||||
mScaleFactor = -1;
|
||||
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
|
||||
final float px0 = prev.getX(0);
|
||||
final float py0 = prev.getY(0);
|
||||
final float px1 = prev.getX(1);
|
||||
final float py1 = prev.getY(1);
|
||||
final float cx0 = curr.getX(0);
|
||||
final float cy0 = curr.getY(0);
|
||||
final float cx1 = curr.getX(1);
|
||||
final float cy1 = curr.getY(1);
|
||||
|
||||
final float pvx = px1 - px0;
|
||||
final float pvy = py1 - py0;
|
||||
final float cvx = cx1 - cx0;
|
||||
final float cvy = cy1 - cy0;
|
||||
mPrevFingerDiffX = pvx;
|
||||
mPrevFingerDiffY = pvy;
|
||||
mCurrFingerDiffX = cvx;
|
||||
mCurrFingerDiffY = cvy;
|
||||
|
||||
mFocusX = cx0 + cvx * 0.5f;
|
||||
mFocusY = cy0 + cvy * 0.5f;
|
||||
mTimeDelta = curr.getEventTime() - prev.getEventTime();
|
||||
mCurrPressure = curr.getPressure(0) + curr.getPressure(1);
|
||||
mPrevPressure = prev.getPressure(0) + prev.getPressure(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* MotionEvent has no getRawX(int) method; simulate it pending future API
|
||||
* approval.
|
||||
*/
|
||||
private static float getRawX(final MotionEvent event, final int pointerIndex) {
|
||||
final float offset = event.getX() - event.getRawX();
|
||||
return event.getX(pointerIndex) + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* MotionEvent has no getRawY(int) method; simulate it pending future API
|
||||
* approval.
|
||||
*/
|
||||
private static float getRawY(final MotionEvent event, final int pointerIndex) {
|
||||
final float offset = event.getY() - event.getRawY();
|
||||
return event.getY(pointerIndex) + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener for receiving notifications when gestures occur. If you want
|
||||
* to listen for all the different gestures then implement this interface.
|
||||
* If you only want to listen for a subset it might be easier to extend
|
||||
* {@link SimpleOnScaleGestureListener}. An application will receive events
|
||||
* in the following order:
|
||||
* <ul>
|
||||
* <li>One {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)}
|
||||
* <li>Zero or more
|
||||
* {@link OnScaleGestureListener#onScale(ScaleGestureDetector)}
|
||||
* <li>One {@link OnScaleGestureListener#onScaleEnd(ScaleGestureDetector)}
|
||||
* </ul>
|
||||
*/
|
||||
public static interface OnScaleGestureListener {
|
||||
/**
|
||||
* Responds to scaling events for a gesture in progress. Reported by
|
||||
* pointer motion.
|
||||
*
|
||||
* @param detector The detector reporting the event - use this to
|
||||
* retrieve extended info about event state.
|
||||
* @return Whether or not the detector should consider this event as
|
||||
* handled. If an event was not handled, the detector will
|
||||
* continue to accumulate movement until an event is handled.
|
||||
* This can be useful if an application, for example, only wants
|
||||
* to update scaling factors if the change is greater than 0.01.
|
||||
*/
|
||||
public boolean onScale(ScaleGestureDetector detector);
|
||||
|
||||
/**
|
||||
* Responds to the beginning of a scaling gesture. Reported by new
|
||||
* pointers going down.
|
||||
*
|
||||
* @param detector The detector reporting the event - use this to
|
||||
* retrieve extended info about event state.
|
||||
* @return Whether or not the detector should continue recognizing this
|
||||
* gesture. For example, if a gesture is beginning with a focal
|
||||
* point outside of a region where it makes sense,
|
||||
* onScaleBegin() may return false to ignore the rest of the
|
||||
* gesture.
|
||||
*/
|
||||
public boolean onScaleBegin(ScaleGestureDetector detector);
|
||||
|
||||
/**
|
||||
* Responds to the end of a scale gesture. Reported by existing pointers
|
||||
* going up. Once a scale has ended,
|
||||
* {@link ScaleGestureDetector#getFocusX()} and
|
||||
* {@link ScaleGestureDetector#getFocusY()} will return the location of
|
||||
* the pointer remaining on the screen.
|
||||
*
|
||||
* @param detector The detector reporting the event - use this to
|
||||
* retrieve extended info about event state.
|
||||
*/
|
||||
public void onScaleEnd(ScaleGestureDetector detector);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience class to extend when you only want to listen for a subset
|
||||
* of scaling-related events. This implements all methods in
|
||||
* {@link OnScaleGestureListener} but does nothing.
|
||||
* {@link OnScaleGestureListener#onScale(ScaleGestureDetector)} returns
|
||||
* {@code false} so that a subclass can retrieve the accumulated scale
|
||||
* factor in an overridden onScaleEnd.
|
||||
* {@link OnScaleGestureListener#onScaleBegin(ScaleGestureDetector)} returns
|
||||
* {@code true}.
|
||||
*/
|
||||
public static class SimpleOnScaleGestureListener implements OnScaleGestureListener {
|
||||
|
||||
@Override
|
||||
public boolean onScale(final ScaleGestureDetector detector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScaleBegin(final ScaleGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScaleEnd(final ScaleGestureDetector detector) {
|
||||
// Intentionally empty
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package it.sephiroth.android.library.imagezoom.easing;
|
||||
|
||||
public class Cubic implements Easing {
|
||||
|
||||
@Override
|
||||
public double easeIn(double time, final double start, final double end, final double duration) {
|
||||
return end * (time /= duration) * time * time + start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double easeInOut(double time, final double start, final double end, final double duration) {
|
||||
if ((time /= duration / 2.0) < 1.0) return end / 2.0 * time * time * time + start;
|
||||
return end / 2.0 * ((time -= 2.0) * time * time + 2.0) + start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double easeOut(double time, final double start, final double end, final double duration) {
|
||||
return end * ((time = time / duration - 1.0) * time * time + 1.0) + start;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package it.sephiroth.android.library.imagezoom.easing;
|
||||
|
||||
public interface Easing {
|
||||
|
||||
double easeIn(double time, double start, double end, double duration);
|
||||
|
||||
double easeInOut(double time, double start, double end, double duration);
|
||||
|
||||
double easeOut(double time, double start, double end, double duration);
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
package it.sephiroth.android.library.imagezoom.graphics;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Fast bitmap drawable. Does not support states. it only support alpha and
|
||||
* colormatrix
|
||||
*
|
||||
* @author alessandro
|
||||
*/
|
||||
public class FastBitmapDrawable extends Drawable implements IBitmapDrawable {
|
||||
|
||||
protected Bitmap mBitmap;
|
||||
protected Paint mPaint;
|
||||
|
||||
public FastBitmapDrawable(final Bitmap b) {
|
||||
mBitmap = b;
|
||||
mPaint = new Paint();
|
||||
mPaint.setDither(true);
|
||||
mPaint.setFilterBitmap(true);
|
||||
}
|
||||
|
||||
public FastBitmapDrawable(final Resources res, final InputStream is) {
|
||||
this(BitmapFactory.decodeStream(is));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(final Canvas canvas) {
|
||||
canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap() {
|
||||
return mBitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return mBitmap.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mBitmap.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumHeight() {
|
||||
return mBitmap.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumWidth() {
|
||||
return mBitmap.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(final int alpha) {
|
||||
mPaint.setAlpha(alpha);
|
||||
}
|
||||
|
||||
public void setAntiAlias(final boolean value) {
|
||||
mPaint.setAntiAlias(value);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(final ColorFilter cf) {
|
||||
mPaint.setColorFilter(cf);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package it.sephiroth.android.library.imagezoom.graphics;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import it.sephiroth.android.library.imagezoom.ImageViewTouchBase;
|
||||
|
||||
/**
|
||||
* Base interface used in the {@link ImageViewTouchBase} view
|
||||
*
|
||||
* @author alessandro
|
||||
*/
|
||||
public interface IBitmapDrawable {
|
||||
|
||||
Bitmap getBitmap();
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package it.sephiroth.android.library.imagezoom.utils;
|
||||
|
||||
public interface IDisposable {
|
||||
|
||||
void dispose();
|
||||
}
|
|
@ -335,7 +335,7 @@ public class SwipeBackLayout extends FrameLayout {
|
|||
* Set a drawable used for edge shadow.
|
||||
*
|
||||
* @param shadow Drawable to use
|
||||
* @param edgeFlags Combination of edge flags describing the edge to set
|
||||
* @param edgeFlag Combination of edge flags describing the edge to set
|
||||
* @see #EDGE_LEFT
|
||||
* @see #EDGE_RIGHT
|
||||
* @see #EDGE_BOTTOM
|
||||
|
@ -355,7 +355,7 @@ public class SwipeBackLayout extends FrameLayout {
|
|||
* Set a drawable used for edge shadow.
|
||||
*
|
||||
* @param resId Resource of drawable to use
|
||||
* @param edgeFlags Combination of edge flags describing the edge to set
|
||||
* @param edgeFlag Combination of edge flags describing the edge to set
|
||||
* @see #EDGE_LEFT
|
||||
* @see #EDGE_RIGHT
|
||||
* @see #EDGE_BOTTOM
|
||||
|
|
|
@ -19,16 +19,12 @@
|
|||
|
||||
package org.mariotaku.twidere.activity;
|
||||
|
||||
import static org.mariotaku.twidere.util.ContentValuesCreator.makeFilterdUserContentValues;
|
||||
import static org.mariotaku.twidere.util.Utils.getDefaultAccountId;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.ActionBar.Tab;
|
||||
import android.app.ActionBar.TabListener;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.app.Dialog;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
|
@ -39,6 +35,7 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v4.view.ViewPager.OnPageChangeListener;
|
||||
import android.support.v4.widget.SimpleCursorAdapter;
|
||||
|
@ -50,227 +47,231 @@ import android.widget.AutoCompleteTextView;
|
|||
|
||||
import org.mariotaku.querybuilder.Where;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.activity.support.BaseSupportActivity;
|
||||
import org.mariotaku.twidere.activity.support.UserListSelectorActivity;
|
||||
import org.mariotaku.twidere.adapter.SourceAutoCompleteAdapter;
|
||||
import org.mariotaku.twidere.adapter.TabsAdapter;
|
||||
import org.mariotaku.twidere.adapter.UserHashtagAutoCompleteAdapter;
|
||||
import org.mariotaku.twidere.fragment.BaseDialogFragment;
|
||||
import org.mariotaku.twidere.adapter.support.SupportTabsAdapter;
|
||||
import org.mariotaku.twidere.fragment.BaseFiltersFragment;
|
||||
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredKeywordsFragment;
|
||||
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredLinksFragment;
|
||||
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredSourcesFragment;
|
||||
import org.mariotaku.twidere.fragment.BaseFiltersFragment.FilteredUsersFragment;
|
||||
import org.mariotaku.twidere.fragment.support.BaseSupportDialogFragment;
|
||||
import org.mariotaku.twidere.model.ParcelableUser;
|
||||
import org.mariotaku.twidere.provider.TweetStore.Filters;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
|
||||
public class FiltersActivity extends BaseActivity implements TabListener, OnPageChangeListener {
|
||||
import static org.mariotaku.twidere.util.ContentValuesCreator.makeFilterdUserContentValues;
|
||||
import static org.mariotaku.twidere.util.Utils.getDefaultAccountId;
|
||||
|
||||
private static final String EXTRA_AUTO_COMPLETE_TYPE = "auto_complete_type";
|
||||
private static final int AUTO_COMPLETE_TYPE_SOURCES = 2;
|
||||
public class FiltersActivity extends BaseSupportActivity implements TabListener, OnPageChangeListener {
|
||||
|
||||
private ViewPager mViewPager;
|
||||
private TabsAdapter mAdapter;
|
||||
private static final String EXTRA_AUTO_COMPLETE_TYPE = "auto_complete_type";
|
||||
private static final int AUTO_COMPLETE_TYPE_SOURCES = 2;
|
||||
|
||||
private ActionBar mActionBar;
|
||||
private SharedPreferences mPreferences;
|
||||
private ViewPager mViewPager;
|
||||
private SupportTabsAdapter mAdapter;
|
||||
|
||||
@Override
|
||||
public void onContentChanged() {
|
||||
mViewPager = (ViewPager) findViewById(R.id.pager);
|
||||
}
|
||||
private ActionBar mActionBar;
|
||||
private SharedPreferences mPreferences;
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
|
||||
setContentView(R.layout.activity_filters);
|
||||
mActionBar = getActionBar();
|
||||
mAdapter = new TabsAdapter(this, getFragmentManager(), null);
|
||||
mActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
addTab(FilteredUsersFragment.class, R.string.users, 0);
|
||||
addTab(FilteredKeywordsFragment.class, R.string.keywords, 1);
|
||||
addTab(FilteredSourcesFragment.class, R.string.sources, 2);
|
||||
addTab(FilteredLinksFragment.class, R.string.links, 3);
|
||||
mViewPager.setAdapter(mAdapter);
|
||||
mViewPager.setOnPageChangeListener(this);
|
||||
}
|
||||
@Override
|
||||
public void onContentChanged() {
|
||||
mViewPager = (ViewPager) findViewById(R.id.pager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_filters, menu);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
|
||||
setContentView(R.layout.activity_filters);
|
||||
mActionBar = getActionBar();
|
||||
mAdapter = new SupportTabsAdapter(this, getSupportFragmentManager(), null);
|
||||
mActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
addTab(FilteredUsersFragment.class, R.string.users, 0);
|
||||
addTab(FilteredKeywordsFragment.class, R.string.keywords, 1);
|
||||
addTab(FilteredSourcesFragment.class, R.string.sources, 2);
|
||||
addTab(FilteredLinksFragment.class, R.string.links, 3);
|
||||
mViewPager.setAdapter(mAdapter);
|
||||
mViewPager.setOnPageChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_HOME: {
|
||||
navigateUpFromSameTask();
|
||||
return true;
|
||||
}
|
||||
case MENU_ADD: {
|
||||
final Fragment f = mAdapter.getItem(mViewPager.getCurrentItem());
|
||||
if (!(f instanceof BaseFiltersFragment)) return true;
|
||||
final Bundle args = new Bundle();
|
||||
if (f instanceof FilteredUsersFragment) {
|
||||
final Intent intent = new Intent(INTENT_ACTION_SELECT_USER);
|
||||
intent.setClass(this, UserListSelectorActivity.class);
|
||||
intent.putExtra(EXTRA_ACCOUNT_ID, getDefaultAccountId(this));
|
||||
startActivityForResult(intent, REQUEST_SELECT_USER);
|
||||
return true;
|
||||
}
|
||||
if (f instanceof FilteredSourcesFragment) {
|
||||
args.putInt(EXTRA_AUTO_COMPLETE_TYPE, AUTO_COMPLETE_TYPE_SOURCES);
|
||||
}
|
||||
args.putParcelable(EXTRA_URI, ((BaseFiltersFragment) f).getContentUri());
|
||||
final AddItemFragment dialog = new AddItemFragment();
|
||||
dialog.setArguments(args);
|
||||
dialog.show(getFragmentManager(), "add_rule");
|
||||
return true;
|
||||
}
|
||||
case R.id.enable_in_home_timeline: {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean(KEY_FILTERS_IN_HOME_TIMELINE, !item.isChecked());
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
case R.id.enable_in_mentions: {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean(KEY_FILTERS_IN_MENTIONS, !item.isChecked());
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
case R.id.enable_for_rts: {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean(KEY_FILTERS_FOR_RTS, !item.isChecked());
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_filters, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_HOME: {
|
||||
navigateUpFromSameTask();
|
||||
return true;
|
||||
}
|
||||
case MENU_ADD: {
|
||||
final Fragment f = mAdapter.getItem(mViewPager.getCurrentItem());
|
||||
if (!(f instanceof BaseFiltersFragment)) return true;
|
||||
final Bundle args = new Bundle();
|
||||
if (f instanceof FilteredUsersFragment) {
|
||||
final Intent intent = new Intent(INTENT_ACTION_SELECT_USER);
|
||||
intent.setClass(this, UserListSelectorActivity.class);
|
||||
intent.putExtra(EXTRA_ACCOUNT_ID, getDefaultAccountId(this));
|
||||
startActivityForResult(intent, REQUEST_SELECT_USER);
|
||||
return true;
|
||||
}
|
||||
if (f instanceof FilteredSourcesFragment) {
|
||||
args.putInt(EXTRA_AUTO_COMPLETE_TYPE, AUTO_COMPLETE_TYPE_SOURCES);
|
||||
}
|
||||
args.putParcelable(EXTRA_URI, ((BaseFiltersFragment) f).getContentUri());
|
||||
final AddItemFragment dialog = new AddItemFragment();
|
||||
dialog.setArguments(args);
|
||||
dialog.show(getSupportFragmentManager(), "add_rule");
|
||||
return true;
|
||||
}
|
||||
case R.id.enable_in_home_timeline: {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean(KEY_FILTERS_IN_HOME_TIMELINE, !item.isChecked());
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
case R.id.enable_in_mentions: {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean(KEY_FILTERS_IN_MENTIONS, !item.isChecked());
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
case R.id.enable_for_rts: {
|
||||
final SharedPreferences.Editor editor = mPreferences.edit();
|
||||
editor.putBoolean(KEY_FILTERS_FOR_RTS, !item.isChecked());
|
||||
editor.apply();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(final int state) {
|
||||
@Override
|
||||
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onPageScrollStateChanged(final int state) {
|
||||
|
||||
@Override
|
||||
public void onPageSelected(final int position) {
|
||||
if (mActionBar == null) return;
|
||||
mActionBar.setSelectedNavigationItem(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(final Menu menu) {
|
||||
final boolean enable_in_home_timeline = mPreferences.getBoolean(KEY_FILTERS_IN_HOME_TIMELINE, true);
|
||||
final boolean enable_in_mentions = mPreferences.getBoolean(KEY_FILTERS_IN_MENTIONS, true);
|
||||
final boolean enable_for_rts = mPreferences.getBoolean(KEY_FILTERS_FOR_RTS, true);
|
||||
menu.findItem(R.id.enable_in_home_timeline).setChecked(enable_in_home_timeline);
|
||||
menu.findItem(R.id.enable_in_mentions).setChecked(enable_in_mentions);
|
||||
menu.findItem(R.id.enable_for_rts).setChecked(enable_for_rts);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void onPageSelected(final int position) {
|
||||
if (mActionBar == null) return;
|
||||
mActionBar.setSelectedNavigationItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(final Tab tab, final FragmentTransaction ft) {
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(final Menu menu) {
|
||||
final boolean enable_in_home_timeline = mPreferences.getBoolean(KEY_FILTERS_IN_HOME_TIMELINE, true);
|
||||
final boolean enable_in_mentions = mPreferences.getBoolean(KEY_FILTERS_IN_MENTIONS, true);
|
||||
final boolean enable_for_rts = mPreferences.getBoolean(KEY_FILTERS_FOR_RTS, true);
|
||||
menu.findItem(R.id.enable_in_home_timeline).setChecked(enable_in_home_timeline);
|
||||
menu.findItem(R.id.enable_in_mentions).setChecked(enable_in_mentions);
|
||||
menu.findItem(R.id.enable_for_rts).setChecked(enable_for_rts);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onTabReselected(final Tab tab, final FragmentTransaction ft) {
|
||||
|
||||
@Override
|
||||
public void onTabSelected(final Tab tab, final FragmentTransaction ft) {
|
||||
mViewPager.setCurrentItem(tab.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(final Tab tab, final FragmentTransaction ft) {
|
||||
@Override
|
||||
public void onTabSelected(final Tab tab, final FragmentTransaction ft) {
|
||||
mViewPager.setCurrentItem(tab.getPosition());
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onTabUnselected(final Tab tab, final FragmentTransaction ft) {
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_SELECT_USER: {
|
||||
final Fragment filter = mAdapter.getItem(mViewPager.getCurrentItem());
|
||||
if (resultCode != RESULT_OK || !(filter instanceof FilteredUsersFragment) || !data.hasExtra(EXTRA_USER))
|
||||
return;
|
||||
final ParcelableUser user = data.getParcelableExtra(EXTRA_USER);
|
||||
final ContentValues values = makeFilterdUserContentValues(user);
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
resolver.delete(Filters.Users.CONTENT_URI, Where.equals(Filters.Users.USER_ID, user.id).getSQL(), null);
|
||||
resolver.insert(Filters.Users.CONTENT_URI, values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addTab(final Class<? extends Fragment> cls, final int name, final int position) {
|
||||
if (mActionBar == null || mAdapter == null) return;
|
||||
mActionBar.addTab(mActionBar.newTab().setText(name).setTabListener(this));
|
||||
mAdapter.addTab(cls, null, getString(name), null, position);
|
||||
}
|
||||
@Override
|
||||
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_SELECT_USER: {
|
||||
final Fragment filter = mAdapter.getItem(mViewPager.getCurrentItem());
|
||||
if (resultCode != RESULT_OK || !(filter instanceof FilteredUsersFragment) || !data.hasExtra(EXTRA_USER))
|
||||
return;
|
||||
final ParcelableUser user = data.getParcelableExtra(EXTRA_USER);
|
||||
final ContentValues values = makeFilterdUserContentValues(user);
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
resolver.delete(Filters.Users.CONTENT_URI, Where.equals(Filters.Users.USER_ID, user.id).getSQL(), null);
|
||||
resolver.insert(Filters.Users.CONTENT_URI, values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class AddItemFragment extends BaseDialogFragment implements OnClickListener {
|
||||
private void addTab(final Class<? extends Fragment> cls, final int name, final int position) {
|
||||
if (mActionBar == null || mAdapter == null) return;
|
||||
mActionBar.addTab(mActionBar.newTab().setText(name).setTabListener(this));
|
||||
mAdapter.addTab(cls, null, getString(name), null, position);
|
||||
}
|
||||
|
||||
private AutoCompleteTextView mEditText;
|
||||
public static final class AddItemFragment extends BaseSupportDialogFragment implements OnClickListener {
|
||||
|
||||
private SimpleCursorAdapter mUserAutoCompleteAdapter;
|
||||
private AutoCompleteTextView mEditText;
|
||||
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_POSITIVE:
|
||||
if (mEditText.length() <= 0) return;
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(Filters.VALUE, getText());
|
||||
final Bundle args = getArguments();
|
||||
final Uri uri = args.getParcelable(EXTRA_URI);
|
||||
getContentResolver().insert(uri, values);
|
||||
break;
|
||||
}
|
||||
private SimpleCursorAdapter mUserAutoCompleteAdapter;
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_POSITIVE:
|
||||
if (mEditText.length() <= 0) return;
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(Filters.VALUE, getText());
|
||||
final Bundle args = getArguments();
|
||||
final Uri uri = args.getParcelable(EXTRA_URI);
|
||||
getContentResolver().insert(uri, values);
|
||||
break;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
|
||||
buildDialog(builder);
|
||||
final View view = LayoutInflater.from(wrapped).inflate(R.layout.auto_complete_textview, null);
|
||||
builder.setView(view);
|
||||
mEditText = (AutoCompleteTextView) view.findViewById(R.id.edit_text);
|
||||
final Bundle args = getArguments();
|
||||
final int auto_complete_type = args != null ? args.getInt(EXTRA_AUTO_COMPLETE_TYPE, 0) : 0;
|
||||
if (auto_complete_type != 0) {
|
||||
if (auto_complete_type == AUTO_COMPLETE_TYPE_SOURCES) {
|
||||
mUserAutoCompleteAdapter = new SourceAutoCompleteAdapter(getActivity());
|
||||
} else {
|
||||
mUserAutoCompleteAdapter = new UserHashtagAutoCompleteAdapter(getActivity());
|
||||
}
|
||||
mEditText.setAdapter(mUserAutoCompleteAdapter);
|
||||
mEditText.setThreshold(1);
|
||||
}
|
||||
builder.setTitle(R.string.add_rule);
|
||||
builder.setPositiveButton(android.R.string.ok, this);
|
||||
builder.setNegativeButton(android.R.string.cancel, this);
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
protected String getText() {
|
||||
return ParseUtils.parseString(mEditText.getText());
|
||||
}
|
||||
@Override
|
||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
|
||||
buildDialog(builder);
|
||||
final View view = LayoutInflater.from(wrapped).inflate(R.layout.auto_complete_textview, null);
|
||||
builder.setView(view);
|
||||
mEditText = (AutoCompleteTextView) view.findViewById(R.id.edit_text);
|
||||
final Bundle args = getArguments();
|
||||
final int auto_complete_type = args != null ? args.getInt(EXTRA_AUTO_COMPLETE_TYPE, 0) : 0;
|
||||
if (auto_complete_type != 0) {
|
||||
if (auto_complete_type == AUTO_COMPLETE_TYPE_SOURCES) {
|
||||
mUserAutoCompleteAdapter = new SourceAutoCompleteAdapter(getActivity());
|
||||
} else {
|
||||
mUserAutoCompleteAdapter = new UserHashtagAutoCompleteAdapter(getActivity());
|
||||
}
|
||||
mEditText.setAdapter(mUserAutoCompleteAdapter);
|
||||
mEditText.setThreshold(1);
|
||||
}
|
||||
builder.setTitle(R.string.add_rule);
|
||||
builder.setPositiveButton(android.R.string.ok, this);
|
||||
builder.setNegativeButton(android.R.string.cancel, this);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void buildDialog(final Builder builder) {
|
||||
// TODO Auto-generated method stub
|
||||
protected String getText() {
|
||||
return ParseUtils.parseString(mEditText.getText());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
private void buildDialog(final Builder builder) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
|
||||
package org.mariotaku.twidere.adapter.support;
|
||||
|
||||
import static org.mariotaku.twidere.util.CustomTabUtils.getTabIconDrawable;
|
||||
import static org.mariotaku.twidere.util.Utils.announceForAccessibilityCompat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
|
@ -39,105 +36,113 @@ import org.mariotaku.twidere.view.TabPageIndicator.TabProvider;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.mariotaku.twidere.util.CustomTabUtils.getTabIconDrawable;
|
||||
import static org.mariotaku.twidere.util.Utils.announceForAccessibilityCompat;
|
||||
|
||||
public class SupportTabsAdapter extends SupportFixedFragmentStatePagerAdapter implements TabProvider, TabListener,
|
||||
Constants {
|
||||
Constants {
|
||||
|
||||
private final ArrayList<SupportTabSpec> mTabs = new ArrayList<SupportTabSpec>();
|
||||
private final ArrayList<SupportTabSpec> mTabs = new ArrayList<SupportTabSpec>();
|
||||
|
||||
private final Context mContext;
|
||||
private final TabPageIndicator mIndicator;
|
||||
private final Context mContext;
|
||||
private final TabPageIndicator mIndicator;
|
||||
|
||||
private final int mColumns;
|
||||
private final int mColumns;
|
||||
|
||||
public SupportTabsAdapter(final Context context, final FragmentManager fm, final TabPageIndicator indicator,
|
||||
final int columns) {
|
||||
super(fm);
|
||||
mContext = context;
|
||||
mIndicator = indicator;
|
||||
mColumns = columns;
|
||||
clear();
|
||||
}
|
||||
public SupportTabsAdapter(final Context context, final FragmentManager fm, final TabPageIndicator indicator) {
|
||||
this(context, fm, indicator, 1);
|
||||
}
|
||||
|
||||
public void addTab(final Class<? extends Fragment> cls, final Bundle args, final String name, final Integer icon,
|
||||
final int position) {
|
||||
addTab(new SupportTabSpec(name, icon, cls, args, position));
|
||||
}
|
||||
public SupportTabsAdapter(final Context context, final FragmentManager fm, final TabPageIndicator indicator,
|
||||
final int columns) {
|
||||
super(fm);
|
||||
mContext = context;
|
||||
mIndicator = indicator;
|
||||
mColumns = columns;
|
||||
clear();
|
||||
}
|
||||
|
||||
public void addTab(final SupportTabSpec spec) {
|
||||
mTabs.add(spec);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void addTab(final Class<? extends Fragment> cls, final Bundle args, final String name, final Integer icon,
|
||||
final int position) {
|
||||
addTab(new SupportTabSpec(name, icon, cls, args, position));
|
||||
}
|
||||
|
||||
public void addTabs(final Collection<? extends SupportTabSpec> specs) {
|
||||
mTabs.addAll(specs);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void addTab(final SupportTabSpec spec) {
|
||||
mTabs.add(spec);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mTabs.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void addTabs(final Collection<? extends SupportTabSpec> specs) {
|
||||
mTabs.addAll(specs);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mTabs.size();
|
||||
}
|
||||
public void clear() {
|
||||
mTabs.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(final int position) {
|
||||
final Fragment fragment = Fragment.instantiate(mContext, mTabs.get(position).cls.getName());
|
||||
fragment.setArguments(mTabs.get(position).args);
|
||||
return fragment;
|
||||
}
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mTabs.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getPageIcon(final int position) {
|
||||
return getTabIconDrawable(mContext, mTabs.get(position).icon);
|
||||
}
|
||||
@Override
|
||||
public Fragment getItem(final int position) {
|
||||
final Fragment fragment = Fragment.instantiate(mContext, mTabs.get(position).cls.getName());
|
||||
fragment.setArguments(mTabs.get(position).args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(final int position) {
|
||||
return mTabs.get(position).name;
|
||||
}
|
||||
@Override
|
||||
public Drawable getPageIcon(final int position) {
|
||||
return getTabIconDrawable(mContext, mTabs.get(position).icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPageWidth(final int position) {
|
||||
return 1.0f / mColumns;
|
||||
}
|
||||
@Override
|
||||
public CharSequence getPageTitle(final int position) {
|
||||
return mTabs.get(position).name;
|
||||
}
|
||||
|
||||
public SupportTabSpec getTab(final int position) {
|
||||
return position >= 0 && position < mTabs.size() ? mTabs.get(position) : null;
|
||||
}
|
||||
@Override
|
||||
public float getPageWidth(final int position) {
|
||||
return 1.0f / mColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
super.notifyDataSetChanged();
|
||||
if (mIndicator != null) {
|
||||
mIndicator.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
public SupportTabSpec getTab(final int position) {
|
||||
return position >= 0 && position < mTabs.size() ? mTabs.get(position) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageReselected(final int position) {
|
||||
if (!(mContext instanceof SupportFragmentCallback)) return;
|
||||
final Fragment f = ((SupportFragmentCallback) mContext).getCurrentVisibleFragment();
|
||||
if (f instanceof RefreshScrollTopInterface) {
|
||||
((RefreshScrollTopInterface) f).scrollToStart();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
super.notifyDataSetChanged();
|
||||
if (mIndicator != null) {
|
||||
mIndicator.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(final int position) {
|
||||
if (mIndicator == null) return;
|
||||
announceForAccessibilityCompat(mContext, mIndicator, getPageTitle(position), getClass());
|
||||
}
|
||||
@Override
|
||||
public void onPageReselected(final int position) {
|
||||
if (!(mContext instanceof SupportFragmentCallback)) return;
|
||||
final Fragment f = ((SupportFragmentCallback) mContext).getCurrentVisibleFragment();
|
||||
if (f instanceof RefreshScrollTopInterface) {
|
||||
((RefreshScrollTopInterface) f).scrollToStart();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTabLongClick(final int position) {
|
||||
if (!(mContext instanceof SupportFragmentCallback)) return false;
|
||||
if (((SupportFragmentCallback) mContext).triggerRefresh(position)) return true;
|
||||
final Fragment f = ((SupportFragmentCallback) mContext).getCurrentVisibleFragment();
|
||||
if (f instanceof RefreshScrollTopInterface) return ((RefreshScrollTopInterface) f).triggerRefresh();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void onPageSelected(final int position) {
|
||||
if (mIndicator == null) return;
|
||||
announceForAccessibilityCompat(mContext, mIndicator, getPageTitle(position), getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTabLongClick(final int position) {
|
||||
if (!(mContext instanceof SupportFragmentCallback)) return false;
|
||||
if (((SupportFragmentCallback) mContext).triggerRefresh(position)) return true;
|
||||
final Fragment f = ((SupportFragmentCallback) mContext).getCurrentVisibleFragment();
|
||||
if (f instanceof RefreshScrollTopInterface)
|
||||
return ((RefreshScrollTopInterface) f).triggerRefresh();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,19 +21,19 @@ package org.mariotaku.twidere.fragment;
|
|||
|
||||
import static org.mariotaku.twidere.util.Utils.getDisplayName;
|
||||
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.CursorLoader;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.Loader;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -49,9 +49,10 @@ import org.mariotaku.querybuilder.Columns.Column;
|
|||
import org.mariotaku.querybuilder.RawItemArray;
|
||||
import org.mariotaku.querybuilder.Where;
|
||||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.fragment.support.BaseSupportListFragment;
|
||||
import org.mariotaku.twidere.provider.TweetStore.Filters;
|
||||
|
||||
public abstract class BaseFiltersFragment extends BaseListFragment implements LoaderCallbacks<Cursor>,
|
||||
public abstract class BaseFiltersFragment extends BaseSupportListFragment implements LoaderManager.LoaderCallbacks<Cursor>,
|
||||
MultiChoiceModeListener {
|
||||
|
||||
private ListView mListView;
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
|
||||
package org.mariotaku.twidere.service;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.service.dreams.DreamService;
|
||||
import android.view.View;
|
||||
import android.view.View.OnSystemUiVisibilityChangeListener;
|
||||
|
@ -30,6 +32,7 @@ import org.mariotaku.twidere.Constants;
|
|||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.view.NyanDaydreamView;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
public class NyanDaydreamService extends DreamService implements Constants, OnSharedPreferenceChangeListener,
|
||||
OnSystemUiVisibilityChangeListener {
|
||||
|
||||
|
|
|
@ -202,23 +202,18 @@ public final class TwidereLinkify implements Constants {
|
|||
* @param highlightColor
|
||||
* @param highlightOption
|
||||
* @param listener
|
||||
*
|
||||
* @param description TextView whose text is to be marked-up with links
|
||||
* @param pattern Regex pattern to be used for finding links
|
||||
* @param scheme Url scheme string (eg <code>http://</code> to be prepended
|
||||
* to the url of links that do not have a scheme specified in the
|
||||
* link text
|
||||
*
|
||||
*/
|
||||
private final void addLinks(final SpannableString string, final long account_id, final int type,
|
||||
private final void addLinks(final SpannableString string, final long accountId, final int type,
|
||||
final boolean sensitive, final OnLinkClickListener listener, final int highlightOption,
|
||||
final int highlightColor) {
|
||||
switch (type) {
|
||||
case LINK_TYPE_MENTION: {
|
||||
addMentionOrListLinks(string, account_id, listener, highlightOption, highlightColor);
|
||||
addMentionOrListLinks(string, accountId, listener, highlightOption, highlightColor);
|
||||
break;
|
||||
}
|
||||
case LINK_TYPE_HASHTAG: {
|
||||
addHashtagLinks(string, account_id, listener, highlightOption, highlightColor);
|
||||
addHashtagLinks(string, accountId, listener, highlightOption, highlightColor);
|
||||
break;
|
||||
}
|
||||
case LINK_TYPE_LINK: {
|
||||
|
@ -230,7 +225,7 @@ public final class TwidereLinkify implements Constants {
|
|||
continue;
|
||||
}
|
||||
string.removeSpan(span);
|
||||
applyLink(span.getURL(), start, end, string, account_id, LINK_TYPE_LINK, sensitive, listener,
|
||||
applyLink(span.getURL(), start, end, string, accountId, LINK_TYPE_LINK, sensitive, listener,
|
||||
highlightOption, highlightColor);
|
||||
}
|
||||
final List<Extractor.Entity> urls = mExtractor.extractURLsWithIndices(ParseUtils.parseString(string));
|
||||
|
@ -240,7 +235,7 @@ public final class TwidereLinkify implements Constants {
|
|||
|| string.getSpans(start, end, URLSpan.class).length > 0) {
|
||||
continue;
|
||||
}
|
||||
applyLink(entity.getValue(), start, end, string, account_id, LINK_TYPE_LINK, sensitive, listener,
|
||||
applyLink(entity.getValue(), start, end, string, accountId, LINK_TYPE_LINK, sensitive, listener,
|
||||
highlightOption, highlightColor);
|
||||
}
|
||||
break;
|
||||
|
@ -254,14 +249,14 @@ public final class TwidereLinkify implements Constants {
|
|||
final int end = string.getSpanEnd(span);
|
||||
final String url = matcherGroup(matcher, GROUP_ID_TWITTER_STATUS_STATUS_ID);
|
||||
string.removeSpan(span);
|
||||
applyLink(url, start, end, string, account_id, LINK_TYPE_STATUS, sensitive, listener,
|
||||
applyLink(url, start, end, string, accountId, LINK_TYPE_STATUS, sensitive, listener,
|
||||
highlightOption, highlightColor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LINK_TYPE_CASHTAG: {
|
||||
addCashtagLinks(string, account_id, listener, highlightOption, highlightColor);
|
||||
addCashtagLinks(string, accountId, listener, highlightOption, highlightColor);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
|
|
@ -21,10 +21,12 @@ package org.mariotaku.twidere.util.content;
|
|||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.CancellationSignal;
|
||||
|
||||
import org.mariotaku.twidere.util.ArrayUtils;
|
||||
|
@ -98,7 +100,8 @@ public class ContentResolverUtils {
|
|||
return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
|
||||
public static Cursor query(final ContentResolver resolver, final Uri uri, final String[] projection,
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
public static Cursor query(final ContentResolver resolver, final Uri uri, final String[] projection,
|
||||
final String selection, final String[] selectionArgs, final String sortOrder,
|
||||
final CancellationSignal cancellationSignal) {
|
||||
StrictModeUtils.checkDiskIO();
|
||||
|
|
|
@ -118,9 +118,6 @@ public final class CursorPaging {
|
|||
* This method also Validates the preset parameters, and throws
|
||||
* IllegalStateException if any unsupported parameter is set.
|
||||
*
|
||||
* @param supportedParams char array representation of supported parameters
|
||||
* @param perPageParamName name used for per-page parameter.
|
||||
* getUserListStatuses() requires "per_page" instead of "count".
|
||||
* @return list of PostParameter
|
||||
*/
|
||||
/* package */List<HttpParameter> asPostParameterList() {
|
||||
|
|
|
@ -175,7 +175,7 @@ public interface ListsResources {
|
|||
* This method calls http://api.twitter.com/1.1/lists/members.json
|
||||
*
|
||||
* @param listId The id of the list
|
||||
* @param cursor Breaks the results into pages. A single page contains 20
|
||||
* @param paging Breaks the results into pages. A single page contains 20
|
||||
* lists. Provide a value of -1 to begin paging. Provide values
|
||||
* as returned to in the response body's next_cursor and
|
||||
* previous_cursor attributes to page back and forth in the list.
|
||||
|
@ -359,7 +359,7 @@ public interface ListsResources {
|
|||
* This method calls http://api.twitter.com/1.1/lists/subscribers.json
|
||||
*
|
||||
* @param listId The id of the list
|
||||
* @param cursor Breaks the results into pages. A single page contains 20
|
||||
* @param paging Breaks the results into pages. A single page contains 20
|
||||
* lists. Provide a value of -1 to begin paging. Provide values
|
||||
* as returned to in the response body's next_cursor and
|
||||
* previous_cursor attributes to page back and forth in the list.
|
||||
|
|
|
@ -21,15 +21,13 @@ import java.util.Map;
|
|||
/**
|
||||
* Simple MBean interface for APIStatistics. Method-level statistics are exposed
|
||||
* as a Map of formatted strings
|
||||
*
|
||||
*
|
||||
* @author Nick Dellamaggiore (nick.dellamaggiore <at> gmail.com)
|
||||
* @see APIStatisticsOpenMBean for a dynamic version of this mbean with tabular
|
||||
* representation
|
||||
*/
|
||||
public interface APIStatisticsMBean extends InvocationStatistics {
|
||||
public Iterable<? extends InvocationStatistics> getInvocationStatistics();
|
||||
public Iterable<? extends InvocationStatistics> getInvocationStatistics();
|
||||
|
||||
public Map<String, String> getMethodLevelSummariesAsString();
|
||||
public Map<String, String> getMethodLevelSummariesAsString();
|
||||
|
||||
public String getMethodLevelSummary(String methodName);
|
||||
public String getMethodLevelSummary(String methodName);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<com.viewpagerindicator.CirclePageIndicator
|
||||
<org.mariotaku.twidere.view.LinePageIndicator
|
||||
android:id="@+id/search_pager_indicator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -444,7 +444,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Un regalet per a «chatterbox»</string>
|
||||
<string name="status_saved_to_draft">S\'ha desat la piulada com a esborrany.</string>
|
||||
<string name="default_account">Compte per defecte</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> piulada/es al dia)</string>
|
||||
<string name="empty_content">No hi ha contingut</string>
|
||||
<string name="fast_image_loading">Càrrega ràpida de les imatges</string>
|
||||
<string name="fast_image_loading_summary">Habilita-ho per a carregar més ràpidament les imatges, però inhabilita-ho si no se\'t mostra alguna imatge.</string>
|
||||
|
|
|
@ -445,7 +445,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Ein kleines Geschenk an die Chatterbox</string>
|
||||
<string name="status_saved_to_draft">Tweet als Entwurf gespeichert.</string>
|
||||
<string name="default_account">Standard-Account</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> Tweet(s) pro Tag)</string>
|
||||
<string name="empty_content">Leerer Inhalt</string>
|
||||
<string name="fast_image_loading">Schnelleres Bilder laden</string>
|
||||
<string name="fast_image_loading_summary">Aktivieren um Bilder schneller zu laden, deaktiveren falls einige Bilder nicht angezeigt werden können.</string>
|
||||
|
|
|
@ -447,7 +447,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Un pequeño regalo para chatterbox</string>
|
||||
<string name="status_saved_to_draft">Tuit salvado como borrador.</string>
|
||||
<string name="default_account">Cuenta predeterminada</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> tweet(s) por dia)</string>
|
||||
<string name="empty_content">Contenido vacío</string>
|
||||
<string name="fast_image_loading">Carga rápida de imágenes</string>
|
||||
<string name="fast_image_loading_summary">Habilitar para acelerar la carga de imágenes, deshabilitar si algunas imágenes no se muestran.</string>
|
||||
|
|
|
@ -447,7 +447,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Pieni lisä chatterboxiin</string>
|
||||
<string name="status_saved_to_draft">Twiitti tallennettu luonnoksiin.</string>
|
||||
<string name="default_account">Oletustili</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> twiittiä päivää kohden)</string>
|
||||
<string name="empty_content">Tyhjennä sisältö</string>
|
||||
<string name="fast_image_loading">Kuvien nopea lataus</string>
|
||||
<string name="fast_image_loading_summary">Ota käyttöön, jotta kuvat latautuvat nopeammin. Ota pois käytöstä, jos jotkin kuvat eivät näy.</string>
|
||||
|
|
|
@ -444,7 +444,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Un petit cadeau pour Chatterbox</string>
|
||||
<string name="status_saved_to_draft">Tweet sauvegardé dans les brouillons.</string>
|
||||
<string name="default_account">Compte par défault</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> tweet(s) par jour)</string>
|
||||
<string name="empty_content">Contenu vide</string>
|
||||
<string name="fast_image_loading">Chargement de l\'image rapide</string>
|
||||
<string name="fast_image_loading_summary">Activer pour permettre aux images de se charger plus rapidement, désactiver si des images ne s\'affichent pas.</string>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="profile_image_size" translatable="false">bigger</string>
|
||||
|
||||
</resources>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="profile_image_size">bigger</string>
|
||||
|
||||
</resources>
|
|
@ -444,7 +444,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Pemberian kecil untuk chatterbox</string>
|
||||
<string name="status_saved_to_draft">Twit disimpan di draf.</string>
|
||||
<string name="default_account">Pengguna utama</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> tweet per hari)</string>
|
||||
<string name="empty_content">Konten kosong</string>
|
||||
<string name="fast_image_loading">Memuat gambar dengan cepat</string>
|
||||
<string name="fast_image_loading_summary">Aktifkan untuk membuat gambar dimuat dengan cepat, nonaktifkan ini jika beberapa gambar tidak bisa ditampilkan.</string>
|
||||
|
|
|
@ -442,7 +442,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Un piccolo regalo per i chiacchieroni</string>
|
||||
<string name="status_saved_to_draft">Tweet salvato in bozze.</string>
|
||||
<string name="default_account">Account principale</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g>tweet al giorno)</string>
|
||||
<string name="empty_content">Contenuto vuoto</string>
|
||||
<string name="fast_image_loading">Caricamento veloce immagini</string>
|
||||
<string name="fast_image_loading_summary">Seleziona per far caricare più velocemente le immagini, disattivalo se alcune immagini non sono mostrate correttamente.</string>
|
||||
|
|
|
@ -447,7 +447,6 @@
|
|||
<string name="no_close_after_status_updated_summary">ツイート編集画面の動作を変更します。</string>
|
||||
<string name="status_saved_to_draft">ツイートは下書きに保存されました。</string>
|
||||
<string name="default_account">デフォルト</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (一日に平均<xliff:g id="daily_tweet">%2$d</xliff:g>回ツイート)</string>
|
||||
<string name="empty_content">コンテンツなし</string>
|
||||
<string name="fast_image_loading">高速画像読み込み</string>
|
||||
<string name="fast_image_loading_summary">有効にすると画像を高速に読み込みます。\n画像が読み込めない場合は無効にしてください。</string>
|
||||
|
|
|
@ -444,7 +444,6 @@
|
|||
<string name="no_close_after_status_updated_summary">트윗 입력창에 작은 특전이 있습니다.</string>
|
||||
<string name="status_saved_to_draft">트윗이 보관함에 저장되었습니다.</string>
|
||||
<string name="default_account">기본 계정</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (하루에 <xliff:g id="daily_tweet">%2$d</xliff:g> 트윗)</string>
|
||||
<string name="empty_content">내용 없음</string>
|
||||
<string name="fast_image_loading">빠른 이미지 불러오기</string>
|
||||
<string name="fast_image_loading_summary">이미지를 빨리 불러오려면 설정하고 이미지가 보이지 않으면 체크를 해재해 주십시오.</string>
|
||||
|
@ -529,7 +528,7 @@
|
|||
<string name="no_tab_hint">탭 없음</string>
|
||||
<string name="delete_user"><xliff:g id="name">%s</xliff:g>님을 삭제하기</string>
|
||||
<string name="delete_users">사용자 삭제하기</string>
|
||||
<string name="delete_user_confirm_message"> <xliff:g id="name">%s</xliff:g>?님을 삭제하겠습니까? 되돌릴 수 없습니다.</string>
|
||||
<string name="delete_user_confirm_message"> <xliff:g id="name">%s</xliff:g>님을 삭제하겠습니까? 되돌릴 수 없습니다.</string>
|
||||
<string name="toggle">토글</string>
|
||||
<string name="general">일반</string>
|
||||
<string name="hints">힌트</string>
|
||||
|
|
|
@ -444,7 +444,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Een klein cadeau voor chatterbox</string>
|
||||
<string name="status_saved_to_draft">Tweet opgeslagen als ontwerp.</string>
|
||||
<string name="default_account">Standaard account</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g>(<xliff:g id="daily_tweet">%2$d</xliff:g> tweet(s) per dag)</string>
|
||||
<string name="empty_content">Lege inhoud</string>
|
||||
<string name="fast_image_loading">Snel foto\'s laden</string>
|
||||
<string name="fast_image_loading_summary">Schakel in om foto\'s sneller te laten laden, schakel uit als sommige foto\'s niet worden weergegeven.</string>
|
||||
|
|
|
@ -442,7 +442,6 @@ Twidere używa znacznie prostszego mechanizmu logowania, bez otwierania okna prz
|
|||
<string name="no_close_after_status_updated_summary">Drobny prezent dla gaduł</string>
|
||||
<string name="status_saved_to_draft">Ćwierk zapisany jako szkic.</string>
|
||||
<string name="default_account">Domyślne konto</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> ćwierknięć na dzień)</string>
|
||||
<string name="empty_content">Pusta zawartość</string>
|
||||
<string name="fast_image_loading">Szybkie ładowanie obrazów</string>
|
||||
<string name="fast_image_loading_summary">Włącz aby ładować obrazy szybciej, wyłącz w przypadku błędów wyświetlania.</string>
|
||||
|
|
|
@ -449,7 +449,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Um presentinho para os tagarelas</string>
|
||||
<string name="status_saved_to_draft">Tweet salvo como rascunho.</string>
|
||||
<string name="default_account">Conta padrão</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> tweet(s) por dia)</string>
|
||||
<string name="empty_content">Nenhum conteúdo</string>
|
||||
<string name="fast_image_loading">Carregamento rápido de imagens</string>
|
||||
<string name="fast_image_loading_summary">Ative para fazer as imagens carregarem mais rápido, desative se alguma apresentar problemas ao carregar.</string>
|
||||
|
|
|
@ -447,7 +447,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Небольшой подарок для любителей поболтать</string>
|
||||
<string name="status_saved_to_draft">Твит сохранен в черновик.</string>
|
||||
<string name="default_account">Аккаунт по умолчанию</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g>(<xliff:g id="daily_tweet">%2$d</xliff:g>твитов за день)</string>
|
||||
<string name="empty_content">Пустое содержимое</string>
|
||||
<string name="fast_image_loading">Быстрая загрузка изображений</string>
|
||||
<string name="fast_image_loading_summary">Включите, для более быстрой загрузки изображений, отключите, если некоторые изображения не показываются.</string>
|
||||
|
|
|
@ -376,7 +376,6 @@
|
|||
<string name="ask">ถาม</string>
|
||||
<string name="status_saved_to_draft">บันทึกข้อความร่างแล้ว</string>
|
||||
<string name="default_account">บัญชีหลัก</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (ทวีต <xliff:g id="daily_tweet">%2$d</xliff:g> ต่อวัน)</string>
|
||||
<string name="select_user">เลือกผู้ใช้</string>
|
||||
<string name="add_to_list">เพิ่มไปยังรายการ</string>
|
||||
<string name="account_delete_confirm_title">ลบบัญชี</string>
|
||||
|
|
|
@ -444,7 +444,6 @@
|
|||
<string name="no_close_after_status_updated_summary">Маленький подарунок для базіки</string>
|
||||
<string name="status_saved_to_draft">Твіт збережено у чернетці.</string>
|
||||
<string name="default_account">Типовий профіль</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (<xliff:g id="daily_tweet">%2$d</xliff:g> твіт(ів) на день)</string>
|
||||
<string name="empty_content">Порожній вміст</string>
|
||||
<string name="fast_image_loading">Швидке завантаження зображення</string>
|
||||
<string name="fast_image_loading_summary">Вмикання робить завантаження зображень швидшим, вимкніть це, якщо деякі малюнки не відображаються.</string>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="profile_image_size" translatable="false">reasonably_small</string>
|
||||
|
||||
</resources>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="profile_image_size">reasonably_small</string>
|
||||
|
||||
</resources>
|
|
@ -444,7 +444,6 @@
|
|||
<string name="no_close_after_status_updated_summary">給不二的小禮物</string>
|
||||
<string name="status_saved_to_draft">推文已經儲存到草稿箱</string>
|
||||
<string name="default_account">預設帳號</string>
|
||||
<string name="daily_statuses_count"><xliff:g id="created_at">%1$s</xliff:g> (每天<xliff:g id="daily_tweet">%2$d</xliff:g>推)</string>
|
||||
<string name="empty_content">空內容</string>
|
||||
<string name="fast_image_loading">快速圖像載入</string>
|
||||
<string name="fast_image_loading_summary">啟用可以使圖片載入更快,如果一些圖片不能顯示的話則可以把它關閉</string>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="default_tab_display_option">icon</string>
|
||||
<string name="default_tab_display_option" translatable="false">icon</string>
|
||||
<string name="profile_image_size" translatable="false">normal</string>
|
||||
|
||||
</resources>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name" translatable="false">Twidere</string>
|
||||
<string name="theme_twidere">@string/app_name</string>
|
||||
<string name="nyan_sakamoto" translatable="false">Nyan Sakamoto!</string>
|
||||
<string name="kuma_union" translatable="false">熊孩子联盟</string>
|
||||
<string name="developer_name" translatable="false">Mariotaku Lee</string>
|
||||
<string name="project_name" translatable="false">Twidere Project</string>
|
||||
<string name="font_family_regular" translatable="false">Regular</string>
|
||||
<string name="font_family_condensed" translatable="false">Condensed</string>
|
||||
<string name="font_family_light" translatable="false">Light</string>
|
||||
<string name="font_family_thin" translatable="false">Thin</string>
|
||||
<string name="easter_egg_triggered_message" translatable="false">不二对你的膝盖发动了会心一击!</string>
|
||||
|
||||
</resources>
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Twidere</string>
|
||||
<string name="theme_twidere">@string/app_name</string>
|
||||
<string name="nyan_sakamoto">Nyan Sakamoto!</string>
|
||||
<string name="kuma_union">熊孩子联盟</string>
|
||||
<string name="developer_name">Mariotaku Lee</string>
|
||||
<string name="project_name">Twidere Project</string>
|
||||
<string name="font_family_regular">Regular</string>
|
||||
<string name="font_family_condensed">Condensed</string>
|
||||
<string name="font_family_light">Light</string>
|
||||
<string name="font_family_thin">Thin</string>
|
||||
<string name="profile_image_size">normal</string>
|
||||
<string name="easter_egg_triggered_message">不二对你的膝盖发动了会心一击!</string>
|
||||
|
||||
</resources>
|
|
@ -16,7 +16,7 @@
|
|||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/../app/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
|
@ -63,7 +63,9 @@
|
|||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="support-v13-20.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="library-2.0.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="android-easing-1.0.3" level="project" />
|
||||
<orderEntry type="library" exported="" name="httpclient-android-4.3.3" level="project" />
|
||||
<orderEntry type="library" exported="" name="imagezoom-1.0.5" level="project" />
|
||||
<orderEntry type="library" exported="" name="play-services-5.0.77" level="project" />
|
||||
<orderEntry type="library" exported="" name="merge-1.0.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="library-1.0.5" level="project" />
|
||||
|
|
Loading…
Reference in New Issue