Alpha color support

pull/199/head
M66B 4 years ago
parent 576388ee16
commit de12fd9d08

@ -36,7 +36,6 @@ import android.content.pm.ResolveInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.Build; import android.os.Build;
@ -88,7 +87,6 @@ import androidx.browser.customtabs.CustomTabsServiceConnection;
import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider; import androidx.core.content.FileProvider;
import androidx.core.graphics.ColorUtils;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LifecycleObserver;
@ -1092,15 +1090,6 @@ public class Helper {
return (tv.string != null && !"light".contentEquals(tv.string)); return (tv.string != null && !"light".contentEquals(tv.string));
} }
static int adjustLuminance(int color, boolean dark, float min) {
float lum = (float) ColorUtils.calculateLuminance(color);
if (dark ? lum < min : lum > 1 - min)
return ColorUtils.blendARGB(color,
dark ? Color.WHITE : Color.BLACK,
dark ? min - lum : lum - (1 - min));
return color;
}
static void hideKeyboard(final View view) { static void hideKeyboard(final View view) {
InputMethodManager imm = InputMethodManager imm =
(InputMethodManager) view.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE); (InputMethodManager) view.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);

@ -399,12 +399,16 @@ public class HtmlEx {
} }
if (style[j] instanceof ForegroundColorSpan) { if (style[j] instanceof ForegroundColorSpan) {
int color = ((ForegroundColorSpan) style[j]).getForegroundColor(); int color = ((ForegroundColorSpan) style[j]).getForegroundColor();
out.append(String.format("<span style=\"color:#%06X;\">", 0xFFFFFF & color)); //out.append(String.format("<span style=\"color:#%06X;\">", 0xFFFFFF & color));
out.append(String.format("<span style=\"color:%s;\">",
eu.faircode.email.HtmlHelper.encodeWebColor(color)));
} }
if (style[j] instanceof BackgroundColorSpan) { if (style[j] instanceof BackgroundColorSpan) {
int color = ((BackgroundColorSpan) style[j]).getBackgroundColor(); int color = ((BackgroundColorSpan) style[j]).getBackgroundColor();
out.append(String.format("<span style=\"background-color:#%06X;\">", //out.append(String.format("<span style=\"background-color:#%06X;\">",
0xFFFFFF & color)); // 0xFFFFFF & color));
out.append(String.format("<span style=\"background-color:%s;\">",
eu.faircode.email.HtmlHelper.encodeWebColor(color)));
} }
} }

@ -592,6 +592,10 @@ public class HtmlHelper {
Integer color = parseColor(value); Integer color = parseColor(value);
// fromHtml does not support transparency
//if (color != null)
// color = (0xFFFFFF & color);
if ("color".equals(key)) { if ("color".equals(key)) {
boolean bg = false; boolean bg = false;
Element e = element; Element e = element;
@ -601,6 +605,7 @@ public class HtmlHelper {
else else
e = e.parent(); e = e.parent();
// Keep color as-is when background set
if (!bg) { if (!bg) {
// Special case: // Special case:
// external draft / dark background / dark font // external draft / dark background / dark font
@ -613,13 +618,31 @@ public class HtmlHelper {
if (color != null && view) if (color != null && view)
color = adjustColor(dark, textColorPrimary, color); color = adjustColor(dark, textColorPrimary, color);
} }
} else {
if (color != null)
element.attr("x-color", "true");
} else /* background */ {
if (color != null && !hasColor(color)) if (color != null && !hasColor(color))
continue; continue;
if (color != null) { if (color != null)
String hex = String.format("#%06X", (0xFFFFFF & color)); element.attr("x-background", "true");
element.attr("x-background", hex);
if (dark) {
boolean fg = (parseColor(kv.get("color")) != null);
Element e = element;
while (e != null && !fg)
if (e.hasAttr("x-color"))
fg = true;
else
e = e.parent();
// Force foreground color
if (!fg)
sb.append("color")
.append(':')
.append(encodeWebColor(textColorPrimaryInverse))
.append(";");
} }
} }
@ -628,8 +651,7 @@ public class HtmlHelper {
continue; continue;
} }
// fromHtml does not support transparency String c = encodeWebColor(color);
String c = String.format("#%06x", color);
sb.append(key).append(':').append(c).append(";"); sb.append(key).append(':').append(c).append(";");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
element.attr(key, c); element.attr(key, c);
@ -1514,7 +1536,10 @@ public class HtmlHelper {
} }
} }
private static Integer parseColor(@NonNull String value) { private static Integer parseColor(String value) {
if (TextUtils.isEmpty(value))
return null;
// https://developer.mozilla.org/en-US/docs/Web/CSS/color_value // https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
String c = value String c = value
.replace("null", "") .replace("null", "")
@ -1530,6 +1555,7 @@ public class HtmlHelper {
.replaceAll("#+", "#"); .replaceAll("#+", "#");
Integer color = null; Integer color = null;
boolean hasAlpha = false;
try { try {
if (TextUtils.isEmpty(c)) if (TextUtils.isEmpty(c))
return null; return null;
@ -1538,8 +1564,10 @@ public class HtmlHelper {
String code = c.substring(1); String code = c.substring(1);
if (x11ColorMap.containsKey(code)) // workaround if (x11ColorMap.containsKey(code)) // workaround
color = x11ColorMap.get(code); color = x11ColorMap.get(code);
else else {
color = parseWebColor(code); color = parseWebColor(c);
hasAlpha = true;
}
} }
} else if (c.startsWith("rgb") || c.startsWith("hsl")) { } else if (c.startsWith("rgb") || c.startsWith("hsl")) {
int s = c.indexOf("("); int s = c.indexOf("(");
@ -1565,14 +1593,25 @@ public class HtmlHelper {
Float.parseFloat(component[0]), Float.parseFloat(component[0]),
Integer.parseInt(component[1]) / 100f, Integer.parseInt(component[1]) / 100f,
Integer.parseInt(component[2]) / 100f}); Integer.parseInt(component[2]) / 100f});
if (color != null && component.length >= 4) {
int alpha = Math.round(Float.parseFloat(component[3]) * 255);
color = ColorUtils.setAlphaComponent(color, alpha);
hasAlpha = true;
}
} }
} else if (x11ColorMap.containsKey(c)) } else if (x11ColorMap.containsKey(c))
color = x11ColorMap.get(c); color = x11ColorMap.get(c);
else else {
color = parseWebColor(c); color = parseWebColor(c);
hasAlpha = true;
}
if (color != null && !hasAlpha)
color = ColorUtils.setAlphaComponent(color, 255);
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG)
Log.i("Color " + c + "=" + (color == null ? null : Long.toHexString(color))); Log.i("Color " + c + "=" + (color == null ? null : encodeWebColor(color)));
} catch (Throwable ex) { } catch (Throwable ex) {
Log.i("Color=" + c + ": " + ex); Log.i("Color=" + c + ": " + ex);
@ -1581,28 +1620,55 @@ public class HtmlHelper {
return color; return color;
} }
private static int parseWebColor(String value) { private static int parseWebColor(@NonNull String value) {
if (value.length() == 3 || value.length() == 6 || value.length() == 8) { if (value.startsWith("#"))
if (value.length() == 3) value = value.substring(1);
value = "" +
value.charAt(0) + value.charAt(0) + if (value.length() == 3)
value.charAt(1) + value.charAt(1) + value = "FF" +
value.charAt(2) + value.charAt(2); value.charAt(0) + value.charAt(0) +
return (int) Long.parseLong(value, 16); value.charAt(1) + value.charAt(1) +
} else value.charAt(2) + value.charAt(2);
else if (value.length() == 6)
value = "FF" + value;
else if (value.length() == 8)
value = value.substring(6, 8) + value.substring(0, 6);
else
throw new IllegalArgumentException("Unknown color=" + value); throw new IllegalArgumentException("Unknown color=" + value);
return (int) Long.parseLong(value, 16);
}
static String encodeWebColor(int color) {
int alpha = Color.alpha(color);
int rgb = 0xFFFFFF & color;
if (alpha == 0)
return String.format("#%06X", rgb);
else
return String.format("#%06X%02X", rgb, alpha);
} }
private static Integer adjustColor(boolean dark, int textColorPrimary, Integer color) { private static Integer adjustColor(boolean dark, int textColorPrimary, Integer color) {
// Special case:
// shades of gray
int r = Color.red(color); int r = Color.red(color);
int g = Color.green(color); int g = Color.green(color);
int b = Color.blue(color); int b = Color.blue(color);
if (r == g && r == b && (dark ? 255 - r : r) < GRAY_THRESHOLD) float a = Color.alpha(color) / 255f;
if (r == g && r == b && (dark ? 255 - r : r) * a < GRAY_THRESHOLD)
color = textColorPrimary; color = textColorPrimary;
else
color = Helper.adjustLuminance(color, dark, MIN_LUMINANCE);
return (color & 0xFFFFFF); return adjustLuminance(color, dark, MIN_LUMINANCE);
}
static int adjustLuminance(int color, boolean dark, float min) {
int c = ColorUtils.compositeColors(color, dark ? Color.BLACK : Color.WHITE);
float lum = (float) ColorUtils.calculateLuminance(c);
if (dark ? lum < min : lum > 1 - min)
color = ColorUtils.blendARGB(color,
dark ? Color.WHITE : Color.BLACK,
dark ? min - lum : lum - (1 - min));
return color;
} }
private static boolean hasColor(int color) { private static boolean hasColor(int color) {
@ -2413,7 +2479,7 @@ public class HtmlHelper {
case "background-color": case "background-color":
if (!TextUtils.isEmpty(value)) if (!TextUtils.isEmpty(value))
try { try {
int color = Integer.parseInt(value.substring(1), 16) | 0xFF000000; int color = parseWebColor(value);
CharacterStyle span; CharacterStyle span;
if ("color".equals(key)) if ("color".equals(key))
span = new ForegroundColorSpan(color); span = new ForegroundColorSpan(color);
@ -2775,6 +2841,7 @@ public class HtmlHelper {
static void clearAnnotations(Document d) { static void clearAnnotations(Document d) {
d.select("*") d.select("*")
.removeAttr("x-background") .removeAttr("x-background")
.removeAttr("x-color")
.removeAttr("x-block") .removeAttr("x-block")
.removeAttr("x-inline") .removeAttr("x-inline")
.removeAttr("x-paragraph") .removeAttr("x-paragraph")

@ -254,7 +254,7 @@ public class StyleHelper {
.setColorEditTextColor(editTextColor) .setColorEditTextColor(editTextColor)
.wheelType(ColorPickerView.WHEEL_TYPE.FLOWER) .wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)
.density(6) .density(6)
.lightnessSliderOnly() //.lightnessSliderOnly()
.setPositiveButton(android.R.string.ok, new ColorPickerClickListener() { .setPositiveButton(android.R.string.ok, new ColorPickerClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) { public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {
@ -307,7 +307,7 @@ public class StyleHelper {
.setColorEditTextColor(editTextColor) .setColorEditTextColor(editTextColor)
.wheelType(ColorPickerView.WHEEL_TYPE.FLOWER) .wheelType(ColorPickerView.WHEEL_TYPE.FLOWER)
.density(6) .density(6)
.lightnessSliderOnly() //.lightnessSliderOnly()
.setPositiveButton(android.R.string.ok, new ColorPickerClickListener() { .setPositiveButton(android.R.string.ok, new ColorPickerClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) { public void onClick(DialogInterface dialog, int selectedColor, Integer[] allColors) {

Loading…
Cancel
Save