mirror of https://github.com/kurisufriend/Clover
parent
f8213fef73
commit
2ae40e97f7
@ -0,0 +1,52 @@ |
||||
package org.floens.chan.ui.controller; |
||||
|
||||
import android.content.Context; |
||||
import android.view.View; |
||||
import android.widget.ImageView; |
||||
|
||||
import org.floens.chan.controller.Controller; |
||||
import org.floens.chan.core.model.PostImage; |
||||
import org.floens.chan.ui.layout.ThreadLayout; |
||||
import org.floens.chan.utils.AndroidUtils; |
||||
|
||||
import java.util.List; |
||||
|
||||
public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewController.Callback { |
||||
protected ThreadLayout threadLayout; |
||||
private ImageView presentingImageView; |
||||
|
||||
public ThreadController(Context context) { |
||||
super(context); |
||||
|
||||
threadLayout = new ThreadLayout(context); |
||||
threadLayout.setCallback(this); |
||||
view = threadLayout; |
||||
} |
||||
|
||||
@Override |
||||
public void showImages(List<PostImage> images, int index, final ImageView thumbnail) { |
||||
presentingImageView = thumbnail; |
||||
presentingImageView.setVisibility(View.INVISIBLE); |
||||
|
||||
final ImageViewController imageViewController = new ImageViewController(context); |
||||
presentController(imageViewController, false); |
||||
AndroidUtils.waitForMeasure(imageViewController.view, new AndroidUtils.OnMeasuredCallback() { |
||||
@Override |
||||
public boolean onMeasured(View view) { |
||||
imageViewController.setImage(ThreadController.this, thumbnail); |
||||
return true; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
public ImageView getImageView(ImageViewController imageViewController) { |
||||
return presentingImageView; |
||||
} |
||||
|
||||
@Override |
||||
public void onImageViewLayoutDestroy(ImageViewController imageViewController) { |
||||
presentingImageView.setVisibility(View.VISIBLE); |
||||
presentingImageView = null; |
||||
} |
||||
} |
@ -1,251 +0,0 @@ |
||||
/* |
||||
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||
* Copyright (C) 2014 Floens |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
package org.floens.chan.ui.layout; |
||||
|
||||
import android.animation.Animator; |
||||
import android.animation.AnimatorListenerAdapter; |
||||
import android.animation.AnimatorSet; |
||||
import android.animation.ObjectAnimator; |
||||
import android.animation.ValueAnimator; |
||||
import android.app.Activity; |
||||
import android.content.Context; |
||||
import android.graphics.Color; |
||||
import android.graphics.Point; |
||||
import android.graphics.Rect; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.os.Build; |
||||
import android.util.AttributeSet; |
||||
import android.view.LayoutInflater; |
||||
import android.view.MotionEvent; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.view.Window; |
||||
import android.view.animation.DecelerateInterpolator; |
||||
import android.widget.FrameLayout; |
||||
import android.widget.ImageView; |
||||
|
||||
import org.floens.chan.R; |
||||
|
||||
import static org.floens.chan.utils.AndroidUtils.dp; |
||||
import static org.floens.chan.utils.AnimationUtils.calculateBoundsAnimation; |
||||
|
||||
|
||||
public class ImageViewLayout extends FrameLayout implements View.OnClickListener { |
||||
private ImageView imageView; |
||||
|
||||
private Callback callback; |
||||
private Drawable drawable; |
||||
|
||||
private int statusBarColorPrevious; |
||||
private AnimatorSet startAnimation; |
||||
private AnimatorSet endAnimation; |
||||
|
||||
public static ImageViewLayout attach(Window window) { |
||||
ImageViewLayout imageViewLayout = (ImageViewLayout) LayoutInflater.from(window.getContext()).inflate(R.layout.image_view_layout, null); |
||||
window.addContentView(imageViewLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); |
||||
return imageViewLayout; |
||||
} |
||||
|
||||
public ImageViewLayout(Context context, AttributeSet attrs) { |
||||
super(context, attrs); |
||||
} |
||||
|
||||
@Override |
||||
protected void onFinishInflate() { |
||||
super.onFinishInflate(); |
||||
this.imageView = (ImageView) findViewById(R.id.image); |
||||
setOnClickListener(this); |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent event) { |
||||
super.onTouchEvent(event); |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public void onClick(View v) { |
||||
removeImage(); |
||||
} |
||||
|
||||
public void setImage(Callback callback, final Drawable drawable) { |
||||
this.callback = callback; |
||||
this.drawable = drawable; |
||||
|
||||
this.imageView.setImageDrawable(drawable); |
||||
|
||||
Rect startBounds = callback.getImageViewLayoutStartBounds(); |
||||
final Rect endBounds = new Rect(); |
||||
final Point globalOffset = new Point(); |
||||
getGlobalVisibleRect(endBounds, globalOffset); |
||||
float startScale = calculateBoundsAnimation(startBounds, endBounds, globalOffset); |
||||
|
||||
imageView.setPivotX(0f); |
||||
imageView.setPivotY(0f); |
||||
imageView.setX(startBounds.left); |
||||
imageView.setY(startBounds.top); |
||||
imageView.setScaleX(startScale); |
||||
imageView.setScaleY(startScale); |
||||
|
||||
Window window = ((Activity) getContext()).getWindow(); |
||||
if (Build.VERSION.SDK_INT >= 21) { |
||||
statusBarColorPrevious = window.getStatusBarColor(); |
||||
} |
||||
|
||||
startAnimation(startBounds, endBounds, startScale); |
||||
} |
||||
|
||||
public void removeImage() { |
||||
if (startAnimation != null || endAnimation != null) { |
||||
return; |
||||
} |
||||
|
||||
endAnimation(); |
||||
// endAnimationEmpty();
|
||||
} |
||||
|
||||
private void startAnimation(Rect startBounds, Rect finalBounds, float startScale) { |
||||
startAnimation = new AnimatorSet(); |
||||
|
||||
ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(0f, 1f); |
||||
backgroundAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { |
||||
@Override |
||||
public void onAnimationUpdate(ValueAnimator animation) { |
||||
setBackgroundAlpha((float) animation.getAnimatedValue()); |
||||
} |
||||
}); |
||||
|
||||
startAnimation |
||||
.play(ObjectAnimator.ofFloat(imageView, View.X, startBounds.left, finalBounds.left)) |
||||
.with(ObjectAnimator.ofFloat(imageView, View.Y, startBounds.top, finalBounds.top)) |
||||
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_X, startScale, 1f)) |
||||
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_Y, startScale, 1f)) |
||||
.with(backgroundAlpha); |
||||
|
||||
startAnimation.setDuration(200); |
||||
startAnimation.setInterpolator(new DecelerateInterpolator()); |
||||
startAnimation.addListener(new AnimatorListenerAdapter() { |
||||
@Override |
||||
public void onAnimationEnd(Animator animation) { |
||||
startAnimationEnd(); |
||||
startAnimation = null; |
||||
} |
||||
}); |
||||
startAnimation.start(); |
||||
} |
||||
|
||||
private void startAnimationEnd() { |
||||
imageView.setX(0f); |
||||
imageView.setY(0f); |
||||
imageView.setScaleX(1f); |
||||
imageView.setScaleY(1f); |
||||
// controller.setVisibility(false);
|
||||
} |
||||
|
||||
private void endAnimation() { |
||||
// controller.setVisibility(true);
|
||||
|
||||
Rect startBounds = callback.getImageViewLayoutStartBounds(); |
||||
final Rect endBounds = new Rect(); |
||||
final Point globalOffset = new Point(); |
||||
getGlobalVisibleRect(endBounds, globalOffset); |
||||
float startScale = calculateBoundsAnimation(startBounds, endBounds, globalOffset); |
||||
|
||||
endAnimation = new AnimatorSet(); |
||||
|
||||
ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(1f, 0f); |
||||
backgroundAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { |
||||
@Override |
||||
public void onAnimationUpdate(ValueAnimator animation) { |
||||
setBackgroundAlpha((float) animation.getAnimatedValue()); |
||||
} |
||||
}); |
||||
|
||||
endAnimation |
||||
.play(ObjectAnimator.ofFloat(imageView, View.X, startBounds.left)) |
||||
.with(ObjectAnimator.ofFloat(imageView, View.Y, startBounds.top)) |
||||
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_X, 1f, startScale)) |
||||
.with(ObjectAnimator.ofFloat(imageView, View.SCALE_Y, 1f, startScale)) |
||||
.with(backgroundAlpha); |
||||
|
||||
endAnimation.setDuration(200); |
||||
endAnimation.setInterpolator(new DecelerateInterpolator()); |
||||
endAnimation.addListener(new AnimatorListenerAdapter() { |
||||
@Override |
||||
public void onAnimationEnd(Animator animation) { |
||||
endAnimationEnd(); |
||||
} |
||||
}); |
||||
endAnimation.start(); |
||||
} |
||||
|
||||
private void endAnimationEmpty() { |
||||
endAnimation = new AnimatorSet(); |
||||
|
||||
ValueAnimator backgroundAlpha = ValueAnimator.ofFloat(1f, 0f); |
||||
backgroundAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { |
||||
@Override |
||||
public void onAnimationUpdate(ValueAnimator animation) { |
||||
setBackgroundAlpha((float) animation.getAnimatedValue()); |
||||
} |
||||
}); |
||||
endAnimation |
||||
.play(ObjectAnimator.ofFloat(imageView, View.Y, imageView.getTop(), imageView.getTop() + dp(20))) |
||||
.with(ObjectAnimator.ofFloat(imageView, View.ALPHA, 1f, 0f)) |
||||
.with(backgroundAlpha); |
||||
|
||||
endAnimation.setDuration(200); |
||||
endAnimation.setInterpolator(new DecelerateInterpolator()); |
||||
endAnimation.addListener(new AnimatorListenerAdapter() { |
||||
@Override |
||||
public void onAnimationEnd(Animator animation) { |
||||
endAnimationEnd(); |
||||
} |
||||
}); |
||||
endAnimation.start(); |
||||
} |
||||
|
||||
private void endAnimationEnd() { |
||||
Window window = ((Activity) getContext()).getWindow(); |
||||
if (Build.VERSION.SDK_INT >= 21) { |
||||
window.setStatusBarColor(statusBarColorPrevious); |
||||
} |
||||
|
||||
callback.onImageViewLayoutDestroy(); |
||||
} |
||||
|
||||
private void setBackgroundAlpha(float alpha) { |
||||
setBackgroundColor(Color.argb((int) (alpha * 255f), 0, 0, 0)); |
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) { |
||||
Window window = ((Activity) getContext()).getWindow(); |
||||
|
||||
int r = (int) ((1f - alpha) * Color.red(statusBarColorPrevious)); |
||||
int g = (int) ((1f - alpha) * Color.green(statusBarColorPrevious)); |
||||
int b = (int) ((1f - alpha) * Color.blue(statusBarColorPrevious)); |
||||
|
||||
window.setStatusBarColor(Color.argb(255, r, g, b)); |
||||
} |
||||
} |
||||
|
||||
public interface Callback { |
||||
public Rect getImageViewLayoutStartBounds(); |
||||
|
||||
public void onImageViewLayoutDestroy(); |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
package org.floens.chan.ui.transition; |
||||
|
||||
import org.floens.chan.controller.ControllerTransition; |
||||
|
||||
public class ImageTransition extends ControllerTransition { |
||||
@Override |
||||
public void perform() { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
package org.floens.chan.ui.view; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.Canvas; |
||||
import android.graphics.Rect; |
||||
import android.util.AttributeSet; |
||||
import android.widget.ImageView; |
||||
|
||||
public class ClippingImageView extends ImageView { |
||||
private Rect clipRect = new Rect(); |
||||
|
||||
public ClippingImageView(Context context) { |
||||
super(context); |
||||
} |
||||
|
||||
public ClippingImageView(Context context, AttributeSet attrs) { |
||||
super(context, attrs); |
||||
} |
||||
|
||||
public ClippingImageView(Context context, AttributeSet attrs, int defStyleAttr) { |
||||
super(context, attrs, defStyleAttr); |
||||
} |
||||
|
||||
@Override |
||||
protected void onDraw(Canvas canvas) { |
||||
if (!clipRect.isEmpty() && (clipRect.width() < getWidth() || clipRect.height() < getHeight())) { |
||||
canvas.clipRect(clipRect); |
||||
} |
||||
|
||||
super.onDraw(canvas); |
||||
} |
||||
|
||||
public void clip(Rect rect) { |
||||
clipRect.set(rect); |
||||
invalidate(); |
||||
} |
||||
} |
@ -1,29 +1,12 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<org.floens.chan.ui.view.TouchBlockingFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:orientation="vertical" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:background="#ffffffff" |
||||
android:padding="16dp"> |
||||
android:layout_height="match_parent"> |
||||
|
||||
<LinearLayout |
||||
<org.floens.chan.ui.view.ClippingImageView |
||||
android:id="@+id/image" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical"> |
||||
android:layout_height="match_parent" /> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="Hello, world!" |
||||
android:textColor="#dd000000" |
||||
android:textSize="20sp" /> |
||||
|
||||
<Button |
||||
android:id="@+id/button" |
||||
android:text="Back" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
</org.floens.chan.ui.view.TouchBlockingFrameLayout> |
||||
</FrameLayout> |
||||
|
@ -1,28 +0,0 @@ |
||||
<?xml version="1.0" encoding="utf-8"?><!-- |
||||
Clover - 4chan browser https://github.com/Floens/Clover/ |
||||
Copyright (C) 2014 Floens |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
--> |
||||
<org.floens.multipanetest.layout.ImageViewLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:background="#ff000000"> |
||||
|
||||
<ImageView |
||||
android:id="@+id/image" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" /> |
||||
|
||||
</org.floens.multipanetest.layout.ImageViewLayout> |
Loading…
Reference in new issue