Collapsable folders

This commit is contained in:
M66B 2019-03-17 21:23:55 +00:00
parent dd025b1ff3
commit 525ed9b50c
5 changed files with 96 additions and 12 deletions

View File

@ -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

View File

@ -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" +

View File

@ -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) {

View File

@ -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;
}

View File

@ -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>