Swipe left to trash, swipe right to archive

Move to inbox when in trash or archive

Refs #10
Refs #55
pull/72/head
M66B 6 years ago
parent 0cb727ba99
commit ab8cf3457f

@ -21,6 +21,7 @@ package eu.faircode.email;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.TextUtils; import android.text.TextUtils;
@ -31,11 +32,13 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import java.util.List; import java.util.List;
@ -49,14 +52,17 @@ import androidx.lifecycle.Observer;
import androidx.paging.DataSource; import androidx.paging.DataSource;
import androidx.paging.LivePagedListBuilder; import androidx.paging.LivePagedListBuilder;
import androidx.paging.PagedList; import androidx.paging.PagedList;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
public class FragmentMessages extends FragmentEx { public class FragmentMessages extends FragmentEx {
private ViewGroup view; private ViewGroup view;
private Button btnHintSwipe;
private RecyclerView rvMessage; private RecyclerView rvMessage;
private TextView tvNoEmail; private TextView tvNoEmail;
private ProgressBar pbWait; private ProgressBar pbWait;
private Group grpHintSwipe;
private Group grpReady; private Group grpReady;
private FloatingActionButton fab; private FloatingActionButton fab;
@ -93,14 +99,25 @@ public class FragmentMessages extends FragmentEx {
setHasOptionsMenu(true); setHasOptionsMenu(true);
// Get controls // Get controls
btnHintSwipe = view.findViewById(R.id.btnHintSwipe);
rvMessage = view.findViewById(R.id.rvFolder); rvMessage = view.findViewById(R.id.rvFolder);
tvNoEmail = view.findViewById(R.id.tvNoEmail); tvNoEmail = view.findViewById(R.id.tvNoEmail);
pbWait = view.findViewById(R.id.pbWait); pbWait = view.findViewById(R.id.pbWait);
grpReady = view.findViewById(R.id.grpReady); grpReady = view.findViewById(R.id.grpReady);
grpHintSwipe = view.findViewById(R.id.grpHintSwipe);
fab = view.findViewById(R.id.fab); fab = view.findViewById(R.id.fab);
// Wire controls // Wire controls
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
btnHintSwipe.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
prefs.edit().putBoolean("understood_swipe", true).apply();
grpHintSwipe.setVisibility(View.GONE);
}
});
rvMessage.setHasFixedSize(false); rvMessage.setHasFixedSize(false);
LinearLayoutManager llm = new LinearLayoutManager(getContext()); LinearLayoutManager llm = new LinearLayoutManager(getContext());
rvMessage.setLayoutManager(llm); rvMessage.setLayoutManager(llm);
@ -120,6 +137,87 @@ public class FragmentMessages extends FragmentEx {
adapter = new AdapterMessage(getContext(), getViewLifecycleOwner(), viewType); adapter = new AdapterMessage(getContext(), getViewLifecycleOwner(), viewType);
rvMessage.setAdapter(adapter); rvMessage.setAdapter(adapter);
new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int pos = viewHolder.getAdapterPosition();
if (pos == RecyclerView.NO_POSITION)
return 0;
TupleMessageEx message = ((AdapterMessage) rvMessage.getAdapter()).getCurrentList().get(pos);
if (EntityFolder.OUTBOX.equals(message.folderType))
return 0;
return makeMovementFlags(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int pos = viewHolder.getAdapterPosition();
if (pos != RecyclerView.NO_POSITION) {
TupleMessageEx message = ((AdapterMessage) rvMessage.getAdapter()).getCurrentList().get(pos);
Log.i(Helper.TAG, "Swiped dir=" + direction + " message=" + message.id);
Bundle args = new Bundle();
args.putLong("id", message.id);
args.putInt("direction", direction);
new SimpleTask<String>() {
@Override
protected String onLoad(Context context, Bundle args) throws Throwable {
long id = args.getLong("id");
int direction = args.getInt("direction");
EntityFolder target = null;
DB db = DB.getInstance(context);
try {
db.beginTransaction();
EntityMessage message = db.message().getMessage(id);
EntityFolder folder = db.folder().getFolder(message.folder);
if (EntityFolder.ARCHIVE.equals(folder.type) || EntityFolder.TRASH.equals(folder.type))
target = db.folder().getFolderByType(message.account, EntityFolder.INBOX);
else {
if (direction == ItemTouchHelper.RIGHT)
target = db.folder().getFolderByType(message.account, EntityFolder.ARCHIVE);
if (direction == ItemTouchHelper.LEFT || target == null)
target = db.folder().getFolderByType(message.account, EntityFolder.TRASH);
}
db.message().setMessageUiHide(message.id, true);
EntityOperation.queue(db, message, EntityOperation.MOVE, target.id);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
EntityOperation.process(context);
return target.name;
}
@Override
protected void onLoaded(Bundle args, String folder) {
Snackbar.make(
view,
getString(R.string.title_moving, Helper.localizeFolderName(getContext(), folder)),
Snackbar.LENGTH_SHORT).show();
}
@Override
protected void onException(Bundle args, Throwable ex) {
Toast.makeText(getContext(), ex.toString(), Toast.LENGTH_LONG).show();
}
}.load(FragmentMessages.this, args);
}
}
}).attachToRecyclerView(rvMessage);
fab.setOnClickListener(new View.OnClickListener() { fab.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
@ -143,6 +241,10 @@ public class FragmentMessages extends FragmentEx {
public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
grpHintSwipe.setVisibility(prefs.getBoolean("understood_swipe", false) ? View.GONE : View.VISIBLE);
final DB db = DB.getInstance(getContext()); final DB db = DB.getInstance(getContext());
db.account().livePrimaryAccount().observe(getViewLifecycleOwner(), new Observer<EntityAccount>() { db.account().livePrimaryAccount().observe(getViewLifecycleOwner(), new Observer<EntityAccount>() {
@ -157,7 +259,7 @@ public class FragmentMessages extends FragmentEx {
// Observe folder/messages/search // Observe folder/messages/search
if (TextUtils.isEmpty(search)) { if (TextUtils.isEmpty(search)) {
boolean debug = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("debug", false); boolean debug = prefs.getBoolean("debug", false);
if (thread < 0) if (thread < 0)
if (folder < 0) { if (folder < 0) {
db.folder().liveUnified().observe(getViewLifecycleOwner(), new Observer<List<TupleFolderEx>>() { db.folder().liveUnified().observe(getViewLifecycleOwner(), new Observer<List<TupleFolderEx>>() {

@ -17,6 +17,39 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvHintSwipe"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:layout_marginTop="6dp"
android:text="@string/title_hint_swipe"
app:layout_constraintEnd_toStartOf="@+id/btnHintSwipe"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnHintSwipe"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:minWidth="0dp"
android:text="@string/title_understood"
app:layout_constraintBottom_toBottomOf="@id/tvHintSwipe"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvHintSwipe" />
<View
android:id="@+id/vSeparator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="6dp"
android:background="?attr/colorSeparator"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnHintSwipe" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvFolder" android:id="@+id/rvFolder"
android:layout_width="0dp" android:layout_width="0dp"
@ -26,7 +59,7 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toBottomOf="@id/vSeparator" />
<ProgressBar <ProgressBar
android:id="@+id/pbWait" android:id="@+id/pbWait"
@ -51,6 +84,12 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpHintSwipe"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="tvHintSwipe,btnHintSwipe,vSeparator" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/grpReady" android:id="@+id/grpReady"
android:layout_width="0dp" android:layout_width="0dp"

@ -144,6 +144,7 @@
<string name="title_move">Move</string> <string name="title_move">Move</string>
<string name="title_archive">Archive</string> <string name="title_archive">Archive</string>
<string name="title_reply">Reply</string> <string name="title_reply">Reply</string>
<string name="title_moving">Moving message to %1$s</string>
<string name="title_no_viewer">No viewer app available for %1$s</string> <string name="title_no_viewer">No viewer app available for %1$s</string>
<string name="title_attachment_saved">Attachment saved</string> <string name="title_attachment_saved">Attachment saved</string>
@ -192,6 +193,9 @@
<string name="title_legend_connected">Connected</string> <string name="title_legend_connected">Connected</string>
<string name="title_legend_closing">Closing</string> <string name="title_legend_closing">Closing</string>
<string name="title_hint_swipe">Swipe left to trash and swipe right to archive (if available)</string>
<string name="title_understood">Understood</string>
<string name="title_pro_feature">This is a pro feature</string> <string name="title_pro_feature">This is a pro feature</string>
<string name="title_pro_list">List of pro features</string> <string name="title_pro_list">List of pro features</string>
<string name="title_pro_purchase">Buy</string> <string name="title_pro_purchase">Buy</string>

Loading…
Cancel
Save