fedilab-Android-App/app/src/main/java/app/fedilab/android/mastodon/helper/ThemeHelper.java

325 lines
12 KiB
Java

package app.fedilab.android.mastodon.helper;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* 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.
*
* Fedilab 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 Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static android.content.Context.WINDOW_SERVICE;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import androidx.annotation.AttrRes;
import androidx.annotation.ColorInt;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.color.DynamicColors;
import com.google.android.material.color.DynamicColorsOptions;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import app.fedilab.android.R;
public class ThemeHelper {
@ColorInt
public static int getAttColor(Context context, @AttrRes int attColor) {
TypedValue typedValue = new TypedValue();
Resources.Theme theme = context.getTheme();
theme.resolveAttribute(attColor, typedValue, true);
return typedValue.data;
}
public static int fetchAccentColor(Context context) {
TypedValue typedValue = new TypedValue();
TypedArray a = context.obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorAccent});
int color = a.getColor(0, 0);
a.recycle();
return color;
}
/**
* Animate two views, the current view will be hidden to left
*
* @param viewToHide View to hide
* @param viewToShow View to show
* @param slideAnimation listener for the animation
*/
public static void slideViewsToLeft(View viewToHide, View viewToShow, SlideAnimation slideAnimation) {
TranslateAnimation animateHide = new TranslateAnimation(
0,
-viewToHide.getWidth(),
0,
0);
TranslateAnimation animateShow = new TranslateAnimation(
viewToShow.getWidth(),
0,
0,
0);
animateShow.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
viewToShow.setVisibility(View.VISIBLE);
viewToHide.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animation animation) {
viewToHide.setVisibility(View.GONE);
if (slideAnimation != null) {
slideAnimation.onAnimationEnded();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
animateHide.setDuration(300);
animateHide.setFillAfter(true);
animateShow.setDuration(300);
animateShow.setFillAfter(true);
viewToHide.startAnimation(animateHide);
viewToShow.startAnimation(animateShow);
}
/**
* Animate two views, the current view will be hidden to right
*
* @param viewToHide View to hide
* @param viewToShow View to show
* @param slideAnimation listener for the animation
*/
public static void slideViewsToRight(View viewToHide, View viewToShow, SlideAnimation slideAnimation) {
TranslateAnimation animateHide = new TranslateAnimation(
0,
viewToHide.getWidth(),
0,
0);
TranslateAnimation animateShow = new TranslateAnimation(
-viewToShow.getWidth(),
0,
0,
0);
animateShow.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
viewToShow.setVisibility(View.VISIBLE);
viewToHide.setVisibility(View.VISIBLE);
if (slideAnimation != null) {
slideAnimation.onAnimationEnded();
}
}
@Override
public void onAnimationEnd(Animation animation) {
viewToHide.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
animateHide.setDuration(300);
animateShow.setDuration(300);
viewToHide.requestLayout();
viewToHide.startAnimation(animateHide);
viewToShow.startAnimation(animateShow);
}
public static List<LinkedHashMap<String, String>> getContributorsTheme(Context context) {
List<LinkedHashMap<String, String>> linkedHashMaps = new ArrayList<>();
String[] list;
try {
list = context.getAssets().list("themes/contributors");
if (list.length > 0) {
for (String file : list) {
InputStream is = context.getAssets().open("themes/contributors/" + file);
LinkedHashMap<String, String> data = readCSVFile(is);
linkedHashMaps.add(data);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return linkedHashMaps;
}
private static LinkedHashMap<String, String> readCSVFile(InputStream inputStream) {
LinkedHashMap<String, String> readValues = new LinkedHashMap<>();
if (inputStream != null) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
String[] line = sCurrentLine.split(",");
if (line.length > 1) {
String key = line[0];
String value = line[1];
readValues.put(key, value);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
return readValues;
}
/**
* Allow to set colors for no description on media
*
* @param context - Context
* @return - ColorStateList
*/
public static ColorStateList getNoDescriptionColorStateList(Context context) {
int[][] states = new int[][]{
new int[]{android.R.attr.state_selected},
new int[]{-android.R.attr.state_selected},
};
int[] colors = new int[]{
ContextCompat.getColor(context, R.color.no_description),
ContextCompat.getColor(context, R.color.no_description),
};
return new ColorStateList(states, colors);
}
/**
* Allow to set colors for having description on media
*
* @param context - Context
* @return - ColorStateList
*/
public static ColorStateList getHavingDescriptionColorStateList(Context context) {
int[][] states = new int[][]{
new int[]{android.R.attr.state_selected},
new int[]{-android.R.attr.state_selected},
};
int[] colors = new int[]{
ContextCompat.getColor(context, R.color.having_description),
ContextCompat.getColor(context, R.color.having_description),
};
return new ColorStateList(states, colors);
}
/**
* Allow to change font scale in activities
*
* @param activity - Activity
* @param configuration - Configuration
*/
public static void adjustFontScale(Activity activity, Configuration configuration) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
configuration.fontScale = prefs.getFloat(activity.getString(R.string.SET_FONT_SCALE), 1.1f);
DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
WindowManager wm = (WindowManager) activity.getSystemService(WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics(metrics);
metrics.scaledDensity = configuration.fontScale * metrics.density;
activity.getBaseContext().getResources().updateConfiguration(configuration, metrics);
}
public static void switchTo(String themePref) {
if (themes.LIGHT.name().equals(themePref) || themes.SOLARIZED_LIGHT.name().equals(themePref)) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else if (themes.DARK.name().equals(themePref) || themes.SOLARIZED_DARK.name().equals(themePref)) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
}
}
}
public static void applyThemeColor(Activity activity) {
int currentNightMode = activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
boolean dynamicColor = sharedpreferences.getBoolean(activity.getString(R.string.SET_DYNAMICCOLOR), false);
boolean customAccentEnabled = sharedpreferences.getBoolean(activity.getString(R.string.SET_CUSTOM_ACCENT) + currentUserID + currentInstance, false);
int customAccentLight = sharedpreferences.getInt(activity.getString(R.string.SET_CUSTOM_ACCENT_LIGHT_VALUE) + currentUserID + currentInstance, -1);
int customAccentDark = sharedpreferences.getInt(activity.getString(R.string.SET_CUSTOM_ACCENT_DARK_VALUE) + currentUserID + currentInstance, -1);
if (customAccentEnabled) {
Bitmap bmp = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
//Light theme enabled
if (currentNightMode == Configuration.UI_MODE_NIGHT_NO && customAccentLight != -1) {
canvas.drawColor(customAccentLight);
} else if (customAccentDark != -1) {
canvas.drawColor(customAccentDark);
}
DynamicColorsOptions.Builder builder = new DynamicColorsOptions.Builder();
builder.setContentBasedSource(bmp);
DynamicColorsOptions dynamicColorsOptions = builder.build();
DynamicColors.applyToActivityIfAvailable(activity, dynamicColorsOptions);
} else if (dynamicColor) {
DynamicColors.applyToActivityIfAvailable(activity);
}
}
public enum themes {
LIGHT,
DARK,
SYSTEM,
SOLARIZED_LIGHT,
SOLARIZED_DARK
}
public interface SlideAnimation {
void onAnimationEnded();
}
}