package com.quran.labs.androidquran.widgets;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.os.Build;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Px;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import com.quran.labs.androidquran.R;
import com.quran.labs.androidquran.data.Constants;
import com.quran.labs.androidquran.ui.helpers.QuranDisplayHelper;
import com.quran.labs.androidquran.ui.util.PageController;
import com.quran.labs.androidquran.util.QuranSettings;
public abstract class QuranPageLayout extends QuranPageWrapperLayout
implements ObservableScrollView.OnScrollListener {
@IntDef( { BorderMode.HIDDEN, BorderMode.LIGHT, BorderMode.DARK, BorderMode.LINE } )
@interface BorderMode {
int HIDDEN = 0;
int LIGHT = 1;
int DARK = 2;
int LINE = 3;
}
private static PaintDrawable leftGradient;
private static PaintDrawable rightGradient;
private static int gradientForNumberOfPages;
private static boolean areGradientsLandscape;
private static BitmapDrawable leftPageBorder;
private static BitmapDrawable rightPageBorder;
private static BitmapDrawable leftPageBorderNight;
private static BitmapDrawable rightPageBorderNight;
private static int lineColor;
private static ShapeDrawable lineDrawable;
protected Context context;
protected PageController pageController;
protected int pageNumber;
protected boolean shouldHideLine;
protected boolean isFullWidth;
private ObservableScrollView scrollView;
private @BorderMode int leftBorder;
private @BorderMode int rightBorder;
private View innerView;
private int viewPaddingSmall;
private int viewPaddingLarge;
public QuranPageLayout(Context context) {
super(context);
this.context = context;
ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR);
Resources resources = context.getResources();
final boolean isLandscape =
resources.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
innerView = generateContentView(context, isLandscape);
viewPaddingSmall = resources.getDimensionPixelSize(R.dimen.page_margin_small);
viewPaddingLarge = resources.getDimensionPixelSize(R.dimen.page_margin_large);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
if (isLandscape && shouldWrapWithScrollView()) {
scrollView = new ObservableScrollView(context);
scrollView.setFillViewport(true);
addView(scrollView, lp);
scrollView.addView(innerView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
scrollView.setOnScrollListener(this);
} else {
addView(innerView, lp);
}
if (areGradientsLandscape != isLandscape) {
leftGradient = null;
rightGradient = null;
areGradientsLandscape = isLandscape;
}
if (lineDrawable == null) {
lineDrawable = new ShapeDrawable(new RectShape());
lineDrawable.setIntrinsicWidth(1);
lineDrawable.setIntrinsicHeight(1);
// these bitmaps are 11x1, so fairly small to keep both day and night versions around
leftPageBorder = new BitmapDrawable(resources,
BitmapFactory.decodeResource(resources, R.drawable.border_left));
leftPageBorderNight = new BitmapDrawable(resources,
BitmapFactory.decodeResource(resources, R.drawable.night_left_border));
rightPageBorder = new BitmapDrawable(resources,
BitmapFactory.decodeResource(resources, R.drawable.border_right));
rightPageBorderNight = new BitmapDrawable(resources,
BitmapFactory.decodeResource(resources, R.drawable.night_right_border));
}
updateGradients();
setWillNotDraw(false);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
View view = resolveView();
if (view != null) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (!isFullWidth) {
int leftLineWidth = leftBorder == BorderMode.LINE ? 1 : leftPageBorder.getIntrinsicWidth();
int rightLineWidth = rightBorder == BorderMode.HIDDEN ?
0 : rightPageBorder.getIntrinsicWidth();
int headerFooterHeight = 0;
width = width - (leftLineWidth + rightLineWidth + viewPaddingSmall + viewPaddingLarge);
height = height - 2 * headerFooterHeight;
}
view.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View view = resolveView();
if (view != null) {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
@Px int leftLineWidth = leftBorder == BorderMode.LINE ?
1 : leftPageBorder.getIntrinsicWidth();
@Px int rightLineWidth = rightBorder == BorderMode.HIDDEN ?
0 : rightPageBorder.getIntrinsicWidth();
int headerFooterHeight = 0;
view.layout(leftLineWidth, headerFooterHeight,
width - rightLineWidth, height - headerFooterHeight);
super.onLayout(changed, l, t, r, b);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
if (width > 0) {
int height = getHeight();
if (leftBorder != BorderMode.LINE || !shouldHideLine) {
Drawable left = leftBorder == BorderMode.LINE ? lineDrawable :
leftBorder == BorderMode.LIGHT ? leftPageBorder : leftPageBorderNight;
left.setBounds(0, 0, left.getIntrinsicWidth(), height);
left.draw(canvas);
}
if (rightBorder != BorderMode.HIDDEN) {
Drawable right = rightBorder == BorderMode.LIGHT ? rightPageBorder : rightPageBorderNight;
right.setBounds(width - right.getIntrinsicWidth(), 0, width, height);
right.draw(canvas);
}
}
}
protected abstract View generateContentView(Context context, boolean isLandscape);
protected boolean shouldWrapWithScrollView() {
return true;
}
private View resolveView() {
return scrollView != null ? scrollView : innerView;
}
public void setPageController(PageController controller, int pageNumber) {
this.pageNumber = pageNumber;
this.pageController = controller;
}
protected int getPagesVisible() {
return 1;
}
private void updateGradients() {
int pagesVisible = getPagesVisible();
if (rightGradient == null || gradientForNumberOfPages != pagesVisible) {
final WindowManager mgr =
(WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display display = mgr.getDefaultDisplay();
int width = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ?
QuranDisplayHelper.getWidthKitKat(display) : display.getWidth();
width = width / pagesVisible;
leftGradient = QuranDisplayHelper.getPaintDrawable(width, 0);
rightGradient = QuranDisplayHelper.getPaintDrawable(0, width);
gradientForNumberOfPages = pagesVisible;
}
}
@Override
public void updateView(@NonNull QuranSettings quranSettings) {
super.updateView(quranSettings);
boolean nightMode = quranSettings.isNightMode();
int lineColor = Color.BLACK;
final int nightModeTextBrightness = nightMode ?
quranSettings.getNightModeTextBrightness() : Constants.DEFAULT_NIGHT_MODE_TEXT_BRIGHTNESS;
if (nightMode) {
lineColor = Color.argb(nightModeTextBrightness, 255, 255, 255);
}
if (pageNumber % 2 == 0) {
leftBorder = nightMode ? BorderMode.DARK : BorderMode.LIGHT;
rightBorder = BorderMode.HIDDEN;
} else {
rightBorder = nightMode ? BorderMode.DARK : BorderMode.LIGHT;
if (QuranPageLayout.lineColor != lineColor) {
QuranPageLayout.lineColor = lineColor;
lineDrawable.getPaint().setColor(lineColor);
}
leftBorder = BorderMode.LINE;
}
updateBackground(nightMode, quranSettings);
}
protected void updateBackground(boolean nightMode, QuranSettings quranSettings) {
if (nightMode) {
setBackgroundColor(Color.BLACK);
} else if (quranSettings.useNewBackground()) {
setBackgroundDrawable((pageNumber % 2 == 0 ? leftGradient : rightGradient));
} else {
setBackgroundColor(ContextCompat.getColor(context, R.color.page_background));
}
}
@Override
void handleRetryClicked() {
if (pageController != null) {
pageController.handleRetryClicked();
}
}
public int getCurrentScrollY() {
return scrollView == null ? 0 : scrollView.getScrollY();
}
public boolean canScroll() {
return scrollView != null;
}
public void smoothScrollLayoutTo(int y) {
scrollView.smoothScrollTo(scrollView.getScrollX(), y);
}
@Override
public void onScrollChanged(ObservableScrollView scrollView,
int x, int y, int oldx, int oldy) {
if (pageController != null) {
pageController.onScrollChanged(x, y, oldx, oldy);
}
}
}