mirror of https://github.com/M66B/FairEmail.git
Added identicons
This commit is contained in:
parent
3f3915ebf7
commit
e6970faf6e
1
FAQ.md
1
FAQ.md
|
@ -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:
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -107,6 +107,7 @@ public class FragmentSetup extends FragmentEx {
|
|||
static final List<String> EXPORT_SETTINGS = Arrays.asList(
|
||||
"enabled",
|
||||
"avatars",
|
||||
"identicons",
|
||||
"light",
|
||||
"browse",
|
||||
"swipe",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue