Added setting to enable/disable conversation threading

pull/146/head
M66B 7 years ago
parent 15b9351cd8
commit b5b0e56fea

@ -52,7 +52,6 @@ Anything on this list is in random order and *might* be added in the near future
* Better design: please let me know what you have in mind [in this forum](https://forum.xda-developers.com/android/apps-games/source-email-t3824168).
* Hide archived messages: hiding archived messages which exists in other folders too would have a performance impact.
* Save all attachments: there is no [Storage Access Framework](https://developer.android.com/guide/topics/providers/document-provider) API to selected multiple files to save.
* Show single messages: listing single messages just clutters the list without much benefit, so this will not be added.
* S/MIME encryption: only PGP encryption will be supported, see [this FAQ](#user-content-faq12) for more information.
Since FairEmail is meant to be privacy friendly, the following will not be added:

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

@ -1077,6 +1077,7 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
Bundle args = new Bundle();
args.putLong("account", intent.getLongExtra("account", -1));
args.putString("thread", intent.getStringExtra("thread"));
args.putLong("id", intent.getLongExtra("id", -1));
args.putBoolean("found", intent.getBooleanExtra("found", false));
FragmentMessages fragment = new FragmentMessages();

@ -113,6 +113,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
private boolean outgoing;
private IProperties properties;
private boolean threading;
private boolean compact;
private boolean contacts;
private boolean avatars;
@ -353,7 +354,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
vwColor.setBackgroundColor(message.accountColor == null ? Color.TRANSPARENT : message.accountColor);
ivExpander.setImageResource(show_expanded ? R.drawable.baseline_expand_less_24 : R.drawable.baseline_expand_more_24);
if (viewType == ViewType.THREAD)
if (viewType == ViewType.THREAD && threading)
ivExpander.setVisibility(EntityFolder.DRAFTS.equals(message.folderType) ? View.INVISIBLE : View.VISIBLE);
else
ivExpander.setVisibility(View.GONE);
@ -386,7 +387,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
tvPreview.setText(message.preview);
tvPreview.setVisibility(preview && !TextUtils.isEmpty(message.preview) ? View.VISIBLE : View.GONE);
if (viewType == ViewType.THREAD) {
if (viewType == ViewType.THREAD || !threading) {
tvCount.setVisibility(View.GONE);
ivThread.setVisibility(View.GONE);
} else {
@ -565,6 +566,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
new Intent(ActivityView.ACTION_VIEW_THREAD)
.putExtra("account", message.account)
.putExtra("thread", message.thread)
.putExtra("id", message.id)
.putExtra("found", message.ui_found));
}
}
@ -1519,6 +1521,7 @@ public class AdapterMessage extends PagedListAdapter<TupleMessageEx, AdapterMess
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
this.threading = prefs.getBoolean("threading", true);
this.compact = prefs.getBoolean("compact", false);
this.contacts = (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
== PackageManager.PERMISSION_GRANTED);

@ -58,7 +58,7 @@ public interface DaoMessage {
" WHERE account.`synchronize`" +
" AND (NOT message.ui_hide OR :debug)" +
" AND NOT ui_found" +
" GROUP BY account.id, CASE WHEN message.thread IS NULL THEN message.id ELSE message.thread END" +
" GROUP BY account.id, CASE WHEN message.thread IS NULL OR NOT :threading THEN message.id ELSE message.thread END" +
" HAVING SUM(unified) > 0" +
" ORDER BY CASE" +
" WHEN 'unread' = :sort THEN NOT message.ui_seen" +
@ -66,7 +66,7 @@ public interface DaoMessage {
" ELSE 0" +
" END DESC, message.received DESC")
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
DataSource.Factory<Integer, TupleMessageEx> pagedUnifiedInbox(String sort, boolean debug);
DataSource.Factory<Integer, TupleMessageEx> pagedUnifiedInbox(boolean threading, String sort, boolean debug);
@Query("SELECT message.*" +
", account.name AS accountName, identity.color AS accountColor, account.notify AS accountNotify" +
@ -91,7 +91,7 @@ public interface DaoMessage {
" WHERE (message.account = f.account OR folder.type = '" + EntityFolder.OUTBOX + "')" +
" AND (NOT message.ui_hide OR :debug)" +
" AND ui_found = :found" +
" GROUP BY CASE WHEN message.thread IS NULL THEN message.id ELSE message.thread END" +
" GROUP BY CASE WHEN message.thread IS NULL OR NOT :threading THEN message.id ELSE message.thread END" +
" HAVING SUM(CASE WHEN folder.id = :folder THEN 1 ELSE 0 END) > 0" +
" ORDER BY CASE" +
" WHEN 'unread' = :sort THEN NOT message.ui_seen" +
@ -99,7 +99,7 @@ public interface DaoMessage {
" ELSE 0" +
" END DESC, message.received DESC")
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
DataSource.Factory<Integer, TupleMessageEx> pagedFolder(long folder, String sort, boolean found, boolean debug);
DataSource.Factory<Integer, TupleMessageEx> pagedFolder(long folder, boolean threading, String sort, boolean found, boolean debug);
@Query("SELECT message.*" +
", account.name AS accountName, identity.color AS accountColor, account.notify AS accountNotify" +
@ -125,6 +125,7 @@ public interface DaoMessage {
" JOIN folder ON folder.id = message.folder" +
" WHERE message.account = :account" +
" AND message.thread = :thread" +
" AND (:id IS NULL OR message.id = :id)" +
" AND ui_found = :found" +
" AND (NOT message.ui_hide OR :debug)" +
" ORDER BY CASE" +
@ -132,7 +133,7 @@ public interface DaoMessage {
" WHEN 'starred' = :sort THEN message.ui_flagged" +
" ELSE 0" +
" END DESC, message.received DESC")
DataSource.Factory<Integer, TupleMessageEx> pagedThread(long account, String thread, boolean found, String sort, boolean debug);
DataSource.Factory<Integer, TupleMessageEx> pagedThread(long account, String thread, Long id, boolean found, String sort, boolean debug);
@Query("SELECT COUNT(id)" +
" FROM message" +

@ -93,9 +93,11 @@ public class FragmentMessages extends FragmentEx {
private long folder = -1;
private boolean outgoing = false;
private String thread = null;
private long id = -1;
private boolean found = false;
private String search = null;
private boolean threading = true;
private boolean actionbar = false;
private boolean autoclose = false;
@ -136,10 +138,12 @@ public class FragmentMessages extends FragmentEx {
folder = args.getLong("folder", -1);
outgoing = args.getBoolean("outgoing", false);
thread = args.getString("thread");
id = args.getLong("id", -1);
found = args.getBoolean("found", false);
search = args.getString("search");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
threading = prefs.getBoolean("threading", true);
actionbar = prefs.getBoolean("actionbar", true);
autoclose = prefs.getBoolean("autoclose", false);
@ -1222,7 +1226,7 @@ public class FragmentMessages extends FragmentEx {
switch (viewType) {
case UNIFIED:
messages = new LivePagedListBuilder<>(db.message().pagedUnifiedInbox(sort, debug), LOCAL_PAGE_SIZE).build();
messages = new LivePagedListBuilder<>(db.message().pagedUnifiedInbox(threading, sort, debug), LOCAL_PAGE_SIZE).build();
break;
case FOLDER:
if (searchCallback == null)
@ -1255,14 +1259,15 @@ public class FragmentMessages extends FragmentEx {
.setPrefetchDistance(REMOTE_PAGE_SIZE)
.build();
LivePagedListBuilder<Integer, TupleMessageEx> builder = new LivePagedListBuilder<>(
db.message().pagedFolder(folder, sort, false, debug), config);
db.message().pagedFolder(folder, threading, sort, false, debug), config);
if (browse)
builder.setBoundaryCallback(searchCallback);
messages = builder.build();
break;
case THREAD:
messages = new LivePagedListBuilder<>(db.message().pagedThread(account, thread, found, sort, debug), LOCAL_PAGE_SIZE).build();
messages = new LivePagedListBuilder<>(
db.message().pagedThread(account, thread, threading ? null : id, found, sort, debug), LOCAL_PAGE_SIZE).build();
break;
}
} else {
@ -1299,7 +1304,7 @@ public class FragmentMessages extends FragmentEx {
.setPrefetchDistance(REMOTE_PAGE_SIZE)
.build();
LivePagedListBuilder<Integer, TupleMessageEx> builder = new LivePagedListBuilder<>(
db.message().pagedFolder(folder, "time", true, false), config);
db.message().pagedFolder(folder, threading, "time", true, false), config);
builder.setBoundaryCallback(searchCallback);
messages = builder.build();
}
@ -1497,6 +1502,7 @@ public class FragmentMessages extends FragmentEx {
new Intent(ActivityView.ACTION_VIEW_THREAD)
.putExtra("account", target.account)
.putExtra("thread", target.thread)
.putExtra("id", target.id)
.putExtra("found", target.found));
}

@ -43,9 +43,10 @@ import androidx.appcompat.widget.SwitchCompat;
public class FragmentOptions extends FragmentEx implements SharedPreferences.OnSharedPreferenceChangeListener {
private SwitchCompat swEnabled;
private SwitchCompat swMetered;
private SwitchCompat swThreading;
private SwitchCompat swCompact;
private SwitchCompat swAvatars;
private SwitchCompat swIdenticons;
private SwitchCompat swCompact;
private SwitchCompat swPreview;
private SwitchCompat swLight;
private SwitchCompat swBrowse;
@ -69,6 +70,7 @@ public class FragmentOptions extends FragmentEx implements SharedPreferences.OnS
// Get controls
swEnabled = view.findViewById(R.id.swEnabled);
swMetered = view.findViewById(R.id.swMetered);
swThreading = view.findViewById(R.id.swThreading);
swCompact = view.findViewById(R.id.swCompact);
swAvatars = view.findViewById(R.id.swAvatars);
swIdenticons = view.findViewById(R.id.swIdenticons);
@ -107,6 +109,14 @@ public class FragmentOptions extends FragmentEx implements SharedPreferences.OnS
}
});
swThreading.setChecked(prefs.getBoolean("threading", true));
swThreading.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("threading", checked).apply();
}
});
swCompact.setChecked(prefs.getBoolean("compact", false));
swCompact.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override

@ -56,18 +56,20 @@ public class ViewModelMessages extends ViewModel {
next = item;
}
return new Target[]{
prev == null ? null : new Target(prev.account, prev.thread, prev.ui_found),
next == null ? null : new Target(next.account, next.thread, next.ui_found)};
prev == null ? null : new Target(prev.account, prev.thread, prev.id, prev.ui_found),
next == null ? null : new Target(next.account, next.thread, next.id, next.ui_found)};
}
class Target {
long account;
String thread;
long id;
boolean found;
Target(long account, String thread, boolean found) {
Target(long account, String thread, long id, boolean found) {
this.account = account;
this.thread = thread;
this.id = id;
this.found = found;
}
}

@ -29,6 +29,15 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swEnabled" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swThreading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_threading"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swMetered" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swCompact"
android:layout_width="match_parent"
@ -36,7 +45,7 @@
android:layout_marginTop="12dp"
android:text="@string/title_advanced_compact"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swMetered" />
app:layout_constraintTop_toBottomOf="@id/swThreading" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swAvatars"

@ -98,6 +98,7 @@
<string name="title_advanced">Advanced options</string>
<string name="title_advanced_enabled">Synchronize</string>
<string name="title_advanced_metered">Use metered connections</string>
<string name="title_advanced_threading">Conversation threading</string>
<string name="title_advanced_compact">Compact message view</string>
<string name="title_advanced_avatars">Show contact photos</string>
<string name="title_advanced_identicons">Show identicons</string>

Loading…
Cancel
Save