diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 783605dd37..629f8e300d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -93,6 +93,15 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/java/eu/faircode/email/ActivityWidget.java b/app/src/main/java/eu/faircode/email/ActivityWidget.java
new file mode 100644
index 0000000000..a5bce79a8a
--- /dev/null
+++ b/app/src/main/java/eu/faircode/email/ActivityWidget.java
@@ -0,0 +1,130 @@
+package eu.faircode.email;
+
+/*
+ This file is part of FairEmail.
+
+ FairEmail is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ FairEmail is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with FairEmail. If not, see .
+
+ Copyright 2018-2019 by Marcel Bokhorst (M66B)
+*/
+
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+
+import androidx.constraintlayout.widget.Group;
+import androidx.preference.PreferenceManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ActivityWidget extends ActivityBase {
+ private int appWidgetId;
+
+ private Spinner spAccount;
+ private Button btnSave;
+ private ContentLoadingProgressBar pbWait;
+ private Group grpReady;
+
+ private ArrayAdapter adapterAccount;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Bundle extras = getIntent().getExtras();
+ if (extras == null) {
+ finish();
+ return;
+ }
+
+ appWidgetId = extras.getInt(
+ AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
+
+ getSupportActionBar().setSubtitle(R.string.title_widget_title_count);
+ setContentView(R.layout.activity_widget);
+
+ spAccount = findViewById(R.id.spAccount);
+ btnSave = findViewById(R.id.btnSave);
+ pbWait = findViewById(R.id.pbWait);
+ grpReady = findViewById(R.id.grpReady);
+
+ final Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+
+ btnSave.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ EntityAccount account = (EntityAccount) spAccount.getSelectedItem();
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ActivityWidget.this);
+ SharedPreferences.Editor editor = prefs.edit();
+ if (account != null && account.id > 0)
+ editor.putString("widget." + appWidgetId + ".name", account.name);
+ else
+ editor.remove("widget." + appWidgetId + ".name");
+ editor.putLong("widget." + appWidgetId + ".account", account == null ? -1L : account.id);
+ editor.apply();
+
+ Widget.init(ActivityWidget.this, appWidgetId);
+
+ setResult(RESULT_OK, resultValue);
+ finish();
+ }
+ });
+
+ adapterAccount = new ArrayAdapter<>(this, R.layout.spinner_item1, android.R.id.text1, new ArrayList());
+ adapterAccount.setDropDownViewResource(R.layout.spinner_item1_dropdown);
+ spAccount.setAdapter(adapterAccount);
+
+ grpReady.setVisibility(View.GONE);
+ pbWait.setVisibility(View.VISIBLE);
+
+ setResult(RESULT_CANCELED, resultValue);
+
+ new SimpleTask>() {
+ @Override
+ protected List onExecute(Context context, Bundle args) {
+ DB db = DB.getInstance(context);
+
+ return db.account().getSynchronizingAccounts();
+ }
+
+ @Override
+ protected void onExecuted(Bundle args, List accounts) {
+ EntityAccount all = new EntityAccount();
+ all.id = -1L;
+ all.name = getString(R.string.title_widget_account_all);
+ all.primary = false;
+ accounts.add(0, all);
+
+ adapterAccount.addAll(accounts);
+
+ grpReady.setVisibility(View.VISIBLE);
+ pbWait.setVisibility(View.GONE);
+ }
+
+ @Override
+ protected void onException(Bundle args, Throwable ex) {
+ Log.unexpectedError(getSupportFragmentManager(), ex);
+ }
+ }.execute(this, new Bundle(), "widget:accounts");
+ }
+}
diff --git a/app/src/main/java/eu/faircode/email/DaoMessage.java b/app/src/main/java/eu/faircode/email/DaoMessage.java
index c8819f7766..051db0e362 100644
--- a/app/src/main/java/eu/faircode/email/DaoMessage.java
+++ b/app/src/main/java/eu/faircode/email/DaoMessage.java
@@ -300,19 +300,27 @@ public interface DaoMessage {
" WHERE message.id = :id")
LiveData liveMessage(long id);
- String widget = "SELECT COUNT(message.id) AS unseen, SUM(ABS(notifying)) AS notifying" +
+ @Query("SELECT account.id, COUNT(message.id) AS unseen, SUM(ABS(notifying)) AS notifying" +
" FROM message" +
" JOIN account ON account.id = message.account" +
" JOIN folder ON folder.id = message.folder" +
- " WHERE account.`synchronize`" +
+ " WHERE (:account IS NULL OR account.id = :account)" +
+ " AND account.`synchronize`" +
" AND folder.notify" +
- " AND NOT (message.ui_seen OR message.ui_hide)";
+ " AND NOT (message.ui_seen OR message.ui_hide)" +
+ " GROUP BY account.id" +
+ " ORDER BY account.id")
+ LiveData> liveUnseenWidget(Long account);
- @Query(widget)
- LiveData liveUnseenWidget();
-
- @Query(widget)
- TupleMessageStats getUnseenWidget();
+ @Query("SELECT :account AS account, COUNT(message.id) AS unseen, SUM(ABS(notifying)) AS notifying" +
+ " FROM message" +
+ " JOIN account ON account.id = message.account" +
+ " JOIN folder ON folder.id = message.folder" +
+ " WHERE (:account IS NULL OR account.id = :account)" +
+ " AND account.`synchronize`" +
+ " AND folder.notify" +
+ " AND NOT (message.ui_seen OR message.ui_hide)")
+ TupleMessageStats getUnseenWidget(Long account);
@Query("SELECT message.*" +
", account.pop AS accountProtocol, account.name AS accountName, COALESCE(identity.color, folder.color, account.color) AS accountColor" +
diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
index 1c987d3a3e..9b6f18b8fc 100644
--- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
+++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java
@@ -362,23 +362,46 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- db.message().liveUnseenWidget().observe(this, new Observer() {
- private Integer lastUnseen = null;
+ db.message().liveUnseenWidget(null).observe(this, new Observer>() {
+ private List last = null;
@Override
- public void onChanged(TupleMessageStats stats) {
+ public void onChanged(List stats) {
if (stats == null)
- stats = new TupleMessageStats();
+ stats = new ArrayList<>();
+ boolean changed = false;
+ if (last == null || last.size() != stats.size())
+ changed = true;
+ else
+ for (int i = 0; i < stats.size(); i++)
+ if (!last.get(i).equals(stats.get(i))) {
+ changed = true;
+ break;
+ }
+
+ if (!changed)
+ return;
+
+ Widget.update(ServiceSynchronize.this);
+
+ boolean badge = prefs.getBoolean("badge", true);
boolean unseen_ignored = prefs.getBoolean("unseen_ignored", false);
- Integer unseen = (unseen_ignored ? stats.notifying : stats.unseen);
- if (unseen == null)
- unseen = 0;
- if (lastUnseen == null || !lastUnseen.equals(unseen)) {
- Log.i("Stats " + stats);
- lastUnseen = unseen;
- setUnseen(unseen);
+ int count = 0;
+ for (TupleMessageStats stat : stats) {
+ Integer unseen = (unseen_ignored ? stat.notifying : stat.unseen);
+ if (unseen != null)
+ count += unseen;
+ }
+
+ try {
+ if (count == 0 || !badge)
+ ShortcutBadger.removeCount(ServiceSynchronize.this);
+ else
+ ShortcutBadger.applyCount(ServiceSynchronize.this, count);
+ } catch (Throwable ex) {
+ Log.e(ex);
}
}
});
@@ -510,8 +533,6 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
liveAccountNetworkState.postDestroy();
- setUnseen(null);
-
try {
stopForeground(true);
} catch (Throwable ex) {
@@ -687,22 +708,6 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
return builder;
}
- private void setUnseen(Integer unseen) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean badge = prefs.getBoolean("badge", true);
-
- Widget.update(this, unseen);
-
- try {
- if (unseen == null || !badge)
- ShortcutBadger.removeCount(this);
- else
- ShortcutBadger.applyCount(this, unseen);
- } catch (Throwable ex) {
- Log.e(ex);
- }
- }
-
private void monitorAccount(final EntityAccount account, final Core.State state, final boolean sync) throws NoSuchProviderException {
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock wlAccount = pm.newWakeLock(
diff --git a/app/src/main/java/eu/faircode/email/TupleMessageStats.java b/app/src/main/java/eu/faircode/email/TupleMessageStats.java
index 7726a71672..1911791ddb 100644
--- a/app/src/main/java/eu/faircode/email/TupleMessageStats.java
+++ b/app/src/main/java/eu/faircode/email/TupleMessageStats.java
@@ -25,6 +25,7 @@ import androidx.annotation.Nullable;
import java.util.Objects;
public class TupleMessageStats {
+ public Long account;
public Integer unseen;
public Integer notifying;
@@ -32,7 +33,8 @@ public class TupleMessageStats {
public boolean equals(@Nullable Object obj) {
if (obj instanceof TupleMessageStats) {
TupleMessageStats other = (TupleMessageStats) obj;
- return (Objects.equals(this.unseen, other.unseen) &&
+ return (Objects.equals(this.account, other.account) &&
+ Objects.equals(this.unseen, other.unseen) &&
Objects.equals(this.notifying, other.notifying));
} else
return false;
diff --git a/app/src/main/java/eu/faircode/email/Widget.java b/app/src/main/java/eu/faircode/email/Widget.java
index 49b91fc679..d284e7b456 100644
--- a/app/src/main/java/eu/faircode/email/Widget.java
+++ b/app/src/main/java/eu/faircode/email/Widget.java
@@ -26,6 +26,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.text.TextUtils;
import android.widget.RemoteViews;
import androidx.preference.PreferenceManager;
@@ -42,21 +43,49 @@ public class Widget extends AppWidgetProvider {
executor.submit(new Runnable() {
@Override
public void run() {
- DB db = DB.getInstance(context);
- TupleMessageStats stats = db.message().getUnseenWidget();
-
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean unseen_ignored = prefs.getBoolean("unseen_ignored", false);
- Integer unseen = (unseen_ignored ? stats.notifying : stats.unseen);
- if (unseen == null)
- unseen = 0;
- update(context, appWidgetManager, appWidgetIds, unseen);
+ DB db = DB.getInstance(context);
+ NumberFormat nf = NumberFormat.getIntegerInstance();
+
+ Intent view = new Intent(context, ActivityView.class);
+ view.setAction("unified");
+ view.putExtra("refresh", true);
+ view.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ PendingIntent pi = PendingIntent.getActivity(context, ActivityView.REQUEST_UNIFIED, view, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ for (int appWidgetId : appWidgetIds) {
+ long account = prefs.getLong("widget." + appWidgetId + ".account", -1L);
+ String name = prefs.getString("widget." + appWidgetId + ".name", null);
+
+ TupleMessageStats stats = db.message().getUnseenWidget(account < 0 ? null : account);
+ Integer unseen = (unseen_ignored ? stats.notifying : stats.unseen);
+ if (unseen == null)
+ unseen = 0;
+
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
+
+ views.setOnClickPendingIntent(R.id.widget, pi);
+
+ views.setTextViewText(R.id.tvCount, unseen < 100 ? nf.format(unseen) : "∞");
+
+ if (!TextUtils.isEmpty(name)) {
+ views.setTextViewText(R.id.tvAccount, name);
+ views.setViewVisibility(R.id.tvAccount, ViewStripe.VISIBLE);
+ }
+
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
}
});
}
- static void update(Context context, Integer count) {
+ static void init(Context context, int appWidgetId) {
+ update(context);
+ }
+
+ static void update(Context context) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
if (appWidgetManager == null) {
Log.w("No app widget manager"); // Fairphone FP2
@@ -64,31 +93,10 @@ public class Widget extends AppWidgetProvider {
}
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, Widget.class));
- update(context, appWidgetManager, appWidgetIds, count);
- }
- private static void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, Integer count) {
- NumberFormat nf = NumberFormat.getIntegerInstance();
-
- Intent view = new Intent(context, ActivityView.class);
- view.setAction("unified");
- view.putExtra("refresh", true);
- view.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- PendingIntent pi = PendingIntent.getActivity(context, ActivityView.REQUEST_UNIFIED, view, PendingIntent.FLAG_UPDATE_CURRENT);
-
- for (int appWidgetId : appWidgetIds) {
- RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
-
- views.setOnClickPendingIntent(R.id.widget, pi);
-
- if (count == null)
- views.setTextViewText(R.id.tvCount, "?");
- else if (count > 99)
- views.setTextViewText(R.id.tvCount, "∞");
- else
- views.setTextViewText(R.id.tvCount, nf.format(count));
-
- appWidgetManager.updateAppWidget(appWidgetId, views);
- }
+ Intent intent = new Intent(context, Widget.class);
+ intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+ context.sendBroadcast(intent);
}
}
diff --git a/app/src/main/res/layout/activity_widget.xml b/app/src/main/res/layout/activity_widget.xml
new file mode 100644
index 0000000000..fec0c83ab0
--- /dev/null
+++ b/app/src/main/res/layout/activity_widget.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/widget.xml b/app/src/main/res/layout/widget.xml
index 9b497bdacc..a778b701c8 100644
--- a/app/src/main/res/layout/widget.xml
+++ b/app/src/main/res/layout/widget.xml
@@ -11,7 +11,7 @@
android:layout_width="24dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
- android:layout_weight="1"
+ android:layout_weight="2"
android:contentDescription="@string/title_legend_count"
android:src="@drawable/baseline_mail_24"
android:tint="@color/colorWidgetForeground" />
@@ -21,10 +21,22 @@
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
- android:layout_weight="1"
+ android:layout_weight="2"
android:text="\?"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="@color/colorWidgetForeground"
android:textSize="18dp"
android:textStyle="bold" />
+
+
diff --git a/app/src/main/res/xml/widget.xml b/app/src/main/res/xml/widget.xml
index d367755204..29abb26029 100644
--- a/app/src/main/res/xml/widget.xml
+++ b/app/src/main/res/xml/widget.xml
@@ -1,5 +1,6 @@