mirror of https://github.com/M66B/FairEmail.git
Added settings for generated icons saturation and brightness
This commit is contained in:
parent
89041dc5ef
commit
ec75c1f8cb
|
@ -27,13 +27,6 @@ import android.database.ContentObserver;
|
|||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
@ -168,54 +161,20 @@ public class ContactInfo {
|
|||
boolean identicon = false;
|
||||
if (info.bitmap == null) {
|
||||
int dp = Helper.dp2pixels(context, 96);
|
||||
boolean dark = Helper.isDarkTheme(context);
|
||||
boolean generated = prefs.getBoolean("generated_icons", true);
|
||||
if (generated) {
|
||||
boolean identicons = prefs.getBoolean("identicons", false);
|
||||
if (identicons) {
|
||||
identicon = true;
|
||||
info.bitmap = ImageHelper.generateIdenticon(key, dp, 5, dark);
|
||||
info.bitmap = ImageHelper.generateIdenticon(key, dp, 5, context);
|
||||
} else
|
||||
info.bitmap = ImageHelper.generateLetterIcon(key, dp, dark);
|
||||
info.bitmap = ImageHelper.generateLetterIcon(key, dp, context);
|
||||
}
|
||||
}
|
||||
|
||||
boolean circular = prefs.getBoolean("circular", true);
|
||||
if (info.bitmap != null) {
|
||||
int w = info.bitmap.getWidth();
|
||||
int h = info.bitmap.getHeight();
|
||||
|
||||
Rect source;
|
||||
if (w > h) {
|
||||
int off = (w - h) / 2;
|
||||
source = new Rect(off, 0, w - off, h);
|
||||
} else if (w < h) {
|
||||
int off = (h - w) / 2;
|
||||
source = new Rect(0, off, w, h - off);
|
||||
} else
|
||||
source = new Rect(0, 0, w, h);
|
||||
|
||||
Rect dest = new Rect(0, 0, source.width(), source.height());
|
||||
|
||||
Bitmap round = Bitmap.createBitmap(source.width(), source.height(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(round);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
canvas.drawARGB(0, 0, 0, 0);
|
||||
paint.setColor(Color.GRAY);
|
||||
if (circular && !identicon)
|
||||
canvas.drawOval(new RectF(dest), paint);
|
||||
else {
|
||||
float radius = Helper.dp2pixels(context, 3);
|
||||
canvas.drawRoundRect(new RectF(dest), radius, radius, paint);
|
||||
}
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
|
||||
canvas.drawBitmap(info.bitmap, source, dest, paint);
|
||||
|
||||
info.bitmap.recycle();
|
||||
info.bitmap = round;
|
||||
}
|
||||
info.bitmap = ImageHelper.makeCircular(info.bitmap,
|
||||
circular && !identicon ? null : Helper.dp2pixels(context, 3));
|
||||
|
||||
if (info.displayName == null)
|
||||
info.displayName = address.getPersonal();
|
||||
|
|
|
@ -40,7 +40,7 @@ public class FragmentOptions extends FragmentBase {
|
|||
static String[] OPTIONS_RESTART = new String[]{
|
||||
"subscriptions",
|
||||
"startup", "cards", "date", "threading", "indentation", "highlight_unread",
|
||||
"avatars", "generated_icons", "identicons", "circular",
|
||||
"avatars", "generated_icons", "identicons", "circular", "saturation", "brightness",
|
||||
"name_email", "distinguish_contacts", "authentication",
|
||||
"subject_top", "subject_italic", "subject_ellipsize",
|
||||
"flags", "flags_background", "preview", "preview_italic",
|
||||
|
|
|
@ -20,7 +20,9 @@ package eu.faircode.email;
|
|||
*/
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -31,7 +33,9 @@ import android.view.ViewGroup;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -54,6 +58,11 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
|
|||
private SwitchCompat swGeneratedIcons;
|
||||
private SwitchCompat swIdenticons;
|
||||
private SwitchCompat swCircular;
|
||||
private ImageView ivRed;
|
||||
private ImageView ivGreen;
|
||||
private ImageView ivBlue;
|
||||
private SeekBar sbSaturation;
|
||||
private SeekBar sbBrightness;
|
||||
private SwitchCompat swNameEmail;
|
||||
private SwitchCompat swDistinguishContacts;
|
||||
private SwitchCompat swAuthentication;
|
||||
|
@ -77,7 +86,8 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
|
|||
|
||||
private final static String[] RESET_OPTIONS = new String[]{
|
||||
"theme", "startup", "cards", "date", "threading", "indentation", "highlight_unread",
|
||||
"avatars", "generated_icons", "identicons", "circular", "name_email", "distinguish_contacts", "authentication",
|
||||
"avatars", "generated_icons", "identicons", "circular", "saturation", "brightness",
|
||||
"name_email", "distinguish_contacts", "authentication",
|
||||
"subject_top", "subject_italic", "subject_ellipsize",
|
||||
"flags", "flags_background", "preview", "preview_italic", "addresses", "attachments_alt",
|
||||
"contrast", "monospaced", "text_color",
|
||||
|
@ -105,6 +115,11 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
|
|||
swGeneratedIcons = view.findViewById(R.id.swGeneratedIcons);
|
||||
swIdenticons = view.findViewById(R.id.swIdenticons);
|
||||
swCircular = view.findViewById(R.id.swCircular);
|
||||
ivRed = view.findViewById(R.id.ivRed);
|
||||
ivGreen = view.findViewById(R.id.ivGreen);
|
||||
ivBlue = view.findViewById(R.id.ivBlue);
|
||||
sbSaturation = view.findViewById(R.id.sbSaturation);
|
||||
sbBrightness = view.findViewById(R.id.sbBrightness);
|
||||
swNameEmail = view.findViewById(R.id.swNameEmail);
|
||||
swDistinguishContacts = view.findViewById(R.id.swDistinguishContacts);
|
||||
swAuthentication = view.findViewById(R.id.swAuthentication);
|
||||
|
@ -216,10 +231,49 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
|
|||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
prefs.edit().putBoolean("circular", checked).apply();
|
||||
updateColor();
|
||||
ContactInfo.clearCache();
|
||||
}
|
||||
});
|
||||
|
||||
sbSaturation.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
prefs.edit().putInt("saturation", progress).apply();
|
||||
updateColor();
|
||||
ContactInfo.clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
|
||||
sbBrightness.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
prefs.edit().putInt("brightness", progress).apply();
|
||||
updateColor();
|
||||
ContactInfo.clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
|
||||
swNameEmail.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
|
||||
|
@ -426,6 +480,8 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
|
|||
swIdenticons.setChecked(prefs.getBoolean("identicons", false));
|
||||
swIdenticons.setEnabled(swGeneratedIcons.isChecked());
|
||||
swCircular.setChecked(prefs.getBoolean("circular", true));
|
||||
sbSaturation.setProgress(prefs.getInt("saturation", 100));
|
||||
sbBrightness.setProgress(prefs.getInt("brightness", 100));
|
||||
swNameEmail.setChecked(prefs.getBoolean("name_email", false));
|
||||
swDistinguishContacts.setChecked(prefs.getBoolean("distinguish_contacts", false));
|
||||
swAuthentication.setChecked(prefs.getBoolean("authentication", true));
|
||||
|
@ -454,6 +510,29 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
|
|||
swImagesInline.setChecked(prefs.getBoolean("inline_images", false));
|
||||
swSeekbar.setChecked(prefs.getBoolean("seekbar", false));
|
||||
swActionbar.setChecked(prefs.getBoolean("actionbar", true));
|
||||
|
||||
updateColor();
|
||||
}
|
||||
|
||||
private void updateColor() {
|
||||
Context context = getContext();
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean circular = prefs.getBoolean("circular", true);
|
||||
|
||||
int size = Helper.dp2pixels(context, 36);
|
||||
Integer radius = (circular ? null : Helper.dp2pixels(context, 3));
|
||||
|
||||
Bitmap red = ImageHelper.generateLetterIcon(0f, "A", size, context);
|
||||
Bitmap green = ImageHelper.generateLetterIcon(120f, "B", size, context);
|
||||
Bitmap blue = ImageHelper.generateLetterIcon(240f, "C", size, context);
|
||||
|
||||
red = ImageHelper.makeCircular(red, radius);
|
||||
green = ImageHelper.makeCircular(green, radius);
|
||||
blue = ImageHelper.makeCircular(blue, radius);
|
||||
|
||||
ivRed.setImageBitmap(red);
|
||||
ivGreen.setImageBitmap(green);
|
||||
ivBlue.setImageBitmap(blue);
|
||||
}
|
||||
|
||||
public static class FragmentDialogTheme extends FragmentDialogBase {
|
||||
|
|
|
@ -28,6 +28,8 @@ import android.graphics.Canvas;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.ImageDecoder;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Typeface;
|
||||
|
@ -64,10 +66,17 @@ class ImageHelper {
|
|||
private static final ExecutorService executor =
|
||||
Helper.getBackgroundExecutor(1, "image");
|
||||
|
||||
static Bitmap generateIdenticon(@NonNull String email, int size, int pixels, boolean dark) {
|
||||
static Bitmap generateIdenticon(@NonNull String email, int size, int pixels, Context context) {
|
||||
byte[] hash = getHash(email);
|
||||
|
||||
int color = Color.HSVToColor(127, new float[]{Math.abs(email.hashCode()) % 360, 1, 1});
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
int saturation = prefs.getInt("saturation", 100);
|
||||
int brightness = prefs.getInt("brightness", 100);
|
||||
|
||||
int color = Color.HSVToColor(new float[]{
|
||||
Math.abs(email.hashCode()) % 360,
|
||||
saturation / 100f,
|
||||
brightness / 100f});
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(color);
|
||||
|
@ -91,34 +100,43 @@ class ImageHelper {
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
static Bitmap generateLetterIcon(@NonNull String email, int size, boolean dark) {
|
||||
String text = null;
|
||||
static Bitmap generateLetterIcon(@NonNull String email, int size, Context context) {
|
||||
String letter = null;
|
||||
for (int i = 0; i < email.length(); i++) {
|
||||
char kar = email.charAt(i);
|
||||
if (Character.isAlphabetic(kar)) {
|
||||
text = email.substring(i, i + 1).toUpperCase();
|
||||
letter = email.substring(i, i + 1).toUpperCase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (text == null)
|
||||
if (letter == null)
|
||||
return null;
|
||||
|
||||
int color = Color.HSVToColor(127, new float[]{Math.abs(email.hashCode()) % 360, 1, 1});
|
||||
float h = Math.abs(email.hashCode()) % 360f;
|
||||
return generateLetterIcon(h, letter, size, context);
|
||||
}
|
||||
|
||||
static Bitmap generateLetterIcon(float h, String letter, int size, Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
float s = prefs.getInt("saturation", 100) / 100f;
|
||||
float v = prefs.getInt("brightness", 100) / 100f;
|
||||
|
||||
int bg = Color.HSVToColor(new float[]{h, s, v});
|
||||
|
||||
double lum = ColorUtils.calculateLuminance(bg);
|
||||
int fg = Color.HSVToColor(new float[]{0, 0, lum < 0.5 ? v : 0});
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.drawColor(color);
|
||||
|
||||
double lum = ColorUtils.calculateLuminance(color);
|
||||
canvas.drawColor(bg);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(lum < 0.5 ? Color.WHITE : Color.BLACK);
|
||||
paint.setColor(fg);
|
||||
paint.setTextSize(size / 2f);
|
||||
paint.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
|
||||
canvas.drawText(
|
||||
text,
|
||||
size / 2f - paint.measureText(text) / 2,
|
||||
canvas.drawText(letter,
|
||||
size / 2f - paint.measureText(letter) / 2,
|
||||
size / 2f - (paint.descent() + paint.ascent()) / 2, paint);
|
||||
|
||||
return bitmap;
|
||||
|
@ -132,6 +150,43 @@ class ImageHelper {
|
|||
}
|
||||
}
|
||||
|
||||
static Bitmap makeCircular(Bitmap bitmap, Integer radius) {
|
||||
if (bitmap == null)
|
||||
return null;
|
||||
|
||||
int w = bitmap.getWidth();
|
||||
int h = bitmap.getHeight();
|
||||
|
||||
Rect source;
|
||||
if (w > h) {
|
||||
int off = (w - h) / 2;
|
||||
source = new Rect(off, 0, w - off, h);
|
||||
} else if (w < h) {
|
||||
int off = (h - w) / 2;
|
||||
source = new Rect(0, off, w, h - off);
|
||||
} else
|
||||
source = new Rect(0, 0, w, h);
|
||||
|
||||
Rect dest = new Rect(0, 0, source.width(), source.height());
|
||||
|
||||
Bitmap round = Bitmap.createBitmap(source.width(), source.height(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(round);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
canvas.drawARGB(0, 0, 0, 0);
|
||||
paint.setColor(Color.GRAY);
|
||||
if (radius == null)
|
||||
canvas.drawOval(new RectF(dest), paint); // round
|
||||
else
|
||||
canvas.drawRoundRect(new RectF(dest), radius, radius, paint); // rounded
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
|
||||
canvas.drawBitmap(bitmap, source, dest, paint);
|
||||
|
||||
bitmap.recycle();
|
||||
return round;
|
||||
}
|
||||
|
||||
static Drawable decodeImage(final Context context, final long id, String source, boolean show, final TextView view) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean compact = prefs.getBoolean("compact", false);
|
||||
|
|
|
@ -187,6 +187,81 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/swIdenticons"
|
||||
app:switchPadding="12dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivRed"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:src="@drawable/baseline_person_24"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ivGreen"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/swCircular" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivGreen"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:src="@drawable/baseline_person_24"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ivBlue"
|
||||
app:layout_constraintStart_toEndOf="@id/ivRed"
|
||||
app:layout_constraintTop_toBottomOf="@id/swCircular" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivBlue"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:src="@drawable/baseline_person_24"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/ivGreen"
|
||||
app:layout_constraintTop_toBottomOf="@id/swCircular" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSaturation"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="48dp"
|
||||
android:text="@string/title_advanced_color_saturation"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/ivRed" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/sbSaturation"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:max="100"
|
||||
android:min="0"
|
||||
android:progress="50"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvSaturation" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBrightness"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="48dp"
|
||||
android:text="@string/title_advanced_color_value"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/sbSaturation" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/sbBrightness"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:max="100"
|
||||
android:min="0"
|
||||
android:progress="50"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvBrightness" />
|
||||
|
||||
<androidx.appcompat.widget.SwitchCompat
|
||||
android:id="@+id/swNameEmail"
|
||||
android:layout_width="0dp"
|
||||
|
@ -195,7 +270,7 @@
|
|||
android:text="@string/title_advanced_name_email"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/swCircular"
|
||||
app:layout_constraintTop_toBottomOf="@id/sbBrightness"
|
||||
app:switchPadding="12dp" />
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -250,6 +250,8 @@
|
|||
<string name="title_advanced_generated_icons">Show generated icons</string>
|
||||
<string name="title_advanced_identicons">Show identicons</string>
|
||||
<string name="title_advanced_circular">Show round icons</string>
|
||||
<string name="title_advanced_color_saturation">Saturation</string>
|
||||
<string name="title_advanced_color_value">Brightness</string>
|
||||
<string name="title_advanced_name_email">Show names and email addresses</string>
|
||||
<string name="title_advanced_authentication">Show a warning when the receiving server could not authenticate the message</string>
|
||||
<string name="title_advanced_subject_top">Show subject above sender</string>
|
||||
|
|
Loading…
Reference in New Issue