Commit d542b9ff authored by rahadi's avatar rahadi

Added real time validation mechanism

parent 255714c9
......@@ -4,24 +4,36 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.javarosa.core.model.FormIndex;
import java.io.InvalidObjectException;
import java.util.ArrayList;
import id.ac.stis.capi.lessthink.listeners.OnChangeListener;
import id.ac.stis.capi.lessthink.models.BaseHierarchy;
import id.ac.stis.capi.lessthink.models.PromptHierarchy;
import id.ac.stis.capi.lessthink.utils.ViewUtils;
import id.ac.stis.capi.odk.widgets.QuestionWidget;
import timber.log.Timber;
/**
* Author : Rahadi Jalu
* Email : 14.8325@stis.ac.id
* Company: Politeknik Statistika STIS
*/
public class HierarchyAdapter extends BaseAdapter {
public class HierarchyAdapter extends BaseAdapter implements OnChangeListener {
private ArrayList<BaseHierarchy> hierarchies;
private OnChangeListener onChangeListener;
public HierarchyAdapter(ArrayList<BaseHierarchy> hierarchies) {
this.hierarchies = hierarchies;
}
public void setOnChangeListener(OnChangeListener onChangeListener) {
this.onChangeListener = onChangeListener;
}
@Override
public int getCount() {
return hierarchies.size();
......@@ -45,19 +57,36 @@ public class HierarchyAdapter extends BaseAdapter {
@Override
public View getView(final int position, View view, final ViewGroup parent) {
View v = hierarchies.get(position).getView();
BaseHierarchy hierarchy = hierarchies.get(position);
View v = hierarchy.getView();
if (v instanceof QuestionWidget) {
v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
((QuestionWidget) v).setFocus(parent.getContext());
}
if (hierarchy instanceof PromptHierarchy) {
final QuestionWidget widget = ((PromptHierarchy) hierarchy).getWidget();
// widget.setOnFocusChangeListener(new View.OnFocusChangeListener() {
// @Override
// public void onFocusChange(View v, boolean hasFocus) {
// if (hasFocus) {
// widget.setFocus(parent.getContext());
// }
// }
// });
try {
ViewUtils.setChangeListener(widget, ((PromptHierarchy) hierarchy).getPrompt().getIndex(),
this);
} catch (InvalidObjectException e) {
Timber.e(e);
}
});
}
return v;
}
@Override
public void onChange(QuestionWidget questionWidget, FormIndex formIndex) {
if (onChangeListener != null) {
onChangeListener.onChange(questionWidget, formIndex);
}
}
}
\ No newline at end of file
......@@ -15,6 +15,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
......@@ -24,7 +25,6 @@ import org.javarosa.core.model.data.IAnswerData;
import org.javarosa.form.api.FormEntryController;
import java.io.File;
import java.io.InvalidObjectException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
......@@ -38,7 +38,6 @@ import id.ac.stis.capi.lessthink.listeners.OnChangeListener;
import id.ac.stis.capi.lessthink.listeners.OnEditRutaSavedListener;
import id.ac.stis.capi.lessthink.models.BaseHierarchy;
import id.ac.stis.capi.lessthink.models.PromptHierarchy;
import id.ac.stis.capi.lessthink.utils.ViewUtils;
import id.ac.stis.capi.odk.application.Collect;
import id.ac.stis.capi.odk.dao.FormsDao;
import id.ac.stis.capi.odk.dao.InstancesDao;
......@@ -190,26 +189,40 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
FormController controller = Collect.getInstance().getFormController();
hierarchies = controller.getAllQuestions(getContext());
setupChangeListener();
adapter = new HierarchyAdapter(hierarchies);
mainContent.setAdapter(adapter);
// adapter.notifyDataSetChanged();
// populateQuestionWidgets(hierarchies, questionContainer);
mainContent.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
view.setFocusable(true);
} else {
view.setFocusable(false);
}
private void setupChangeListener() {
for (BaseHierarchy hierarchy : hierarchies) {
if (hierarchy instanceof PromptHierarchy) {
QuestionWidget widget = ((PromptHierarchy) hierarchy).getWidget();
try {
ViewUtils.setChangeListener(widget, ((PromptHierarchy) hierarchy).getPrompt().getIndex(), this);
} catch (InvalidObjectException e) {
e.printStackTrace();
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
adapter.setOnChangeListener(this);
setPositiveButtonState(saveAnswers(false));
// adapter.notifyDataSetChanged();
// populateQuestionWidgets(hierarchies, questionContainer);
}
private void refreshView() {
FormController controller = Collect.getInstance().getFormController();
newHierarchies = controller.getAllQuestions(getContext());
hierarchies.clear();
hierarchies.addAll(newHierarchies);
adapter.notifyDataSetChanged();
}
// private void refreshView(FormIndex index) {
......@@ -485,71 +498,120 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
* @return false if any error occurs while saving (constraint violated,
* etc...), true otherwise.
*/
// private boolean saveAnswers() {
// FormController formController = Collect.getInstance()
// .getFormController();
//
// if (formController.currentPromptIsQuestion()) {
// LinkedHashMap<FormIndex, IAnswerData> answers = new LinkedHashMap<>();
//
// Set<String> references = questionWidgets.keySet();
// for (String reference : references) {
// Timber.d("Put Reference : %s", reference);
// answers.put(questionWidgets.get(reference).getPrompt().getIndex(),
// questionWidgets.get(reference).getAnswer());
// }
//
// try {
// ArrayList<FailedConstraint> constraints = formController.saveAllScreenAnswers(answers,
// true);
// if (constraints != null) {
// for (FailedConstraint constraint : constraints) {
// String message = null;
// switch (constraint.status) {
// case FormEntryController.ANSWER_REQUIRED_BUT_EMPTY:
// message = formController.getQuestionPromptRequiredText(constraint.index);
// if (message == null || message.trim().length() == 0) {
// message = formController.getQuestionPrompt(constraint.index)
// .getSpecialFormQuestionText("requiredMsg");
//
// if (message == null || message.trim().length() == 0) {
// message = "Answer is Required";
// }
// }
// break;
// case FormEntryController.ANSWER_CONSTRAINT_VIOLATED:
// message = formController.getQuestionPromptConstraintText(constraint.index);
// if (message == null || message.trim().length() == 0) {
// message = formController.getQuestionPrompt(constraint.index)
// .getSpecialFormQuestionText("constraintMsg");
//
// if (message == null || message.trim().length() == 0) {
// message = "Answer violates Constraint";
// }
// }
// break;
// }
//
// QuestionWidget questionWidget = questionWidgets.get(constraint.index.getReference().toString());
// answers.remove(questionWidget.getPrompt().getIndex());
// ViewUtils.setError(questionWidget, message);
// }
//
// Set<FormIndex> formIndices = answers.keySet();
// for (FormIndex formIndex : formIndices) {
// ViewUtils.clearError(questionWidgets.get(formIndex.getReference().toString()));
// }
//
// return false;
// }
// } catch (JavaRosaException e) {
// Timber.e(e);
//// createErrorDialog(e.getCause().getMessage(), DO_NOT_EXIT);
// return false;
// }
// }
// return true;
// }
private boolean saveAnswers(boolean refreshView) {
AlertDialog dialog = (AlertDialog) getDialog();
Window window = dialog.getWindow();
if (window != null) {
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
boolean isClean = true;
FormController formController = Collect.getInstance()
.getFormController();
if (formController.currentPromptIsQuestion()) {
LinkedHashMap<FormIndex, IAnswerData> answers = new LinkedHashMap<>();
for (int i = 0; i < adapter.getCount(); i++) {
if (adapter.getItem(i) instanceof PromptHierarchy) {
PromptHierarchy hierarchy = (PromptHierarchy) adapter.getItem(i);
answers.put(hierarchy.getPrompt().getIndex(),
hierarchy.getWidget().getAnswer());
}
}
try {
ArrayList<FailedConstraint> constraints = formController.saveAllScreenAnswers(answers,
true);
if (refreshView) {
refreshView();
}
if (constraints != null) {
for (FailedConstraint constraint : constraints) {
String message = null;
switch (constraint.status) {
case FormEntryController.ANSWER_REQUIRED_BUT_EMPTY:
message = formController.getQuestionPromptRequiredText(constraint.index);
if (message == null || message.trim().length() == 0) {
message = formController.getQuestionPrompt(constraint.index)
.getSpecialFormQuestionText("requiredMsg");
if (message == null || message.trim().length() == 0) {
message = "Answer is Required";
}
}
break;
case FormEntryController.ANSWER_CONSTRAINT_VIOLATED:
message = formController.getQuestionPromptConstraintText(constraint.index);
if (message == null || message.trim().length() == 0) {
message = formController.getQuestionPrompt(constraint.index)
.getSpecialFormQuestionText("constraintMsg");
if (message == null || message.trim().length() == 0) {
message = "Answer violates Constraint";
}
}
break;
}
Timber.d("Current Index: %s %s", constraint.index,
constraint.index.getReference());
for (int i = 0; i < adapter.getCount(); i++) {
if (adapter.getItem(i) instanceof PromptHierarchy) {
PromptHierarchy h = (PromptHierarchy) adapter.getItem(i);
if (h.getPrompt().getIndex().getReference().toString()
.equals(constraint.index.getReference().toString())) {
Timber.d("Error caught! (%s) Index: %s %s", message,
constraint.index, constraint.index.getReference());
answers.remove(constraint.index);
h.setError(message);
break;
}
}
}
}
isClean = false;
}
Set<FormIndex> formIndices = answers.keySet();
for (FormIndex formIndex : formIndices) {
for (int i = 0; i < adapter.getCount(); i++) {
if (adapter.getItem(i) instanceof PromptHierarchy) {
PromptHierarchy h = (PromptHierarchy) adapter.getItem(i);
if (h.getPrompt().getIndex().getReference().toString()
.equals(formIndex.getReference().toString())) {
Timber.d("Clean! Index: %s %s", formIndex,
formIndex.getReference());
h.setError(null);
break;
}
}
}
}
} catch (JavaRosaException e) {
Timber.e(e);
// createErrorDialog(e.getCause().getMessage(), DO_NOT_EXIT);
isClean = false;
}
}
if (window != null) {
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
/*| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL*/
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
return isClean;
}
@Override
public void loadingError(String errorMsg) {
......@@ -568,8 +630,7 @@ public class FormEntryDialogFragment extends DialogFragment implements FormLoade
.getFormController();
formController.jumpToIndex(index);
// saveAnswers();
// refreshView(index);
setPositiveButtonState(saveAnswers(true));
}
}
......@@ -54,7 +54,7 @@ public class CaptionHierarchy extends BaseHierarchy {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
75, 75);
params.topMargin = 15;
params.topMargin = 26;
params.bottomMargin = 15;
textView.setLayoutParams(params);
} else if (getType() == TYPE_NEW_REPEAT) {
......@@ -67,7 +67,7 @@ public class CaptionHierarchy extends BaseHierarchy {
ta.recycle();
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, Collect.getQuestionFontsize() - 1);
textView.setPadding(25, 45, 25, 45);
textView.setPadding(15, 45, 15, 45);
textView.setTextColor(ContextCompat.getColor(context, R.color.white));
textView.setBackground(drawable);
......@@ -165,6 +165,20 @@ public class CaptionHierarchy extends BaseHierarchy {
this.captionView = container;
// View v = LayoutInflater.from(context).inflate(R.layout.item_updating_hierarchy, null);
// View mainContent = v.findViewById(R.id.main_content);
//
// ViewGroup parent = (ViewGroup) mainContent.getParent();
// int index = parent.indexOfChild(mainContent);
//
// parent.removeView(mainContent);
// parent.addView(textView, index);
//
// ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) parent.getLayoutParams();
// params.setMargins(6 * getLevel(), 0, 6 * getLevel(), 0);
// parent.setLayoutParams(params);
//
// this.captionView = v;
}
public View getText() {
......
......@@ -8,12 +8,18 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import org.javarosa.core.model.FormIndex;
import org.javarosa.form.api.FormEntryPrompt;
import java.io.InvalidObjectException;
import id.ac.stis.capi.R;
import id.ac.stis.capi.lessthink.listeners.OnChangeListener;
import id.ac.stis.capi.lessthink.utils.ViewUtils;
import id.ac.stis.capi.lessthink.views.HierarchyErrorView;
import id.ac.stis.capi.odk.widgets.QuestionWidget;
import id.ac.stis.capi.odk.widgets.WidgetFactory;
import timber.log.Timber;
/**
* Author : Rahadi Jalu
......@@ -70,10 +76,10 @@ public class PromptHierarchy extends BaseHierarchy {
LinearLayout.LayoutParams errorParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
errorParams.leftMargin = 15;
errorParams.bottomMargin = 15;
errorParams.rightMargin = 15;
errorParams.topMargin = 15;
// errorParams.leftMargin = 20;
// errorParams.bottomMargin = 14;
// errorParams.rightMargin = 20;
// errorParams.topMargin = 14;
errorView.setLayoutParams(errorParams);
widgetContainer.addView(errorView);
......@@ -138,6 +144,7 @@ public class PromptHierarchy extends BaseHierarchy {
}
public void setError(String message) {
Timber.d("Set Error: %s %s", message, prompt.getIndex().getReference().toString());
if (message == null) {
widgetContainer.setBackgroundColor(ContextCompat.getColor(context, R.color.white));
errorView.setVisibility(View.GONE);
......
......@@ -2,6 +2,7 @@ package id.ac.stis.capi.lessthink.utils;
import android.support.v7.widget.AppCompatButton;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
......@@ -17,6 +18,8 @@ import org.javarosa.core.model.FormIndex;
import java.io.InvalidObjectException;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import id.ac.stis.capi.lessthink.interfaces.UpdatingErrorInterface;
import id.ac.stis.capi.lessthink.listeners.OnChangeListener;
......@@ -33,7 +36,6 @@ import id.ac.stis.capi.odk.widgets.SelectOneWidget;
import id.ac.stis.capi.odk.widgets.SpinnerWidget;
import id.ac.stis.capi.odk.widgets.StringWidget;
import id.ac.stis.capi.odk.widgets.TriggerWidget;
import timber.log.Timber;
/**
* Author : Rahadi Jalu
......@@ -178,6 +180,10 @@ public class ViewUtils {
if (ed != null) {
ed.addTextChangedListener(new TextWatcher() {
private final long DELAY = 500;
private Timer timer = new Timer();
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
......@@ -190,6 +196,11 @@ public class ViewUtils {
@Override
public void afterTextChanged(Editable s) {
timer.cancel();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if (onChangeListener != null) {
onChangeListener.onChange(qw, index);
}
......@@ -199,6 +210,8 @@ public class ViewUtils {
else if (qw instanceof ExStringWidget)
((ExStringWidget) qw).getEditText().requestFocus();
}
}, DELAY);
}
});
return;
}
......
package id.ac.stis.capi.lessthink.views;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.util.TypedValue;
import android.view.Gravity;
......@@ -30,7 +28,8 @@ public class HierarchyErrorView extends LinearLayout {
setGravity(Gravity.CENTER_VERTICAL);
setPadding(25, 25, 25, 25);
setBackground(ContextCompat.getDrawable(context, R.drawable.bg_border_tb));
// setBackground(ContextCompat.getDrawable(context, R.drawable.bg_border_t));
setBackgroundColor(ContextCompat.getColor(context, R.color.smooth_red));
this.messageView = new TextView(context);
messageView.setGravity(Gravity.CENTER_VERTICAL);
......
......@@ -1032,7 +1032,7 @@ public class FormController {
prompts.add(new CaptionHierarchy(context, fcRep, CaptionHierarchy.TYPE_NEW_REPEAT,
prevType, currLevel, prevLevel));
prevLevel = CaptionHierarchy.TYPE_NEW_REPEAT;
prevType = CaptionHierarchy.TYPE_NEW_REPEAT;
prevLevel = currLevel;
break;
case FormEntryController.EVENT_REPEAT:
......@@ -1052,14 +1052,13 @@ public class FormController {
// Display the repeat header for the group.
prompts.add(new CaptionHierarchy(context, fc, CaptionHierarchy.TYPE_REPEAT,
prevType, currLevel, prevLevel));
prevType = CaptionHierarchy.TYPE_REPEAT;
prevLevel = currLevel;
}
prompts.add(new CaptionHierarchy(context, fc, CaptionHierarchy.TYPE_MULTIPLICITY,
prevType, currLevel, prevLevel));
prevType = CaptionHierarchy.TYPE_REPEAT;
prevLevel = currLevel;
// prevLevel = currLevel;
// currLevel++;
break;
......
......@@ -8,6 +8,7 @@
</item>
<item
android:top="-2dp"
android:left="-2dp"
android:right="-2dp">
<shape>
......
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/smooth_red" />
</shape>
</item>
<item
android:bottom="-2dp"
android:left="-2dp"
android:right="-2dp">
<shape>
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="@color/red_latte" />
</shape>
</item>
</layer-list>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment