Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2024-01-18 15:30:06 +0300
committerStefan Niedermann <info@niedermann.it>2024-01-18 15:30:06 +0300
commiteea21c772af0b525674837ff3aa3d1e6ec9d380b (patch)
tree641142c8920e5dc8ba3ef06ecd8518be47d53e2f /app/src
parent55abed7577387ba3b2167238882e81b80ce4cba5 (diff)
feat(done): Allow filtering for (un)done cards
Refs: #1556 https://github.com/nextcloud/deck/issues/5406 Signed-off-by: Stefan Niedermann <info@niedermann.it>
Diffstat (limited to 'app/src')
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/database/DataBaseAdapter.java27
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/enums/EDoneType.java40
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/internal/FilterInformation.java15
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java7
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeAdapter.java96
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeFragment.java47
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java7
-rw-r--r--app/src/main/res/layout/dialog_filter.xml2
-rw-r--r--app/src/main/res/layout/dialog_filter_done.xml10
-rw-r--r--app/src/main/res/layout/item_filter_donetype.xml29
-rw-r--r--app/src/main/res/values/strings.xml5
12 files changed, 279 insertions, 8 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/database/DataBaseAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/database/DataBaseAdapter.java
index 5d3b28950..a7cd3a2af 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/database/DataBaseAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/database/DataBaseAdapter.java
@@ -60,6 +60,7 @@ import it.niedermann.nextcloud.deck.model.Stack;
import it.niedermann.nextcloud.deck.model.User;
import it.niedermann.nextcloud.deck.model.appwidgets.StackWidgetModel;
import it.niedermann.nextcloud.deck.model.enums.DBStatus;
+import it.niedermann.nextcloud.deck.model.enums.EDoneType;
import it.niedermann.nextcloud.deck.model.enums.EDueType;
import it.niedermann.nextcloud.deck.model.full.FullBoard;
import it.niedermann.nextcloud.deck.model.full.FullCard;
@@ -259,9 +260,9 @@ public class DataBaseAdapter {
public LiveData<List<FullCard>> getFullCardsForStack(long accountId, long localStackId, @Nullable FilterInformation filter) {
return new ReactiveLiveData<>(
- filter == null
- ? db.getCardDao().getFullCardsForStack(accountId, localStackId)
- : db.getCardDao().getFilteredFullCardsForStack(getQueryForFilter(filter, accountId, localStackId)))
+ FilterInformation.hasActiveFilter(filter)
+ ? db.getCardDao().getFilteredFullCardsForStack(getQueryForFilter(filter, accountId, localStackId))
+ : db.getCardDao().getFullCardsForStack(accountId, localStackId))
.tap(this::filterRelationsForCard, executor)
.distinctUntilChanged();
@@ -284,9 +285,9 @@ public class DataBaseAdapter {
@WorkerThread
public List<FullCard> getFullCardsForStackDirectly(long accountId, long localStackId, @Nullable FilterInformation filter) {
- return filter == null
- ? db.getCardDao().getFullCardsForStackDirectly(accountId, localStackId)
- : db.getCardDao().getFilteredFullCardsForStackDirectly(getQueryForFilter(filter, accountId, localStackId));
+ return FilterInformation.hasActiveFilter(filter)
+ ? db.getCardDao().getFilteredFullCardsForStackDirectly(getQueryForFilter(filter, accountId, localStackId))
+ : db.getCardDao().getFullCardsForStackDirectly(accountId, localStackId);
}
@AnyThread
@@ -369,6 +370,20 @@ public class DataBaseAdapter {
throw new IllegalArgumentException("You need to add your new EDueType value\"" + filter.getDueType() + "\" here!");
}
}
+
+ if (filter.getDoneType() != EDoneType.NO_FILTER) {
+ switch (filter.getDoneType()) {
+ case DONE:
+ query.append("and (c.done is not null and c.done != 0)");
+ break;
+ case UNDONE:
+ query.append("and (c.done is null or c.done = 0)");
+ break;
+ default:
+ throw new IllegalArgumentException("You need to add your new EDueType value\"" + filter.getDueType() + "\" here!");
+ }
+ }
+
if (!TextUtils.isEmpty(filter.getFilterText())) {
query.append(" and (c.description like ? or c.title like ?) ");
String filterText = "%" + filter.getFilterText() + "%";
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/enums/EDoneType.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/enums/EDoneType.java
new file mode 100644
index 000000000..4222ee487
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/enums/EDoneType.java
@@ -0,0 +1,40 @@
+package it.niedermann.nextcloud.deck.model.enums;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+import it.niedermann.nextcloud.deck.R;
+
+public enum EDoneType {
+ NO_FILTER(1, R.string.filter_done_no_filter),
+ DONE(2, R.string.filter_done_done),
+ UNDONE(3, R.string.filter_done_undone);
+
+ private final int value;
+ private final int id;
+
+ EDoneType(int id, @StringRes int value) {
+ this.value = value;
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public static EDoneType findById(int id) {
+ for (EDoneType s : EDoneType.values()) {
+ if (s.getId() == id) {
+ return s;
+ }
+ }
+ throw new IllegalArgumentException("unknown " + EDoneType.class.getSimpleName() + " key: " + id);
+ }
+
+ @NonNull
+ public String toString(Context context) {
+ return context.getString(this.value);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/internal/FilterInformation.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/internal/FilterInformation.java
index da0501779..8c7da2b24 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/internal/FilterInformation.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/internal/FilterInformation.java
@@ -9,6 +9,7 @@ import java.util.List;
import it.niedermann.nextcloud.deck.model.Label;
import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.model.enums.EDoneType;
import it.niedermann.nextcloud.deck.model.enums.EDueType;
import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProject;
@@ -20,6 +21,8 @@ public class FilterInformation implements Serializable {
@NonNull
private EDueType dueType = EDueType.NO_FILTER;
+ @NonNull
+ private EDoneType doneType = EDoneType.NO_FILTER;
private boolean noAssignedLabel = false;
private boolean noAssignedUser = false;
private boolean noAssignedProject = false;
@@ -41,6 +44,7 @@ public class FilterInformation implements Serializable {
public FilterInformation(@Nullable FilterInformation filterInformation) {
if (filterInformation != null) {
this.dueType = filterInformation.getDueType();
+ this.doneType = filterInformation.getDoneType();
this.archiveStatus = filterInformation.getArchiveStatus();
this.users.addAll(filterInformation.getUsers());
this.labels.addAll(filterInformation.getLabels());
@@ -72,6 +76,15 @@ public class FilterInformation implements Serializable {
}
@NonNull
+ public EDoneType getDoneType() {
+ return doneType;
+ }
+
+ public void setDoneType(@NonNull EDoneType doneType) {
+ this.doneType = doneType;
+ }
+
+ @NonNull
public List<User> getUsers() {
return users;
}
@@ -152,6 +165,7 @@ public class FilterInformation implements Serializable {
public String toString() {
return "FilterInformation{" +
"dueType=" + dueType +
+ ", doneType=" + doneType +
", noAssignedLabel=" + noAssignedLabel +
", noAssignedUser=" + noAssignedUser +
", users=" + users +
@@ -169,6 +183,7 @@ public class FilterInformation implements Serializable {
return false;
}
return !(filterInformation.getDueType() == EDueType.NO_FILTER
+ && filterInformation.getDoneType() == EDoneType.NO_FILTER
&& filterInformation.getUsers().isEmpty()
&& filterInformation.getProjects().isEmpty()
&& filterInformation.getLabels().isEmpty()
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java
index 7a6aba31d..807130a0d 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/ocs/Version.java
@@ -182,7 +182,7 @@ public class Version implements Comparable<Version> {
* @see <a href="https://github.com/nextcloud/deck/issues/534">Deck server issue #534</a>
*/
public boolean supportsDone() {
- return isGreaterOrEqualTo(VERSION_1_12_2);
+ return isGreaterOrEqualTo(VERSION_1_12_0);
}
/**
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java
index 8eac0dbb4..65c7f824e 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDialogFragment.java
@@ -19,6 +19,7 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.DialogFilterBinding;
+import it.niedermann.nextcloud.deck.model.enums.EDoneType;
import it.niedermann.nextcloud.deck.model.enums.EDueType;
import it.niedermann.nextcloud.deck.ui.theme.ThemeUtils;
import it.niedermann.nextcloud.deck.ui.theme.ThemedDialogFragment;
@@ -32,6 +33,7 @@ public class FilterDialogFragment extends ThemedDialogFragment {
private final static int[] tabTitles = new int[]{
R.string.filter_tags_title,
R.string.filter_user_title,
+ R.string.filter_done_title,
R.string.filter_duedate_title
};
@@ -63,6 +65,9 @@ public class FilterDialogFragment extends ThemedDialogFragment {
tab.setIcon(draft.getUsers().size() > 0 || draft.isNoAssignedUser() ? indicator : null);
break;
case 2:
+ tab.setIcon(draft.getDoneType() != EDoneType.NO_FILTER ? indicator : null);
+ break;
+ case 3:
tab.setIcon(draft.getDueType() != EDueType.NO_FILTER ? indicator : null);
break;
default:
@@ -124,6 +129,8 @@ public class FilterDialogFragment extends ThemedDialogFragment {
case 1:
return new FilterUserFragment();
case 2:
+ return new FilterDoneTypeFragment();
+ case 3:
return new FilterDueTypeFragment();
default:
throw new IllegalArgumentException("position must be between 0 and 2 but was " + position);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeAdapter.java
new file mode 100644
index 000000000..d194f78ab
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeAdapter.java
@@ -0,0 +1,96 @@
+package it.niedermann.nextcloud.deck.ui.filter;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.Arrays;
+
+import it.niedermann.nextcloud.deck.databinding.ItemFilterDonetypeBinding;
+import it.niedermann.nextcloud.deck.model.enums.EDoneType;
+import it.niedermann.nextcloud.deck.ui.theme.ThemeUtils;
+import it.niedermann.nextcloud.deck.ui.theme.Themed;
+
+public class FilterDoneTypeAdapter extends RecyclerView.Adapter<FilterDoneTypeAdapter.DoneTypeViewHolder> {
+ @NonNull
+ private final EDoneType[] doneTypes = EDoneType.values();
+ private int selectedDoneTypePosition;
+ @Nullable
+ private final SelectionListener<EDoneType> selectionListener;
+ @ColorInt
+ private final int color;
+
+ @SuppressWarnings("WeakerAccess")
+ public FilterDoneTypeAdapter(@NonNull EDoneType selectedDoneType, @Nullable SelectionListener<EDoneType> selectionListener, @ColorInt int color) {
+ super();
+ this.selectedDoneTypePosition = Arrays.binarySearch(doneTypes, selectedDoneType);
+ this.selectionListener = selectionListener;
+ this.color = color;
+ setHasStableIds(true);
+ }
+
+ @NonNull
+ @Override
+ public DoneTypeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new DoneTypeViewHolder(ItemFilterDonetypeBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull DoneTypeViewHolder viewHolder, int position) {
+ viewHolder.bind(doneTypes[position]);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemCount() {
+ return doneTypes.length;
+ }
+
+ class DoneTypeViewHolder extends RecyclerView.ViewHolder implements Themed {
+ private final ItemFilterDonetypeBinding binding;
+
+ DoneTypeViewHolder(@NonNull ItemFilterDonetypeBinding binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+
+ void bind(final EDoneType doneType) {
+ binding.doneType.setText(doneType.toString(binding.doneType.getContext()));
+ itemView.setSelected(doneTypes[selectedDoneTypePosition].equals(doneType));
+ applyTheme(color);
+
+ itemView.setOnClickListener(view -> {
+ final int oldSelection = selectedDoneTypePosition;
+ if (doneTypes[selectedDoneTypePosition].equals(doneType)) {
+ selectedDoneTypePosition = Arrays.binarySearch(doneTypes, EDoneType.NO_FILTER);
+ itemView.setSelected(false);
+ if (selectionListener != null) {
+ selectionListener.onItemSelected(EDoneType.NO_FILTER);
+ }
+ notifyItemChanged(selectedDoneTypePosition);
+ } else {
+ selectedDoneTypePosition = Arrays.binarySearch(doneTypes, doneType);
+ itemView.setSelected(true);
+ if (selectionListener != null) {
+ selectionListener.onItemSelected(doneType);
+ }
+ }
+ notifyItemChanged(oldSelection);
+ });
+ }
+
+ @Override
+ public void applyTheme(int color) {
+ final var utils = ThemeUtils.of(color, itemView.getContext());
+ utils.deck.themeSelectedCheck(binding.selectedCheck.getContext(), binding.selectedCheck.getDrawable());
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeFragment.java
new file mode 100644
index 000000000..8cee39d1e
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterDoneTypeFragment.java
@@ -0,0 +1,47 @@
+package it.niedermann.nextcloud.deck.ui.filter;
+
+import static java.util.Objects.requireNonNull;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+
+import it.niedermann.nextcloud.deck.databinding.DialogFilterDoneBinding;
+import it.niedermann.nextcloud.deck.model.enums.EDoneType;
+
+public class FilterDoneTypeFragment extends Fragment implements SelectionListener<EDoneType> {
+
+ private FilterViewModel filterViewModel;
+ private DialogFilterDoneBinding binding;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ binding = DialogFilterDoneBinding.inflate(requireActivity().getLayoutInflater());
+
+ filterViewModel = new ViewModelProvider(requireActivity()).get(FilterViewModel.class);
+
+ binding.doneType.setItemAnimator(null);
+ filterViewModel.getCurrentBoardColor$().observe(getViewLifecycleOwner(),
+ color -> binding.doneType.setAdapter(new FilterDoneTypeAdapter(requireNonNull(filterViewModel.getFilterInformationDraft().getValue()).getDoneType(), this, color)));
+
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ this.binding = null;
+ }
+
+ @Override
+ public void onItemSelected(EDoneType item) {
+ filterViewModel.setFilterInformationDraftDoneType(item);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java
index 09f2f4fa1..5bd226e9f 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/filter/FilterViewModel.java
@@ -15,6 +15,7 @@ import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.model.Label;
import it.niedermann.nextcloud.deck.model.User;
+import it.niedermann.nextcloud.deck.model.enums.EDoneType;
import it.niedermann.nextcloud.deck.model.enums.EDueType;
import it.niedermann.nextcloud.deck.model.internal.FilterInformation;
import it.niedermann.nextcloud.deck.ui.viewmodel.BaseViewModel;
@@ -80,6 +81,12 @@ public class FilterViewModel extends BaseViewModel {
this.filterInformationDraft.postValue(newDraft);
}
+ public void setFilterInformationDraftDoneType(@NonNull EDoneType doneType) {
+ final var newDraft = new FilterInformation(filterInformationDraft.getValue());
+ newDraft.setDoneType(doneType);
+ this.filterInformationDraft.postValue(newDraft);
+ }
+
public void addFilterInformationDraftLabel(@NonNull Label label) {
final var newDraft = new FilterInformation(filterInformationDraft.getValue());
newDraft.addLabel(label);
diff --git a/app/src/main/res/layout/dialog_filter.xml b/app/src/main/res/layout/dialog_filter.xml
index b95c2b0c8..2b1e3499c 100644
--- a/app/src/main/res/layout/dialog_filter.xml
+++ b/app/src/main/res/layout/dialog_filter.xml
@@ -11,7 +11,7 @@
android:layout_height="wrap_content"
android:background="@null"
app:tabInlineLabel="true"
- app:tabMode="fixed"
+ app:tabMode="auto"
app:tabUnboundedRipple="true" />
<androidx.viewpager2.widget.ViewPager2
diff --git a/app/src/main/res/layout/dialog_filter_done.xml b/app/src/main/res/layout/dialog_filter_done.xml
new file mode 100644
index 000000000..5cf3fedb0
--- /dev/null
+++ b/app/src/main/res/layout/dialog_filter_done.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/doneType"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="?attr/dialogPreferredPadding"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:listitem="@layout/item_filter_duetype" /> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_filter_donetype.xml b/app/src/main/res/layout/item_filter_donetype.xml
new file mode 100644
index 000000000..9cf823c77
--- /dev/null
+++ b/app/src/main/res/layout/item_filter_donetype.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.google.android.flexbox.FlexboxLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/doneType"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="middle"
+ android:padding="@dimen/spacer_2x"
+ android:textAppearance="?attr/textAppearanceListItem"
+ tools:text="@tools:sample/lorem" />
+
+ <androidx.appcompat.widget.AppCompatImageView
+ android:id="@+id/selected_check"
+ android:layout_width="22dp"
+ android:layout_height="22dp"
+ android:layout_marginStart="@dimen/spacer_1x"
+ app:layout_alignSelf="center"
+ app:layout_flexShrink="0"
+ app:srcCompat="@drawable/selected_check"
+ tools:src="@drawable/ic_check_grey600_24dp" />
+
+</com.google.android.flexbox.FlexboxLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ec1b84a5d..dabf27783 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -197,6 +197,10 @@
<string name="filter_no_due">No due date</string>
<string name="filter_later">Later</string>
+ <string name="filter_done_no_filter">All</string>
+ <string name="filter_done_done">Completed</string>
+ <string name="filter_done_undone">Uncompleted</string>
+
<string name="archived_cards">Archived cards</string>
<string name="attachment_already_exists">Attachment already exists</string>
<string name="pick_custom_color">Pick custom color</string>
@@ -208,6 +212,7 @@
<string name="filter_tags_title">Tags</string>
<string name="filter_user_title">Users</string>
<string name="filter_duedate_title">Due date</string>
+ <string name="filter_done_title">Completed</string>
<string name="action_board_dearchive">Undo board archiving</string>
<string name="archived_boards">Archived boards</string>