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

394 lines
14 KiB
Java

package app.fedilab.android.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 android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
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.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.PreferenceManager;
import com.google.android.material.button.MaterialButton;
import com.jaredrummler.cyanea.Cyanea;
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;
import app.fedilab.android.activities.BaseActivity;
public class ThemeHelper {
public static int linkColor;
@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;
}
/**
* Initialize colors in a static variable
* Currently link_color cannot be retrieved with getAttColor in ViewModel due to application and theme
*
* @param activity Activity
*/
public static void initiliazeColors(Activity activity) {
TypedValue typedValue = new TypedValue();
Resources.Theme theme = activity.getTheme();
theme.resolveAttribute(R.attr.linkColor, typedValue, true);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
linkColor = -1;
if (prefs.getBoolean("use_custom_theme", false)) {
linkColor = prefs.getInt("theme_link_color", -1);
}
if (linkColor == -1) {
linkColor = typedValue.data;
}
}
public static void applyTheme(BaseActivity activity) {
if (Cyanea.getInstance().isDark()) {
activity.setTheme(R.style.AppThemeDark);
} else {
activity.setTheme(R.style.AppTheme);
}
}
public static void applyThemeDialog(BaseActivity activity) {
if (Cyanea.getInstance().isDark()) {
activity.setTheme(R.style.DialogDark);
} else {
activity.setTheme(R.style.Dialog);
}
}
public static void applyThemeBar(BaseActivity activity) {
if (Cyanea.getInstance().isDark()) {
activity.setTheme(R.style.AppThemeBarDark);
} else {
activity.setTheme(R.style.AppThemeBar);
}
}
/**
* 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 tablayout
*
* @param context - Context
* @return - ColorStateList
*/
public static ColorStateList getColorStateList(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.cyanea_accent_dark_reference),
getAttColor(context, R.attr.mTextColor)
};
return new ColorStateList(states, colors);
}
/**
* Change all color for a Material button
*
* @param context - Context
* @param materialButton - MaterialButton
*/
public static void changeButtonColor(Context context, MaterialButton materialButton) {
materialButton.setRippleColor(ThemeHelper.getButtonColorStateList(context));
materialButton.setStrokeColor(ThemeHelper.getButtonColorStateList(context));
materialButton.setTextColor(ThemeHelper.getButtonColorStateList(context));
materialButton.setIconTint(ThemeHelper.getButtonColorStateList(context));
materialButton.setBackgroundTintList(ThemeHelper.getBackgroundButtonColorStateList(context));
}
/**
* Allow to set ThumbDrawable colors for SwitchCompat
*
* @param context - Context
* @return - ColorStateList
*/
public static ColorStateList getSwitchCompatThumbDrawable(Context context) {
int[][] states = new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{-android.R.attr.state_checked},
};
int alphaColor = ColorUtils.setAlphaComponent(ContextCompat.getColor(context, R.color.cyanea_accent_dark_reference), 0xee);
int alphaColorUnchecked = ColorUtils.setAlphaComponent(getAttColor(context, R.attr.mTextColor), 0xaa);
int[] colors = new int[]{
alphaColor,
alphaColorUnchecked
};
return new ColorStateList(states, colors);
}
/**
* Allow to set TrackDrawable colors for SwitchCompat
*
* @param context - Context
* @return - ColorStateList
*/
public static ColorStateList getSwitchCompatTrackDrawable(Context context) {
int[][] states = new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{-android.R.attr.state_checked},
};
int alphaColor = ColorUtils.setAlphaComponent(ContextCompat.getColor(context, R.color.cyanea_accent_dark_reference), 0x33);
int alphaColorUnchecked = ColorUtils.setAlphaComponent(getAttColor(context, R.attr.mTextColor), 0x33);
int[] colors = new int[]{
alphaColor,
alphaColorUnchecked
};
return new ColorStateList(states, colors);
}
/**
* Allow to set colors for Material buttons inside a toggle group
*
* @param context - Context
* @return - ColorStateList
*/
public static ColorStateList getButtonColorStateList(Context context) {
int[][] states = new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{-android.R.attr.state_checked},
};
int[] colors = new int[]{
ContextCompat.getColor(context, R.color.cyanea_accent_dark_reference),
getAttColor(context, R.attr.mTextColor)
};
return new ColorStateList(states, colors);
}
/**
* Allow to set background colors for Material buttons inside a toggle group
*
* @param context - Context
* @return - ColorStateList
*/
private static ColorStateList getBackgroundButtonColorStateList(Context context) {
int[][] states = new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{-android.R.attr.state_checked},
};
int alphaColor = ColorUtils.setAlphaComponent(ContextCompat.getColor(context, R.color.cyanea_accent_dark_reference), 0x33);
int[] colors = new int[]{
alphaColor,
ContextCompat.getColor(context, R.color.transparent)
};
return new ColorStateList(states, colors);
}
/**
* Send broadcast to recreate Mainactivity
*
* @param activity - Activity
*/
public static void recreateMainActivity(Activity activity) {
Bundle b = new Bundle();
b.putBoolean(Helper.RECEIVE_RECREATE_ACTIVITY, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
intentBD.putExtras(b);
LocalBroadcastManager.getInstance(activity).sendBroadcast(intentBD);
}
public interface SlideAnimation {
void onAnimationEnded();
}
/**
* 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);
}
}