Merge branch 'master' of github.com:M66B/FairEmail

pull/187/head
M66B 5 years ago
commit 261d32c515

@ -82,7 +82,6 @@ Related questions:
* A preview of a message text doesn't (always) appear on Samsung watches because [setLocalOnly](https://developer.android.com/reference/androidx/core/app/NotificationCompat.Builder.html#setLocalOnly(boolean)) seem to be ignored. Message preview texts are known to be displayed correctly on Pebble 2, Fitbit Charge 3, and Mi band 3 wearables. See also [this FAQ](#user-content-faq126).
* A [bug in Android 6.0](https://issuetracker.google.com/issues/37068143) causes a crash with *... Invalid offset: ... Valid range is ...* when text is selected and tapping outside of the selected text. This bug has been fixed in Android 6.0.1.
* Internal (anchor) links will not work because original messages are shown in an embedded WebView in a scrolling view (the conversation list). This is an Android limitation which cannot be fixed or worked around.
* The expanded/collapsed state and the visibility of the message body are sometimes not in sync. This seems to be caused by a bug in the AndroidX ConstraintLayout.
## Planned features

@ -901,24 +901,10 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
// Text size
if (textSize != 0) {
float fz_sender = (font_size_sender == null ? textSize : font_size_sender) * (message.unseen > 0 ? 1.1f : 1f);
float fz_subject = (font_size_subject == null ? textSize : font_size_subject) * 0.9f;
tvFrom.setTextSize(TypedValue.COMPLEX_UNIT_PX, fz_sender);
tvSubject.setTextSize(TypedValue.COMPLEX_UNIT_PX, fz_subject);
tvKeywords.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize * 0.9f);
tvFolder.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize * 0.9f);
tvLabels.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize * 0.9f);
tvPreview.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize * 0.9f);
if (avatars) {
int px = Math.round(fz_sender + fz_subject + (compact ? 0 : textSize * 0.9f));
ViewGroup.LayoutParams lparams = ibAvatar.getLayoutParams();
if (lparams.width != px || lparams.height != px) {
lparams.width = px;
lparams.height = px;
ibAvatar.requestLayout();
}
}
}
// Selected / disabled
@ -959,27 +945,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvError.setAlpha(dim ? Helper.LOW_LIGHT : 1.0f);
}
// Unseen
Typeface typeface = (message.unseen > 0 ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
tvFrom.setTypeface(typeface);
tvSize.setTypeface(typeface);
tvTime.setTypeface(typeface);
if (subject_italic)
if (message.unseen > 0)
tvSubject.setTypeface(null, Typeface.BOLD_ITALIC);
else
tvSubject.setTypeface(null, Typeface.ITALIC);
else
tvSubject.setTypeface(typeface);
tvCount.setTypeface(typeface);
int colorUnseen = (message.unseen > 0 ? colorUnread : colorRead);
if (!Objects.equals(tvFrom.getTag(), colorUnseen)) {
tvFrom.setTag(colorUnseen);
tvFrom.setTextColor(colorUnseen);
tvSize.setTextColor(colorUnseen);
tvTime.setTextColor(colorUnseen);
}
bindSeen(message);
// Account color
int colorBackground =
@ -1382,6 +1348,46 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
pbCalendarWait.setVisibility(View.GONE);
}
private void bindSeen(TupleMessageEx message) {
if (textSize != 0) {
float fz_sender = (font_size_sender == null ? textSize : font_size_sender) * (message.unseen > 0 ? 1.1f : 1f);
float fz_subject = (font_size_subject == null ? textSize : font_size_subject) * 0.9f;
tvFrom.setTextSize(TypedValue.COMPLEX_UNIT_PX, fz_sender);
tvSubject.setTextSize(TypedValue.COMPLEX_UNIT_PX, fz_subject);
if (avatars) {
int px = Math.round(fz_sender + fz_subject + (compact ? 0 : textSize * 0.9f));
ViewGroup.LayoutParams lparams = ibAvatar.getLayoutParams();
if (lparams.width != px || lparams.height != px) {
lparams.width = px;
lparams.height = px;
ibAvatar.requestLayout();
}
}
}
Typeface typeface = (message.unseen > 0 ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
tvFrom.setTypeface(typeface);
tvSize.setTypeface(typeface);
tvTime.setTypeface(typeface);
if (subject_italic)
if (message.unseen > 0)
tvSubject.setTypeface(null, Typeface.BOLD_ITALIC);
else
tvSubject.setTypeface(null, Typeface.ITALIC);
else
tvSubject.setTypeface(typeface);
tvCount.setTypeface(typeface);
int colorUnseen = (message.unseen > 0 ? colorUnread : colorRead);
if (!Objects.equals(tvFrom.getTag(), colorUnseen)) {
tvFrom.setTag(colorUnseen);
tvFrom.setTextColor(colorUnseen);
tvSize.setTextColor(colorUnseen);
tvTime.setTextColor(colorUnseen);
}
}
private void bindFlagged(TupleMessageEx message, boolean expanded) {
boolean pro = ActivityBilling.isPro(context);
boolean flagged = (message.count - message.unflagged) > 0;
@ -3048,7 +3054,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} else {
message.ui_seen = !message.ui_seen;
message.unseen = (message.ui_seen ? 0 : message.count);
bindTo(message, false);
bindSeen(message);
Bundle args = new Bundle();
args.putLong("id", message.id);
@ -3529,16 +3535,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
else {
boolean expanded = !properties.getValue("expanded", message.id);
// Prevent flicker
if (expanded && message.accountAutoSeen && !message.folderReadOnly) {
message.unseen = 0;
message.ui_seen = true;
message.visible_unseen = 0;
message.ui_unsnoozed = false;
}
properties.setValue("expanded", message.id, expanded);
bindTo(message, expanded);
properties.setExpanded(message, expanded);
// Needed to scroll to item after collapsing other items
@ -4288,10 +4284,9 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
if (amessage == null || !amessage.id.equals(id))
return;
properties.setExpanded(message, false);
message.ui_seen = args.getBoolean("seen");
message.unseen = (message.ui_seen ? 0 : message.count);
bindTo(message, false);
properties.setExpanded(message, false);
}
@Override

@ -101,6 +101,7 @@ public class ContactInfo {
private static final int FAVICON_READ_BYTES = 2048;
private static final long CACHE_CONTACT_DURATION = 2 * 60 * 1000L; // milliseconds
private static final long CACHE_GRAVATAR_DURATION = 2 * 60 * 60 * 1000L; // milliseconds
private static final long CACHE_FAVICON_DURATION = 2 * 7 * 24 * 60 * 60 * 1000L; // milliseconds
private ContactInfo() {
}
@ -137,6 +138,21 @@ public class ContactInfo {
return (new Date().getTime() - time > CACHE_CONTACT_DURATION);
}
static void cleanup(Context context) {
long now = new Date().getTime();
// Favicons
Log.i("Cleanup favicons");
File[] favicons = new File(context.getCacheDir(), "favicons").listFiles();
if (favicons != null)
for (File file : favicons)
if (file.lastModified() + CACHE_FAVICON_DURATION < now) {
Log.i("Deleting " + file);
if (!file.delete())
Log.w("Error deleting " + file);
}
}
static void clearCache(Context context) {
clearCache(context, true);
}

@ -1653,6 +1653,19 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
setValue("expanded", message.id, value);
final int p = adapter.getPositionForKey(message.id);
if (p != NO_POSITION)
rvMessage.post(new Runnable() {
@Override
public void run() {
try {
adapter.notifyItemChanged(p);
} catch (Throwable ex) {
Log.e(ex);
}
}
});
// Collapse other messages
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
boolean expand_all = prefs.getBoolean("expand_all", false);

@ -54,8 +54,9 @@ public abstract class SimpleTask<T> implements LifecycleObserver {
private String name;
private Future<?> future;
private ExecutorService localExecutor;
private static ExecutorService executor = null;
private static ExecutorService globalExecutor = null;
private static final List<SimpleTask> tasks = new ArrayList<>();
static final String ACTION_TASK_COUNT = BuildConfig.APPLICATION_ID + ".ACTION_TASK_COUNT";
@ -70,6 +71,25 @@ public abstract class SimpleTask<T> implements LifecycleObserver {
return this;
}
public SimpleTask<T> setExecutor(ExecutorService executor) {
this.localExecutor = executor;
return this;
}
private ExecutorService getExecutor(Context context) {
if (localExecutor != null)
return localExecutor;
if (globalExecutor == null) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int threads = prefs.getInt("query_threads", Runtime.getRuntime().availableProcessors());
Log.i("Task threads=" + threads);
globalExecutor = Helper.getBackgroundExecutor(threads, "task");
}
return globalExecutor;
}
public void execute(Context context, LifecycleOwner owner, @NonNull Bundle args, @NonNull String name) {
run(context, owner, args, name);
}
@ -114,14 +134,7 @@ public abstract class SimpleTask<T> implements LifecycleObserver {
onException(args, ex);
}
if (executor == null) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int threads = prefs.getInt("query_threads", Runtime.getRuntime().availableProcessors());
Log.i("Task threads=" + threads);
executor = Helper.getBackgroundExecutor(threads, "task");
}
future = executor.submit(new Runnable() {
future = getExecutor(context).submit(new Runnable() {
private Object data;
private long elapsed;
private Throwable ex;

@ -248,6 +248,10 @@ public class WorkerCleanup extends Worker {
}
}
// Cleanup contact info
if (!manual)
ContactInfo.cleanup(context);
Log.i("Cleanup FTS=" + fts);
if (fts) {
int deleted = 0;

@ -1,5 +1,7 @@
FairEmail is easy to setup and works with virtually all email providers, including Gmail, Outlook and Yahoo!
<b>Note that OAuth was not approved for the F-Droid build. For this you'll need to use the Play store version or the GitHub release.</b>
FairEmail might be for you if you value your privacy.
<i>FairEmail is an email client only, so you need to bring your own email address.</i>

Loading…
Cancel
Save