Move to favorite folder

pull/197/head
M66B 4 years ago
parent d0eb35edd1
commit fe12c64f89

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1340,6 +1340,6 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
} }
interface IFolderSelectedListener { interface IFolderSelectedListener {
void onFolderSelected(TupleFolderEx folder); void onFolderSelected(@NonNull TupleFolderEx folder);
} }
} }

@ -1254,6 +1254,9 @@ class Core {
itarget.close(); itarget.close();
} }
if (EntityFolder.USER.equals(target.type))
db.folder().increaseSelectedCount(target.id, new Date().getTime());
// Delete junk contacts // Delete junk contacts
if (EntityFolder.JUNK.equals(target.type)) if (EntityFolder.JUNK.equals(target.type))
for (EntityMessage message : map.values()) { for (EntityMessage message : map.values()) {

@ -65,7 +65,7 @@ import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_PASSWORD;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 189, version = 191,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -1953,6 +1953,20 @@ public abstract class DB extends RoomDatabase {
db.execSQL("ALTER TABLE `identity` ADD COLUMN `sign_default` INTEGER NOT NULL DEFAULT 0"); db.execSQL("ALTER TABLE `identity` ADD COLUMN `sign_default` INTEGER NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE `identity` ADD COLUMN `encrypt_default` INTEGER NOT NULL DEFAULT 0"); db.execSQL("ALTER TABLE `identity` ADD COLUMN `encrypt_default` INTEGER NOT NULL DEFAULT 0");
} }
})
.addMigrations(new Migration(189, 190) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `folder` ADD COLUMN `selected_count` INTEGER NOT NULL DEFAULT 0");
}
})
.addMigrations(new Migration(190, 191) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `folder` ADD COLUMN `selected_last` INTEGER NOT NULL DEFAULT 0");
}
}); });
} }

@ -198,6 +198,22 @@ public interface DaoFolder {
" GROUP BY folder.type") " GROUP BY folder.type")
LiveData<List<TupleFolderUnified>> liveUnified(); LiveData<List<TupleFolderUnified>> liveUnified();
@Query("SELECT * FROM folder" +
" WHERE selected_count > 0" +
" AND NOT folder.id IN (:disabled)" +
" ORDER BY selected_count DESC, selected_last DESC" +
" LIMIT :count")
List<EntityFolder> getFavoriteFolders(int count, long[] disabled);
@Query("UPDATE folder" +
" SET selected_last = :last, selected_count = selected_count + 1" +
" WHERE id = :id")
int increaseSelectedCount(long id, long last);
@Query("UPDATE folder" +
" SET selected_last = 0, selected_count = 0")
int resetSelectedCount();
@Query("SELECT * FROM folder WHERE id = :id") @Query("SELECT * FROM folder WHERE id = :id")
EntityFolder getFolder(Long id); EntityFolder getFolder(Long id);

@ -116,6 +116,11 @@ public class EntityFolder extends EntityOrder implements Serializable {
public Integer total; // messages on server public Integer total; // messages on server
public String[] keywords; public String[] keywords;
@NonNull
public Long selected_last = 0L;
@NonNull
public Integer selected_count = 0;
@NonNull @NonNull
public Integer initialize = DEFAULT_KEEP; public Integer initialize = DEFAULT_KEEP;
public Boolean tbc; // to be created public Boolean tbc; // to be created

@ -22,6 +22,7 @@ package eu.faircode.email;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Paint;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
@ -77,9 +78,12 @@ public class FragmentDialogFolder extends FragmentDialogBase {
} }
final View dview = LayoutInflater.from(context).inflate(R.layout.dialog_folder_select, null); final View dview = LayoutInflater.from(context).inflate(R.layout.dialog_folder_select, null);
final TextView tvNoFolder = dview.findViewById(R.id.tvNoFolder);
final AutoCompleteTextView etSearch = dview.findViewById(R.id.etSearch); final AutoCompleteTextView etSearch = dview.findViewById(R.id.etSearch);
final ImageButton ibNext = dview.findViewById(R.id.ibNext); final ImageButton ibNext = dview.findViewById(R.id.ibNext);
final TextView tvNoFolder = dview.findViewById(R.id.tvNoFolder);
final TextView tvFavorite1 = dview.findViewById(R.id.tvFavorite1);
final TextView tvFavorite2 = dview.findViewById(R.id.tvFavorite2);
final TextView tvFavorite3 = dview.findViewById(R.id.tvFavorite3);
final RecyclerView rvFolder = dview.findViewById(R.id.rvFolder); final RecyclerView rvFolder = dview.findViewById(R.id.rvFolder);
final ContentLoadingProgressBar pbWait = dview.findViewById(R.id.pbWait); final ContentLoadingProgressBar pbWait = dview.findViewById(R.id.pbWait);
final Group grpReady = dview.findViewById(R.id.grpReady); final Group grpReady = dview.findViewById(R.id.grpReady);
@ -123,7 +127,7 @@ public class FragmentDialogFolder extends FragmentDialogBase {
final AdapterFolder adapter = new AdapterFolder(context, getViewLifecycleOwner(), final AdapterFolder adapter = new AdapterFolder(context, getViewLifecycleOwner(),
account, false, false, false, false, new AdapterFolder.IFolderSelectedListener() { account, false, false, false, false, new AdapterFolder.IFolderSelectedListener() {
@Override @Override
public void onFolderSelected(TupleFolderEx folder) { public void onFolderSelected(@NonNull TupleFolderEx folder) {
String name = folder.getDisplayName(context, folder.parent_ref); String name = folder.getDisplayName(context, folder.parent_ref);
selected_folders.remove(name); selected_folders.remove(name);
selected_folders.add(0, name); selected_folders.add(0, name);
@ -140,6 +144,32 @@ public class FragmentDialogFolder extends FragmentDialogBase {
} }
}); });
tvFavorite1.setVisibility(View.GONE);
tvFavorite2.setVisibility(View.GONE);
tvFavorite3.setVisibility(View.GONE);
tvFavorite1.setPaintFlags(tvFavorite1.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
tvFavorite2.setPaintFlags(tvFavorite2.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
tvFavorite3.setPaintFlags(tvFavorite3.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Long id = (Long) v.getTag();
if (id == null)
return;
Bundle args = getArguments();
args.putLong("folder", id);
sendResult(RESULT_OK);
dismiss();
}
};
tvFavorite1.setOnClickListener(listener);
tvFavorite2.setOnClickListener(listener);
tvFavorite3.setOnClickListener(listener);
rvFolder.setAdapter(adapter); rvFolder.setAdapter(adapter);
etSearch.addTextChangedListener(new TextWatcher() { etSearch.addTextChangedListener(new TextWatcher() {
@ -200,8 +230,9 @@ public class FragmentDialogFolder extends FragmentDialogBase {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putLong("account", account); args.putLong("account", account);
args.putLongArray("disabled", disabled);
new SimpleTask<List<TupleFolderEx>>() { new SimpleTask<Data>() {
@Override @Override
protected void onPreExecute(Bundle args) { protected void onPreExecute(Bundle args) {
tvNoFolder.setVisibility(View.GONE); tvNoFolder.setVisibility(View.GONE);
@ -215,20 +246,35 @@ public class FragmentDialogFolder extends FragmentDialogBase {
} }
@Override @Override
protected List<TupleFolderEx> onExecute(Context context, Bundle args) { protected Data onExecute(Context context, Bundle args) {
long account = args.getLong("account"); long account = args.getLong("account");
long[] disabled = args.getLongArray("disabled");
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
return db.folder().getFoldersEx(account);
Data data = new Data();
data.folders = db.folder().getFoldersEx(account);
data.favorites = db.folder().getFavoriteFolders(3, disabled);
return data;
} }
@Override @Override
protected void onExecuted(final Bundle args, List<TupleFolderEx> folders) { protected void onExecuted(final Bundle args, Data data) {
if (folders == null || folders.size() == 0) if (data.folders == null || data.folders.size() == 0)
tvNoFolder.setVisibility(View.VISIBLE); tvNoFolder.setVisibility(View.VISIBLE);
else { else {
adapter.setDisabled(Helper.fromLongArray(disabled)); adapter.setDisabled(Helper.fromLongArray(disabled));
adapter.set(folders); adapter.set(data.folders);
if (data.favorites != null) {
TextView[] tv = new TextView[]{tvFavorite1, tvFavorite2, tvFavorite3};
for (int i = 0; i < data.favorites.size(); i++) {
EntityFolder favorite = data.favorites.get(i);
tv[i].setTag(favorite.id);
tv[i].setText(favorite.getDisplayName(context));
tv[i].setVisibility(View.VISIBLE);
}
}
grpReady.setVisibility(View.VISIBLE); grpReady.setVisibility(View.VISIBLE);
} }
} }
@ -246,4 +292,9 @@ public class FragmentDialogFolder extends FragmentDialogBase {
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.create(); .create();
} }
private static class Data {
private List<TupleFolderEx> folders;
private List<EntityFolder> favorites;
}
} }

@ -3496,7 +3496,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
if (sourceFolder == null || sourceFolder.read_only) if (sourceFolder == null || sourceFolder.read_only)
continue; continue;
result.add(new MessageTarget(context, threaded, sourceAccount, sourceFolder, targetAccount, targetFolder, copy)); result.add(new MessageTarget(context, threaded, sourceAccount, sourceFolder, targetAccount, targetFolder).setCopy(copy));
} }
} }
@ -7957,19 +7957,16 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
MessageTarget(Context context, EntityMessage message, MessageTarget(Context context, EntityMessage message,
EntityAccount sourceAccount, EntityFolder sourceFolder, EntityAccount sourceAccount, EntityFolder sourceFolder,
EntityAccount targetAccount, EntityFolder targetFolder) { EntityAccount targetAccount, EntityFolder targetFolder) {
this(context, message, sourceAccount, sourceFolder, targetAccount, targetFolder, false);
}
MessageTarget(Context context, EntityMessage message,
EntityAccount sourceAccount, EntityFolder sourceFolder,
EntityAccount targetAccount, EntityFolder targetFolder,
boolean copy) {
this.id = message.id; this.id = message.id;
this.sourceAccount = new Account(sourceAccount); this.sourceAccount = new Account(sourceAccount);
this.sourceFolder = new Folder(context, sourceFolder); this.sourceFolder = new Folder(context, sourceFolder);
this.targetAccount = new Account(targetAccount); this.targetAccount = new Account(targetAccount);
this.targetFolder = new Folder(context, targetFolder); this.targetFolder = new Folder(context, targetFolder);
}
MessageTarget setCopy(boolean copy) {
this.copy = copy; this.copy = copy;
return this;
} }
protected MessageTarget(Parcel in) { protected MessageTarget(Parcel in) {

@ -834,6 +834,21 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
if (key.endsWith(".show_full") || key.endsWith(".show_images") || key.endsWith(".confirm_link")) if (key.endsWith(".show_full") || key.endsWith(".show_images") || key.endsWith(".confirm_link"))
editor.remove(key); editor.remove(key);
editor.apply(); editor.apply();
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) {
DB db = DB.getInstance(context);
db.folder().resetSelectedCount();
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(this, new Bundle(), "reset:questions");
ToastEx.makeText(getContext(), R.string.title_setup_done, Toast.LENGTH_LONG).show(); ToastEx.makeText(getContext(), R.string.title_setup_done, Toast.LENGTH_LONG).show();
} }

@ -8,18 +8,6 @@
android:focusableInTouchMode="true" android:focusableInTouchMode="true"
android:padding="12dp"> android:padding="12dp">
<eu.faircode.email.FixedTextView
android:id="@+id/tvNoFolder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp"
android:text="@string/title_no_folders"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<AutoCompleteTextView <AutoCompleteTextView
android:id="@+id/etSearch" android:id="@+id/etSearch"
android:layout_width="0dp" android:layout_width="0dp"
@ -42,6 +30,68 @@
app:layout_constraintTop_toTopOf="@+id/etSearch" app:layout_constraintTop_toTopOf="@+id/etSearch"
app:srcCompat="@drawable/twotone_fast_forward_24" /> app:srcCompat="@drawable/twotone_fast_forward_24" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvNoFolder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="12dp"
android:text="@string/title_no_folders"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etSearch" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvFavorite1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="start"
android:padding="6dp"
android:singleLine="true"
android:text="favorite1"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:attr/textColorLink"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/tvFavorite2"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvNoFolder" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvFavorite2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="start"
android:padding="6dp"
android:singleLine="true"
android:text="favorite2"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:attr/textColorLink"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/tvFavorite3"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toEndOf="@id/tvFavorite1"
app:layout_constraintTop_toBottomOf="@id/tvNoFolder" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvFavorite3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="start"
android:padding="6dp"
android:singleLine="true"
android:text="favorite3"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textColor="?android:attr/textColorLink"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toEndOf="@id/tvFavorite2"
app:layout_constraintTop_toBottomOf="@id/tvNoFolder" />
<eu.faircode.email.FixedRecyclerView <eu.faircode.email.FixedRecyclerView
android:id="@+id/rvFolder" android:id="@+id/rvFolder"
android:layout_width="0dp" android:layout_width="0dp"
@ -58,7 +108,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_toBottomOf="@+id/etSearch" /> app:layout_constraintTop_toBottomOf="@+id/tvFavorite1" />
<eu.faircode.email.ContentLoadingProgressBar <eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbWait" android:id="@+id/pbWait"

Loading…
Cancel
Save