Search in sources :

Example 1 with HierarchyElement

use of org.odk.collect.android.logic.HierarchyElement in project collect by opendatakit.

the class EditFormHierarchyActivity method onItemClick.

@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
    HierarchyElement h = (HierarchyElement) listView.getItemAtPosition(position);
    FormIndex index = h.getFormIndex();
    if (index == null) {
        goUpLevel();
        return;
    }
    switch(h.getType()) {
        case EXPANDED:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "COLLAPSED", h.getFormIndex());
            h.setType(COLLAPSED);
            ArrayList<HierarchyElement> children = h.getChildren();
            for (int i = 0; i < children.size(); i++) {
                formList.remove(position + 1);
            }
            h.setIcon(ContextCompat.getDrawable(getApplicationContext(), R.drawable.expander_ic_minimized));
            break;
        case COLLAPSED:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "EXPANDED", h.getFormIndex());
            h.setType(EXPANDED);
            ArrayList<HierarchyElement> children1 = h.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));
            }
            h.setIcon(ContextCompat.getDrawable(getApplicationContext(), R.drawable.expander_ic_maximized));
            break;
        case QUESTION:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "QUESTION-JUMP", 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();
            return;
        case CHILD:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "REPEAT-JUMP", h.getFormIndex());
            Collect.getInstance().getFormController().jumpToIndex(h.getFormIndex());
            setResult(RESULT_OK);
            refreshView();
            return;
    }
    // Should only get here if we've expanded or collapsed a group
    HierarchyListAdapter itla = new HierarchyListAdapter(this);
    itla.setListItems(formList);
    listView.setAdapter(itla);
    listView.setSelection(position);
}
Also used : HierarchyElement(org.odk.collect.android.logic.HierarchyElement) HierarchyListAdapter(org.odk.collect.android.adapters.HierarchyListAdapter) FormIndex(org.javarosa.core.model.FormIndex) JavaRosaException(org.odk.collect.android.exception.JavaRosaException)

Example 2 with HierarchyElement

use of org.odk.collect.android.logic.HierarchyElement in project collect by opendatakit.

the class ViewFormHierarchyActivity method onItemClick.

@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
    HierarchyElement h = (HierarchyElement) listView.getItemAtPosition(position);
    FormIndex index = h.getFormIndex();
    if (index == null) {
        goUpLevel();
        return;
    }
    switch(h.getType()) {
        case EXPANDED:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "COLLAPSED", h.getFormIndex());
            h.setType(COLLAPSED);
            ArrayList<HierarchyElement> children = h.getChildren();
            for (int i = 0; i < children.size(); i++) {
                formList.remove(position + 1);
            }
            h.setIcon(ContextCompat.getDrawable(getApplicationContext(), R.drawable.expander_ic_minimized));
            break;
        case COLLAPSED:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "EXPANDED", h.getFormIndex());
            h.setType(EXPANDED);
            ArrayList<HierarchyElement> children1 = h.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));
            }
            h.setIcon(ContextCompat.getDrawable(getApplicationContext(), R.drawable.expander_ic_maximized));
            break;
        case QUESTION:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "QUESTION-JUMP", 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);
            return;
        case CHILD:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onListItemClick", "REPEAT-JUMP", h.getFormIndex());
            Collect.getInstance().getFormController().jumpToIndex(h.getFormIndex());
            setResult(RESULT_OK);
            refreshView();
            return;
    }
    // Should only get here if we've expanded or collapsed a group
    HierarchyListAdapter itla = new HierarchyListAdapter(this);
    itla.setListItems(formList);
    listView.setAdapter(itla);
    listView.setSelection(position);
}
Also used : HierarchyElement(org.odk.collect.android.logic.HierarchyElement) HierarchyListAdapter(org.odk.collect.android.adapters.HierarchyListAdapter) FormIndex(org.javarosa.core.model.FormIndex) JavaRosaException(org.odk.collect.android.exception.JavaRosaException)

Example 3 with HierarchyElement

use of org.odk.collect.android.logic.HierarchyElement in project collect by opendatakit.

the class FormHierarchyActivity method onCreate.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.hierarchy_layout);
    Collect.getInstance().getComponent().inject(this);
    recyclerView = findViewById(R.id.list);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
    TextView emptyView = findViewById(android.R.id.empty);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    FormController formController = Collect.getInstance().getFormController();
    // https://github.com/getodk/collect/issues/998
    if (formController == null) {
        finish();
        Timber.w("FormController is null");
        return;
    }
    formEntryViewModel = new ViewModelProvider(this, formEntryViewModelFactory).get(FormEntryViewModel.class);
    formEntryViewModel.formLoaded(Collect.getInstance().getFormController());
    startIndex = formController.getFormIndex();
    setTitle(formController.getFormTitle());
    groupPathTextView = findViewById(R.id.pathtext);
    jumpBeginningButton = findViewById(R.id.jumpBeginningButton);
    jumpEndButton = findViewById(R.id.jumpEndButton);
    configureButtons(formController);
    restoreInstanceState(savedInstanceState);
    refreshView();
    // 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;
            // 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;
                }
            }
            ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(position, 0);
        });
    }
}
Also used : FormController(org.odk.collect.android.javarosawrapper.FormController) HierarchyElement(org.odk.collect.android.logic.HierarchyElement) FormIndex(org.javarosa.core.model.FormIndex) TextView(android.widget.TextView) FormEntryViewModel(org.odk.collect.android.formentry.FormEntryViewModel) LinearLayoutManager(androidx.recyclerview.widget.LinearLayoutManager) DividerItemDecoration(androidx.recyclerview.widget.DividerItemDecoration) Toolbar(androidx.appcompat.widget.Toolbar) ViewModelProvider(androidx.lifecycle.ViewModelProvider)

Example 4 with HierarchyElement

use of org.odk.collect.android.logic.HierarchyElement in project collect by opendatakit.

the class FormHierarchyActivity method refreshView.

/**
 * @see #refreshView()
 */
private void refreshView(boolean isGoingUp) {
    try {
        FormController formController = Collect.getInstance().getFormController();
        // Save the current index so we can return to the problematic question
        // in the event of an error.
        currentIndex = formController.getFormIndex();
        elementsToDisplay = new ArrayList<>();
        jumpToHierarchyStartIndex();
        updateOptionsMenu();
        int event = formController.getEvent();
        if (event == FormEntryController.EVENT_BEGINNING_OF_FORM && !shouldShowRepeatGroupPicker()) {
            // The beginning of form has no valid prompt to display.
            groupPathTextView.setVisibility(View.GONE);
        } else {
            groupPathTextView.setVisibility(View.VISIBLE);
            groupPathTextView.setText(getCurrentPath());
        }
        // Refresh the current event in case we did step forward.
        event = formController.getEvent();
        // Ref to the parent group that's currently being displayed.
        // 
        // Because of the guard conditions below, we will skip
        // everything until we exit this group.
        TreeReference visibleGroupRef = null;
        while (event != FormEntryController.EVENT_END_OF_FORM) {
            // get the ref to this element
            TreeReference currentRef = formController.getFormIndex().getReference();
            // retrieve the current group
            TreeReference curGroup = (visibleGroupRef == null) ? contextGroupRef : visibleGroupRef;
            if (curGroup != null && !curGroup.isParentOf(currentRef, false)) {
                // We have left the current group
                if (visibleGroupRef == null) {
                    // We are done.
                    break;
                } else {
                    // exit the inner group
                    visibleGroupRef = null;
                }
            }
            if (visibleGroupRef != null) {
                // We're in a group within the one we want to list
                // skip this question/group/repeat and move to the next index.
                event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
                continue;
            }
            switch(event) {
                case FormEntryController.EVENT_QUESTION:
                    {
                        // Nothing but repeat group instances should show up in the picker.
                        if (shouldShowRepeatGroupPicker()) {
                            break;
                        }
                        FormEntryPrompt fp = formController.getQuestionPrompt();
                        String label = fp.getShortText();
                        String answerDisplay = FormEntryPromptUtils.getAnswerText(fp, this, formController);
                        elementsToDisplay.add(new HierarchyElement(FormEntryPromptUtils.markQuestionIfIsRequired(label, fp.isRequired()), answerDisplay, null, HierarchyElement.Type.QUESTION, fp.getIndex()));
                        break;
                    }
                case FormEntryController.EVENT_GROUP:
                    {
                        if (!formController.isGroupRelevant()) {
                            break;
                        }
                        // Nothing but repeat group instances should show up in the picker.
                        if (shouldShowRepeatGroupPicker()) {
                            break;
                        }
                        FormIndex index = formController.getFormIndex();
                        // Only display groups with a specific appearance attribute.
                        if (!formController.isDisplayableGroup(index)) {
                            break;
                        }
                        // Don't render other groups' children.
                        if (contextGroupRef != null && !contextGroupRef.isParentOf(currentRef, false)) {
                            break;
                        }
                        visibleGroupRef = currentRef;
                        FormEntryCaption caption = formController.getCaptionPrompt();
                        HierarchyElement groupElement = new HierarchyElement(caption.getShortText(), getString(R.string.group_label), ContextCompat.getDrawable(this, R.drawable.ic_folder_open), HierarchyElement.Type.VISIBLE_GROUP, caption.getIndex());
                        elementsToDisplay.add(groupElement);
                        // Skip to the next item outside the group.
                        event = formController.stepOverGroup();
                        continue;
                    }
                case FormEntryController.EVENT_PROMPT_NEW_REPEAT:
                    {
                        // ignore it.
                        break;
                    }
                case FormEntryController.EVENT_REPEAT:
                    {
                        boolean forPicker = shouldShowRepeatGroupPicker();
                        // Only break to exclude non-relevant repeat from picker
                        if (!formController.isGroupRelevant() && forPicker) {
                            break;
                        }
                        visibleGroupRef = currentRef;
                        // Don't render other groups' children.
                        if (contextGroupRef != null && !contextGroupRef.isParentOf(currentRef, false)) {
                            break;
                        }
                        FormEntryCaption fc = formController.getCaptionPrompt();
                        if (forPicker) {
                            // Don't render other groups' instances.
                            String repeatGroupPickerRef = repeatGroupPickerIndex.getReference().toString(false);
                            if (!currentRef.toString(false).equals(repeatGroupPickerRef)) {
                                break;
                            }
                            int itemNumber = fc.getMultiplicity() + 1;
                            // e.g. `friends > 1`
                            String repeatLabel = fc.getShortText() + " > " + itemNumber;
                            // If the child of the group has a more descriptive label, use that instead.
                            if (fc.getFormElement().getChildren().size() == 1 && fc.getFormElement().getChild(0) instanceof GroupDef) {
                                formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
                                String itemLabel = formController.getCaptionPrompt().getShortText();
                                if (itemLabel != null) {
                                    // e.g. `1. Alice`
                                    repeatLabel = itemNumber + ".\u200E " + itemLabel;
                                }
                            }
                            HierarchyElement instance = new HierarchyElement(repeatLabel, null, null, HierarchyElement.Type.REPEAT_INSTANCE, fc.getIndex());
                            elementsToDisplay.add(instance);
                        } else if (fc.getMultiplicity() == 0) {
                            // Display the repeat header for the group.
                            HierarchyElement group = new HierarchyElement(fc.getShortText(), getString(R.string.repeatable_group_label), ContextCompat.getDrawable(this, R.drawable.ic_repeat), HierarchyElement.Type.REPEATABLE_GROUP, fc.getIndex());
                            elementsToDisplay.add(group);
                        }
                        break;
                    }
            }
            event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
        }
        recyclerView.setAdapter(new HierarchyListAdapter(elementsToDisplay, this::onElementClick));
        formController.jumpToIndex(currentIndex);
        // that use presentation groups to display labels).
        if (isDisplayingSingleGroup() && !screenIndex.isBeginningOfFormIndex()) {
            if (isGoingUp) {
                // Back out once more.
                goUpLevel();
            } else {
                // Enter automatically.
                formController.jumpToIndex(elementsToDisplay.get(0).getFormIndex());
                refreshView();
            }
        }
    } catch (Exception e) {
        Timber.e(e);
        createErrorDialog(e.getMessage());
    }
}
Also used : FormController(org.odk.collect.android.javarosawrapper.FormController) FormEntryPrompt(org.javarosa.form.api.FormEntryPrompt) HierarchyElement(org.odk.collect.android.logic.HierarchyElement) TreeReference(org.javarosa.core.model.instance.TreeReference) HierarchyListAdapter(org.odk.collect.android.adapters.HierarchyListAdapter) FormEntryCaption(org.javarosa.form.api.FormEntryCaption) FormIndex(org.javarosa.core.model.FormIndex) GroupDef(org.javarosa.core.model.GroupDef) JavaRosaException(org.odk.collect.android.exception.JavaRosaException)

Example 5 with HierarchyElement

use of org.odk.collect.android.logic.HierarchyElement in project collect by opendatakit.

the class FormHierarchyActivity method refreshView.

public void refreshView() {
    try {
        FormController formController = Collect.getInstance().getFormController();
        // Record the current index so we can return to the same place if the user hits 'back'.
        currentIndex = formController.getFormIndex();
        // If we're not at the first level, we're inside a repeated group so we want to only
        // display
        // everything enclosed within that group.
        String contextGroupRef = "";
        formList = new ArrayList<HierarchyElement>();
        // node to display.
        if (formController.getEvent() == FormEntryController.EVENT_REPEAT) {
            contextGroupRef = formController.getFormIndex().getReference().toString(true);
            formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
        } else {
            FormIndex startTest = formController.stepIndexOut(currentIndex);
            // beginning.
            while (startTest != null && formController.getEvent(startTest) == FormEntryController.EVENT_GROUP) {
                startTest = formController.stepIndexOut(startTest);
            }
            if (startTest == null) {
                // check to see if the question is at the first level of the hierarchy. If it
                // is,
                // display the root level from the beginning.
                formController.jumpToIndex(FormIndex.createBeginningOfFormIndex());
            } else {
                // otherwise we're at a repeated group
                formController.jumpToIndex(startTest);
            }
            // beginning
            if (formController.getEvent() == FormEntryController.EVENT_REPEAT) {
                contextGroupRef = formController.getFormIndex().getReference().toString(true);
                formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
            }
        }
        int event = formController.getEvent();
        if (event == FormEntryController.EVENT_BEGINNING_OF_FORM) {
            // The beginning of form has no valid prompt to display.
            formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
            contextGroupRef = formController.getFormIndex().getReference().getParentRef().toString(true);
            path.setVisibility(View.GONE);
            jumpPreviousButton.setEnabled(false);
        } else {
            path.setVisibility(View.VISIBLE);
            path.setText(getCurrentPath());
            jumpPreviousButton.setEnabled(true);
        }
        // Refresh the current event in case we did step forward.
        event = formController.getEvent();
        // Big change from prior implementation:
        // 
        // The ref strings now include the instance number designations
        // i.e., [0], [1], etc. of the repeat groups (and also [1] for
        // non-repeat elements).
        // 
        // The contextGroupRef is now also valid for the top-level form.
        // 
        // The repeatGroupRef is null if we are not skipping a repeat
        // section.
        // 
        String repeatGroupRef = null;
        event_search: while (event != FormEntryController.EVENT_END_OF_FORM) {
            // get the ref to this element
            String currentRef = formController.getFormIndex().getReference().toString(true);
            // retrieve the current group
            String curGroup = (repeatGroupRef == null) ? contextGroupRef : repeatGroupRef;
            if (!currentRef.startsWith(curGroup)) {
                // We have left the current group
                if (repeatGroupRef == null) {
                    // We are done.
                    break;
                } else {
                    // exit the inner repeat group
                    repeatGroupRef = null;
                }
            }
            if (repeatGroupRef != null) {
                // We're in a repeat group within the one we want to list
                // skip this question/group/repeat and move to the next index.
                event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
                continue;
            }
            switch(event) {
                case FormEntryController.EVENT_QUESTION:
                    FormEntryPrompt fp = formController.getQuestionPrompt();
                    String label = fp.getLongText();
                    if (!fp.isReadOnly() || (label != null && label.length() > 0)) {
                        // 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(new HierarchyElement(FormEntryPromptUtils.markQuestionIfIsRequired(label, fp.isRequired()), answerDisplay, null, Color.WHITE, QUESTION, fp.getIndex()));
                    }
                    break;
                case FormEntryController.EVENT_GROUP:
                    // ignore group events
                    break;
                case FormEntryController.EVENT_PROMPT_NEW_REPEAT:
                    // ignore it.
                    break;
                case FormEntryController.EVENT_REPEAT:
                    FormEntryCaption fc = formController.getCaptionPrompt();
                    // push this repeat onto the stack.
                    repeatGroupRef = currentRef;
                    if (fc.getMultiplicity() == 0) {
                        // Display the repeat header for the group.
                        HierarchyElement group = new HierarchyElement(fc.getLongText(), null, ContextCompat.getDrawable(getApplicationContext(), R.drawable.expander_ic_minimized), Color.WHITE, COLLAPSED, fc.getIndex());
                        formList.add(group);
                    }
                    String repeatLabel = mIndent + fc.getLongText();
                    if (fc.getFormElement().getChildren().size() == 1 && fc.getFormElement().getChild(0) instanceof GroupDef) {
                        formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
                        FormEntryCaption fc2 = formController.getCaptionPrompt();
                        if (fc2.getLongText() != null) {
                            repeatLabel = fc2.getLongText();
                        }
                    }
                    repeatLabel += " (" + (fc.getMultiplicity() + 1) + ")";
                    // 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, Color.WHITE, CHILD, fc.getIndex()));
                    break;
            }
            event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
        }
        HierarchyListAdapter itla = new HierarchyListAdapter(this);
        itla.setListItems(formList);
        listView.setAdapter(itla);
        // set the controller back to the current index in case the user hits 'back'
        formController.jumpToIndex(currentIndex);
    } catch (Exception e) {
        Timber.e(e);
        createErrorDialog(e.getMessage());
    }
}
Also used : FormController(org.odk.collect.android.logic.FormController) FormEntryPrompt(org.javarosa.form.api.FormEntryPrompt) HierarchyElement(org.odk.collect.android.logic.HierarchyElement) HierarchyListAdapter(org.odk.collect.android.adapters.HierarchyListAdapter) FormEntryCaption(org.javarosa.form.api.FormEntryCaption) FormIndex(org.javarosa.core.model.FormIndex) GroupDef(org.javarosa.core.model.GroupDef)

Aggregations

HierarchyElement (org.odk.collect.android.logic.HierarchyElement)6 FormIndex (org.javarosa.core.model.FormIndex)5 HierarchyListAdapter (org.odk.collect.android.adapters.HierarchyListAdapter)4 JavaRosaException (org.odk.collect.android.exception.JavaRosaException)3 GroupDef (org.javarosa.core.model.GroupDef)2 FormEntryCaption (org.javarosa.form.api.FormEntryCaption)2 FormEntryPrompt (org.javarosa.form.api.FormEntryPrompt)2 FormController (org.odk.collect.android.javarosawrapper.FormController)2 TextView (android.widget.TextView)1 Toolbar (androidx.appcompat.widget.Toolbar)1 ViewModelProvider (androidx.lifecycle.ViewModelProvider)1 DividerItemDecoration (androidx.recyclerview.widget.DividerItemDecoration)1 LinearLayoutManager (androidx.recyclerview.widget.LinearLayoutManager)1 TreeReference (org.javarosa.core.model.instance.TreeReference)1 FormEntryViewModel (org.odk.collect.android.formentry.FormEntryViewModel)1 FormController (org.odk.collect.android.logic.FormController)1