mirror of
https://github.com/M66B/FairEmail.git
synced 2025-01-01 12:44:42 +00:00
Expandable messages
This commit is contained in:
parent
36a36ae62d
commit
9f753a014e
20 changed files with 1568 additions and 333 deletions
|
@ -82,23 +82,24 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
|||
private ListView drawerList;
|
||||
private ActionBarDrawerToggle drawerToggle;
|
||||
|
||||
private boolean newMessages = false;
|
||||
private long attachment = -1;
|
||||
|
||||
private static final int ATTACHMENT_BUFFER_SIZE = 8192; // bytes
|
||||
|
||||
static final int REQUEST_SERVICE = 1;
|
||||
static final int REQUEST_UNSEEN = 2;
|
||||
static final int REQUEST_UNIFIED = 1;
|
||||
static final int REQUEST_THREAD = 2;
|
||||
static final int REQUEST_ERROR = 3;
|
||||
|
||||
static final int REQUEST_ATTACHMENT = 1;
|
||||
static final int REQUEST_INVITE = 2;
|
||||
|
||||
static final String ACTION_VIEW_MESSAGES = BuildConfig.APPLICATION_ID + ".VIEW_MESSAGES";
|
||||
static final String ACTION_VIEW_MESSAGE = BuildConfig.APPLICATION_ID + ".VIEW_MESSAGE";
|
||||
static final String ACTION_VIEW_THREAD = BuildConfig.APPLICATION_ID + ".VIEW_THREAD";
|
||||
static final String ACTION_VIEW_FULL = BuildConfig.APPLICATION_ID + ".VIEW_FULL";
|
||||
static final String ACTION_EDIT_FOLDER = BuildConfig.APPLICATION_ID + ".EDIT_FOLDER";
|
||||
static final String ACTION_EDIT_ANSWER = BuildConfig.APPLICATION_ID + ".EDIT_ANSWER";
|
||||
static final String ACTION_STORE_ATTACHMENT = BuildConfig.APPLICATION_ID + ".STORE_ATTACHMENT";
|
||||
static final String ACTION_SHOW_PRO = BuildConfig.APPLICATION_ID + ".SHOW_PRO";
|
||||
|
||||
static final String UPDATE_LATEST_API = "https://api.github.com/repos/M66B/open-source-email/releases/latest";
|
||||
static final long UPDATE_INTERVAL = 12 * 3600 * 1000L; // milliseconds
|
||||
|
@ -286,19 +287,13 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
|||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
|
||||
IntentFilter iff = new IntentFilter();
|
||||
iff.addAction(ACTION_VIEW_MESSAGES);
|
||||
iff.addAction(ACTION_VIEW_MESSAGE);
|
||||
iff.addAction(ACTION_VIEW_THREAD);
|
||||
iff.addAction(ACTION_VIEW_FULL);
|
||||
iff.addAction(ACTION_EDIT_FOLDER);
|
||||
iff.addAction(ACTION_EDIT_ANSWER);
|
||||
iff.addAction(ACTION_STORE_ATTACHMENT);
|
||||
iff.addAction(ACTION_SHOW_PRO);
|
||||
lbm.registerReceiver(receiver, iff);
|
||||
|
||||
if (newMessages) {
|
||||
newMessages = false;
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
fm.popBackStackImmediate("unified", 0);
|
||||
FragmentMessages fragment = (FragmentMessages) fm.findFragmentById(R.id.content_frame);
|
||||
fragment.onNewMessages();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -463,12 +458,13 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
|||
}
|
||||
|
||||
private void checkIntent(Intent intent) {
|
||||
Log.i(Helper.TAG, "View intent=" + intent + " action=" + intent.getAction());
|
||||
String action = intent.getAction();
|
||||
if ("notification".equals(action)) {
|
||||
Log.i(Helper.TAG, "View intent=" + intent + " action=" + action);
|
||||
if (action != null && action.startsWith("thread")) {
|
||||
intent.setAction(null);
|
||||
setIntent(intent);
|
||||
newMessages = true;
|
||||
intent.putExtra("id", Long.parseLong(action.split(":")[1]));
|
||||
onViewThread(intent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -739,14 +735,18 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
|||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_VIEW_MESSAGES.equals(intent.getAction()))
|
||||
onViewMessages(intent);
|
||||
else if (ACTION_VIEW_MESSAGE.equals(intent.getAction()))
|
||||
onViewMessage(intent);
|
||||
else if (ACTION_VIEW_THREAD.equals(intent.getAction()))
|
||||
onViewThread(intent);
|
||||
else if (ACTION_VIEW_FULL.equals(intent.getAction()))
|
||||
onViewFull(intent);
|
||||
else if (ACTION_EDIT_FOLDER.equals(intent.getAction()))
|
||||
onEditFolder(intent);
|
||||
else if (ACTION_EDIT_ANSWER.equals(intent.getAction()))
|
||||
onEditAnswer(intent);
|
||||
else if (ACTION_STORE_ATTACHMENT.equals(intent.getAction()))
|
||||
onStoreAttachment(intent);
|
||||
else if (ACTION_SHOW_PRO.equals(intent.getAction()))
|
||||
onShowPro(intent);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -758,65 +758,25 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
|||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
private void onViewMessage(Intent intent) {
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onLoad(Context context, Bundle args) {
|
||||
TupleMessageEx message = (TupleMessageEx) args.getSerializable("message");
|
||||
private void onViewThread(Intent intent) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("thread", intent.getLongExtra("id", -1));
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
FragmentMessages fragment = new FragmentMessages();
|
||||
fragment.setArguments(args);
|
||||
|
||||
if (!EntityFolder.OUTBOX.equals(message.folderType)) {
|
||||
if (!message.content)
|
||||
EntityOperation.queue(db, message, EntityOperation.BODY);
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("thread");
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
if (!message.threaded) {
|
||||
db.message().setMessageUiSeen(message.id, true);
|
||||
EntityOperation.queue(db, message, EntityOperation.SEEN, true);
|
||||
}
|
||||
}
|
||||
private void onViewFull(Intent intent) {
|
||||
FragmentWebView fragment = new FragmentWebView();
|
||||
fragment.setArguments(intent.getExtras());
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
EntityOperation.process(context);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoaded(Bundle args, Void result) {
|
||||
TupleMessageEx message = (TupleMessageEx) args.getSerializable("message");
|
||||
|
||||
if (message.threaded) {
|
||||
Bundle targs = new Bundle();
|
||||
targs.putLong("thread", message.id);
|
||||
|
||||
FragmentMessages fragment = new FragmentMessages();
|
||||
fragment.setArguments(targs);
|
||||
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("thread");
|
||||
fragmentTransaction.commit();
|
||||
|
||||
} else {
|
||||
FragmentMessage fragment = new FragmentMessage();
|
||||
fragment.setArguments(args);
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("message");
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Helper.unexpectedError(ActivityView.this, ex);
|
||||
}
|
||||
}.load(ActivityView.this, intent.getExtras());
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("webview");
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
private void onEditFolder(Intent intent) {
|
||||
|
@ -844,6 +804,12 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
|||
startActivityForResult(create, REQUEST_ATTACHMENT);
|
||||
}
|
||||
|
||||
private void onShowPro(Intent intent) {
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, new FragmentPro()).addToBackStack("pro");
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Log.i(Helper.TAG, "View onActivityResult request=" + requestCode + " result=" + resultCode + " data=" + data);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -75,9 +75,6 @@ public interface DaoAccount {
|
|||
@Update
|
||||
void updateAccount(EntityAccount account);
|
||||
|
||||
@Query("UPDATE account SET seen_until = :time WHERE id = :id")
|
||||
int setAccountSeenUntil(long id, long time);
|
||||
|
||||
@Query("UPDATE account SET state = :state WHERE id = :id")
|
||||
int setAccountState(long id, String state);
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ public interface DaoMessage {
|
|||
@Query("SELECT message.*" +
|
||||
", account.name AS accountName, account.color AS accountColor" +
|
||||
", folder.name AS folderName, folder.display AS folderDisplay, folder.type AS folderType" +
|
||||
", SUM(CASE WHEN folder.type = '" + EntityFolder.ARCHIVE + "' THEN 0 ELSE 1 END) > 1 AS threaded" +
|
||||
", COUNT(message.id) AS count" +
|
||||
", SUM(CASE WHEN message.ui_seen" +
|
||||
" OR folder.type = '" + EntityFolder.ARCHIVE + "'" +
|
||||
|
@ -67,7 +66,6 @@ public interface DaoMessage {
|
|||
@Query("SELECT message.*" +
|
||||
", account.name AS accountName, account.color AS accountColor" +
|
||||
", folder.name AS folderName, folder.display AS folderDisplay, folder.type AS folderType" +
|
||||
", SUM(CASE WHEN folder.type = '" + EntityFolder.ARCHIVE + "' THEN 0 ELSE 1 END) > 1 AS threaded" +
|
||||
", COUNT(message.id) AS count" +
|
||||
", SUM(CASE WHEN message.ui_seen" +
|
||||
" OR (folder.id <> :folder AND folder.type = '" + EntityFolder.ARCHIVE + "')" +
|
||||
|
@ -98,7 +96,6 @@ public interface DaoMessage {
|
|||
@Query("SELECT message.*" +
|
||||
", account.name AS accountName, account.color AS accountColor" +
|
||||
", folder.name AS folderName, folder.display AS folderDisplay, folder.type AS folderType" +
|
||||
", 0 AS threaded" +
|
||||
", (SELECT COUNT(m1.id) FROM message m1 WHERE m1.account = message.account AND m1.thread = message.thread AND NOT m1.ui_hide) AS count" +
|
||||
", CASE WHEN message.ui_seen THEN 0 ELSE 1 END AS unseen" +
|
||||
", CASE WHEN message.ui_flagged THEN 0 ELSE 1 END AS unflagged" +
|
||||
|
@ -147,7 +144,6 @@ public interface DaoMessage {
|
|||
@Query("SELECT message.*" +
|
||||
", account.name AS accountName, account.color AS accountColor" +
|
||||
", folder.name AS folderName, folder.display AS folderDisplay, folder.type AS folderType" +
|
||||
", 0 AS threaded" +
|
||||
", (SELECT COUNT(m1.id) FROM message m1 WHERE m1.account = message.account AND m1.thread = message.thread AND NOT m1.ui_hide) AS count" +
|
||||
", CASE WHEN message.ui_seen THEN 0 ELSE 1 END AS unseen" +
|
||||
", CASE WHEN message.ui_flagged THEN 0 ELSE 1 END AS unflagged" +
|
||||
|
@ -164,7 +160,6 @@ public interface DaoMessage {
|
|||
" WHERE account.`synchronize`" +
|
||||
" AND folder.unified" +
|
||||
" AND NOT message.ui_seen AND NOT message.ui_hide" +
|
||||
" AND (account.seen_until IS NULL OR message.stored > account.seen_until)" +
|
||||
" ORDER BY message.received")
|
||||
LiveData<List<EntityMessage>> liveUnseenUnified();
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public class EntityAccount {
|
|||
public Boolean store_sent; // obsolete
|
||||
@NonNull
|
||||
public Integer poll_interval; // keep-alive interval
|
||||
public Long seen_until;
|
||||
public Long seen_until; // obsolete
|
||||
public String state;
|
||||
public String error;
|
||||
|
||||
|
@ -76,7 +76,6 @@ public class EntityAccount {
|
|||
this.primary.equals(other.primary) &&
|
||||
(this.color == null ? other.color == null : this.color.equals(other.color)) &&
|
||||
this.poll_interval.equals(other.poll_interval) &&
|
||||
(this.seen_until == null ? other.seen_until == null : this.seen_until.equals(other.seen_until)) &&
|
||||
(this.state == null ? other.state == null : this.state.equals(other.state)) &&
|
||||
(this.error == null ? other.error == null : this.error.equals(other.error)));
|
||||
} else
|
||||
|
|
|
@ -189,6 +189,7 @@ public class EntityMessage implements Serializable {
|
|||
(this.uid == null ? other.uid == null : this.uid.equals(other.uid)) &&
|
||||
(this.msgid == null ? other.msgid == null : this.msgid.equals(other.msgid)) &&
|
||||
(this.references == null ? other.references == null : this.references.equals(other.references)) &&
|
||||
(this.deliveredto == null ? other.deliveredto == null : this.deliveredto.equals(other.deliveredto)) &&
|
||||
(this.inreplyto == null ? other.inreplyto == null : this.inreplyto.equals(other.inreplyto)) &&
|
||||
(this.thread == null ? other.thread == null : this.thread.equals(other.thread)) &&
|
||||
(this.avatar == null ? other.avatar == null : this.avatar.equals(other.avatar)) &&
|
||||
|
@ -199,12 +200,14 @@ public class EntityMessage implements Serializable {
|
|||
equal(this.reply, other.reply) &&
|
||||
(this.headers == null ? other.headers == null : this.headers.equals(other.headers)) &&
|
||||
(this.subject == null ? other.subject == null : this.subject.equals(other.subject)) &&
|
||||
(this.size == null ? other.size == null : this.size.equals(other.size)) &&
|
||||
this.content == other.content &&
|
||||
(this.sent == null ? other.sent == null : this.sent.equals(other.sent)) &&
|
||||
this.received.equals(other.received) &&
|
||||
this.stored.equals(other.stored) &&
|
||||
this.seen.equals(other.seen) &&
|
||||
this.ui_seen.equals(other.ui_seen) &&
|
||||
this.flagged.equals(other.flagged) &&
|
||||
this.ui_seen.equals(other.ui_seen) &&
|
||||
this.ui_flagged.equals(other.ui_flagged) &&
|
||||
this.ui_hide.equals(other.ui_hide) &&
|
||||
this.ui_found.equals(other.ui_found) &&
|
||||
|
|
|
@ -71,7 +71,6 @@ import java.text.Collator;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
@ -683,10 +682,8 @@ public class FragmentAccount extends FragmentEx {
|
|||
account.primary = (account.synchronize && primary);
|
||||
account.poll_interval = Integer.parseInt(interval);
|
||||
|
||||
if (!update)
|
||||
account.seen_until = new Date().getTime();
|
||||
|
||||
account.store_sent = false;
|
||||
account.store_sent = false; // obsolete
|
||||
account.seen_until = null; // obsolete
|
||||
|
||||
if (!synchronize)
|
||||
account.error = null;
|
||||
|
|
|
@ -167,7 +167,7 @@ public class FragmentMessage extends FragmentEx {
|
|||
ivFlagged = view.findViewById(R.id.ivFlagged);
|
||||
ivAvatar = view.findViewById(R.id.ivAvatar);
|
||||
tvFrom = view.findViewById(R.id.tvFrom);
|
||||
ivContactAdd = view.findViewById(R.id.ivContactAdd);
|
||||
ivContactAdd = view.findViewById(R.id.ivAddContact);
|
||||
tvTime = view.findViewById(R.id.tvTime);
|
||||
tvCount = view.findViewById(R.id.tvCount);
|
||||
tvTo = view.findViewById(R.id.tvTo);
|
||||
|
|
|
@ -42,7 +42,6 @@ import android.widget.TextView;
|
|||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
@ -185,7 +184,7 @@ public class FragmentMessages extends FragmentEx {
|
|||
return 0;
|
||||
|
||||
TupleMessageEx message = ((AdapterMessage) rvMessage.getAdapter()).getCurrentList().get(pos);
|
||||
if (message == null || message.threaded || EntityFolder.OUTBOX.equals(message.folderType))
|
||||
if (message == null || viewType != AdapterMessage.ViewType.THREAD || EntityFolder.OUTBOX.equals(message.folderType))
|
||||
return 0;
|
||||
|
||||
return makeMovementFlags(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
|
||||
|
@ -403,7 +402,7 @@ public class FragmentMessages extends FragmentEx {
|
|||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
grpHintSupport.setVisibility(prefs.getBoolean("app_support", false) ? View.GONE : View.VISIBLE);
|
||||
grpHintActions.setVisibility(prefs.getBoolean("message_actions", false) ? View.GONE : View.VISIBLE);
|
||||
grpHintActions.setVisibility(prefs.getBoolean("message_actions", false) || viewType != AdapterMessage.ViewType.THREAD ? View.GONE : View.VISIBLE);
|
||||
|
||||
final DB db = DB.getInstance(getContext());
|
||||
|
||||
|
@ -522,37 +521,6 @@ public class FragmentMessages extends FragmentEx {
|
|||
public void onResume() {
|
||||
super.onResume();
|
||||
grpSupport.setVisibility(Helper.isPro(getContext()) ? View.GONE : View.VISIBLE);
|
||||
|
||||
if (viewType == AdapterMessage.ViewType.UNIFIED) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("time", new Date().getTime());
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onLoad(Context context, Bundle args) {
|
||||
long time = args.getLong("time");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
for (EntityAccount account : db.account().getAccounts(true))
|
||||
db.account().setAccountSeenUntil(account.id, time);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Helper.unexpectedError(getContext(), ex);
|
||||
}
|
||||
}.load(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -793,8 +761,4 @@ public class FragmentMessages extends FragmentEx {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
void onNewMessages() {
|
||||
rvMessage.scrollToPosition(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|||
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
|
||||
|
||||
public class ServiceSynchronize extends LifecycleService {
|
||||
private TupleAccountStats stats = null;
|
||||
private final Object lock = new Object();
|
||||
private ServiceManager serviceManager = new ServiceManager();
|
||||
|
||||
|
@ -188,7 +187,6 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
db.account().liveStats().observe(this, new Observer<TupleAccountStats>() {
|
||||
@Override
|
||||
public void onChanged(@Nullable TupleAccountStats stats) {
|
||||
ServiceSynchronize.this.stats = stats;
|
||||
NotificationManager nm = getSystemService(NotificationManager.class);
|
||||
nm.notify(NOTIFICATION_SYNCHRONIZE,
|
||||
getNotificationService(stats.accounts, stats.operations, stats.unsent).build());
|
||||
|
@ -241,37 +239,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
serviceManager.queue_stop();
|
||||
else if ("reload".equals(action))
|
||||
serviceManager.queue_reload();
|
||||
else if ("until".equals(action)) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("time", new Date().getTime());
|
||||
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onLoad(Context context, Bundle args) {
|
||||
long time = args.getLong("time");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
for (EntityAccount account : db.account().getAccounts(true))
|
||||
db.account().setAccountSeenUntil(account.id, time);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoaded(Bundle args, Void data) {
|
||||
Log.i(Helper.TAG, "Updated seen until");
|
||||
}
|
||||
}.load(this, args);
|
||||
|
||||
} else if (action.startsWith("seen:") || action.startsWith("trash:")) {
|
||||
else if (action.startsWith("seen:") || action.startsWith("trash:")) {
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("id", Long.parseLong(action.split(":")[1]));
|
||||
args.putString("action", action.split(":")[0]);
|
||||
|
@ -323,7 +291,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
Intent intent = new Intent(this, ActivityView.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent pi = PendingIntent.getActivity(
|
||||
this, ActivityView.REQUEST_SERVICE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
this, ActivityView.REQUEST_UNIFIED, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
// Build notification
|
||||
Notification.Builder builder;
|
||||
|
@ -364,15 +332,9 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
|
||||
// Build pending intent
|
||||
Intent view = new Intent(this, ActivityView.class);
|
||||
view.setAction("notification");
|
||||
view.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent piView = PendingIntent.getActivity(
|
||||
this, ActivityView.REQUEST_UNSEEN, view, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
Intent until = new Intent(this, ServiceSynchronize.class);
|
||||
until.setAction("until");
|
||||
PendingIntent piUntil = PendingIntent.getService(
|
||||
this, PI_UNSEEN, until, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
this, ActivityView.REQUEST_UNIFIED, view, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
// Build notification
|
||||
Notification.Builder builder;
|
||||
|
@ -388,10 +350,10 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
.setContentIntent(piView)
|
||||
.setNumber(messages.size())
|
||||
.setShowWhen(false)
|
||||
.setOngoing(true)
|
||||
.setPriority(Notification.PRIORITY_DEFAULT)
|
||||
.setCategory(Notification.CATEGORY_STATUS)
|
||||
.setVisibility(Notification.VISIBILITY_PRIVATE)
|
||||
.setDeleteIntent(piUntil)
|
||||
.setGroup(BuildConfig.APPLICATION_ID)
|
||||
.setGroupSummary(true);
|
||||
|
||||
|
@ -428,6 +390,12 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
Bundle args = new Bundle();
|
||||
args.putLong("id", message.id);
|
||||
|
||||
Intent thread = new Intent(this, ActivityView.class);
|
||||
thread.setAction("thread:" + message.id);
|
||||
thread.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent piThread = PendingIntent.getActivity(
|
||||
this, ActivityView.REQUEST_THREAD, thread, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
Intent seen = new Intent(this, ServiceSynchronize.class);
|
||||
seen.setAction("seen:" + message.id);
|
||||
PendingIntent piSeen = PendingIntent.getService(this, PI_SEEN, seen, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
@ -456,9 +424,10 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
.addExtras(args)
|
||||
.setSmallIcon(R.drawable.baseline_mail_24)
|
||||
.setContentTitle(MessageHelper.getFormattedAddresses(message.from, true))
|
||||
.setContentIntent(piView)
|
||||
.setContentIntent(piThread)
|
||||
.setSound(uri)
|
||||
.setWhen(message.sent == null ? message.received : message.sent)
|
||||
.setOngoing(true)
|
||||
.setPriority(Notification.PRIORITY_DEFAULT)
|
||||
.setCategory(Notification.CATEGORY_STATUS)
|
||||
.setVisibility(Notification.VISIBILITY_PRIVATE)
|
||||
|
|
|
@ -25,7 +25,6 @@ public class TupleMessageEx extends EntityMessage {
|
|||
public String folderName;
|
||||
public String folderDisplay;
|
||||
public String folderType;
|
||||
public boolean threaded;
|
||||
public int count;
|
||||
public int unseen;
|
||||
public int unflagged;
|
||||
|
@ -41,7 +40,6 @@ public class TupleMessageEx extends EntityMessage {
|
|||
this.folderName.equals(other.folderName) &&
|
||||
(this.folderDisplay == null ? other.folderDisplay == null : this.folderDisplay.equals(other.folderDisplay)) &&
|
||||
this.folderType.equals(other.folderType) &&
|
||||
this.threaded == other.threaded &&
|
||||
this.count == other.count &&
|
||||
this.unseen == other.unseen &&
|
||||
this.unflagged == other.unflagged &&
|
||||
|
|
10
app/src/main/res/drawable/baseline_expand_less_24.xml
Normal file
10
app/src/main/res/drawable/baseline_expand_less_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/baseline_expand_more_24.xml
Normal file
10
app/src/main/res/drawable/baseline_expand_more_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/baseline_more_horiz_24.xml
Normal file
10
app/src/main/res/drawable/baseline_more_horiz_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/baseline_more_vert_24.xml
Normal file
10
app/src/main/res/drawable/baseline_more_vert_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
|
@ -41,14 +41,14 @@
|
|||
android:id="@+id/tvFrom"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:text="From"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ivContactAdd"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ivAddContact"
|
||||
app:layout_constraintStart_toEndOf="@id/ivAvatar"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
@ -56,8 +56,8 @@
|
|||
android:id="@+id/ivContactAdd"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:src="@drawable/baseline_import_contacts_24"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvFrom"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -67,9 +67,9 @@
|
|||
android:id="@+id/tvTime"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:maxLines="1"
|
||||
android:text="12:34:56"
|
||||
|
@ -114,8 +114,8 @@
|
|||
android:id="@+id/tvTo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
|
@ -130,8 +130,8 @@
|
|||
android:id="@+id/tvSubject"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:text="Subject"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
|
@ -163,8 +163,8 @@
|
|||
android:id="@+id/tvReplyTo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
|
@ -189,8 +189,8 @@
|
|||
android:id="@+id/tvCc"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
|
@ -215,8 +215,8 @@
|
|||
android:id="@+id/tvBcc"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
|
@ -241,9 +241,9 @@
|
|||
android:id="@+id/tvRawHeaders"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:fontFamily="monospace"
|
||||
|
||||
android:freezesText="true"
|
||||
|
@ -279,9 +279,9 @@
|
|||
android:id="@+id/rvAttachment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_constrainedHeight="true"
|
||||
|
@ -303,9 +303,9 @@
|
|||
android:id="@+id/tvError"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:freezesText="true"
|
||||
android:text="error"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
|
@ -330,8 +330,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:minHeight="0dp"
|
||||
android:text="@string/title_show_images"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorBody" />
|
||||
|
@ -340,9 +340,9 @@
|
|||
android:id="@+id/scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:fillViewport="true"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
|
||||
|
|
|
@ -15,7 +15,19 @@
|
|||
android:layout_width="6dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@color/colorAccent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/vSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivExpander"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:src="@drawable/baseline_expand_less_24"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvError"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
|
@ -26,7 +38,7 @@
|
|||
android:src="@drawable/baseline_star_24"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvFrom"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintStart_toEndOf="@id/ivExpander"
|
||||
app:layout_constraintTop_toTopOf="@+id/tvFrom" />
|
||||
|
||||
<ImageView
|
||||
|
@ -44,8 +56,8 @@
|
|||
android:id="@+id/tvFrom"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="From"
|
||||
|
@ -63,7 +75,8 @@
|
|||
android:text="123 KB"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvFrom"
|
||||
app:layout_constraintEnd_toStartOf="@id/tvTime" />
|
||||
app:layout_constraintEnd_toStartOf="@id/tvTime"
|
||||
app:layout_constraintTop_toTopOf="@id/tvFrom" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTime"
|
||||
|
@ -74,7 +87,8 @@
|
|||
android:text="Time"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvFrom"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/tvFrom" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivAttachments"
|
||||
|
@ -83,15 +97,15 @@
|
|||
android:layout_marginStart="6dp"
|
||||
android:src="@drawable/baseline_attachment_24"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvSubject"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintStart_toEndOf="@id/ivExpander"
|
||||
app:layout_constraintTop_toTopOf="@+id/tvSubject" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSubject"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="Subject"
|
||||
|
@ -136,13 +150,14 @@
|
|||
android:id="@+id/tvError"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:text="error"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="?attr/colorWarning"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintStart_toEndOf="@id/ivExpander"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvSubject" />
|
||||
|
||||
<ProgressBar
|
||||
|
@ -152,25 +167,322 @@
|
|||
android:layout_height="24dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvError"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/marginBottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:id="@+id/vSeparatorAddress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvError" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFromExTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="@string/title_from"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorAddress" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvFromEx"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
android:text="From"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ivAddContact"
|
||||
app:layout_constraintStart_toEndOf="@id/tvFromExTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorAddress" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivAddContact"
|
||||
android:layout_width="21dp"
|
||||
android:layout_height="21dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:src="@drawable/baseline_import_contacts_24"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorAddress" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvToTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="@string/title_to"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvFromEx" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
android:text="To"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tvToTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvFromEx" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvReplyToTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="@string/title_reply_to"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvTo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvReplyTo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
android:text="Reply to"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tvReplyToTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvTo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCcTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="@string/title_cc"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvReplyTo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCc"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
android:text="Cc"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tvCcTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvReplyTo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBccTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="@string/title_bcc"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvCc" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBcc"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
android:text="Bcc"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/tvBccTitle"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvCc" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvTimeEx"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:text="12:34:56"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvBcc" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSubjectEx"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:maxHeight="60dp"
|
||||
android:scrollbars="vertical"
|
||||
android:text="Subject"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvTimeEx" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorRawHeaders"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvSubjectEx" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvHeaders"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:fontFamily="monospace"
|
||||
android:text="Headers"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorRawHeaders" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pbHeaders"
|
||||
style="@style/Base.Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/vSeparatorBody"
|
||||
app:layout_constraintEnd_toEndOf="@id/tvHeaders"
|
||||
app:layout_constraintStart_toStartOf="@id/tvHeaders"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorRawHeaders" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bnvActions"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:itemIconTint="@color/bottomnav_background"
|
||||
app:itemTextColor="@color/bottomnav_background"
|
||||
app:labelVisibilityMode="labeled"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvHeaders"
|
||||
app:menu="@menu/action_message" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnImages"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:minWidth="0dp"
|
||||
android:minHeight="0dp"
|
||||
android:text="@string/title_show_images"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/bnvActions" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvBody"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:fontFamily="monospace"
|
||||
android:text="Body"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textIsSelectable="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnImages" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pbBody"
|
||||
style="@style/Base.Widget.AppCompat.ProgressBar"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/vSeparatorAttachments"
|
||||
app:layout_constraintEnd_toEndOf="@id/tvBody"
|
||||
app:layout_constraintStart_toStartOf="@id/tvBody"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparatorBody" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorAttachments"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvBody" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvAttachment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintTop_toBottomOf="@+id/vSeparatorAttachments" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/marginBottom" />
|
||||
app:layout_constraintTop_toBottomOf="@id/rvAttachment" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/grpHeaders"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:constraint_referenced_ids="vSeparatorRawHeaders,tvHeaders" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/grpAttachments"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:constraint_referenced_ids="vSeparatorAttachments,rvAttachment" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/grpExpanded"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="visible"
|
||||
app:constraint_referenced_ids="ivAddContact,vSeparatorAddress,tvFromExTitle,tvFromEx,tvToTitle,tvTo,tvReplyToTitle,tvReplyTo,tvCcTitle,tvCc,tvBccTitle,tvBcc,tvTimeEx,tvSubjectEx,bnvActions,tvBody,bottom_navigation" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
34
app/src/main/res/menu/action_message.xml
Normal file
34
app/src/main/res/menu/action_message.xml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_more"
|
||||
android:icon="@drawable/baseline_more_vert_24"
|
||||
android:title="@string/title_more"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_delete"
|
||||
android:icon="@drawable/baseline_delete_24"
|
||||
android:title="@string/title_trash"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_move"
|
||||
android:icon="@drawable/baseline_folder_24"
|
||||
android:title="@string/title_move"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_archive"
|
||||
android:icon="@drawable/baseline_archive_24"
|
||||
android:title="@string/title_archive"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_reply"
|
||||
android:icon="@drawable/baseline_reply_24"
|
||||
android:title="@string/title_reply"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
33
app/src/main/res/menu/menu_message.xml
Normal file
33
app/src/main/res/menu/menu_message.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_forward"
|
||||
android:title="@string/title_forward" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_reply_all"
|
||||
android:title="@string/title_reply_all" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_show_headers"
|
||||
android:checkable="true"
|
||||
android:title="@string/title_show_headers" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_show_html"
|
||||
android:title="@string/title_show_html" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_unseen"
|
||||
android:title="@string/title_unseen" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_flag"
|
||||
android:checkable="true"
|
||||
android:title="@string/title_flag" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_answer"
|
||||
android:title="@string/title_answer_reply" />
|
||||
</menu>
|
|
@ -187,6 +187,7 @@
|
|||
|
||||
<string name="title_trash">Trash</string>
|
||||
<string name="title_delete">Delete</string>
|
||||
<string name="title_more">More</string>
|
||||
<string name="title_spam">Spam</string>
|
||||
<string name="title_move">Move</string>
|
||||
<string name="title_archive">Archive</string>
|
||||
|
@ -261,7 +262,7 @@
|
|||
|
||||
<string name="title_hint_folder_actions">Long press for options</string>
|
||||
<string name="title_hint_support">If you have a question or a problem, please use the support menu to get help</string>
|
||||
<string name="title_hint_message_actions">Swipe left to trash; swipe right to archive (if available); long press to mark read/unread or to add/remove star</string>
|
||||
<string name="title_hint_message_actions">Swipe left to trash; swipe right to archive (if available)</string>
|
||||
<string name="title_hint_sync">Downloading messages can take some time, depending on the number of messages, the speed of your internet connection and your email provider</string>
|
||||
|
||||
<string name="title_open_link">Open link</string>
|
||||
|
|
Loading…
Reference in a new issue