parent
8159a60012
commit
d81b86ea99
|
@ -9,8 +9,8 @@ android {
|
|||
applicationId "jp.juggler.subwaytooter"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 114
|
||||
versionName "1.1.4"
|
||||
versionCode 115
|
||||
versionName "1.1.5"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
package com.bumptech.glide.load.resource.bitmap;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
|
||||
@SuppressWarnings("unused") public class MyGlideBitmapDrawable extends GlideDrawable {
|
||||
|
||||
private static final LogCategory log = new LogCategory( "MyGlideBitmapDrawable" );
|
||||
|
||||
|
||||
private final Rect destRect = new Rect();
|
||||
private int width;
|
||||
private int height;
|
||||
private boolean applyGravity;
|
||||
private boolean mutated;
|
||||
private GlideBitmapDrawable.BitmapState state;
|
||||
|
||||
private static Field field_state;
|
||||
|
||||
private static GlideBitmapDrawable.BitmapState cloneState( GlideBitmapDrawable other ){
|
||||
try{
|
||||
if( field_state == null ){
|
||||
field_state = GlideBitmapDrawable.class.getDeclaredField( "state" );
|
||||
field_state.setAccessible( true );
|
||||
}
|
||||
GlideBitmapDrawable.BitmapState other_state = (GlideBitmapDrawable.BitmapState) field_state.get( other );
|
||||
|
||||
return new GlideBitmapDrawable.BitmapState( other_state );
|
||||
}catch( Throwable ex ){
|
||||
throw new RuntimeException( "cloning GlideBitmapDrawable.BitmapState failed.", ex );
|
||||
}
|
||||
}
|
||||
|
||||
private float mCornerRadius;
|
||||
|
||||
public MyGlideBitmapDrawable( Resources res,GlideBitmapDrawable other, float radius ){
|
||||
this( res, cloneState( other ) );
|
||||
this.mCornerRadius = radius;
|
||||
}
|
||||
|
||||
private MyGlideBitmapDrawable(Resources res, GlideBitmapDrawable.BitmapState state) {
|
||||
if (state == null) {
|
||||
throw new NullPointerException("BitmapState must not be null");
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
final int targetDensity;
|
||||
if (res != null) {
|
||||
final int density = res.getDisplayMetrics().densityDpi;
|
||||
targetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
|
||||
state.targetDensity = targetDensity;
|
||||
} else {
|
||||
targetDensity = state.targetDensity;
|
||||
}
|
||||
width = state.bitmap.getScaledWidth(targetDensity);
|
||||
height = state.bitmap.getScaledHeight(targetDensity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnimated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoopCount(int loopCount) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
applyGravity = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantState getConstantState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw( @NonNull Canvas canvas) {
|
||||
if (applyGravity) {
|
||||
Gravity.apply(Gravity.FILL, width, height, getBounds(), destRect);
|
||||
applyGravity = false;
|
||||
mBitmapShader = null;
|
||||
}
|
||||
|
||||
Bitmap toDraw = state.bitmap;
|
||||
|
||||
if( mCornerRadius <= 0f ){
|
||||
state.paint.setShader( null );
|
||||
canvas.drawBitmap( toDraw, null, destRect, state.paint );
|
||||
mBitmapShader = null;
|
||||
}else{
|
||||
drawRoundImage(canvas,toDraw );
|
||||
}
|
||||
}
|
||||
|
||||
private final Matrix mShaderMatrix = new Matrix();
|
||||
private final RectF mDstRectF = new RectF();
|
||||
private BitmapShader mBitmapShader;
|
||||
|
||||
private void drawRoundImage( Canvas canvas, Bitmap src){
|
||||
if( src == null ) return;
|
||||
int src_w = src.getWidth();
|
||||
int src_h = src.getHeight();
|
||||
if( src_w < 1 || src_h < 1 ) return;
|
||||
|
||||
if( mBitmapShader == null ){
|
||||
int outWidth = destRect.width();
|
||||
int outHeight = destRect.height();
|
||||
mDstRectF.set( destRect );
|
||||
mShaderMatrix.preScale( mDstRectF.width() / src_w, mDstRectF.height() / src_h );
|
||||
|
||||
mBitmapShader = new BitmapShader( src, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP );
|
||||
mBitmapShader.setLocalMatrix( mShaderMatrix );
|
||||
}
|
||||
|
||||
state.paint.setShader( mBitmapShader );
|
||||
canvas.drawRoundRect( mDstRectF, mCornerRadius, mCornerRadius, state.paint );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
int currentAlpha = state.paint.getAlpha();
|
||||
if (currentAlpha != alpha) {
|
||||
state.setAlpha(alpha);
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
state.setColorFilter(colorFilter);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
Bitmap bm = state.bitmap;
|
||||
return bm == null || bm.hasAlpha() || state.paint.getAlpha() < 255
|
||||
? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public Drawable mutate() {
|
||||
if (!mutated && super.mutate() == this) {
|
||||
state = new GlideBitmapDrawable.BitmapState(state);
|
||||
mutated = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
return state.bitmap;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,370 @@
|
|||
package com.bumptech.glide.load.resource.gif;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
|
||||
import com.bumptech.glide.gifdecoder.GifDecoder;
|
||||
import com.bumptech.glide.load.Transformation;
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
|
||||
import static com.bumptech.glide.gifdecoder.GifDecoder.TOTAL_ITERATION_COUNT_FOREVER;
|
||||
|
||||
@SuppressWarnings({ "WeakerAccess", "unused", "ObsoleteSdkInt" })
|
||||
public class MyGifDrawable extends GlideDrawable implements GifFrameLoader.FrameCallback {
|
||||
|
||||
static final LogCategory log = new LogCategory( "MyGifDrawable" );
|
||||
|
||||
private final Paint paint;
|
||||
private final Rect destRect = new Rect();
|
||||
private final GifDrawable.GifState state;
|
||||
private final GifDecoder decoder;
|
||||
private final GifFrameLoader frameLoader;
|
||||
|
||||
/**
|
||||
* True if the drawable is currently animating.
|
||||
*/
|
||||
private boolean isRunning;
|
||||
/**
|
||||
* True if the drawable should animate while visible.
|
||||
*/
|
||||
private boolean isStarted;
|
||||
/**
|
||||
* True if the drawable's resources have been recycled.
|
||||
*/
|
||||
private boolean isRecycled;
|
||||
/**
|
||||
* True if the drawable is currently visible. Default to true because on certain platforms (at least 4.1.1),
|
||||
* setVisible is not called on {@link android.graphics.drawable.Drawable Drawables} during
|
||||
* {@link android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}. See issue #130.
|
||||
*/
|
||||
private boolean isVisible = true;
|
||||
/**
|
||||
* The number of times we've looped over all the frames in the gif.
|
||||
*/
|
||||
private int loopCount;
|
||||
/**
|
||||
* The number of times to loop through the gif animation.
|
||||
*/
|
||||
private int maxLoopCount = LOOP_FOREVER;
|
||||
|
||||
private boolean applyGravity;
|
||||
|
||||
static Field field_state;
|
||||
|
||||
static GifDrawable.GifState cloneState( GifDrawable other ){
|
||||
try{
|
||||
if( field_state == null ){
|
||||
field_state = GifDrawable.class.getDeclaredField( "state" );
|
||||
field_state.setAccessible( true );
|
||||
}
|
||||
GifDrawable.GifState other_state = (GifDrawable.GifState) field_state.get( other );
|
||||
|
||||
return new GifDrawable.GifState(
|
||||
other_state.gifHeader,
|
||||
other_state.data,
|
||||
other_state.context,
|
||||
other.getFrameTransformation(),
|
||||
other_state.targetWidth,
|
||||
other_state.targetHeight,
|
||||
other_state.bitmapProvider,
|
||||
other_state.bitmapPool,
|
||||
other.getFirstFrame()
|
||||
);
|
||||
}catch( Throwable ex ){
|
||||
throw new RuntimeException( "cloning GifDrawable.GifState failed.", ex );
|
||||
}
|
||||
}
|
||||
|
||||
float mCornerRadius;
|
||||
|
||||
public MyGifDrawable( GifDrawable other, float radius ){
|
||||
this( cloneState( other ) );
|
||||
this.mCornerRadius = radius;
|
||||
}
|
||||
|
||||
private MyGifDrawable( GifDrawable.GifState state ){
|
||||
if( state == null ){
|
||||
throw new NullPointerException( "GifState must not be null" );
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
this.decoder = new GifDecoder( state.bitmapProvider );
|
||||
this.paint = new Paint( Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG );
|
||||
|
||||
decoder.setData( state.gifHeader, state.data );
|
||||
frameLoader = new GifFrameLoader( state.context, this, decoder, state.targetWidth, state.targetHeight );
|
||||
frameLoader.setFrameTransformation( state.frameTransformation );
|
||||
}
|
||||
|
||||
// Visible for testing.
|
||||
MyGifDrawable( GifDecoder decoder, GifFrameLoader frameLoader, Bitmap firstFrame, BitmapPool bitmapPool, Paint paint ){
|
||||
this.decoder = decoder;
|
||||
this.frameLoader = frameLoader;
|
||||
this.state = new GifDrawable.GifState( null );
|
||||
this.paint = paint;
|
||||
state.bitmapPool = bitmapPool;
|
||||
state.firstFrame = firstFrame;
|
||||
}
|
||||
|
||||
public Bitmap getFirstFrame(){
|
||||
return state.firstFrame;
|
||||
}
|
||||
|
||||
public void setFrameTransformation( Transformation< Bitmap > frameTransformation, Bitmap firstFrame ){
|
||||
if( firstFrame == null ){
|
||||
throw new NullPointerException( "The first frame of the GIF must not be null" );
|
||||
}
|
||||
if( frameTransformation == null ){
|
||||
throw new NullPointerException( "The frame transformation must not be null" );
|
||||
}
|
||||
state.frameTransformation = frameTransformation;
|
||||
state.firstFrame = firstFrame;
|
||||
frameLoader.setFrameTransformation( frameTransformation );
|
||||
}
|
||||
|
||||
public GifDecoder getDecoder(){
|
||||
return decoder;
|
||||
}
|
||||
|
||||
public Transformation< Bitmap > getFrameTransformation(){
|
||||
return state.frameTransformation;
|
||||
}
|
||||
|
||||
public byte[] getData(){
|
||||
return state.data;
|
||||
}
|
||||
|
||||
public int getFrameCount(){
|
||||
return decoder.getFrameCount();
|
||||
}
|
||||
|
||||
private void resetLoopCount(){
|
||||
loopCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(){
|
||||
log.d("start");
|
||||
isStarted = true;
|
||||
resetLoopCount();
|
||||
if( isVisible ){
|
||||
startRunning();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(){
|
||||
isStarted = false;
|
||||
stopRunning();
|
||||
|
||||
// On APIs > honeycomb we know our drawable is not being displayed anymore when it's callback is cleared and so
|
||||
// we can use the absence of a callback as an indication that it's ok to clear our temporary data. Prior to
|
||||
// honeycomb we can't tell if our callback is null and instead eagerly reset to avoid holding on to resources we
|
||||
// no longer need.
|
||||
if( Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ){
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears temporary data and resets the drawable back to the first frame.
|
||||
*/
|
||||
private void reset(){
|
||||
frameLoader.clear();
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
private void startRunning(){
|
||||
// If we have only a single frame, we don't want to decode it endlessly.
|
||||
if( decoder.getFrameCount() == 1 ){
|
||||
invalidateSelf();
|
||||
}else if( ! isRunning ){
|
||||
isRunning = true;
|
||||
frameLoader.start();
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopRunning(){
|
||||
isRunning = false;
|
||||
frameLoader.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setVisible( boolean visible, boolean restart ){
|
||||
isVisible = visible;
|
||||
if( ! visible ){
|
||||
stopRunning();
|
||||
}else if( isStarted ){
|
||||
startRunning();
|
||||
}
|
||||
return super.setVisible( visible, restart );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth(){
|
||||
return state.firstFrame.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight(){
|
||||
return state.firstFrame.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning(){
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
// For testing.
|
||||
void setIsRunning( boolean isRunning ){
|
||||
this.isRunning = isRunning;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange( Rect bounds ){
|
||||
super.onBoundsChange( bounds );
|
||||
applyGravity = true;
|
||||
}
|
||||
|
||||
final Matrix mShaderMatrix = new Matrix();
|
||||
final RectF mDstRectF = new RectF();
|
||||
|
||||
@Override
|
||||
public void draw( @NonNull Canvas canvas ){
|
||||
if( isRecycled ){
|
||||
return;
|
||||
}
|
||||
|
||||
if( applyGravity ){
|
||||
Gravity.apply( Gravity.FILL, getIntrinsicWidth(), getIntrinsicHeight(), getBounds(), destRect );
|
||||
applyGravity = false;
|
||||
}
|
||||
|
||||
Bitmap currentFrame = frameLoader.getCurrentFrame();
|
||||
Bitmap toDraw = currentFrame != null ? currentFrame : state.firstFrame;
|
||||
|
||||
if( mCornerRadius <= 0f ){
|
||||
paint.setShader( null );
|
||||
canvas.drawBitmap( toDraw, null, destRect, paint );
|
||||
}else{
|
||||
drawRoundImage(canvas,toDraw );
|
||||
}
|
||||
}
|
||||
|
||||
private void drawRoundImage( Canvas canvas, Bitmap src){
|
||||
if( src == null ) return;
|
||||
int src_w = src.getWidth();
|
||||
int src_h = src.getHeight();
|
||||
if( src_w < 1 || src_h < 1 ) return;
|
||||
int outWidth = destRect.width();
|
||||
int outHeight = destRect.height();
|
||||
|
||||
mDstRectF.set( destRect );
|
||||
mShaderMatrix.preScale( mDstRectF.width() / src_w, mDstRectF.height() / src_h );
|
||||
|
||||
BitmapShader mBitmapShader = new BitmapShader( src, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP );
|
||||
mBitmapShader.setLocalMatrix( mShaderMatrix );
|
||||
|
||||
paint.setShader( mBitmapShader );
|
||||
canvas.drawRoundRect( mDstRectF, mCornerRadius, mCornerRadius, paint );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha( int i ){
|
||||
paint.setAlpha( i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter( ColorFilter colorFilter ){
|
||||
paint.setColorFilter( colorFilter );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity(){
|
||||
// We can't tell, so default to transparent to be safe.
|
||||
return PixelFormat.TRANSPARENT;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
@Override
|
||||
public void onFrameReady( int frameIndex ){
|
||||
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && getCallback() == null ){
|
||||
stop();
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
invalidateSelf();
|
||||
|
||||
if( frameIndex == decoder.getFrameCount() - 1 ){
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
if( maxLoopCount != LOOP_FOREVER && loopCount >= maxLoopCount ){
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstantState getConstantState(){
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any resources for loading frames that are currently held on to by this object.
|
||||
*/
|
||||
public void recycle(){
|
||||
isRecycled = true;
|
||||
state.bitmapPool.put( state.firstFrame );
|
||||
frameLoader.clear();
|
||||
frameLoader.stop();
|
||||
}
|
||||
|
||||
// For testing.
|
||||
boolean isRecycled(){
|
||||
return isRecycled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnimated(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoopCount( int loopCount ){
|
||||
if( loopCount <= 0 && loopCount != LOOP_FOREVER && loopCount != LOOP_INTRINSIC ){
|
||||
throw new IllegalArgumentException( "Loop count must be greater than 0, or equal to "
|
||||
+ "GlideDrawable.LOOP_FOREVER, or equal to GlideDrawable.LOOP_INTRINSIC" );
|
||||
}
|
||||
|
||||
if( loopCount == LOOP_INTRINSIC ){
|
||||
int intrinsicCount = decoder.getTotalIterationCount();
|
||||
maxLoopCount = ( intrinsicCount == TOTAL_ITERATION_COUNT_FOREVER ) ? LOOP_FOREVER : intrinsicCount;
|
||||
}else{
|
||||
maxLoopCount = loopCount;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -98,7 +98,7 @@ public class ActAppSetting extends AppCompatActivity
|
|||
Switch swPostButtonBarTop;
|
||||
Switch swDontDuplicationCheck;
|
||||
Switch swQuickTootBar;
|
||||
Switch swDisableGifAnimation;
|
||||
Switch swEnableGifAnimation;
|
||||
|
||||
Spinner spBackButtonAction;
|
||||
Spinner spUITheme;
|
||||
|
@ -197,8 +197,8 @@ public class ActAppSetting extends AppCompatActivity
|
|||
swQuickTootBar = (Switch) findViewById( R.id.swQuickTootBar );
|
||||
swQuickTootBar.setOnCheckedChangeListener( this );
|
||||
|
||||
swDisableGifAnimation = (Switch) findViewById( R.id.swDisableGifAnimation );
|
||||
swDisableGifAnimation.setOnCheckedChangeListener( this );
|
||||
swEnableGifAnimation = (Switch) findViewById( R.id.swEnableGifAnimation );
|
||||
swEnableGifAnimation.setOnCheckedChangeListener( this );
|
||||
|
||||
cbNotificationSound = (CheckBox) findViewById( R.id.cbNotificationSound );
|
||||
cbNotificationVibration = (CheckBox) findViewById( R.id.cbNotificationVibration );
|
||||
|
@ -340,7 +340,7 @@ public class ActAppSetting extends AppCompatActivity
|
|||
swPostButtonBarTop.setChecked( pref.getBoolean( Pref.KEY_POST_BUTTON_BAR_AT_TOP, false ) );
|
||||
swDontDuplicationCheck.setChecked( pref.getBoolean( Pref.KEY_DONT_DUPLICATION_CHECK, false ) );
|
||||
swQuickTootBar.setChecked( pref.getBoolean( Pref.KEY_QUICK_TOOT_BAR, false ) );
|
||||
swDisableGifAnimation.setChecked( pref.getBoolean( Pref.KEY_DISABLE_GIF_ANIMATION, false ) );
|
||||
swEnableGifAnimation.setChecked( pref.getBoolean( Pref.KEY_ENABLE_GIF_ANIMATION, false ) );
|
||||
|
||||
// Switch with default true
|
||||
swDisableFastScroller.setChecked( pref.getBoolean( Pref.KEY_DISABLE_FAST_SCROLLER, true ) );
|
||||
|
@ -403,7 +403,7 @@ public class ActAppSetting extends AppCompatActivity
|
|||
.putBoolean( Pref.KEY_POST_BUTTON_BAR_AT_TOP, swPostButtonBarTop.isChecked() )
|
||||
.putBoolean( Pref.KEY_DONT_DUPLICATION_CHECK, swDontDuplicationCheck.isChecked() )
|
||||
.putBoolean( Pref.KEY_QUICK_TOOT_BAR, swQuickTootBar.isChecked() )
|
||||
.putBoolean( Pref.KEY_DISABLE_GIF_ANIMATION, swDisableGifAnimation.isChecked() )
|
||||
.putBoolean( Pref.KEY_ENABLE_GIF_ANIMATION, swEnableGifAnimation.isChecked() )
|
||||
|
||||
.putBoolean( Pref.KEY_NOTIFICATION_SOUND, cbNotificationSound.isChecked() )
|
||||
.putBoolean( Pref.KEY_NOTIFICATION_VIBRATION, cbNotificationVibration.isChecked() )
|
||||
|
|
|
@ -313,7 +313,7 @@ public class AppDataExporter {
|
|||
case Pref.KEY_POST_BUTTON_BAR_AT_TOP:
|
||||
case Pref.KEY_DONT_DUPLICATION_CHECK:
|
||||
case Pref.KEY_QUICK_TOOT_BAR:
|
||||
case Pref.KEY_DISABLE_GIF_ANIMATION:
|
||||
case Pref.KEY_ENABLE_GIF_ANIMATION:
|
||||
boolean bv = reader.nextBoolean();
|
||||
e.putBoolean( k, bv );
|
||||
break;
|
||||
|
@ -373,6 +373,7 @@ public class AppDataExporter {
|
|||
// just ignore
|
||||
case "device_token":
|
||||
case "install_id":
|
||||
case "disable_gif_animation":
|
||||
reader.skipValue();
|
||||
e.remove( k );
|
||||
break;
|
||||
|
|
|
@ -72,7 +72,7 @@ public class Pref {
|
|||
|
||||
public static final String KEY_QUOTE_NAME_FORMAT = "quote_name_format";
|
||||
|
||||
public static final String KEY_DISABLE_GIF_ANIMATION = "disable_gif_animation";
|
||||
public static final String KEY_ENABLE_GIF_ANIMATION = "enable_gif_animation";
|
||||
|
||||
// 項目を追加したらAppDataExporter#importPref のswitch文も更新すること
|
||||
}
|
||||
|
|
|
@ -1,6 +1,54 @@
|
|||
package jp.juggler.subwaytooter.api_msp.entity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
|
||||
public class MSPAccount extends TootAccount {
|
||||
|
||||
private static final Pattern reAccountUrl = Pattern.compile( "\\Ahttps://([^/#?]+)/@([^/#?]+)\\z" );
|
||||
|
||||
|
||||
static TootAccount parseAccount( @NonNull Context context, LogCategory log, SavedAccount access_info, JSONObject src ){
|
||||
|
||||
if( src == null ) return null;
|
||||
|
||||
MSPAccount dst = new MSPAccount();
|
||||
dst.url = Utils.optStringX( src, "url" );
|
||||
dst.username = Utils.optStringX( src, "username" );
|
||||
dst.avatar = dst.avatar_static = Utils.optStringX( src, "avatar" );
|
||||
|
||||
String sv = Utils.optStringX( src, "display_name" );
|
||||
dst.setDisplayName( context, dst.username , sv );
|
||||
|
||||
dst.id = src.optLong( "id" );
|
||||
|
||||
dst.note = Utils.optStringX( src, "note" );
|
||||
dst.decoded_note = HTMLDecoder.decodeHTML( context,access_info, ( dst.note != null ? dst.note : null ), true, true,null );
|
||||
|
||||
if( TextUtils.isEmpty( dst.url ) ){
|
||||
log.e( "parseAccount: missing url" );
|
||||
return null;
|
||||
}
|
||||
Matcher m = reAccountUrl.matcher( dst.url );
|
||||
if( ! m.find() ){
|
||||
log.e( "parseAccount: not account url: %s", dst.url );
|
||||
return null;
|
||||
}else{
|
||||
dst.acct = dst.username + "@" + m.group( 1 );
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import java.util.TimeZone;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatusLike;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||
|
@ -29,40 +28,6 @@ public class MSPToot extends TootStatusLike {
|
|||
|
||||
}
|
||||
|
||||
private static final Pattern reAccountUrl = Pattern.compile( "\\Ahttps://([^/#?]+)/@([^/#?]+)\\z" );
|
||||
|
||||
private static TootAccount parseAccount( @NonNull Context context, LogCategory log, SavedAccount access_info, JSONObject src ){
|
||||
|
||||
if( src == null ) return null;
|
||||
|
||||
MSPAccount dst = new MSPAccount();
|
||||
dst.url = Utils.optStringX( src, "url" );
|
||||
dst.username = Utils.optStringX( src, "username" );
|
||||
dst.avatar = dst.avatar_static = Utils.optStringX( src, "avatar" );
|
||||
|
||||
String sv = Utils.optStringX( src, "display_name" );
|
||||
dst.setDisplayName( context, dst.username , sv );
|
||||
|
||||
dst.id = src.optLong( "id" );
|
||||
|
||||
dst.note = Utils.optStringX( src, "note" );
|
||||
dst.decoded_note = HTMLDecoder.decodeHTML( context,access_info, ( dst.note != null ? dst.note : null ), true, true,null );
|
||||
|
||||
if( TextUtils.isEmpty( dst.url ) ){
|
||||
log.e( "parseAccount: missing url" );
|
||||
return null;
|
||||
}
|
||||
Matcher m = reAccountUrl.matcher( dst.url );
|
||||
if( ! m.find() ){
|
||||
log.e( "parseAccount: not account url: %s", dst.url );
|
||||
return null;
|
||||
}else{
|
||||
dst.acct = dst.username + "@" + m.group( 1 );
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
// private static final Pattern reTime = Pattern.compile( "\\A(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)" );
|
||||
//
|
||||
// private static final TimeZone tz_tokyo = TimeZone.getTimeZone( "Asia/Tokyo" );
|
||||
|
@ -103,7 +68,7 @@ public class MSPToot extends TootStatusLike {
|
|||
if( src == null ) return null;
|
||||
MSPToot dst = new MSPToot();
|
||||
|
||||
dst.account = parseAccount( context,log, access_info, src.optJSONObject( "account" ) );
|
||||
dst.account = MSPAccount.parseAccount( context, log, access_info, src.optJSONObject( "account" ) );
|
||||
if( dst.account == null ){
|
||||
log.e( "missing status account" );
|
||||
return null;
|
||||
|
@ -136,20 +101,20 @@ public class MSPToot extends TootStatusLike {
|
|||
// dst.msp_id = src.optLong( "msp_id" );
|
||||
dst.sensitive = ( src.optInt( "sensitive", 0 ) != 0 );
|
||||
|
||||
dst.setSpoilerText(context,Utils.optStringX( src, "spoiler_text" ));
|
||||
dst.setSpoilerText( context, Utils.optStringX( src, "spoiler_text" ) );
|
||||
|
||||
dst.content = Utils.optStringX( src, "content" );
|
||||
dst.decoded_content = HTMLDecoder.decodeHTML( context,access_info, dst.content, true,true, null );
|
||||
dst.decoded_content = HTMLDecoder.decodeHTML( context, access_info, dst.content, true, true, null );
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static List parseList( @NonNull Context context, LogCategory log, SavedAccount access_info, JSONArray array ){
|
||||
public static List parseList( @NonNull Context context, LogCategory log, SavedAccount access_info, JSONArray array ){
|
||||
List list = new List();
|
||||
for( int i = 0, ie = array.length() ; i < ie ; ++ i ){
|
||||
JSONObject src = array.optJSONObject( i );
|
||||
if( src == null ) continue;
|
||||
MSPToot item = parse( context,log, access_info, src );
|
||||
MSPToot item = parse( context, log, access_info, src );
|
||||
if( item == null ) continue;
|
||||
list.add( item );
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package jp.juggler.subwaytooter.view;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.bumptech.glide.load.Transformation;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
||||
|
||||
class MyGifDrawable extends GifDrawable {
|
||||
|
||||
MyGifDrawable( GifDrawable other, Bitmap firstFrame, Transformation< Bitmap > frameTransformation ){
|
||||
super( other, firstFrame, frameTransformation );
|
||||
}
|
||||
|
||||
// このクラスに追加された機能は特にないが、GifDrawableから差し替え済みであることを検出できるようにするため派生クラスとしている
|
||||
}
|
|
@ -4,14 +4,7 @@ import android.annotation.SuppressLint;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
@ -19,22 +12,19 @@ import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
|
|||
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.support.v7.widget.AppCompatImageView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
|
||||
import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
|
||||
import com.bumptech.glide.load.resource.bitmap.MyGlideBitmapDrawable;
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
import com.bumptech.glide.load.resource.gif.GifDrawable;
|
||||
import com.bumptech.glide.load.resource.gif.MyGifDrawable;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.BaseTarget;
|
||||
import com.bumptech.glide.request.target.ImageViewTarget;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.bumptech.glide.request.target.SquaringDrawable;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import jp.juggler.subwaytooter.Pref;
|
||||
|
@ -97,7 +87,7 @@ public class MyNetworkImageView extends AppCompatImageView {
|
|||
mCornerRadius = r;
|
||||
}
|
||||
|
||||
if( pref.getBoolean( Pref.KEY_DISABLE_GIF_ANIMATION, false ) ){
|
||||
if( ! pref.getBoolean( Pref.KEY_ENABLE_GIF_ANIMATION, false ) ){
|
||||
gif_url = null;
|
||||
}
|
||||
|
||||
|
@ -116,6 +106,14 @@ public class MyNetworkImageView extends AppCompatImageView {
|
|||
|
||||
private void cancelLoading(){
|
||||
if( mTarget != null ){
|
||||
Drawable d = getDrawable();
|
||||
if( d instanceof GlideDrawable ){
|
||||
GlideDrawable gd =(GlideDrawable)d;
|
||||
if( gd.isRunning() ){
|
||||
log.d("cancelLoading: GlideDrawable.stop()");
|
||||
gd.stop();
|
||||
}
|
||||
}
|
||||
setImageDrawable( null );
|
||||
Glide.clear( mTarget );
|
||||
mTarget = null;
|
||||
|
@ -124,6 +122,16 @@ public class MyNetworkImageView extends AppCompatImageView {
|
|||
|
||||
// デフォルト画像かnullを表示する
|
||||
private void setDefaultImageOrNull(){
|
||||
|
||||
Drawable d = getDrawable();
|
||||
if( d instanceof GlideDrawable ){
|
||||
GlideDrawable gd =(GlideDrawable)d;
|
||||
if( gd.isRunning() ){
|
||||
log.d("setDefaultImageOrNull: GlideDrawable.stop()");
|
||||
gd.stop();
|
||||
}
|
||||
}
|
||||
|
||||
if( mDefaultImageId != 0 ){
|
||||
setImageResource( mDefaultImageId );
|
||||
}else{
|
||||
|
@ -171,17 +179,9 @@ public class MyNetworkImageView extends AppCompatImageView {
|
|||
}
|
||||
|
||||
if( mMayGif ){
|
||||
if( mCornerRadius > 0f ){
|
||||
mTarget = Glide.with( getContext() )
|
||||
.load( mUrl )
|
||||
.transform( new RoundTransformation( mCornerRadius ) )
|
||||
.into( new MyTargetGif( mUrl ) );
|
||||
}else{
|
||||
mTarget = Glide.with( getContext() )
|
||||
.load( mUrl )
|
||||
.into( new MyTargetGif( mUrl ) );
|
||||
|
||||
}
|
||||
mTarget = Glide.with( getContext() )
|
||||
.load( mUrl )
|
||||
.into( new MyTargetGif( mUrl ) );
|
||||
}else{
|
||||
mTarget = Glide.with( getContext() )
|
||||
.load( mUrl )
|
||||
|
@ -310,38 +310,47 @@ public class MyNetworkImageView extends AppCompatImageView {
|
|||
// このViewは別の画像を表示するように指定が変わっていた
|
||||
if( ! url.equals( mUrl ) ) return;
|
||||
|
||||
// ディスクキャッシュから読んだ画像は角丸が正しく扱われない
|
||||
// transformを設定しなおす
|
||||
if( ( resource instanceof GifDrawable ) && ! ( resource instanceof MyGifDrawable ) ){
|
||||
GifDrawable src = (GifDrawable) resource;
|
||||
if( app_context != null && mCornerRadius > 0f ){
|
||||
RoundTransformation t = new RoundTransformation( mCornerRadius );
|
||||
try{
|
||||
BitmapPool pool = Glide.get( app_context ).getBitmapPool();
|
||||
Bitmap first_frame = t.transform( pool, src.getFirstFrame(), getWidth(), getHeight() );
|
||||
resource = new MyGifDrawable( src,first_frame, t );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
// view#getWidth() が 0 だと firstFrame の transform がnullを返してGifDrawableを作れない
|
||||
resource = new MyGifDrawable( src,src.getFirstFrame(), t );
|
||||
|
||||
if( mCornerRadius > 0f ){
|
||||
if( resource instanceof GifDrawable ){
|
||||
// ディスクキャッシュから読んだ画像は角丸が正しく扱われない
|
||||
// MyGifDrawable に差し替えて描画させる
|
||||
GifDrawable src = (GifDrawable) resource;
|
||||
if( app_context != null ){
|
||||
try{
|
||||
resource = new MyGifDrawable( src, mCornerRadius );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}else if ( resource instanceof GlideBitmapDrawable ){
|
||||
GlideBitmapDrawable src = (GlideBitmapDrawable) resource;
|
||||
if( app_context != null ){
|
||||
try{
|
||||
resource = new MyGlideBitmapDrawable( getResources(), src, mCornerRadius );
|
||||
}catch( Throwable ex ){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
throw new RuntimeException( String.format("unsupported draw type : %s", resource.getClass()) );
|
||||
}
|
||||
}
|
||||
|
||||
if( ! resource.isAnimated() ){
|
||||
//TODO: Try to generalize this to other sizes/shapes.
|
||||
// This is a dirty hack that tries to make loading square thumbnails and then square full images less costly
|
||||
// by forcing both the smaller thumb and the larger version to have exactly the same intrinsic dimensions.
|
||||
// If a drawable is replaced in an ImageView by another drawable with different intrinsic dimensions,
|
||||
// the ImageView requests a layout. Scrolling rapidly while replacing thumbs with larger images triggers
|
||||
// lots of these calls and causes significant amounts of jank.
|
||||
float viewRatio = view.getWidth() / (float) view.getHeight();
|
||||
float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
|
||||
if( Math.abs( viewRatio - 1f ) <= SQUARE_RATIO_MARGIN
|
||||
&& Math.abs( drawableRatio - 1f ) <= SQUARE_RATIO_MARGIN ){
|
||||
resource = new SquaringDrawable( resource, view.getWidth() );
|
||||
}
|
||||
}
|
||||
// if( ! resource.isAnimated() ){
|
||||
// //TODO: Try to generalize this to other sizes/shapes.
|
||||
// // This is a dirty hack that tries to make loading square thumbnails and then square full images less costly
|
||||
// // by forcing both the smaller thumb and the larger version to have exactly the same intrinsic dimensions.
|
||||
// // If a drawable is replaced in an ImageView by another drawable with different intrinsic dimensions,
|
||||
// // the ImageView requests a layout. Scrolling rapidly while replacing thumbs with larger images triggers
|
||||
// // lots of these calls and causes significant amounts of jank.
|
||||
// float viewRatio = view.getWidth() / (float) view.getHeight();
|
||||
// float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
|
||||
// if( Math.abs( viewRatio - 1f ) <= SQUARE_RATIO_MARGIN
|
||||
// && Math.abs( drawableRatio - 1f ) <= SQUARE_RATIO_MARGIN ){
|
||||
// resource = new SquaringDrawable( resource, view.getWidth() );
|
||||
// }
|
||||
// }
|
||||
super.onResourceReady( resource, animation );
|
||||
this.glide_drawable = resource;
|
||||
resource.setLoopCount( maxLoopCount );
|
||||
|
@ -366,16 +375,16 @@ public class MyNetworkImageView extends AppCompatImageView {
|
|||
|
||||
@Override
|
||||
public void onStart(){
|
||||
// log.d( "MyTargetGif onStart glide_drawable=%s", glide_drawable );
|
||||
if( glide_drawable != null ){
|
||||
if( glide_drawable != null && ! glide_drawable.isRunning() ){
|
||||
log.d( "MyTargetGif onStart glide_drawable=%s", glide_drawable );
|
||||
glide_drawable.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop(){
|
||||
log.d( "MyTargetGif onStop glide_drawable=%s", glide_drawable );
|
||||
if( glide_drawable != null ){
|
||||
if( glide_drawable != null && glide_drawable.isRunning() ){
|
||||
log.d( "MyTargetGif onStop glide_drawable=%s", glide_drawable );
|
||||
glide_drawable.stop();
|
||||
}
|
||||
}
|
||||
|
@ -388,86 +397,6 @@ public class MyNetworkImageView extends AppCompatImageView {
|
|||
|
||||
}
|
||||
|
||||
private static class RoundTransformation extends BitmapTransformation {
|
||||
private final float radius;
|
||||
|
||||
RoundTransformation( float radius ){
|
||||
super( app_context );
|
||||
this.radius = radius;
|
||||
mPaint.setAntiAlias( true );
|
||||
mPaint.setFilterBitmap( true );
|
||||
}
|
||||
|
||||
@Override public String getId(){
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
final Matrix mShaderMatrix = new Matrix();
|
||||
final Rect mViewContainer = new Rect();
|
||||
final Rect mDstRect = new Rect();
|
||||
final RectF mDstRectF = new RectF();
|
||||
final Paint mPaint = new Paint( Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG );
|
||||
|
||||
@Override
|
||||
protected Bitmap transform( BitmapPool pool, Bitmap source, int outWidth, int outHeight ){
|
||||
if( source == null ) return null;
|
||||
int src_w = source.getWidth();
|
||||
int src_h = source.getHeight();
|
||||
if( src_w < 1 || src_h < 1 ) return null;
|
||||
if( outWidth < 1 || outHeight < 1 ) return null;
|
||||
|
||||
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
|
||||
int mBitmapWidth = source.getScaledWidth( mTargetDensity );
|
||||
int mBitmapHeight = source.getScaledHeight( mTargetDensity );
|
||||
|
||||
mViewContainer.left = 0;
|
||||
mViewContainer.top = 0;
|
||||
mViewContainer.right = outWidth;
|
||||
mViewContainer.bottom = outHeight;
|
||||
|
||||
int mGravity = Gravity.FILL;
|
||||
Gravity.apply( mGravity, mBitmapWidth, mBitmapHeight, mViewContainer, mDstRect, View.LAYOUT_DIRECTION_LTR );
|
||||
mDstRectF.set( mDstRect );
|
||||
|
||||
mShaderMatrix.setTranslate( mDstRectF.left, mDstRectF.top );
|
||||
mShaderMatrix.preScale( mDstRectF.width() / src_w, mDstRectF.height() / src_h );
|
||||
|
||||
BitmapShader mBitmapShader = new BitmapShader( source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP );
|
||||
mBitmapShader.setLocalMatrix( mShaderMatrix );
|
||||
|
||||
Bitmap result = pool.getDirty( outWidth, outHeight, Bitmap.Config.ARGB_8888 );
|
||||
if( result == null ){
|
||||
result = Bitmap.createBitmap( outWidth, outHeight, Bitmap.Config.ARGB_8888 );
|
||||
}
|
||||
Canvas canvas = new Canvas( result );
|
||||
canvas.drawColor( Color.TRANSPARENT, PorterDuff.Mode.CLEAR );
|
||||
mPaint.setShader( mBitmapShader );
|
||||
// mPaint.setColor( 0xffff0000 );
|
||||
canvas.drawRoundRect( mDstRectF, radius, radius, mPaint );
|
||||
|
||||
// log.d("transform radius=%.2f,outWidth=%d,outHeight=%d",radius,outWidth,outHeight);
|
||||
|
||||
// int dst_wh = Math.min( src_w,src_h );
|
||||
// int offset_x = ( src_w - dst_wh ) / 2;
|
||||
// int offset_y = ( src_h - dst_wh ) / 2;
|
||||
//
|
||||
//
|
||||
// // TODO this could be acquired from the pool too
|
||||
// pool.
|
||||
// Bitmap squared = Bitmap.createBitmap( source, x, y, size, size );
|
||||
//
|
||||
//
|
||||
// Paint paint = new Paint();
|
||||
// paint.setShader( new BitmapShader( squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP ) );
|
||||
// paint.setAntiAlias( true );
|
||||
// float r = size / 2f;
|
||||
// canvas.drawCircle( r, r, r, paint );
|
||||
// // canvas.drawRoundRect( float left, float top, float right, float bottom, float rx, float ry,
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
final Runnable proc_load_image = new Runnable() {
|
||||
@Override public void run(){
|
||||
loadImageIfNecessary();
|
||||
|
|
|
@ -542,13 +542,13 @@
|
|||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/disable_gif_animation"
|
||||
android:text="@string/enable_gif_animation"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Switch
|
||||
android:id="@+id/swDisableGifAnimation"
|
||||
android:id="@+id/swEnableGifAnimation"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:gravity="center"
|
||||
/>
|
||||
|
|
|
@ -411,7 +411,7 @@
|
|||
<string name="acct_color">Acct text color</string>
|
||||
<string name="content_color">Content text color</string>
|
||||
<string name="content_sample">(sample)Le cœur déçu mais l\'âme plutôt naïve, Louÿs rêva de crapaüter en canoë au delà des îles, près du mälströn où brûlent les novæ.</string>
|
||||
<string name="disable_gif_animation">Disable GIF animation (app restart required)</string>
|
||||
<string name="enable_gif_animation">Enable GIF animation (It wastes the battery very much)</string>
|
||||
<string name="acct_sample">(sample)username@instance</string>
|
||||
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
|
|
|
@ -698,7 +698,6 @@
|
|||
<string name="background_image_alpha">背景画像のアルファ値</string>
|
||||
<string name="content_color">本文の文字色</string>
|
||||
<string name="content_sample">(見本)色はにほへど 散りぬるを 我が世たれぞ 常ならむ 有為の奥山 今日越えて 浅き夢見じ 酔ひもせず</string>
|
||||
<string name="disable_gif_animation">GIFアニメ表示を無効(アプリ再起動が必要)</string>
|
||||
<string name="acct_sample">(見本)username@instance</string>
|
||||
|
||||
<string name="enable_gif_animation">GIFアニメーションを有効にする(バッテリーをとても浪費します)</string>
|
||||
</resources>
|
||||
|
|
|
@ -406,7 +406,7 @@
|
|||
<string name="acct_color">Acct text color</string>
|
||||
<string name="content_color">Content text color</string>
|
||||
<string name="content_sample">(sample)The quick brown fox jumps over the lazy dog.</string>
|
||||
<string name="disable_gif_animation">Disable GIF animation (app restart required)</string>
|
||||
<string name="enable_gif_animation">Enable GIF animation (It wastes the battery very much)</string>
|
||||
<string name="acct_sample">(sample)username@instance</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue