diff --git a/collect_app/src/main/AndroidManifest.xml b/collect_app/src/main/AndroidManifest.xml
index ae95c4ed85b..2820c39836a 100644
--- a/collect_app/src/main/AndroidManifest.xml
+++ b/collect_app/src/main/AndroidManifest.xml
@@ -195,8 +195,8 @@ the specific language governing permissions and limitations under the License.
-
-
+
+
children = element.getChildren();
- for (int i = 0; i < children.size(); i++) {
- formList.remove(position + 1);
- }
- element.setIcon(ContextCompat.getDrawable(this, R.drawable.expander_ic_minimized));
- break;
- case COLLAPSED:
- element.setType(EXPANDED);
- ArrayList children1 = element.getChildren();
- for (int i = 0; i < children1.size(); i++) {
- Timber.i("adding child: %s", children1.get(i).getFormIndex());
- formList.add(position + 1 + i, children1.get(i));
-
- }
- element.setIcon(ContextCompat.getDrawable(this, R.drawable.expander_ic_maximized));
- break;
- case QUESTION:
- Collect.getInstance().getFormController().jumpToIndex(index);
- if (Collect.getInstance().getFormController().indexIsInFieldList()) {
- try {
- Collect.getInstance().getFormController().stepToPreviousScreenEvent();
- } catch (JavaRosaException e) {
- Timber.d(e);
- createErrorDialog(e.getCause().getMessage());
- return;
- }
- }
- setResult(RESULT_OK);
- finish();
- return;
- case CHILD:
- Collect.getInstance().getFormController().jumpToIndex(element.getFormIndex());
- setResult(RESULT_OK);
- refreshView();
- return;
- }
-
- recyclerView.setAdapter(new HierarchyListAdapter(formList, this::onElementClick));
- ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_BACK:
- FormController fc = Collect.getInstance().getFormController();
- if (fc != null) {
- fc.getTimerLogger().exitView();
- fc.jumpToIndex(startIndex);
- }
- }
- return super.onKeyDown(keyCode, event);
- }
-}
diff --git a/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java b/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java
index 6473d719e24..9def827e828 100644
--- a/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java
+++ b/collect_app/src/main/java/org/odk/collect/android/activities/FormEntryActivity.java
@@ -987,7 +987,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
0, null, false, true);
}
- Intent i = new Intent(this, EditFormHierarchyActivity.class);
+ Intent i = new Intent(this, FormHierarchyActivity.class);
startActivityForResult(i, RequestCodes.HIERARCHY_ACTIVITY);
return true;
case R.id.menu_preferences:
@@ -2377,11 +2377,11 @@ public void denied() {
if (formMode == null || ApplicationConstants.FormModes.EDIT_SAVED.equalsIgnoreCase(formMode)) {
formController.getTimerLogger().logTimerEvent(TimerLogger.EventTypes.FORM_RESUME, 0, null, false, true);
formController.getTimerLogger().logTimerEvent(TimerLogger.EventTypes.HIERARCHY, 0, null, false, true);
- startActivity(new Intent(this, EditFormHierarchyActivity.class));
+ startActivity(new Intent(this, FormHierarchyActivity.class));
return; // so we don't show the intro screen before jumping to the hierarchy
} else {
if (ApplicationConstants.FormModes.VIEW_SENT.equalsIgnoreCase(formMode)) {
- startActivity(new Intent(this, ViewFormHierarchyActivity.class));
+ startActivity(new Intent(this, ViewOnlyFormHierarchyActivity.class));
}
finish();
}
diff --git a/collect_app/src/main/java/org/odk/collect/android/activities/FormHierarchyActivity.java b/collect_app/src/main/java/org/odk/collect/android/activities/FormHierarchyActivity.java
index a3481bf4afb..2cb95a3f750 100644
--- a/collect_app/src/main/java/org/odk/collect/android/activities/FormHierarchyActivity.java
+++ b/collect_app/src/main/java/org/odk/collect/android/activities/FormHierarchyActivity.java
@@ -23,7 +23,6 @@
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
-import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
@@ -35,6 +34,7 @@
import org.odk.collect.android.R;
import org.odk.collect.android.adapters.HierarchyListAdapter;
import org.odk.collect.android.application.Collect;
+import org.odk.collect.android.exception.JavaRosaException;
import org.odk.collect.android.logic.FormController;
import org.odk.collect.android.logic.HierarchyElement;
import org.odk.collect.android.utilities.FormEntryPromptUtils;
@@ -45,18 +45,54 @@
import timber.log.Timber;
-public abstract class FormHierarchyActivity extends CollectAbstractActivity {
+/**
+ * Displays the structure of a form along with the answers for the current instance. Different form
+ * elements are displayed in the following ways:
+ * - Questions each take up a row with their full label shown and their answers below
+ * - Non-repeat groups are not represented at all
+ * - Repeat groups are initially shown as collapsed and are expanded when tapped, revealing instances
+ * of that repeat
+ * - Repeat instances are displayed with their label and a count after (e.g. My group (1))
+ *
+ * Tapping on a repeat instance shows all the questions in that repeat instance using the display
+ * rules above.
+ *
+ * Tapping on a question sets the app-wide current question to that question and terminates the
+ * activity, returning to {@link FormEntryActivity}.
+ *
+ * Although the user gets the impression of navigating "into" a repeat, the view is refreshed in
+ * {@link #refreshView()} rather than another activity/fragment being added to the backstack.
+ *
+ * Buttons at the bottom of the screen allow users to navigate the form.
+ */
+public class FormHierarchyActivity extends CollectAbstractActivity {
+ /**
+ * The questions and repeats at the current level. If a repeat is expanded, also includes the
+ * instances of that repeat. Recreated every time {@link #refreshView()} is called. Modified
+ * by the expand/collapse behavior in {@link #onElementClick(HierarchyElement)}.
+ */
+ private List elementsToDisplay;
- protected static final int CHILD = 1;
- protected static final int EXPANDED = 2;
- protected static final int COLLAPSED = 3;
- protected static final int QUESTION = 4;
+ /**
+ * The label shown at the top of a hierarchy screen for a repeat instance. Set by
+ * {@link #getCurrentPath()}.
+ */
+ private TextView groupPathTextView;
- List formList;
- TextView path;
+ /**
+ * The index of the question or the field list the FormController was set to when the hierarchy
+ * was accessed. Used to jump the user back to where they were if applicable.
+ */
+ private FormIndex startIndex;
- FormIndex startIndex;
+ /**
+ * The index of the question that is being displayed in the hierarchy. On first launch, it is
+ * the same as {@link #startIndex}. It can then become the index of a repeat instance.
+ * TODO: Is keeping this as a field necessary? I believe what it is used for is to send the user
+ * to edit a question that caused an error in the hierarchy.
+ */
private FormIndex currentIndex;
+
protected Button jumpPreviousButton;
protected Button jumpBeginningButton;
protected Button jumpEndButton;
@@ -84,59 +120,32 @@ public void onCreate(Bundle savedInstanceState) {
return;
}
- // We use a static FormEntryController to make jumping faster.
startIndex = formController.getFormIndex();
setTitle(formController.getFormTitle());
- path = findViewById(R.id.pathtext);
+ groupPathTextView = findViewById(R.id.pathtext);
jumpPreviousButton = findViewById(R.id.jumpPreviousButton);
- jumpPreviousButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- goUpLevel();
- }
- });
-
jumpBeginningButton = findViewById(R.id.jumpBeginningButton);
- jumpBeginningButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- FormController fc = Collect.getInstance().getFormController();
- if (fc != null) {
- fc.getTimerLogger().exitView();
- fc.jumpToIndex(FormIndex.createBeginningOfFormIndex());
- }
- setResult(RESULT_OK);
- finish();
- }
- });
-
jumpEndButton = findViewById(R.id.jumpEndButton);
- jumpEndButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- FormController fc = Collect.getInstance().getFormController();
- if (fc != null) {
- fc.getTimerLogger().exitView();
- fc.jumpToIndex(FormIndex.createEndOfFormIndex());
- }
- setResult(RESULT_OK);
- finish();
- }
- });
+ configureButtons(formController);
refreshView();
- // Kinda slow, but works. This scrolls to the last question the user was looking at.
+ // Scroll to the last question the user was looking at
+ // TODO: avoid another iteration through all displayed elements
if (recyclerView != null && recyclerView.getAdapter() != null && recyclerView.getAdapter().getItemCount() > 0) {
emptyView.setVisibility(View.GONE);
recyclerView.post(() -> {
int position = 0;
- for (HierarchyElement hierarchyElement : formList) {
- if (shouldScrollToTheGivenIndex(hierarchyElement.getFormIndex(), formController)) {
- position = formList.indexOf(hierarchyElement);
+ // Iterate over all the elements currently displayed looking for a match with the
+ // startIndex which can either represent a question or a field list.
+ for (HierarchyElement hierarchyElement : elementsToDisplay) {
+ FormIndex indexToCheck = hierarchyElement.getFormIndex();
+ if (startIndex.equals(indexToCheck)
+ || (formController.indexIsInFieldList(startIndex) && indexToCheck.toString().startsWith(startIndex.toString()))) {
+ position = elementsToDisplay.indexOf(hierarchyElement);
break;
}
}
@@ -145,9 +154,28 @@ public void onClick(View v) {
}
}
- private boolean shouldScrollToTheGivenIndex(FormIndex formIndex, FormController formController) {
- return startIndex.equals(formIndex)
- || (formController.indexIsInFieldList(startIndex) && formIndex.toString().startsWith(startIndex.toString()));
+
+ /**
+ * Configure the navigation buttons at the bottom of the screen.
+ */
+ void configureButtons(FormController formController) {
+ jumpPreviousButton.setOnClickListener(v -> goUpLevel());
+
+ jumpBeginningButton.setOnClickListener(v -> {
+ formController.getTimerLogger().exitView();
+ formController.jumpToIndex(FormIndex.createBeginningOfFormIndex());
+
+ setResult(RESULT_OK);
+ finish();
+ });
+
+ jumpEndButton.setOnClickListener(v -> {
+ formController.getTimerLogger().exitView();
+ formController.jumpToIndex(FormIndex.createEndOfFormIndex());
+
+ setResult(RESULT_OK);
+ finish();
+ });
}
protected void goUpLevel() {
@@ -156,6 +184,9 @@ protected void goUpLevel() {
refreshView();
}
+ /**
+ * Builds a string representing the path of the current group. Each level is separated by a <.
+ */
private String getCurrentPath() {
FormController formController = Collect.getInstance().getFormController();
FormIndex index = formController.getFormIndex();
@@ -170,6 +201,11 @@ private String getCurrentPath() {
return ODKView.getGroupsPath(groups.toArray(new FormEntryCaption[groups.size()]));
}
+ /**
+ * Rebuilds the view to reflect the elements that should be displayed based on the
+ * FormController's current index. This index is either set prior to the activity opening or
+ * mutated by {@link #onElementClick(HierarchyElement)} if a repeat instance was tapped.
+ */
public void refreshView() {
try {
FormController formController = Collect.getInstance().getFormController();
@@ -180,7 +216,7 @@ public void refreshView() {
// display
// everything enclosed within that group.
String contextGroupRef = "";
- formList = new ArrayList<>();
+ elementsToDisplay = new ArrayList<>();
// If we're currently at a repeat node, record the name of the node and step to the next
// node to display.
@@ -222,11 +258,11 @@ public void refreshView() {
formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
contextGroupRef =
formController.getFormIndex().getReference().getParentRef().toString(true);
- path.setVisibility(View.GONE);
+ groupPathTextView.setVisibility(View.GONE);
jumpPreviousButton.setEnabled(false);
} else {
- path.setVisibility(View.VISIBLE);
- path.setText(getCurrentPath());
+ groupPathTextView.setVisibility(View.VISIBLE);
+ groupPathTextView.setText(getCurrentPath());
jumpPreviousButton.setEnabled(true);
}
@@ -283,9 +319,9 @@ public void refreshView() {
// show the question if it is an editable field.
// or if it is read-only and the label is not blank.
String answerDisplay = FormEntryPromptUtils.getAnswerText(fp, this, formController);
- formList.add(
+ elementsToDisplay.add(
new HierarchyElement(FormEntryPromptUtils.markQuestionIfIsRequired(label, fp.isRequired()), answerDisplay, null,
- QUESTION, fp.getIndex()));
+ HierarchyElement.Type.QUESTION, fp.getIndex()));
}
break;
case FormEntryController.EVENT_GROUP:
@@ -313,8 +349,8 @@ public void refreshView() {
HierarchyElement group =
new HierarchyElement(getLabel(fc), null, ContextCompat
.getDrawable(this, R.drawable.expander_ic_minimized),
- COLLAPSED, fc.getIndex());
- formList.add(group);
+ HierarchyElement.Type.COLLAPSED, fc.getIndex());
+ elementsToDisplay.add(group);
}
String repeatLabel = getLabel(fc);
if (fc.getFormElement().getChildren().size() == 1 && fc.getFormElement().getChild(0) instanceof GroupDef) {
@@ -326,17 +362,16 @@ public void refreshView() {
}
repeatLabel += " (" + (fc.getMultiplicity() + 1) + ")\u200E";
// Add this group name to the drop down list for this repeating group.
- HierarchyElement h = formList.get(formList.size() - 1);
- h.addChild(new HierarchyElement(repeatLabel, null, null, CHILD, fc.getIndex()));
+ HierarchyElement h = elementsToDisplay.get(elementsToDisplay.size() - 1);
+ h.addChild(new HierarchyElement(repeatLabel, null, null, HierarchyElement.Type.CHILD, fc.getIndex()));
break;
}
event =
formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
}
- recyclerView.setAdapter(new HierarchyListAdapter(formList, this::onElementClick));
+ recyclerView.setAdapter(new HierarchyListAdapter(elementsToDisplay, this::onElementClick));
- // set the controller back to the current index in case the user hits 'back'
formController.jumpToIndex(currentIndex);
} catch (Exception e) {
Timber.e(e);
@@ -344,7 +379,88 @@ public void refreshView() {
}
}
- protected abstract void onElementClick(HierarchyElement element);
+ /**
+ * Handles clicks on a specific row in the hierarchy view. Clicking on a:
+ * - group makes it toggle between expanded and collapsed
+ * - question jumps to the form filling view with that question shown. If the question is in a
+ * field list, shows that entire field list.
+ * - group's child element causes this hierarchy view to be refreshed with that element's
+ * questions shown
+ */
+ public void onElementClick(HierarchyElement element) {
+ int position = elementsToDisplay.indexOf(element);
+ FormIndex index = element.getFormIndex();
+
+ switch (element.getType()) {
+ case EXPANDED:
+ element.setType(HierarchyElement.Type.COLLAPSED);
+ ArrayList children = element.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ elementsToDisplay.remove(position + 1);
+ }
+ element.setIcon(ContextCompat.getDrawable(this, R.drawable.expander_ic_minimized));
+ break;
+ case COLLAPSED:
+ element.setType(HierarchyElement.Type.EXPANDED);
+ ArrayList children1 = element.getChildren();
+ for (int i = 0; i < children1.size(); i++) {
+ Timber.i("adding child: %s", children1.get(i).getFormIndex());
+ elementsToDisplay.add(position + 1 + i, children1.get(i));
+
+ }
+ element.setIcon(ContextCompat.getDrawable(this, R.drawable.expander_ic_maximized));
+ break;
+ case QUESTION:
+ onQuestionClicked(index);
+ return;
+ case CHILD:
+ Collect.getInstance().getFormController().jumpToIndex(element.getFormIndex());
+ setResult(RESULT_OK);
+ refreshView();
+ return;
+ }
+
+ recyclerView.setAdapter(new HierarchyListAdapter(elementsToDisplay, this::onElementClick));
+ ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0);
+ }
+
+ /**
+ * Handles clicks on a question. Jumps to the form filling view with the selected question shown.
+ * If the selected question is in a field list, show the entire field list.
+ */
+ void onQuestionClicked(FormIndex index) {
+ Collect.getInstance().getFormController().jumpToIndex(index);
+ if (Collect.getInstance().getFormController().indexIsInFieldList()) {
+ try {
+ Collect.getInstance().getFormController().stepToPreviousScreenEvent();
+ } catch (JavaRosaException e) {
+ Timber.d(e);
+ createErrorDialog(e.getCause().getMessage());
+ return;
+ }
+ }
+ setResult(RESULT_OK);
+ finish();
+ }
+
+ /**
+ * When the device back button is pressed, go back to the previous activity, NOT the previous
+ * level in the hierarchy as the "Go Up" button does.
+ */
+ @Override
+ public void onBackPressed() {
+ FormController formController = Collect.getInstance().getFormController();
+ if (formController != null) {
+ formController.getTimerLogger().exitView();
+ formController.jumpToIndex(startIndex);
+ }
+
+ onBackPressedWithoutLogger();
+ }
+
+ protected void onBackPressedWithoutLogger() {
+ super.onBackPressed();
+ }
/**
* Creates and displays dialog with the given errorMsg.
diff --git a/collect_app/src/main/java/org/odk/collect/android/activities/ViewFormHierarchyActivity.java b/collect_app/src/main/java/org/odk/collect/android/activities/ViewFormHierarchyActivity.java
deleted file mode 100644
index 0dca2e12523..00000000000
--- a/collect_app/src/main/java/org/odk/collect/android/activities/ViewFormHierarchyActivity.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2017 Shobhit
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package org.odk.collect.android.activities;
-
-import android.os.Bundle;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.LinearLayoutManager;
-import android.view.View;
-import android.widget.Button;
-
-import org.javarosa.core.model.FormIndex;
-import org.odk.collect.android.R;
-import org.odk.collect.android.adapters.HierarchyListAdapter;
-import org.odk.collect.android.application.Collect;
-import org.odk.collect.android.exception.JavaRosaException;
-import org.odk.collect.android.logic.HierarchyElement;
-
-import java.util.ArrayList;
-
-import timber.log.Timber;
-
-public class ViewFormHierarchyActivity extends FormHierarchyActivity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // super.onCreate() can call finish() if it finds the FormController to be null
- // in that case, we want to shortcut this method, and let the Activity finish itself
- if (isFinishing()) {
- return;
- }
-
- Collect.getInstance().getFormController().stepToOuterScreenEvent();
-
- Button exitButton = findViewById(R.id.exitButton);
- exitButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(RESULT_OK);
- finish();
- }
- });
-
- exitButton.setVisibility(View.VISIBLE);
-
- jumpBeginningButton.setVisibility(View.GONE);
- jumpEndButton.setVisibility(View.GONE);
- }
-
- @Override
- public void onElementClick(HierarchyElement element) {
- int position = formList.indexOf(element);
- FormIndex index = element.getFormIndex();
- if (index == null) {
- goUpLevel();
- return;
- }
-
- switch (element.getType()) {
- case EXPANDED:
- element.setType(COLLAPSED);
- ArrayList children = element.getChildren();
- for (int i = 0; i < children.size(); i++) {
- formList.remove(position + 1);
- }
- element.setIcon(ContextCompat.getDrawable(this, R.drawable.expander_ic_minimized));
- break;
- case COLLAPSED:
- element.setType(EXPANDED);
- ArrayList children1 = element.getChildren();
- for (int i = 0; i < children1.size(); i++) {
- Timber.i("adding child: %s", children1.get(i).getFormIndex());
- formList.add(position + 1 + i, children1.get(i));
-
- }
- element.setIcon(ContextCompat.getDrawable(this, R.drawable.expander_ic_maximized));
- break;
- case QUESTION:
- Collect.getInstance().getFormController().jumpToIndex(index);
- if (Collect.getInstance().getFormController().indexIsInFieldList()) {
- try {
- Collect.getInstance().getFormController().stepToPreviousScreenEvent();
- } catch (JavaRosaException e) {
- Timber.d(e);
- createErrorDialog(e.getCause().getMessage());
- return;
- }
- }
- setResult(RESULT_OK);
- return;
- case CHILD:
- Collect.getInstance().getFormController().jumpToIndex(element.getFormIndex());
- setResult(RESULT_OK);
- refreshView();
- return;
- }
-
- recyclerView.setAdapter(new HierarchyListAdapter(formList, this::onElementClick));
- ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0);
- }
-}
diff --git a/collect_app/src/main/java/org/odk/collect/android/activities/ViewOnlyFormHierarchyActivity.java b/collect_app/src/main/java/org/odk/collect/android/activities/ViewOnlyFormHierarchyActivity.java
new file mode 100644
index 00000000000..f3017ac6d3d
--- /dev/null
+++ b/collect_app/src/main/java/org/odk/collect/android/activities/ViewOnlyFormHierarchyActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 Shobhit
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.odk.collect.android.activities;
+
+import android.view.View;
+import android.widget.Button;
+
+import org.javarosa.core.model.FormIndex;
+import org.odk.collect.android.R;
+import org.odk.collect.android.logic.FormController;
+
+/**
+ * Displays the structure of a form along with the answers for the current instance. Disables all
+ * features that allow the user to edit the form instance.
+ */
+public class ViewOnlyFormHierarchyActivity extends FormHierarchyActivity {
+ /**
+ * Hides buttons to jump to the beginning and to the end of the form instance to edit it. Adds
+ * an extra exit button that exits this activity.
+ */
+ @Override
+ void configureButtons(FormController formController) {
+ jumpPreviousButton.setOnClickListener(v -> goUpLevel());
+
+ Button exitButton = findViewById(R.id.exitButton);
+ exitButton.setOnClickListener(v -> {
+ setResult(RESULT_OK);
+ finish();
+ });
+
+ exitButton.setVisibility(View.VISIBLE);
+
+ jumpBeginningButton.setVisibility(View.GONE);
+ jumpEndButton.setVisibility(View.GONE);
+ }
+
+ /**
+ * Prevents the user from clicking on individual questions to jump into the form-filling view.
+ */
+ @Override
+ void onQuestionClicked(FormIndex index) {
+ // Do nothing
+ }
+
+ /**
+ * Prevents logging an audit event when the user exits the activity.
+ */
+ @Override
+ public void onBackPressed() {
+ onBackPressedWithoutLogger();
+ }
+}
diff --git a/collect_app/src/main/java/org/odk/collect/android/logic/HierarchyElement.java b/collect_app/src/main/java/org/odk/collect/android/logic/HierarchyElement.java
index fcca05fe41b..979a619d7af 100644
--- a/collect_app/src/main/java/org/odk/collect/android/logic/HierarchyElement.java
+++ b/collect_app/src/main/java/org/odk/collect/android/logic/HierarchyElement.java
@@ -15,21 +15,57 @@
package org.odk.collect.android.logic;
import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import org.javarosa.core.model.FormIndex;
import java.util.ArrayList;
+/**
+ * Represents a question or repeat to be shown in
+ * {@link org.odk.collect.android.activities.FormHierarchyActivity}.
+ */
public class HierarchyElement {
+ /**
+ * Repeat instances (always of type {@link Type#CHILD}) if this element is a repeat
+ * ({@link Type#COLLAPSED} or {@link Type#EXPANDED}). Not relevant otherwise.
+ */
private final ArrayList children = new ArrayList<>();
- private int type;
+ /**
+ * The type and state of this element. See {@link Type}.
+ */
+ @NonNull
+ private Type type;
+
+ /**
+ * The form index of this element.
+ */
+ @NonNull
private final FormIndex formIndex;
+
+ /**
+ * The primary text this element should be displayed with.
+ */
+ @NonNull
private final String primaryText;
+
+ /**
+ * The secondary text this element should be displayed with.
+ */
+ @Nullable
private final String secondaryText;
+
+ /**
+ * The collapsed or expanded icon if this element is a repeat ({@link Type#COLLAPSED} or
+ * {@link Type#EXPANDED}). Not relevant otherwise.
+ */
+ @Nullable
private Drawable icon;
- public HierarchyElement(String primaryText, String secondaryText, Drawable icon, int type, FormIndex formIndex) {
+ public HierarchyElement(@NonNull String primaryText, @Nullable String secondaryText,
+ @Nullable Drawable icon, @NonNull Type type, @NonNull FormIndex formIndex) {
this.primaryText = primaryText;
this.secondaryText = secondaryText;
this.icon = icon;
@@ -37,31 +73,36 @@ public HierarchyElement(String primaryText, String secondaryText, Drawable icon,
this.formIndex = formIndex;
}
+ @NonNull
public String getPrimaryText() {
return primaryText;
}
+ @Nullable
public String getSecondaryText() {
return secondaryText;
}
+ @Nullable
public Drawable getIcon() {
return icon;
}
- public void setIcon(Drawable icon) {
+ public void setIcon(@Nullable Drawable icon) {
this.icon = icon;
}
+ @NonNull
public FormIndex getFormIndex() {
return formIndex;
}
- public int getType() {
+ @NonNull
+ public Type getType() {
return type;
}
- public void setType(int newType) {
+ public void setType(@NonNull Type newType) {
type = newType;
}
@@ -72,4 +113,29 @@ public ArrayList getChildren() {
public void addChild(HierarchyElement h) {
children.add(h);
}
+
+ /**
+ * The type and state of this element.
+ */
+ public enum Type {
+ /**
+ * A repeat instance.
+ */
+ CHILD,
+
+ /**
+ * A repeat that should be displayed as expanded.
+ */
+ EXPANDED,
+
+ /**
+ * A repeat that should be displayed as collapsed.
+ */
+ COLLAPSED,
+
+ /**
+ * A question.
+ */
+ QUESTION;
+ }
}