/*
* Copyright (C) 2014 Michell Bak
*
* 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 com.miz.utils;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.GradientDrawable;
import android.preference.PreferenceManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.miz.functions.Actor;
import com.miz.functions.GridSeason;
import com.miz.functions.MizLib;
import com.miz.functions.WebMovie;
import com.miz.mizuu.MizuuApplication;
import com.miz.mizuu.R;
import com.miz.views.ObservableScrollView;
import com.squareup.picasso.Picasso;
import java.util.List;
import static com.miz.functions.PreferenceKeys.GRID_ITEM_SIZE;
public class ViewUtils {
private ViewUtils() {} // No instantiation
/**
* Returns a actor card with name, character, image and click listener.
* @param context
* @param picasso
* @param actor
* @return
*/
@SuppressLint("InflateParams")
public static View setupActorCard(final Activity context, Picasso picasso, final Actor actor) {
View v = LayoutInflater.from(context).inflate(R.layout.horizontal_grid_item_small, null);
// Load image
picasso.load(actor.getUrl()).placeholder(R.color.card_background_dark).error(R.drawable.noactor).config(MizuuApplication.getBitmapConfig()).into(((ImageView) v.findViewById(R.id.cover)));
// Set title
((TextView) v.findViewById(R.id.text)).setText(actor.getName());
((TextView) v.findViewById(R.id.text)).setTypeface(TypefaceUtils.getRobotoMedium(context));
// Set subtitle
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setText(actor.getCharacter());
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setSingleLine(true);
// Set click listener
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
context.startActivity(IntentUtils.getActorIntent(context, actor));
}
});
return v;
}
/**
* Returns a movie card with title, release date, image and click listener.
* @param context
* @param picasso
* @param movie
* @return
*/
@SuppressLint("InflateParams")
public static View setupMovieCard(final Activity context, Picasso picasso, final WebMovie movie) {
final View v = LayoutInflater.from(context).inflate(R.layout.horizontal_grid_item_small, null);
// Load image
picasso.load(movie.getUrl()).placeholder(R.color.card_background_dark).error(R.drawable.loading_image).config(MizuuApplication.getBitmapConfig()).into(((ImageView) v.findViewById(R.id.cover)));
// Set title
((TextView) v.findViewById(R.id.text)).setText(movie.getTitle());
((TextView) v.findViewById(R.id.text)).setTypeface(TypefaceUtils.getRobotoMedium(context));
// Set subtitle
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setText(movie.getSubtitle());
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setSingleLine(true);
// Set click listener
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(context, v.findViewById(R.id.cover), "cover");
ActivityCompat.startActivity(context, IntentUtils.getTmdbMovieDetails(context, movie), options.toBundle());
}
});
return v;
}
/**
* Returns a TV show card with title, release date, image and click listener.
* @param context
* @param picasso
* @param show
* @return
*/
@SuppressLint("InflateParams")
public static View setupTvShowCard(final Context context, Picasso picasso, final WebMovie show) {
View v = LayoutInflater.from(context).inflate(R.layout.horizontal_grid_item_small, null);
// Load image
picasso.load(show.getUrl()).placeholder(R.color.card_background_dark).error(R.drawable.loading_image).config(MizuuApplication.getBitmapConfig()).into(((ImageView) v.findViewById(R.id.cover)));
// Set title
((TextView) v.findViewById(R.id.text)).setText(show.getTitle());
((TextView) v.findViewById(R.id.text)).setTypeface(TypefaceUtils.getRobotoMedium(context));
// Set subtitle
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setText(show.getSubtitle());
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setSingleLine(true);
// Set click listener
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
context.startActivity(IntentUtils.getTmdbTvShowLink(context, show));
}
});
return v;
}
/**
* Returns a TV show season card with title, release date, image and click listener.
* @param context
* @param picasso
* @param season
* @return
*/
@SuppressLint("InflateParams")
public static View setupTvShowSeasonCard(final Activity context, Picasso picasso, final GridSeason season, final int toolbarColor) {
final View v = LayoutInflater.from(context).inflate(R.layout.horizontal_grid_item_small, null);
// Load image
picasso.load(season.getCover()).placeholder(R.color.card_background_dark).error(R.drawable.loading_image).config(
MizuuApplication.getBitmapConfig()).into(((ImageView) v.findViewById(R.id.cover)));
// Set title
((TextView) v.findViewById(R.id.text)).setText(season.getHeaderText());
((TextView) v.findViewById(R.id.text)).setTypeface(TypefaceUtils.getRobotoMedium(context));
// Set subtitle
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setText(season.getSimpleSubtitleText());
((TextView) v.findViewById(R.id.gridCoverSubtitle)).setSingleLine(true);
// Set click listener
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
context.startActivityForResult(IntentUtils.getTvShowSeasonIntent(context, season.getShowId(), season.getSeason(), season.getEpisodeCount(), toolbarColor), 0);
}
});
return v;
}
/**
* Returns a photo card with image and click listener.
* @param context
* @param picasso
* @param url
* @param items
* @param index
* @return
*/
@SuppressLint("InflateParams")
public static View setupPhotoCard(final Context context, Picasso picasso, final String url, final List<String> items, final int index) {
final View v = LayoutInflater.from(context).inflate(R.layout.horizontal_grid_item_small_no_text, null);
// Load image
picasso.load(url).placeholder(R.color.card_background_dark).error(R.drawable.noactor).config(MizuuApplication.getBitmapConfig()).into(((ImageView) v.findViewById(R.id.cover)));
// Set click listener
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
context.startActivity(IntentUtils.getActorPhotoIntent(context, items, index));
}
});
return v;
}
/**
* Returns a photo card with image and click listener.
* @param context
* @param picasso
* @param url
* @param items
* @param index
* @return
*/
@SuppressLint("InflateParams")
public static View setupTaggedPhotoCard(final Context context, Picasso picasso, final String url, final List<String> items, final int index) {
View v = LayoutInflater.from(context).inflate(R.layout.horizontal_grid_item_small_landscape_no_text, null);
// Load image
picasso.load(url).placeholder(R.color.card_background_dark).error(R.drawable.noactor).config(MizuuApplication.getBitmapConfig()).into(((ImageView) v.findViewById(R.id.cover)));
// Set click listener
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
context.startActivity(IntentUtils.getActorTaggedPhotoIntent(context, items, index));
}
});
return v;
}
/**
* Animates the transition when changing the maxLines
* attribute of a TextView.
* @param text
* @param maxLines
*/
public static void animateTextViewMaxLines(TextView text, int maxLines) {
try {
ObjectAnimator animation = ObjectAnimator.ofInt(text, "maxLines", maxLines);
animation.setInterpolator(new AccelerateInterpolator());
animation.setDuration(200);
animation.start();
} catch (Exception e) {
// Some devices crash at runtime when using the ObjectAnimator
text.setMaxLines(maxLines);
}
}
public static void animateFabJump(View fab, Animator.AnimatorListener listener) {
try {
ObjectAnimator animation = ObjectAnimator.ofFloat(fab, "translationY", -10f, -5f, 0f, 5f, 10f, 5f, 0f, -5f, -10f, -5f, 0f);
animation.setDuration(350);
animation.addListener(listener);
animation.start();
} catch (Exception e) {
// Some devices crash at runtime when using the ObjectAnimator
}
}
private static int defaultTitleTextColor = -1;
/**
* Update the Toolbar background color and title.
* @param activity
* @param toolbar
* @param alpha
* @param title
* @param color
*/
public static void updateToolbarBackground(Activity activity, Toolbar toolbar,
int alpha, String title, int color) {
if (defaultTitleTextColor == -1) {
int[] textColorAttr = new int[]{R.attr.actionMenuTextColor};
TypedValue typedValue = new TypedValue();
int indexOfAttrTextColor = 0;
TypedArray a = activity.obtainStyledAttributes(typedValue.data, textColorAttr);
defaultTitleTextColor = a.getColor(indexOfAttrTextColor, -1);
a.recycle();
}
toolbar.setTitle(title);
toolbar.setTitleTextColor(adjustAlpha(defaultTitleTextColor, alpha));
int toolbarColor = adjustAlpha(color, alpha);
if (MizLib.hasJellyBean()) {
int topColor = darkenColor(color, alpha / 255f);
topColor = adjustAlpha(topColor, Math.max(125, alpha));
int[] colors = {topColor, toolbarColor};
toolbar.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors));
} else {
toolbar.setBackgroundColor(toolbarColor);
}
}
public static int adjustAlpha(int color, int alpha) {
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
return Color.argb(alpha, red, green, blue);
}
public static int darkenColor(int color, float factor) {
final float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= factor;
return Color.HSVToColor(hsv);
}
public static boolean isTranslucentDecorAvailable(Context context) {
int id = context.getResources().getIdentifier("config_enableTranslucentDecor", "bool", "android");
return (id == 0) && context.getResources().getBoolean(id);
}
public static int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public static int getNavigationDrawerWidth(Context context) {
int drawerWidth;
// The navigation drawer should have a width equal to
// the screen width minus the Toolbar height - at least
// on mobile devices. Tablets are accounted for below.
int toolbarHeight = MizLib.getActionBarHeight(context);
// Get the display size
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Get the smallest number
int smallestDisplayWidth = Math.min(size.x, size.y);
// Calculate the drawer width
drawerWidth = smallestDisplayWidth - toolbarHeight;
// Make sure that the calculated drawer width
// isn't greater than the max width, i.e.
// 5 times the standard increment (56dp for
// mobile or 64dp for tablets).
int maxWidth = MizLib.convertDpToPixels(context, 5 * (MizLib.isTablet(context) ? 64 : 56));
if (drawerWidth > maxWidth)
drawerWidth = maxWidth;
return drawerWidth;
}
/**
* Since Toolbar needs to be bigger than the default height in some cases,
* this method will change the height to include the status bar on Kitkat and newer.
* @param context
* @param toolbar
*/
public static void setProperToolbarSize(Context context, Toolbar toolbar) {
toolbar.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
MizLib.hasKitKat() ? MizLib.getActionBarAndStatusBarHeight(context) : MizLib.getActionBarHeight(context)));
}
public static void setupWindowFlagsForStatusbarOverlay(Window window, boolean setBackgroundResource) {
if (MizLib.isKitKat()) {
// If we're running on KitKat, we want to enable
// the translucent status bar
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
if (MizLib.hasKitKat()) {
// If we're running on KitKat or above, we want to show
// the background image beneath the status bar as well.
window.getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
// Make the status bar color transparent to begin with
if (MizLib.hasLollipop())
window.setStatusBarColor(Color.TRANSPARENT);
// If requested, set a background resource on the Window object
if (setBackgroundResource)
window.setBackgroundDrawableResource(R.drawable.bg);
}
public static void setLayoutParamsForDetailsEmptyView(Context context, View layout, ImageView background, ObservableScrollView scrollView, ViewTreeObserver.OnGlobalLayoutListener listener) {
if (!MizLib.isPortrait(context)) {
// Let's set the size of the empty view on the scroll container
View empty = layout.findViewById(R.id.empty_view);
if (empty == null)
return;
// First, we get the height of the background image, since that
// fills the available screen estate in its entirety
int fullHeight = background.getHeight();
// Then we get the content height - this is how much of the content
// will be shown on the screen at a minimum
int contentHeight = context.getResources().getDimensionPixelSize(R.dimen.content_details_main_height);
// Finally we set the empty view to fill the width and have a height
// that fills the gap between the full height and content height
empty.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, fullHeight - contentHeight));
}
// Remove the ViewTreeObserver when we're done :-)
MizLib.removeViewTreeObserver(scrollView.getViewTreeObserver(), listener);
}
public static void handleOnScrollChangedEvent(Activity activity, View layout, View background, String title, int height, int t, Toolbar toolbar, int toolbarColor) {
final int headerHeight = (MizLib.isPortrait(activity) ? background.getHeight() : layout.findViewById(R.id.empty_view).getHeight()) - height;
final float ratio = (float) Math.min(Math.max(t, 0), headerHeight) / headerHeight;
final int newAlpha = (int) (ratio * 255);
// Update the Toolbar
ViewUtils.updateToolbarBackground(activity, toolbar, newAlpha, title, toolbarColor);
if (MizLib.isPortrait(activity)) {
// Such parallax, much wow
background.setPadding(0, (int) (t / 1.5), 0, 0);
}
// Update scroll background in landscape mode
if (!MizLib.isPortrait(activity)) {
View v = layout.findViewById(R.id.background_view);
View v2 = layout.findViewById(R.id.background_view_more);
final int backgroundAlpha = (int) (ratio * 15) + 240;
v.setBackgroundColor(ViewUtils.adjustAlpha(Color.parseColor("#303030"), backgroundAlpha));
v2.setBackgroundColor(ViewUtils.adjustAlpha(Color.parseColor("#303030"), backgroundAlpha));
}
}
public static void setToolbarAndStatusBarColor(android.support.v7.app.ActionBar actionBar, Window window, int color) {
if (color != 0) {
actionBar.setBackgroundDrawable(new ColorDrawable(color));
if (MizLib.hasLollipop())
window.setStatusBarColor(color);
}
}
public static int getGridViewThumbSize(Context context) {
int thumbSize = 0;
String thumbnailSize = PreferenceManager.getDefaultSharedPreferences(context).getString(GRID_ITEM_SIZE, context.getString(R.string.normal));
if (thumbnailSize.equals(context.getString(R.string.large)))
thumbSize = (int) (context.getResources().getDimensionPixelSize(R.dimen.image_thumbnail_size) * 1.33);
else if (thumbnailSize.equals(context.getString(R.string.normal)))
thumbSize = (context.getResources().getDimensionPixelSize(R.dimen.image_thumbnail_size) * 1);
else
thumbSize = (int) (context.getResources().getDimensionPixelSize(R.dimen.image_thumbnail_size) * 0.75);
return thumbSize;
}
}