/* * Copyright 2015. Appsi Mobile * * 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.appsimobile.appsii; import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.InsetDrawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.shapes.RoundRectShape; import android.net.Uri; import android.os.Build; import android.support.annotation.StyleRes; import android.util.Log; import android.view.ContextThemeWrapper; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; /** * Created by Nick Martens on 6/21/13. */ public class ThemingUtils { public static final String PREF_APPSII_THEME = "pref_appsii_theme"; public static final String PREF_APPSII_BASE_THEME = "pref_appsii_base_theme"; public static final String PREF_APPSII_COLOR_PRIMARY = "pref_appsii_color_primary"; public static final String PREF_APPSII_COLOR_ACCENT = "pref_appsii_color_accent"; public static final String DEFAULT_APPSII_THEME = "theme_material_teal"; public static final String DEFAULT_BASE_THEME = "theme_light_dark_ab"; public static final String DEFAULT_COLOR_PRIMARY = "teal"; public static final String DEFAULT_COLOR_ACCENT = "orange"; public static Context createContextThemeWrapper(Context context, SharedPreferences prefs) { String theme = prefs.getString(PREF_APPSII_THEME, DEFAULT_APPSII_THEME); String baseTheme = prefs.getString(PREF_APPSII_BASE_THEME, DEFAULT_BASE_THEME); String primary = prefs.getString(PREF_APPSII_COLOR_PRIMARY, DEFAULT_COLOR_PRIMARY); String accent = prefs.getString(PREF_APPSII_COLOR_ACCENT, DEFAULT_COLOR_ACCENT); return createContextThemeWrapper(context, theme, baseTheme, primary, accent); } public static Context createContextThemeWrapper(Context context, String presetTheme, String theme, String primary, String accent) { Context result = getThemeResFallback(context, presetTheme); if (result == null) { boolean isDark = "theme_dark".equals(theme) || "theme_dark_light_ab".equals(theme); int base = getBaseTheme(theme); int primaryColorTheme = getPrimaryColorTheme(primary); // TODO: add dark param int accentColorTheme = getAccentColorTheme(isDark, accent); result = new ContextThemeWrapper(context, base); result = new ContextThemeWrapper(result, accentColorTheme); return new ContextThemeWrapper(result, primaryColorTheme); } return result; } private static Context getThemeResFallback(Context context, String theme) { ContextThemeWrapper result; switch (theme) { case "theme_material_teal": result = new ContextThemeWrapper( context, R.style.Appsi_Sidebar_Material_LightDarkActionBar); result = new ContextThemeWrapper(result, R.style.Palette_Accent_DeepOrange); return new ContextThemeWrapper(result, R.style.Palette_Primary_Teal); case "theme_material_teal_dark": result = new ContextThemeWrapper( context, R.style.Appsi_Sidebar_Material_Dark); result = new ContextThemeWrapper(result, R.style.Palette_Accent_DeepOrange200); return new ContextThemeWrapper(result, R.style.Palette_Primary_Teal); case "theme_material_light_green": result = new ContextThemeWrapper( context, R.style.Appsi_Sidebar_Material_DarkLightActionBar); result = new ContextThemeWrapper(result, R.style.Palette_Accent_Yellow); return new ContextThemeWrapper(result, R.style.Palette_Primary_LightGreen); case "theme_material_blue_grey": result = new ContextThemeWrapper( context, R.style.Appsi_Sidebar_Material_Dark); result = new ContextThemeWrapper(result, R.style.Palette_Accent_Orange700); return new ContextThemeWrapper(result, R.style.Palette_Primary_BlueGrey); case "theme_material_orange": result = new ContextThemeWrapper( context, R.style.Appsi_Sidebar_Material_Light); result = new ContextThemeWrapper(result, R.style.Palette_Accent_DeepPurple); return new ContextThemeWrapper(result, R.style.Palette_Primary_Orange); } return null; } @StyleRes private static int getBaseTheme(String theme) { switch (theme) { case "theme_dark": return R.style.Appsi_Sidebar_Material_Dark; case "theme_light": return R.style.Appsi_Sidebar_Material_Light; case "theme_dark_light_ab": return R.style.Appsi_Sidebar_Material_DarkLightActionBar; case "theme_light_dark_ab": return R.style.Appsi_Sidebar_Material_LightDarkActionBar; } return R.style.Appsi_Sidebar_Material_Light; } @StyleRes private static int getPrimaryColorTheme(String primary) { if (primary == null) { return R.style.Palette_Primary_Teal; } switch (primary) { case "red": return R.style.Palette_Primary_Red; case "pink": return R.style.Palette_Primary_Pink; case "purple": return R.style.Palette_Primary_Purple; case "deep_purple": return R.style.Palette_Primary_DeepPurple; case "indigo": return R.style.Palette_Primary_Indigo; case "blue": return R.style.Palette_Primary_Blue; case "light_blue": return R.style.Palette_Primary_LightBlue; case "cyan": return R.style.Palette_Primary_Cyan; default: case "teal": return R.style.Palette_Primary_Teal; case "green": return R.style.Palette_Primary_Green; case "light_green": return R.style.Palette_Primary_LightGreen; case "lime": return R.style.Palette_Primary_Lime; case "yellow": return R.style.Palette_Primary_Yellow; case "amber": return R.style.Palette_Primary_Amber; case "orange": return R.style.Palette_Primary_Orange; case "deep_orange": return R.style.Palette_Primary_DeepOrange; case "brown": return R.style.Palette_Primary_Brown; case "grey": return R.style.Palette_Primary_Grey; case "blue_grey": return R.style.Palette_Primary_BlueGrey; } } @StyleRes private static int getAccentColorTheme(boolean isDark, String accent) { if (accent == null) { return isDark ? R.style.Palette_Accent_Orange700 : R.style.Palette_Accent_Orange; } switch (accent) { case "red": return isDark ? R.style.Palette_Accent_Red100 : R.style.Palette_Accent_Red; case "pink": return isDark ? R.style.Palette_Accent_Pink100 : R.style.Palette_Accent_Pink; case "purple": return isDark ? R.style.Palette_Accent_Purple100 : R.style.Palette_Accent_Purple; case "deep_purple": return isDark ? R.style.Palette_Accent_DeepPurple100 : R.style.Palette_Accent_DeepPurple; case "indigo": return isDark ? R.style.Palette_Accent_Indigo100 : R.style.Palette_Accent_Indigo; case "blue": return isDark ? R.style.Palette_Accent_Blue100 : R.style.Palette_Accent_Blue; case "light_blue": return isDark ? R.style.Palette_Accent_LightBlue400 : R.style.Palette_Accent_LightBlue; case "cyan": return isDark ? R.style.Palette_Accent_Cyan700 : R.style.Palette_Accent_Cyan; case "teal": return isDark ? R.style.Palette_Accent_Teal400 : R.style.Palette_Accent_Teal; case "green": return isDark ? R.style.Palette_Accent_Green400 : R.style.Palette_Accent_Green; case "light_green": return isDark ? R.style.Palette_Accent_LightGreen400 : R.style.Palette_Accent_LightGreen; case "lime": return isDark ? R.style.Palette_Accent_Lime400 : R.style.Palette_Accent_Lime; case "yellow": return isDark ? R.style.Palette_Accent_Yellow400 : R.style.Palette_Accent_Yellow; case "amber": return isDark ? R.style.Palette_Accent_Amber400 : R.style.Palette_Accent_Amber; default: case "orange": return isDark ? R.style.Palette_Accent_Orange700 : R.style.Palette_Accent_Orange; case "deep_orange": return isDark ? R.style.Palette_Accent_DeepOrange200 : R.style.Palette_Accent_DeepOrange; } } public static Drawable createButtonDrawable(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return context.getDrawable(R.drawable.button_bg_teal); } TypedArray a = context.obtainStyledAttributes(new int[]{ R.attr.colorPrimary, R.attr.colorAccent, R.attr.colorPrimaryDark, }); int tintColor = a.getColor(0, Color.RED); int darkColor = a.getColor(2, Color.RED); a.recycle(); return createTintedButtonDrawable(context, tintColor, darkColor); } private static Drawable createTintedButtonDrawable(Context context, int tintColor, int darkColor) { Drawable normalState = getButtonStateDrawable(context, tintColor); Drawable pressedState = getButtonStateDrawable(context, darkColor); Drawable focusedState = getButtonStateDrawable(context, darkColor); StateListDrawable result = new StateListDrawable(); result.addState(new int[]{android.R.attr.state_pressed}, pressedState); result.addState(new int[]{android.R.attr.state_focused}, focusedState); result.addState(new int[]{}, normalState); return result; } private static Drawable getButtonStateDrawable(Context context, int color) { Resources res = context.getResources(); int r = res.getDimensionPixelSize(R.dimen.control_corner_material); float[] roundedCorner = new float[]{r, r, r, r, r, r, r, r}; float[] innerRoundedCorner = new float[]{0, 0, 0, 0, 0, 0, 0, 0}; RoundRectShape shape = new RoundRectShape(roundedCorner, null, innerRoundedCorner); ShapeDrawable shapeDrawable = new ShapeDrawable(shape); int paddingVertical = res.getDimensionPixelOffset( R.dimen.button_padding_vertical_material); int paddingHorizontal = res.getDimensionPixelOffset( R.dimen.button_padding_horizontal_material); shapeDrawable.setPadding(paddingHorizontal, paddingVertical, paddingVertical, paddingHorizontal); shapeDrawable.getPaint().setColor(color); int insetHorizontal = res.getDimensionPixelSize( R.dimen.button_inset_horizontal_material); int insetVertical = res .getDimensionPixelSize(R.dimen.button_inset_vertical_material); return new InsetDrawable(shapeDrawable, insetHorizontal, insetVertical, insetHorizontal, insetVertical); } public static int[] createPrimaryColorArray(String[] colorNames) { int N = colorNames.length; int[] colors = new int[N]; for (int i = 0; i < N; i++) { colors[i] = getPrimaryColorValue(colorNames[i]); } return colors; } public static int getPrimaryColorValue(String primary) { if (primary == null) { primary = DEFAULT_COLOR_PRIMARY; } switch (primary) { case "red": return 0xFFF44336; case "pink": return 0xFFE91E63; case "purple": return 0xFF9C27B0; case "deep_purple": return 0xFF673AB7; case "indigo": return 0xFF3F51B5; case "blue": return 0xFF2196F3; case "light_blue": return 0xFF03A9F4; case "cyan": return 0xFF00BCD4; default: case "teal": return 0xFF009688; case "green": return 0xFF4CAF50; case "light_green": return 0xFF8BC34A; case "lime": return 0xFFCDDC39; case "yellow": return 0xFFFFEB3B; case "amber": return 0xFFFFC107; case "orange": return 0xFFFF9800; case "deep_orange": return 0xFFFF5722; case "brown": return 0xFF795548; case "grey": return 0xFF9E9E9E; case "blue_grey": return 0xFF607D8B; } } public static int[] createAccentColorArray(boolean dark, String[] colorNames) { int N = colorNames.length; int[] colors = new int[N]; for (int i = 0; i < N; i++) { colors[i] = getAccentColorValue(dark, colorNames[i]); } return colors; } public static int getAccentColorValue(boolean isDark, String accent) { if (accent == null) { accent = DEFAULT_COLOR_ACCENT; } switch (accent) { case "red": return isDark ? 0xFFFF1744 : 0xFFFF8A80; case "pink": return isDark ? 0xFFFF80AB : 0xFFF50057; case "purple": return isDark ? 0xFFEA80FC : 0xFFD500F9; case "deep_purple": return isDark ? 0xFFB388FF : 0xFF651FFF; case "indigo": return isDark ? 0xFF8C9EFF : 0xFF3D5AFE; case "blue": return isDark ? 0xFF82B1FF : 0xFF2979FF; case "light_blue": return isDark ? 0xFF00B0FF : 0xFF0091EA; case "cyan": return isDark ? 0xFF00E5FF : 0xFF00B8D4; case "teal": return isDark ? 0xFF1DE9B6 : 0xFF00BFA5; case "green": return isDark ? 0xFF00E676 : 0xFF00C853; case "light_green": return isDark ? 0xFF76FF03 : 0xFF64DD17; case "lime": return isDark ? 0xFFC6FF00 : 0xFFAEEA00; case "yellow": return isDark ? 0xFFFFEA00 : 0xFFFFD600; case "amber": return isDark ? 0xFFFFC400 : 0xFFFFAB00; default: case "orange": return isDark ? 0xFFFF6D00 : 0xFFFF9100; case "deep_orange": return isDark ? 0xFFFF6E40 : 0xFFFF3D00; } } public static boolean canUseFadingEdges(SharedPreferences preferences) { return false; /* boolean useBackground = preferences.getBoolean("pref_sidebar_custom_background", false); return !useBackground; */ } static int getAlpha(int preferenceValue) { preferenceValue = 100 - Math.min(preferenceValue, 100); return (preferenceValue * 255) / 100; } static float getPercentage(int preferenceValue) { preferenceValue = Math.min(preferenceValue, 100); return (preferenceValue) / 100f; } public static Bitmap getSidebarWallpaper(Context context, SharedPreferences preferences, int sidebarWidth, int sidebarHeight) { return getSidebarWallpaperApi10(context, preferences, sidebarWidth, sidebarHeight); } @TargetApi(10) private static Bitmap getSidebarWallpaperApi10(Context context, SharedPreferences preferences, int sidebarWidth, int sidebarHeight) { boolean useBackground = preferences.getBoolean("pref_sidebar_custom_background", false); if (!useBackground) return null; String path = preferences.getString("pref_sidebar_background_image", null); if (path == null) return null; try { BitmapFactory.Options bounds = decodeBounds(createWallpaperInputStream(context, path)); int decodeHeight = Math.min(bounds.outHeight, sidebarHeight); int decodeWidth = Math.min(bounds.outWidth, sidebarWidth); InputStream in = createWallpaperInputStream(context, path); try { BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(in, false); BitmapFactory.Options options = new BitmapFactory.Options(); return decoder.decodeRegion(new Rect(0, 0, decodeWidth, decodeHeight), options); } finally { in.close(); } } catch (IOException e) { return null; } } static BitmapFactory.Options decodeBounds(InputStream in) throws IOException { BitmapFactory.Options options = new BitmapFactory.Options(); try { // Decode image size options.inJustDecodeBounds = true; BitmapFactory.decodeStream(in, null, options); return options; } finally { in.close(); } } public static InputStream createWallpaperInputStream(Context context, String preferenceValue) throws FileNotFoundException { File file = new File(preferenceValue); if (file.exists()) { return new FileInputStream(file); } Uri uri = Uri.parse(preferenceValue); ContentResolver contentResolver = context.getContentResolver(); try { return contentResolver.openInputStream(uri); } catch (SecurityException e) { Log.i("ThemingUtils", "unable to open background image", e); FileNotFoundException fileNotFoundException = new FileNotFoundException(e.getMessage()); fileNotFoundException.initCause(e); throw fileNotFoundException; } } }