Added identicons

This commit is contained in:
M66B 2018-11-03 16:34:35 +00:00
parent 3f3915ebf7
commit e6970faf6e
8 changed files with 88 additions and 9 deletions

1
FAQ.md
View File

@ -14,7 +14,6 @@ Frequently requested features:
* Executing filter rules: filter rules should be executed on the server because a battery powered device with possibly an unstable internet connection is not suitable for this.
* Widget to read e-mail: widgets do not allow user interaction, so a widget to read e-mail would not be very useful.
* Swipe left/right to go to previous/next message: swiping also selects message text, so this would not work reliably.
* Generate avatars: you can use [Micopi+](https://f-droid.org/en/packages/com.easytarget.micopi/) or a similar app to generate images for your contacts.
Since FairEmail is meant to be privacy friendly, the following will not be added:

View File

@ -81,7 +81,8 @@ abstract class ActivityBase extends AppCompatActivity implements SharedPreferenc
finish();
if (this.getClass().equals(ActivitySetup.class))
startActivity(getIntent());
} else if (!this.getClass().equals(ActivitySetup.class) && ("compact".equals(key) || "debug".equals(key)))
} else if (!this.getClass().equals(ActivitySetup.class) &&
("avatars".equals(key) || "identicons".equals(key) || "compact".equals(key) || "debug".equals(key)))
finish();
}

View File

@ -26,6 +26,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@ -112,9 +113,12 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
private boolean contacts;
private boolean avatars;
private boolean identicons;
private boolean compact;
private boolean debug;
private int dp24;
private SelectionTracker<Long> selectionTracker = null;
private DateFormat df = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.LONG, SimpleDateFormat.LONG);
@ -276,14 +280,23 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
pbLoading.setVisibility(View.GONE);
boolean photo = false;
if (avatars && message.avatar != null) {
ContentResolver resolver = context.getContentResolver();
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(resolver, Uri.parse(message.avatar));
if (is != null) {
photo = true;
ivAvatar.setImageDrawable(Drawable.createFromStream(is, "avatar"));
if (avatars) {
if (message.avatar != null) {
ContentResolver resolver = context.getContentResolver();
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(resolver, Uri.parse(message.avatar));
if (is != null) {
photo = true;
ivAvatar.setImageDrawable(Drawable.createFromStream(is, "avatar"));
}
}
}
if (!photo && identicons) {
if (message.from.length > 0)
ivAvatar.setImageBitmap(Identicon.generate(((InternetAddress) message.from[0]).getAddress(), dp24, 5));
else
ivAvatar.setImageDrawable(null);
photo = true;
}
ivAvatar.setVisibility(photo ? View.VISIBLE : View.GONE);
vwColor.setBackgroundColor(message.accountColor == null ? Color.TRANSPARENT : message.accountColor);
@ -1391,8 +1404,11 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
this.contacts = (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
== PackageManager.PERMISSION_GRANTED);
this.avatars = (prefs.getBoolean("avatars", true) && this.contacts);
this.identicons = prefs.getBoolean("identicons", true);
this.compact = prefs.getBoolean("compact", false);
this.debug = prefs.getBoolean("debug", false);
this.dp24 = Math.round(24 * Resources.getSystem().getDisplayMetrics().density);
}
private static final DiffUtil.ItemCallback<TupleMessageEx> DIFF_CALLBACK =

View File

@ -34,6 +34,7 @@ import androidx.appcompat.widget.SwitchCompat;
public class FragmentOptions extends FragmentEx {
private SwitchCompat swEnabled;
private SwitchCompat swAvatars;
private SwitchCompat swIdenticons;
private SwitchCompat swLight;
private SwitchCompat swBrowse;
private SwitchCompat swSwipe;
@ -52,6 +53,7 @@ public class FragmentOptions extends FragmentEx {
// Get controls
swEnabled = view.findViewById(R.id.swEnabled);
swAvatars = view.findViewById(R.id.swAvatars);
swIdenticons = view.findViewById(R.id.swIdenticons);
swLight = view.findViewById(R.id.swLight);
swBrowse = view.findViewById(R.id.swBrowse);
swSwipe = view.findViewById(R.id.swSwipe);
@ -84,6 +86,14 @@ public class FragmentOptions extends FragmentEx {
}
});
swIdenticons.setChecked(prefs.getBoolean("identicons", true));
swIdenticons.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("identicons", checked).apply();
}
});
swLight.setChecked(prefs.getBoolean("light", false));
swLight.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override

View File

@ -107,6 +107,7 @@ public class FragmentSetup extends FragmentEx {
static final List<String> EXPORT_SETTINGS = Arrays.asList(
"enabled",
"avatars",
"identicons",
"light",
"browse",
"swipe",

View File

@ -0,0 +1,42 @@
package eu.faircode.email;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
class Identicon {
static Bitmap generate(String email, int size, int pixels) {
byte[] hash;
try {
hash = MessageDigest.getInstance("MD5").digest(email.getBytes());
} catch (NoSuchAlgorithmException ignored) {
hash = email.getBytes();
}
Paint paint = new Paint();
paint.setColor(Color.argb(255, hash[0], hash[1], hash[2]));
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.argb(255, 128, 128, 128));
float psize = (float) size / pixels;
for (int x = 0; x < pixels; x++) {
int i = (x > pixels / 2 ? pixels - x - 1 : x);
for (int y = 0; y < pixels; y++) {
if ((hash[i] >> y & 1) == 1) {
RectF rect = new RectF(x * psize, y * psize, (x + 1) * psize, (y + 1) * psize);
canvas.drawRect(rect, paint);
}
}
}
return bitmap;
}
}

View File

@ -29,6 +29,15 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swEnabled" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swIdenticons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_identicons"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swAvatars" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swLight"
android:layout_width="match_parent"
@ -36,7 +45,7 @@
android:layout_marginTop="12dp"
android:text="@string/title_advanced_light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swAvatars" />
app:layout_constraintTop_toBottomOf="@id/swIdenticons" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swBrowse"

View File

@ -83,6 +83,7 @@
<string name="title_advanced">Advanced options</string>
<string name="title_advanced_enabled">Enabled</string>
<string name="title_advanced_avatars">Show contact photos</string>
<string name="title_advanced_identicons">Show identicons</string>
<string name="title_advanced_light">Use notification light</string>
<string name="title_advanced_browse">Browse messages on the server</string>
<string name="title_advanced_swipe">Swipe actions</string>