Search in sources :

Example 21 with FormController

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

the class FormEntryActivity method nonblockingCreateSavePointData.

/**
 * Create save-points asynchronously in order to not affect swiping performance
 * on larger forms.
 */
private void nonblockingCreateSavePointData() {
    try {
        SavePointTask savePointTask = new SavePointTask(this);
        savePointTask.execute();
        if (!allowMovingBackwards) {
            FormController formController = getFormController();
            if (formController != null) {
                new SaveFormIndexTask(this, formController.getFormIndex()).execute();
            }
        }
    } catch (Exception e) {
        Timber.e("Could not schedule SavePointTask. Perhaps a lot of swiping is taking place?");
    }
}
Also used : FormController(org.odk.collect.android.logic.FormController) SaveFormIndexTask(org.odk.collect.android.tasks.SaveFormIndexTask) SavePointTask(org.odk.collect.android.tasks.SavePointTask) GDriveConnectionException(org.odk.collect.android.exception.GDriveConnectionException) JavaRosaException(org.odk.collect.android.exception.JavaRosaException)

Example 22 with FormController

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

the class FormEntryActivity method loadingComplete.

/**
 * loadingComplete() is called by FormLoaderTask once it has finished
 * loading a form.
 */
@Override
public void loadingComplete(FormLoaderTask task, FormDef formDef) {
    dismissDialog(PROGRESS_DIALOG);
    final FormController formController = task.getFormController();
    // these are bogus if
    int requestCode = task.getRequestCode();
    // pendingActivityResult is
    // false
    int resultCode = task.getResultCode();
    Intent intent = task.getIntent();
    formLoaderTask.setFormLoaderListener(null);
    FormLoaderTask t = formLoaderTask;
    formLoaderTask = null;
    t.cancel(true);
    t.destroy();
    Collect.getInstance().setFormController(formController);
    supportInvalidateOptionsMenu();
    Collect.getInstance().setExternalDataManager(task.getExternalDataManager());
    // Set the language if one has already been set in the past
    String[] languageTest = formController.getLanguages();
    if (languageTest != null) {
        String defaultLanguage = formController.getLanguage();
        String newLanguage = FormsDaoHelper.getFormLanguage(formPath);
        long start = System.currentTimeMillis();
        Timber.i("calling formController.setLanguage");
        try {
            formController.setLanguage(newLanguage);
        } catch (Exception e) {
            // if somehow we end up with a bad language, set it to the default
            Timber.e("Ended up with a bad language. %s", newLanguage);
            formController.setLanguage(defaultLanguage);
        }
        Timber.i("Done in %.3f seconds.", (System.currentTimeMillis() - start) / 1000F);
    }
    boolean pendingActivityResult = task.hasPendingActivityResult();
    if (pendingActivityResult) {
        // set the current view to whatever group we were at...
        refreshCurrentView();
        // process the pending activity request...
        onActivityResult(requestCode, resultCode, intent);
        return;
    }
    // it can be a normal flow for a pending activity result to restore from
    // a savepoint
    // (the call flow handled by the above if statement). For all other use
    // cases, the
    // user should be notified, as it means they wandered off doing other
    // things then
    // returned to ODK Collect and chose Edit Saved Form, but that the
    // savepoint for that
    // form is newer than the last saved version of their form data.
    boolean hasUsedSavepoint = task.hasUsedSavepoint();
    if (hasUsedSavepoint) {
        runOnUiThread(() -> ToastUtils.showLongToast(R.string.savepoint_used));
    }
    // Set saved answer path
    if (formController.getInstanceFile() == null) {
        // Create new answer folder.
        String time = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.ENGLISH).format(Calendar.getInstance().getTime());
        String file = formPath.substring(formPath.lastIndexOf('/') + 1, formPath.lastIndexOf('.'));
        String path = Collect.INSTANCES_PATH + File.separator + file + "_" + time;
        if (FileUtils.createFolder(path)) {
            File instanceFile = new File(path + File.separator + file + "_" + time + ".xml");
            formController.setInstanceFile(instanceFile);
        }
        formController.getTimerLogger().logTimerEvent(TimerLogger.EventTypes.FORM_START, 0, null, false, true);
    } else {
        Intent reqIntent = getIntent();
        boolean showFirst = reqIntent.getBooleanExtra("start", false);
        formController.getTimerLogger().logTimerEvent(TimerLogger.EventTypes.FORM_RESUME, 0, null, false, true);
        if (!showFirst) {
            if (!allowMovingBackwards) {
                FormIndex formIndex = SaveFormIndexTask.loadFormIndexFromFile();
                if (formIndex != null) {
                    formController.jumpToIndex(formIndex);
                    refreshCurrentView();
                    return;
                }
            }
            String formMode = reqIntent.getStringExtra(ApplicationConstants.BundleKeys.FORM_MODE);
            if (formMode == null || ApplicationConstants.FormModes.EDIT_SAVED.equalsIgnoreCase(formMode)) {
                startActivity(new Intent(this, EditFormHierarchyActivity.class));
                // so we don't show the intro screen before jumping to the hierarchy
                return;
            } else {
                if (ApplicationConstants.FormModes.VIEW_SENT.equalsIgnoreCase(formMode)) {
                    startActivity(new Intent(this, ViewFormHierarchyActivity.class));
                }
                finish();
            }
        }
    }
    refreshCurrentView();
    if (formDef != null) {
        final File cachedFormDefFile = FormDefCache.getCacheFile(new File(formPath));
        if (cachedFormDefFile.exists()) {
            Timber.i("FormDef %s is already in the cache", cachedFormDefFile.toString());
        } else {
            Disposable formDefCacheDisposable = writeCacheAsync(formDef, cachedFormDefFile).subscribe(() -> {
            }, Timber::e);
            formDefCacheCompositeDisposable.add(formDefCacheDisposable);
        }
    }
}
Also used : FormController(org.odk.collect.android.logic.FormController) CompositeDisposable(io.reactivex.disposables.CompositeDisposable) Disposable(io.reactivex.disposables.Disposable) Timber(timber.log.Timber) Intent(android.content.Intent) FailedConstraint(org.odk.collect.android.logic.FormController.FailedConstraint) GDriveConnectionException(org.odk.collect.android.exception.GDriveConnectionException) JavaRosaException(org.odk.collect.android.exception.JavaRosaException) FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask) FormIndex(org.javarosa.core.model.FormIndex) SimpleDateFormat(java.text.SimpleDateFormat) File(java.io.File)

Example 23 with FormController

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

the class FormEntryActivity method createConstraintToast.

// Hopefully someday we can use managed dialogs when the bugs are fixed
/*
     * Ideally, we'd like to use Android to manage dialogs with onCreateDialog()
     * and onPrepareDialog(), but dialogs with dynamic content are broken in 1.5
     * (cupcake). We do use managed dialogs for our static loading
     * ProgressDialog. The main issue we noticed and are waiting to see fixed
     * is: onPrepareDialog() is not called after a screen orientation change.
     * http://code.google.com/p/android/issues/detail?id=1639
     */
// 
/**
 * Creates and displays a dialog displaying the violated constraint.
 */
private void createConstraintToast(FormIndex index, int saveStatus) {
    FormController formController = getFormController();
    String constraintText;
    switch(saveStatus) {
        case FormEntryController.ANSWER_CONSTRAINT_VIOLATED:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "createConstraintToast.ANSWER_CONSTRAINT_VIOLATED", "show", index);
            constraintText = formController.getQuestionPromptConstraintText(index);
            if (constraintText == null) {
                constraintText = formController.getQuestionPrompt(index).getSpecialFormQuestionText("constraintMsg");
                if (constraintText == null) {
                    constraintText = getString(R.string.invalid_answer_error);
                }
            }
            break;
        case FormEntryController.ANSWER_REQUIRED_BUT_EMPTY:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "createConstraintToast.ANSWER_REQUIRED_BUT_EMPTY", "show", index);
            constraintText = formController.getQuestionPromptRequiredText(index);
            if (constraintText == null) {
                constraintText = formController.getQuestionPrompt(index).getSpecialFormQuestionText("requiredMsg");
                if (constraintText == null) {
                    constraintText = getString(R.string.required_answer_error);
                }
            }
            break;
        default:
            return;
    }
    showCustomToast(constraintText, Toast.LENGTH_SHORT);
}
Also used : FormController(org.odk.collect.android.logic.FormController)

Example 24 with FormController

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

the class FormEntryActivity method createRepeatDialog.

/**
 * Creates and displays a dialog asking the user if they'd like to create a
 * repeat of the current group.
 */
private void createRepeatDialog() {
    Collect.getInstance().getActivityLogger().logInstanceAction(this, "createRepeatDialog", "show");
    // alertDialog is being used for all alert dialogs in this activity.
    if (alertDialog != null && alertDialog.isShowing() && shownAlertDialogIsGroupRepeat) {
        return;
    }
    alertDialog = new AlertDialog.Builder(this).create();
    DialogInterface.OnClickListener repeatListener = new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int i) {
            shownAlertDialogIsGroupRepeat = false;
            FormController formController = getFormController();
            switch(i) {
                case // yes, repeat
                BUTTON_POSITIVE:
                    Collect.getInstance().getActivityLogger().logInstanceAction(this, "createRepeatDialog", "addRepeat");
                    try {
                        formController.newRepeat();
                    } catch (Exception e) {
                        FormEntryActivity.this.createErrorDialog(e.getMessage(), DO_NOT_EXIT);
                        return;
                    }
                    if (!formController.indexIsInFieldList()) {
                        // we are at a REPEAT event that does not have a
                        // field-list appearance
                        // step to the next visible field...
                        // which could be the start of a new repeat group...
                        showNextView();
                    } else {
                        // we are at a REPEAT event that has a field-list
                        // appearance
                        // just display this REPEAT event's group.
                        refreshCurrentView();
                    }
                    break;
                case // no, no repeat
                BUTTON_NEGATIVE:
                    Collect.getInstance().getActivityLogger().logInstanceAction(this, "createRepeatDialog", "showNext");
                    // 
                    // Make sure the error dialog will not disappear.
                    // 
                    // When showNextView() popups an error dialog (because of a
                    // JavaRosaException)
                    // the issue is that the "add new repeat dialog" is referenced by
                    // alertDialog
                    // like the error dialog. When the "no repeat" is clicked, the error dialog
                    // is shown. Android by default dismisses the dialogs when a button is
                    // clicked,
                    // so instead of closing the first dialog, it closes the second.
                    new Thread() {

                        @Override
                        public void run() {
                            FormEntryActivity.this.runOnUiThread(() -> {
                                try {
                                    Thread.sleep(500);
                                } catch (InterruptedException e) {
                                    // This is rare
                                    Timber.e(e);
                                }
                                showNextView();
                            });
                        }
                    }.start();
                    break;
            }
        }
    };
    FormController formController = getFormController();
    if (formController.getLastRepeatCount() > 0) {
        alertDialog.setTitle(getString(R.string.leaving_repeat_ask));
        alertDialog.setMessage(getString(R.string.add_another_repeat, formController.getLastGroupText()));
        alertDialog.setButton(BUTTON_POSITIVE, getString(R.string.add_another), repeatListener);
        alertDialog.setButton(BUTTON_NEGATIVE, getString(R.string.leave_repeat_yes), repeatListener);
    } else {
        alertDialog.setTitle(getString(R.string.entering_repeat_ask));
        alertDialog.setMessage(getString(R.string.add_repeat, formController.getLastGroupText()));
        alertDialog.setButton(BUTTON_POSITIVE, getString(R.string.entering_repeat), repeatListener);
        alertDialog.setButton(BUTTON_NEGATIVE, getString(R.string.add_repeat_no), repeatListener);
    }
    alertDialog.setCancelable(false);
    beenSwiped = false;
    shownAlertDialogIsGroupRepeat = true;
    alertDialog.show();
}
Also used : FormController(org.odk.collect.android.logic.FormController) DialogInterface(android.content.DialogInterface) OnClickListener(android.view.View.OnClickListener) GDriveConnectionException(org.odk.collect.android.exception.GDriveConnectionException) JavaRosaException(org.odk.collect.android.exception.JavaRosaException)

Example 25 with FormController

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

the class FormEntryActivity method onCreateContextMenu.

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    Collect.getInstance().getActivityLogger().logInstanceAction(this, "onCreateContextMenu", "show");
    FormController formController = getFormController();
    menu.add(0, v.getId(), 0, getString(R.string.clear_answer));
    if (formController.indexContainsRepeatableGroup()) {
        menu.add(0, DELETE_REPEAT, 0, getString(R.string.delete_repeat));
    }
    menu.setHeaderTitle(getString(R.string.edit_prompt));
}
Also used : FormController(org.odk.collect.android.logic.FormController)

Aggregations

FormController (org.odk.collect.android.logic.FormController)42 FailedConstraint (org.odk.collect.android.logic.FormController.FailedConstraint)10 FormIndex (org.javarosa.core.model.FormIndex)8 JavaRosaException (org.odk.collect.android.exception.JavaRosaException)8 File (java.io.File)7 OnClickListener (android.view.View.OnClickListener)6 ODKView (org.odk.collect.android.views.ODKView)6 DialogInterface (android.content.DialogInterface)5 View (android.view.View)5 AdapterView (android.widget.AdapterView)5 ListView (android.widget.ListView)5 TextView (android.widget.TextView)5 IOException (java.io.IOException)4 FormEntryPrompt (org.javarosa.form.api.FormEntryPrompt)4 Collect (org.odk.collect.android.application.Collect)4 GDriveConnectionException (org.odk.collect.android.exception.GDriveConnectionException)4 ContentValues (android.content.ContentValues)3 Intent (android.content.Intent)3 Cursor (android.database.Cursor)3 FormEntryCaption (org.javarosa.form.api.FormEntryCaption)3