mirror of https://github.com/M66B/FairEmail.git
Collapsable folders
This commit is contained in:
parent
dd025b1ff3
commit
525ed9b50c
|
@ -50,9 +50,11 @@ import java.util.Locale;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.ListUpdateCallback;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
@ -70,12 +72,14 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
|
||||
private List<TupleFolderEx> all = new ArrayList<>();
|
||||
private List<TupleFolderEx> filtered = new ArrayList<>();
|
||||
private List<Long> collapsed = new ArrayList<>();
|
||||
|
||||
private static NumberFormat nf = NumberFormat.getNumberInstance();
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||
private View view;
|
||||
private View vwColor;
|
||||
private ImageView ivExpander;
|
||||
private View vwLevel;
|
||||
private ImageView ivState;
|
||||
private ImageView ivNotify;
|
||||
|
@ -88,6 +92,10 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
private ImageView ivSync;
|
||||
private TextView tvKeywords;
|
||||
private TextView tvError;
|
||||
private RecyclerView rvChilds;
|
||||
|
||||
private AdapterFolder childs;
|
||||
private TwoStateOwner cowner = new TwoStateOwner(owner);
|
||||
|
||||
private final static int action_synchronize_now = 1;
|
||||
private final static int action_delete_local = 2;
|
||||
|
@ -101,6 +109,7 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
|
||||
view = itemView.findViewById(R.id.clItem);
|
||||
vwColor = itemView.findViewById(R.id.vwColor);
|
||||
ivExpander = itemView.findViewById(R.id.ivExpander);
|
||||
vwLevel = itemView.findViewById(R.id.vwLevel);
|
||||
ivState = itemView.findViewById(R.id.ivState);
|
||||
ivNotify = itemView.findViewById(R.id.ivNotify);
|
||||
|
@ -113,15 +122,25 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
ivSync = itemView.findViewById(R.id.ivSync);
|
||||
tvKeywords = itemView.findViewById(R.id.tvKeywords);
|
||||
tvError = itemView.findViewById(R.id.tvError);
|
||||
|
||||
rvChilds = itemView.findViewById(R.id.rvChilds);
|
||||
LinearLayoutManager llm = new LinearLayoutManager(context);
|
||||
rvChilds.setLayoutManager(llm);
|
||||
rvChilds.setNestedScrollingEnabled(false);
|
||||
|
||||
childs = new AdapterFolder(context, owner);
|
||||
rvChilds.setAdapter(childs);
|
||||
}
|
||||
|
||||
private void wire() {
|
||||
view.setOnClickListener(this);
|
||||
ivExpander.setOnClickListener(this);
|
||||
view.setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
private void unwire() {
|
||||
view.setOnClickListener(null);
|
||||
ivExpander.setOnClickListener(null);
|
||||
view.setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
|
@ -135,6 +154,10 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
vwColor.setBackgroundColor(folder.accountColor == null ? Color.TRANSPARENT : folder.accountColor);
|
||||
vwColor.setVisibility(account < 0 ? View.VISIBLE : View.GONE);
|
||||
|
||||
ivExpander.setImageResource(collapsed.contains(folder.id)
|
||||
? R.drawable.baseline_expand_more_24 : R.drawable.baseline_expand_less_24);
|
||||
ivExpander.setVisibility(folder.childs > 0 ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
if (account > 0) {
|
||||
ViewGroup.LayoutParams lp = vwLevel.getLayoutParams();
|
||||
lp.width = (EntityFolder.USER.equals(folder.type) ? folder.level : 0) * dp12;
|
||||
|
@ -231,6 +254,21 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
|
||||
tvError.setText(folder.error);
|
||||
tvError.setVisibility(folder.error != null ? View.VISIBLE : View.GONE);
|
||||
|
||||
rvChilds.setVisibility(collapsed.contains(folder.id) ? View.GONE : View.VISIBLE);
|
||||
|
||||
cowner.restart();
|
||||
if (folder.childs > 0) {
|
||||
DB db = DB.getInstance(context);
|
||||
cowner.start();
|
||||
db.folder().liveFolders(folder.account, folder.id).observe(cowner, new Observer<List<TupleFolderEx>>() {
|
||||
@Override
|
||||
public void onChanged(List<TupleFolderEx> folders) {
|
||||
childs.set(account, true, folders);
|
||||
}
|
||||
});
|
||||
} else
|
||||
childs.set(account, true, new ArrayList<TupleFolderEx>());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -243,11 +281,26 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
if (folder.tbd != null)
|
||||
return;
|
||||
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
|
||||
lbm.sendBroadcast(
|
||||
new Intent(ActivityView.ACTION_VIEW_MESSAGES)
|
||||
.putExtra("account", folder.account)
|
||||
.putExtra("folder", folder.id));
|
||||
if (view.getId() == R.id.ivExpander) {
|
||||
if (collapsed.contains(folder.id))
|
||||
collapsed.remove(folder.id);
|
||||
else
|
||||
collapsed.add(folder.id);
|
||||
|
||||
boolean expanded = !collapsed.contains(folder.id);
|
||||
Log.i("Expanded=" + expanded);
|
||||
|
||||
ivExpander.setImageResource(collapsed.contains(folder.id)
|
||||
? R.drawable.baseline_expand_more_24 : R.drawable.baseline_expand_less_24);
|
||||
rvChilds.setVisibility(collapsed.contains(folder.id) ? View.GONE : View.VISIBLE);
|
||||
//notifyItemChanged(pos);
|
||||
} else {
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context);
|
||||
lbm.sendBroadcast(
|
||||
new Intent(ActivityView.ACTION_VIEW_MESSAGES)
|
||||
.putExtra("account", folder.account)
|
||||
.putExtra("folder", folder.id));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -56,21 +56,27 @@ public interface DaoFolder {
|
|||
", COUNT(message.id) AS messages" +
|
||||
", SUM(CASE WHEN message.content = 1 THEN 1 ELSE 0 END) AS content" +
|
||||
", SUM(CASE WHEN message.ui_seen = 0 THEN 1 ELSE 0 END) AS unseen" +
|
||||
", (SELECT COUNT(child.id) FROM folder child WHERE child.parent = folder.id) AS childs" +
|
||||
" FROM folder" +
|
||||
" LEFT JOIN account ON account.id = folder.account" +
|
||||
" LEFT JOIN message ON message.folder = folder.id AND NOT message.ui_hide" +
|
||||
" WHERE CASE WHEN :account IS NULL" +
|
||||
" THEN folder.unified AND account.synchronize" +
|
||||
" ELSE (folder.account = :account AND account.synchronize) OR folder.account IS NULL" +
|
||||
" ELSE" +
|
||||
" (folder.account = :account" +
|
||||
" AND account.synchronize" +
|
||||
" AND CASE WHEN :parent IS NULL THEN folder.parent IS NULL ELSE folder.parent = :parent END)" +
|
||||
" OR (folder.account IS NULL AND :parent IS NULL)" +
|
||||
" END" +
|
||||
" GROUP BY folder.id")
|
||||
LiveData<List<TupleFolderEx>> liveFolders(Long account);
|
||||
LiveData<List<TupleFolderEx>> liveFolders(Long account, Long parent);
|
||||
|
||||
@Query("SELECT folder.*" +
|
||||
", account.name AS accountName, account.color AS accountColor, account.state AS accountState" +
|
||||
", COUNT(message.id) AS messages" +
|
||||
", SUM(CASE WHEN message.content = 1 THEN 1 ELSE 0 END) AS content" +
|
||||
", SUM(CASE WHEN message.ui_seen = 0 THEN 1 ELSE 0 END) AS unseen" +
|
||||
", (SELECT COUNT(child.id) FROM folder child WHERE child.parent = folder.id) AS childs" +
|
||||
" FROM folder" +
|
||||
" JOIN account ON account.id = folder.account" +
|
||||
" LEFT JOIN message ON message.folder = folder.id AND NOT message.ui_hide" +
|
||||
|
@ -91,6 +97,7 @@ public interface DaoFolder {
|
|||
", COUNT(message.id) AS messages" +
|
||||
", SUM(CASE WHEN message.content = 1 THEN 1 ELSE 0 END) AS content" +
|
||||
", SUM(CASE WHEN message.ui_seen = 0 THEN 1 ELSE 0 END) AS unseen" +
|
||||
", (SELECT COUNT(child.id) FROM folder child WHERE child.parent = folder.id) AS childs" +
|
||||
" FROM folder" +
|
||||
" LEFT JOIN account ON account.id = folder.account" +
|
||||
" LEFT JOIN message ON message.folder = folder.id AND NOT message.ui_hide" +
|
||||
|
|
|
@ -239,7 +239,7 @@ public class FragmentFolders extends FragmentBase {
|
|||
});
|
||||
|
||||
// Observe folders
|
||||
db.folder().liveFolders(account < 0 ? null : account).observe(getViewLifecycleOwner(), new Observer<List<TupleFolderEx>>() {
|
||||
db.folder().liveFolders(account < 0 ? null : account, null).observe(getViewLifecycleOwner(), new Observer<List<TupleFolderEx>>() {
|
||||
@Override
|
||||
public void onChanged(@Nullable List<TupleFolderEx> folders) {
|
||||
if (folders == null) {
|
||||
|
|
|
@ -28,6 +28,7 @@ public class TupleFolderEx extends EntityFolder {
|
|||
public int messages;
|
||||
public int content;
|
||||
public int unseen;
|
||||
public int childs;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
@ -39,7 +40,8 @@ public class TupleFolderEx extends EntityFolder {
|
|||
Objects.equals(this.accountState, other.accountState) &&
|
||||
this.messages == other.messages &&
|
||||
this.content == other.content &&
|
||||
this.unseen == other.unseen);
|
||||
this.unseen == other.unseen &&
|
||||
this.childs == other.childs);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,20 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivExpander"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:src="@drawable/baseline_expand_less_24"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@+id/vSeparator"
|
||||
app:layout_constraintStart_toEndOf="@+id/vwColor"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivState"
|
||||
android:layout_width="24dp"
|
||||
|
@ -28,7 +42,7 @@
|
|||
android:layout_marginEnd="6dp"
|
||||
android:src="@drawable/baseline_cloud_off_24"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tvName"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintStart_toEndOf="@id/ivExpander"
|
||||
app:layout_constraintTop_toTopOf="@+id/tvName" />
|
||||
|
||||
<ImageView
|
||||
|
@ -38,7 +52,7 @@
|
|||
android:layout_marginStart="12dp"
|
||||
android:src="@drawable/baseline_folder_special_24"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/tvType"
|
||||
app:layout_constraintStart_toEndOf="@id/vwColor"
|
||||
app:layout_constraintStart_toEndOf="@id/ivExpander"
|
||||
app:layout_constraintTop_toTopOf="@+id/tvType" />
|
||||
|
||||
<View
|
||||
|
@ -162,7 +176,7 @@
|
|||
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/tvKeywords" />
|
||||
|
||||
<View
|
||||
|
@ -173,5 +187,13 @@
|
|||
android:background="?attr/colorSeparator"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvError" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rvChilds"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/vSeparator" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
Loading…
Reference in New Issue