Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hierarchical checklists #1058

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ public final class DescriptionItem
public boolean checkbox;
public boolean checked;
public String text;
public int level;


public DescriptionItem(boolean checkbox, boolean checked, String text)
public DescriptionItem(boolean checkbox, boolean checked, String text, int level)
{
this.checkbox = checkbox;
this.checked = checked;
this.text = text;
this.level = level;
}


Expand All @@ -43,13 +45,14 @@ public boolean equals(@Nullable Object obj)
return obj instanceof DescriptionItem
&& ((DescriptionItem) obj).checkbox == checkbox
&& ((DescriptionItem) obj).checked == checked
&& ((DescriptionItem) obj).text.equals(text);
&& ((DescriptionItem) obj).text.equals(text)
&& ((DescriptionItem) obj).level == level;
}


@Override
public int hashCode()
{
return text.hashCode() * 31 + (checkbox ? 1 : 0) + (checked ? 2 : 0);
return text.hashCode() * 31 + (checkbox ? 1 : 0) + (checked ? 2 : 0) + level * 17;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
*/
public final class DescriptionFieldAdapter extends FieldAdapter<List<DescriptionItem>>
{
private final static Pattern CHECKMARK_PATTERN = Pattern.compile("([-*] )?\\[([xX ])\\](.*)");
private final static Pattern CHECKMARK_PATTERN = Pattern.compile("(\\s*)([-*] )?\\[([xX ])\\](.*)");

/**
* The field name this adapter uses to store the values.
Expand Down Expand Up @@ -169,6 +169,7 @@ private static List<DescriptionItem> parseDescription(String description)
StringBuilder currentParagraph = new StringBuilder();
boolean currentHasCheckedMark = false;
boolean currentIsChecked = false;
int currentLevel = 0;
for (String line : description.split("\n"))
{
matcher.reset(line);
Expand All @@ -179,12 +180,13 @@ private static List<DescriptionItem> parseDescription(String description)
if (currentParagraph.length() > 0)
{
result.add(new DescriptionItem(currentHasCheckedMark, currentIsChecked,
currentHasCheckedMark ? currentParagraph.toString().trim() : currentParagraph.toString()));
currentHasCheckedMark ? currentParagraph.toString().trim() : currentParagraph.toString(), currentLevel));
}
currentHasCheckedMark = true;
currentIsChecked = "x".equals(matcher.group(2).toLowerCase());
currentIsChecked = "x".equals(matcher.group(3).toLowerCase());
currentParagraph.setLength(0);
currentParagraph.append(matcher.group(3));
currentParagraph.append(matcher.group(4));
currentLevel = (matcher.group(1).length() + 1) / 2; //FIXME: Make the levels not static
}
else
{
Expand All @@ -194,7 +196,7 @@ private static List<DescriptionItem> parseDescription(String description)
if (currentParagraph.length() > 0)
{
// close last paragraph
result.add(new DescriptionItem(currentHasCheckedMark, currentIsChecked, currentParagraph.toString().trim()));
result.add(new DescriptionItem(currentHasCheckedMark, currentIsChecked, currentParagraph.toString().trim(), currentLevel));
}
currentHasCheckedMark = false;
currentParagraph.setLength(0);
Expand All @@ -211,7 +213,7 @@ private static List<DescriptionItem> parseDescription(String description)
if (currentHasCheckedMark || currentParagraph.length() > 0)
{
result.add(new DescriptionItem(currentHasCheckedMark, currentIsChecked,
currentHasCheckedMark ? currentParagraph.toString().trim() : currentParagraph.toString()));
currentHasCheckedMark ? currentParagraph.toString().trim() : currentParagraph.toString(), currentLevel));
}
return result;
}
Expand All @@ -235,6 +237,10 @@ private static void serializeDescription(StringBuilder sb, List<DescriptionItem>
{
sb.append('\n');
}
for (int i = 0; i < item.level; i++)
{
sb.append(" ");
}
if (item.checkbox)
{
sb.append(item.checked ? "- [x] " : "- [ ] ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@

import java.util.List;

import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.view.ViewCompat;

import static org.dmfs.jems.optional.elementary.Absent.absent;
Expand Down Expand Up @@ -194,6 +195,7 @@ private void updateCheckList(List<DescriptionItem> list)
if (itemView == null || itemView.getId() != R.id.checklist_element)
{
itemView = createItemView();

mContainer.addDragView(itemView, itemView.findViewById(R.id.drag_handle), mContainer.getChildCount() - 1);
}

Expand Down Expand Up @@ -249,9 +251,28 @@ private View createItemView()

private void bindItemView(final View itemView, final DescriptionItem item)
{
// set the left indend button listener
AppCompatImageView indend_left = itemView.findViewById(R.id.indend_left);
indend_left.setOnClickListener((view -> {
if (item.level > 0) {
item.level -= 1;
bindItemView(itemView, item);
}
}));
AppCompatImageView indend_right = itemView.findViewById(R.id.indend_right);
indend_right.setOnClickListener((view -> {
item.level += 1;
bindItemView(itemView, item);
}));

// set the checkbox status
CheckBox checkbox = itemView.findViewById(android.R.id.checkbox);

// set the left margin for hierarchical lists
MarginLayoutParams lp = (MarginLayoutParams) checkbox.getLayoutParams();
lp.leftMargin = checkbox.getPaddingLeft() * 10 * item.level;
checkbox.setLayoutParams(lp);

// make sure we don't receive our own updates
checkbox.setOnCheckedChangeListener(null);
checkbox.setChecked(item.checked && item.checkbox);
Expand Down Expand Up @@ -463,7 +484,7 @@ private void insertItem(boolean withCheckBox, int pos, String initialText)
mContainer.clearFocus();

// create a new empty item
DescriptionItem item = new DescriptionItem(withCheckBox, false, initialText);
DescriptionItem item = new DescriptionItem(withCheckBox, false, initialText, 0);
mCurrentValue.add(pos, item);
View newItem = createItemView();
bindItemView(newItem, item);
Expand Down Expand Up @@ -529,7 +550,7 @@ private void setupActionView(DescriptionItem item)

if (lines.length == 1)
{
DescriptionItem newItem = new DescriptionItem(true, item.checked, item.text);
DescriptionItem newItem = new DescriptionItem(true, item.checked, item.text, 0);
mCurrentValue.add(idx, newItem);
new Animated(mContainer.getChildAt(origidx), v -> (ViewGroup) v).process(v -> bindItemView(v, newItem));
setupActionView(newItem);
Expand All @@ -538,7 +559,7 @@ private void setupActionView(DescriptionItem item)
{
for (String i : lines)
{
DescriptionItem newItem = new DescriptionItem(true, false, i);
DescriptionItem newItem = new DescriptionItem(true, false, i, 0);
mCurrentValue.add(idx, newItem);
if (idx == origidx)
{
Expand All @@ -557,7 +578,7 @@ private void setupActionView(DescriptionItem item)
}
else
{
DescriptionItem newItem = new DescriptionItem(false, item.checked, item.text);
DescriptionItem newItem = new DescriptionItem(false, item.checked, item.text, item.level);
mCurrentValue.add(idx, newItem);
if (idx == 0 || mCurrentValue.get(idx - 1).checkbox)
{
Expand Down
4 changes: 4 additions & 0 deletions opentasks/src/main/res/drawable/ic_left_arrow.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="558.957"
android:viewportWidth="558.957" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M462.745,0l-366.533,279.479l366.533,279.478l0,-139.736l-184.032,-139.742l184.032,-139.741z"/>
</vector>
4 changes: 4 additions & 0 deletions opentasks/src/main/res/drawable/ic_right_arrow.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="558.957"
android:viewportWidth="558.957" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M462.745,279.479l-366.533,279.478l-0,-139.736l184.032,-139.742l-184.032,-139.741l-0,-139.738z"/>
</vector>
51 changes: 27 additions & 24 deletions opentasks/src/main/res/layout/description_field_view_element.xml
Original file line number Diff line number Diff line change
@@ -1,38 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/checklist_element"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="-4dp"
android:layout_marginLeft="-4dp"
android:clipToPadding="false"
android:clipChildren="false"
android:animateLayoutChanges="true">
android:animateLayoutChanges="true"
android:orientation="horizontal">


<androidx.appcompat.widget.AppCompatCheckBox
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:background="@android:color/transparent"
android:padding="4dp" />

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/drag_handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:padding="4dp"
android:src="@drawable/ic_drag_indicator_24px" />
android:padding="4dp"/>

<androidx.appcompat.widget.AppCompatEditText
android:id="@android:id/title"
android:layout_width="0dp"
android:layout_weight="0.7"
android:layout_height="wrap_content"
android:layout_alignWithParentIfMissing="true"
android:layout_toStartOf="@id/drag_handle"
android:layout_toEndOf="@android:id/checkbox"
android:focusable="true"
android:focusableInTouchMode="true"
android:hint="@string/opentasks_checklist_empty_item_hint"
Expand All @@ -42,13 +32,26 @@
android:paddingBottom="8dp"
android:scrollHorizontally="false"
android:singleLine="false"
android:textSize="16sp" />
android:textSize="16sp"/>

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/indend_left"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:padding="4dp"
android:src="@drawable/ic_left_arrow"/>

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/indend_right"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:padding="4dp"
android:src="@drawable/ic_right_arrow"/>

<FrameLayout
android:id="@+id/action_bar"
android:layout_width="match_parent"
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/drag_handle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
android:padding="4dp"
android:src="@drawable/ic_drag_indicator_24px"/>
</LinearLayout>