From d942c9ca737adf9fd9855e81cbb2d9217f5be127 Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Wed, 13 Aug 2014 18:29:33 -0400 Subject: [PATCH 01/17] First draft of Navigation Bar --- res/drawable/badge_background.xml | 33 +++++++ res/drawable/border_top_black.xml | 12 +++ res/drawable/icon_back.png | Bin 0 -> 1372 bytes res/drawable/icon_done.png | Bin 0 -> 1423 bytes res/drawable/icon_exit.png | Bin 0 -> 1428 bytes res/drawable/icon_next.png | Bin 0 -> 1365 bytes res/drawable/progressbar_full.xml | 43 +++++++++ res/layout/screen_form_entry.xml | 67 ++++++++++++++ res/values/colors.xml | 16 ++-- .../android/activities/FormEntryActivity.java | 83 +++++++++++++----- .../odk/collect/android/views/ODKView.java | 31 +------ 11 files changed, 227 insertions(+), 58 deletions(-) create mode 100644 res/drawable/badge_background.xml create mode 100644 res/drawable/border_top_black.xml create mode 100644 res/drawable/icon_back.png create mode 100644 res/drawable/icon_done.png create mode 100644 res/drawable/icon_exit.png create mode 100644 res/drawable/icon_next.png create mode 100644 res/drawable/progressbar_full.xml create mode 100644 res/layout/screen_form_entry.xml diff --git a/res/drawable/badge_background.xml b/res/drawable/badge_background.xml new file mode 100644 index 0000000..cfac6a1 --- /dev/null +++ b/res/drawable/badge_background.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + diff --git a/res/drawable/border_top_black.xml b/res/drawable/border_top_black.xml new file mode 100644 index 0000000..7d52c7a --- /dev/null +++ b/res/drawable/border_top_black.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/icon_back.png b/res/drawable/icon_back.png new file mode 100644 index 0000000000000000000000000000000000000000..f55636234c5439e45caa125ae4f7d32a5d8d8171 GIT binary patch literal 1372 zcmeAS@N?(olHy`uVBq!ia0vp^dO)nj!3-pSf14=`q*&4&eH|GXHuiJ>Nn~YUU}gyL z32_CAOT@3$O5Na9v?HQ&Pio`A?l~70Z@jf}&x8HPpPsw&`p&~o?>_thDjNl(Au#+x zKw_vb}9 zPB<`crj<~Q{Y;&2DOt|@_ujrW6qT(zK0G!d@Off>ubuEndzPmfA&8p_gJ`33(U*?=MVJG&|{VmS*uB8wRq z_zr_G*ARs=V?9$nLqqq^PUb*W&pcfm zLp;2fUcJcItiZz>Q1EI-*Ps8_%X|{I@IH3BWCecsHqUc4mBR?Y>pp?%N*t;t{)Wdayw7kBt6@=ILe^O%41@!a=#f)78&qol`;+ E0F-sYT>t<8 literal 0 HcmV?d00001 diff --git a/res/drawable/icon_exit.png b/res/drawable/icon_exit.png new file mode 100644 index 0000000000000000000000000000000000000000..3c9364da3c3596071f091aa77930596ab5e3247e GIT binary patch literal 1428 zcmeAS@N?(olHy`uVBq!ia0vp^dO)nj!3-pSf14=`q!^2X+?^QKos)S95v-+{m9xQhu$@|GlZ|_s-To2PXbGKKJkWmH)17 z`*-*7zo!@ey}SSK+k2q;Q7{?;!zKhu?sfSA^9e&qkYDiskqsDvzq6|XBbKwkBeIx* zf$uN~Gak=hkpdKyDshb{3C>R|DNig)We7;j%q!9Ja}7}_GuAWJGc|_p9_1e?L zF~q}r>eY)vEeag07j(3@ZTj~=JJvlnyz8{W`nfW$2Nbge`^=nrnosRbHjItEqg#9D zd!f;XllL8`Etc~&yYZ^ARD+2o3>A#OZVKj3jJ@)61R1BFzcVie||qp-#IsYjgfk!wfg6!{p<&9Pn-$+d#dl( z$*sz&o2uesRF@|0P1fJe{$;`J3GQdvZQg|5e0)u8uMy`e_2BhtA$w+u=RYs>-dwyn z&#l7!iX`W(_vRa(-!HqD$Nunf(ftxzE}B$JRD^@Ff~TvW J%Q~loCII^H!+`(* literal 0 HcmV?d00001 diff --git a/res/drawable/icon_next.png b/res/drawable/icon_next.png new file mode 100644 index 0000000000000000000000000000000000000000..b59d39d6e8eaa634c67923a2a4c6f056ae9e7608 GIT binary patch literal 1365 zcmeAS@N?(olHy`uVBq!ia0vp^dO)nj!3-pSf14=`q*&4&eH|GXHuiJ>Nn~YUU}gyL z32_CAOT@3$O5Na9v?HQ&Pio`A?l~70Z@jf}&x8HPpPsw&`p&~o?>_thDjNl(Au#+x zKw>LeXm-g(51-{6bF`xA@5z4-U;5&!O$zwcI^h@W16 zkFE0h_Kiuq_}0!4Z!WR3Sm0-QO;X+Jp^v*?>4TVRy)BQuqV={ujFSE*eIqGFpYKg) n>4mJd!l%;`IQ4S&HD0!Va4Amgyndtr&=U-vu6{1-oD!M<*Fl}T literal 0 HcmV?d00001 diff --git a/res/drawable/progressbar_full.xml b/res/drawable/progressbar_full.xml new file mode 100644 index 0000000..ef8becf --- /dev/null +++ b/res/drawable/progressbar_full.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/screen_form_entry.xml b/res/layout/screen_form_entry.xml new file mode 100644 index 0000000..15d927f --- /dev/null +++ b/res/layout/screen_form_entry.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/colors.xml b/res/values/colors.xml index 58e60a8..9ac3244 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -37,9 +37,15 @@ the License. #000080 #F5A6A6 #20959699 - #ff266cc9 - #ff1e559e - #ff8e9caf - #ff70829a - + + #A3A3A3 + + #ff185FAD + #ff11467F + #A0A6A8 + #868A8C + + #2C9746 + #247A38 + diff --git a/src/org/odk/collect/android/activities/FormEntryActivity.java b/src/org/odk/collect/android/activities/FormEntryActivity.java index e6327d3..a44e436 100644 --- a/src/org/odk/collect/android/activities/FormEntryActivity.java +++ b/src/org/odk/collect/android/activities/FormEntryActivity.java @@ -27,12 +27,10 @@ import org.javarosa.core.model.Constants; import org.javarosa.core.model.FormIndex; import org.javarosa.core.model.data.IAnswerData; -import org.javarosa.core.model.instance.FormInstance; import org.javarosa.core.services.Logger; import org.javarosa.core.services.locale.Localization; import org.javarosa.core.services.locale.Localizer; import org.javarosa.form.api.FormEntryController; -import org.javarosa.form.api.FormEntryModel; import org.javarosa.form.api.FormEntryPrompt; import org.javarosa.model.xform.XFormsModule; import org.javarosa.xpath.XPathException; @@ -62,7 +60,6 @@ import org.odk.collect.android.widgets.QuestionWidget; import org.odk.collect.android.widgets.TimeWidget; -import android.accounts.AccountManager; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.AlertDialog; @@ -103,6 +100,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; @@ -111,6 +109,7 @@ import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; @@ -198,7 +197,7 @@ public class FormEntryActivity extends FragmentActivity implements AnimationList private Animation mInAnimation; private Animation mOutAnimation; - private RelativeLayout mRelativeLayout; + private ViewGroup mViewPane; private View mCurrentView; private AlertDialog mAlertDialog; @@ -263,9 +262,30 @@ public void onCreate(Bundle savedInstanceState) { return; } - setContentView(R.layout.form_entry); + setContentView(R.layout.screen_form_entry); + + ImageButton nextButton = (ImageButton)this.findViewById(R.id.nav_btn_next); + ImageButton prevButton = (ImageButton)this.findViewById(R.id.nav_btn_prev); + + nextButton.setOnClickListener(new OnClickListener() { - mRelativeLayout = (RelativeLayout) findViewById(R.id.rl); + @Override + public void onClick(View v) { + FormEntryActivity.this.showNextView(); + } + + }); + + prevButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + FormEntryActivity.this.showPreviousView(); + } + + }); + + mViewPane = (ViewGroup)findViewById(R.id.form_entry_pane); mBeenSwiped = false; mAlertDialog = null; @@ -736,20 +756,14 @@ public void updateFormRelevencies(){ } /** - * Update progress bar's max and value, based on mCurrentView. - */ - public void updateProgressBar() { - if(!(mCurrentView instanceof ODKView)){ - throw new RuntimeException("Tried to update progress bar not on ODKView"); - } - updateProgressBar((ODKView) mCurrentView); - } - - /** - * Update progress bar's max and value. + * Update progress bar's max and value, and the various buttons and navigation cues + * associated with navigation + * * @param odkv ODKView to update */ - public void updateProgressBar(ODKView odkv) { + public void updateNavigationCues() { + ProgressBar progressBar = (ProgressBar)this.findViewById(R.id.nav_prog_bar); + int totalQuestions = 0; int completedQuestions = 0; @@ -762,6 +776,9 @@ public void updateProgressBar(ODKView odkv) { boolean onCurrentScreen = false; FormIndex currentScreenExit = null; + + //TODO: We can probably evaluate this with a FormIndex walk that _doesn't_ + //affect this form's index. while (event != FormEntryController.EVENT_END_OF_FORM) { int comparison = mFormController.getFormIndex().compareTo(currentFormIndex); @@ -795,10 +812,29 @@ else if (comparison < 0) { } event = mFormController.stepToNextEvent(false); } + + ImageButton nextButton = (ImageButton)this.findViewById(R.id.nav_btn_next); + ImageButton prevButton = (ImageButton)this.findViewById(R.id.nav_btn_prev); // Set form back to correct state & actually update bar mFormController.jumpToIndex(currentFormIndex); - odkv.updateProgressBar(completedQuestions, totalQuestions); + + if(completedQuestions == 0) { + prevButton.setImageResource(R.drawable.icon_exit); + } else { + prevButton.setImageResource(R.drawable.icon_back); + } + + if(totalQuestions == completedQuestions) { + nextButton.setImageResource(R.drawable.icon_done); + progressBar.setProgressDrawable(this.getResources().getDrawable(R.drawable.progressbar_full)); + } else { + nextButton.setImageResource(R.drawable.icon_next); + progressBar.setProgressDrawable(this.getResources().getDrawable(R.drawable.progressbar)); + } + + progressBar.setMax(totalQuestions); + progressBar.setProgress(completedQuestions); } /** @@ -1200,7 +1236,7 @@ public void onClick(View v) { } } - updateProgressBar(odkv); + updateNavigationCues(); return odkv; default: @@ -1399,7 +1435,7 @@ public void showView(View next, AnimationType from, boolean animateLastView) { if(animateLastView) { mCurrentView.startAnimation(mOutAnimation); } - mRelativeLayout.removeView(mCurrentView); + mViewPane.removeView(mCurrentView); } mInAnimation.setAnimationListener(this); @@ -1408,7 +1444,7 @@ public void showView(View next, AnimationType from, boolean animateLastView) { new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); mCurrentView = next; - mRelativeLayout.addView(mCurrentView, lp); + mViewPane.addView(mCurrentView, lp); mCurrentView.startAnimation(mInAnimation); if (mCurrentView instanceof ODKView) @@ -2135,6 +2171,7 @@ public void loadingComplete(FormController fc) { */ refreshCurrentView(); + updateNavigationCues(); } @@ -2356,7 +2393,7 @@ public void advance() { @Override public void widgetEntryChanged() { updateFormRelevencies(); - updateProgressBar(); + updateNavigationCues(); } } diff --git a/src/org/odk/collect/android/views/ODKView.java b/src/org/odk/collect/android/views/ODKView.java index e6cdb92..9f085ab 100644 --- a/src/org/odk/collect/android/views/ODKView.java +++ b/src/org/odk/collect/android/views/ODKView.java @@ -24,7 +24,6 @@ import android.view.ViewParent; import android.view.View.OnLongClickListener; import android.widget.LinearLayout; -import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.TextView; @@ -49,9 +48,7 @@ public class ODKView extends ScrollView implements OnLongClickListener, WidgetCh private LinearLayout mView; private LinearLayout.LayoutParams mLayout; private ArrayList widgets; - private ArrayList dividers; - private ProgressBar mProgressBar; - + private ArrayList dividers; private int mQuestionFontsize; public final static String FIELD_LIST = "field-list"; @@ -104,22 +101,6 @@ public ODKView(Context context, FormEntryPrompt[] questionPrompts, FormEntryCapt mView.setGravity(Gravity.TOP); mView.setPadding(0, 7, 0, 0); - // Construct progress bar - mProgressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleHorizontal); - mProgressBar.setProgressDrawable(getResources().getDrawable(R.drawable.progressbar)); - - LinearLayout.LayoutParams barLayout = - new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT); - barLayout.setMargins(15, 15, 15, 15); - barLayout.gravity = Gravity.BOTTOM; - - LinearLayout barView = new LinearLayout(getContext()); - barView.setOrientation(LinearLayout.VERTICAL); - barView.setGravity(Gravity.BOTTOM); - barView.addView((View) mProgressBar); - mView.addView(barView, barLayout); - mLayout = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, @@ -282,16 +263,6 @@ private void updateConstraintRelevancies(){ } } - /** - * Update progress bar - * @param progress Current value - * @param max Progress bar will be given range 0..max - */ - public void updateProgressBar(int progress, int max) { - mProgressBar.setMax(max); - mProgressBar.setProgress(progress); - } - /** * // * Add a TextView containing the hierarchy of groups to which the question belongs. // */ From c5b31d1c7d6f1526bde04b428998b6fc5be706ef Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Thu, 14 Aug 2014 12:00:17 -0400 Subject: [PATCH 02/17] Implemented badges for required questions --- res/drawable/badge_background.xml | 9 ++--- res/drawable/badge_border.xml | 32 +++++++++++++++ res/layout/screen_form_entry.xml | 34 ++++++++++++++-- res/values/colors.xml | 1 + res/values/styles.xml | 33 +++++++++++++++ .../android/activities/FormEntryActivity.java | 40 ++++++++++++++++++- 6 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 res/drawable/badge_border.xml create mode 100644 res/values/styles.xml diff --git a/res/drawable/badge_background.xml b/res/drawable/badge_background.xml index cfac6a1..9e3c51a 100644 --- a/res/drawable/badge_background.xml +++ b/res/drawable/badge_background.xml @@ -14,8 +14,8 @@ limitations under the License. --> - - + + @@ -24,10 +24,9 @@ android:color="#BF3D3D"/> + android:width="@dimen/badge_circum" + android:height="@dimen/badge_circum"/> - diff --git a/res/drawable/badge_border.xml b/res/drawable/badge_border.xml new file mode 100644 index 0000000..4a902c8 --- /dev/null +++ b/res/drawable/badge_border.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/res/layout/screen_form_entry.xml b/res/layout/screen_form_entry.xml index 15d927f..a6c3899 100644 --- a/res/layout/screen_form_entry.xml +++ b/res/layout/screen_form_entry.xml @@ -1,8 +1,8 @@ - + android:layout_height="match_parent"> + + + + + + - + + diff --git a/res/values/colors.xml b/res/values/colors.xml index 9ac3244..c3752d9 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -26,6 +26,7 @@ the License. #e0000000 #00000000 + #ffffff #f00 #0000ff #f0f0 diff --git a/res/values/styles.xml b/res/values/styles.xml new file mode 100644 index 0000000..8cb0804 --- /dev/null +++ b/res/values/styles.xml @@ -0,0 +1,33 @@ + + + + + 2dp + + + 22dp + -17dp + + 7dp + + + 20dp + 8dp + diff --git a/src/org/odk/collect/android/activities/FormEntryActivity.java b/src/org/odk/collect/android/activities/FormEntryActivity.java index a44e436..2599d02 100644 --- a/src/org/odk/collect/android/activities/FormEntryActivity.java +++ b/src/org/odk/collect/android/activities/FormEntryActivity.java @@ -770,10 +770,14 @@ public void updateNavigationCues() { // Step through form and count questions FormIndex currentFormIndex = mFormController.getFormIndex(); int event = mFormController.getEvent(); + while (event != FormEntryController.EVENT_BEGINNING_OF_FORM) { event = mFormController.stepToPreviousEvent(); } + int answeredOnScreen = 0; + int requiredOnScreen = 0; + boolean onCurrentScreen = false; FormIndex currentScreenExit = null; @@ -800,7 +804,17 @@ public void updateNavigationCues() { // Future questions are never complete. if (onCurrentScreen) { for (FormEntryPrompt prompt : prompts) { - if (prompt.getAnswerValue() != null || prompt.getDataType() == Constants.DATATYPE_NULL) { + boolean isAnswered = prompt.getAnswerValue() != null; + + if(prompt.isRequired()) { + requiredOnScreen++; + + if(isAnswered) { + answeredOnScreen++; + } + } + + if (isAnswered || prompt.getDataType() == Constants.DATATYPE_NULL) { completedQuestions++; } } @@ -808,6 +822,8 @@ public void updateNavigationCues() { else if (comparison < 0) { // For previous questions, consider all "complete" completedQuestions += prompts.length; + //TODO: This doesn't properly capture state to determine whether we will end up out of the form if we hit back! + //Need to test _until_ we get a question that is relevant, then we can skip the relevancy tests } } event = mFormController.stepToNextEvent(false); @@ -835,6 +851,28 @@ else if (comparison < 0) { progressBar.setMax(totalQuestions); progressBar.setProgress(completedQuestions); + + + //We should probably be doing this based on the widgets, maybe, not the model? Hard to call. + updateBadgeInfo(requiredOnScreen, answeredOnScreen); + } + + private void updateBadgeInfo(int requiredOnScreen, int answeredOnScreen) { + View badgeBorder = this.findViewById(R.id.nav_badge_border_drawer); + TextView badge = (TextView)this.findViewById(R.id.nav_badge); + + //If we don't need this stuff, just bail + if(requiredOnScreen <= 1) { + //Hide all badge related items + badgeBorder.setVisibility(View.INVISIBLE); + badge.setVisibility(View.INVISIBLE); + return; + } + //Otherwise, update badge stuff + badgeBorder.setVisibility(View.VISIBLE); + badge.setVisibility(View.VISIBLE); + + badge.setText(requiredOnScreen - answeredOnScreen); } /** From fa516a5d10e4bb41675507a06031de96bc299916 Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Thu, 14 Aug 2014 14:39:51 -0400 Subject: [PATCH 03/17] Fixes for badge layout structure. Fix for Android 2.3 drawable incompatibility. --- res/drawable/badge_background.xml | 8 +++++--- res/drawable/badge_border.xml | 6 +++--- .../{border_top_black.xml => top_border_black.xml} | 0 res/layout/screen_form_entry.xml | 4 ++-- res/values/colors.xml | 2 ++ res/values/styles.xml | 9 +++------ .../collect/android/activities/FormEntryActivity.java | 10 +++++++++- 7 files changed, 24 insertions(+), 15 deletions(-) rename res/drawable/{border_top_black.xml => top_border_black.xml} (100%) diff --git a/res/drawable/badge_background.xml b/res/drawable/badge_background.xml index 9e3c51a..1c5478a 100644 --- a/res/drawable/badge_background.xml +++ b/res/drawable/badge_background.xml @@ -15,7 +15,7 @@ --> - + @@ -23,9 +23,11 @@ + + android:width="@dimen/badge_circum_outer" + android:height="@dimen/badge_circum_outer"/> diff --git a/res/drawable/badge_border.xml b/res/drawable/badge_border.xml index 4a902c8..792363d 100644 --- a/res/drawable/badge_border.xml +++ b/res/drawable/badge_border.xml @@ -15,7 +15,7 @@ --> - + @@ -24,8 +24,8 @@ android:color="@color/dark_grey"/> + android:width="@dimen/badge_circum_border" + android:height="@dimen/badge_circum_border"/> diff --git a/res/drawable/border_top_black.xml b/res/drawable/top_border_black.xml similarity index 100% rename from res/drawable/border_top_black.xml rename to res/drawable/top_border_black.xml diff --git a/res/layout/screen_form_entry.xml b/res/layout/screen_form_entry.xml index a6c3899..815bd8d 100644 --- a/res/layout/screen_form_entry.xml +++ b/res/layout/screen_form_entry.xml @@ -35,7 +35,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" - android:background="@drawable/border_top_black" + android:background="@drawable/top_border_black" android:paddingBottom="5dp" android:paddingTop="5dp" > @@ -87,7 +87,7 @@ android:layout_marginRight="@dimen/badge_offset_side" android:background="@drawable/badge_background" android:gravity="center_vertical|center_horizontal" - android:text="3" + android:text="6" android:textColor="@drawable/white" android:textStyle="bold" android:visibility="invisible" /> diff --git a/res/values/colors.xml b/res/values/colors.xml index c3752d9..ea7528b 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -49,4 +49,6 @@ the License. #2C9746 #247A38 + #E2ECF0 + diff --git a/res/values/styles.xml b/res/values/styles.xml index 8cb0804..26f094a 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -19,15 +19,12 @@ the License. 22dp + 20dp + -17dp 7dp - - - 20dp 8dp diff --git a/src/org/odk/collect/android/activities/FormEntryActivity.java b/src/org/odk/collect/android/activities/FormEntryActivity.java index 2599d02..b8dfce4 100644 --- a/src/org/odk/collect/android/activities/FormEntryActivity.java +++ b/src/org/odk/collect/android/activities/FormEntryActivity.java @@ -72,6 +72,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; +import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -841,6 +842,11 @@ else if (comparison < 0) { prevButton.setImageResource(R.drawable.icon_back); } + //Apparently in Android 2.3 setting the drawable resource for the progress bar + //causes it to lose it bounds. It's a bit cheaper to keep them around than it + //is to invalidate the view, though. + Rect bounds = progressBar.getProgressDrawable().getBounds(); //Save the drawable bound + if(totalQuestions == completedQuestions) { nextButton.setImageResource(R.drawable.icon_done); progressBar.setProgressDrawable(this.getResources().getDrawable(R.drawable.progressbar_full)); @@ -849,6 +855,8 @@ else if (comparison < 0) { progressBar.setProgressDrawable(this.getResources().getDrawable(R.drawable.progressbar)); } + progressBar.getProgressDrawable().setBounds(bounds); //Set the bounds to the saved value + progressBar.setMax(totalQuestions); progressBar.setProgress(completedQuestions); @@ -872,7 +880,7 @@ private void updateBadgeInfo(int requiredOnScreen, int answeredOnScreen) { badgeBorder.setVisibility(View.VISIBLE); badge.setVisibility(View.VISIBLE); - badge.setText(requiredOnScreen - answeredOnScreen); + badge.setText(String.valueOf(requiredOnScreen - answeredOnScreen)); } /** From ccf86f90a8dcc63aadb0baed5fac1354e5e001d3 Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Thu, 14 Aug 2014 15:17:51 -0400 Subject: [PATCH 04/17] Implemented affordance for finished question lists --- res/drawable/badge_background_complete.xml | 34 +++++++++++++++++++ .../android/activities/FormEntryActivity.java | 9 ++++- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 res/drawable/badge_background_complete.xml diff --git a/res/drawable/badge_background_complete.xml b/res/drawable/badge_background_complete.xml new file mode 100644 index 0000000..0f63380 --- /dev/null +++ b/res/drawable/badge_background_complete.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + diff --git a/src/org/odk/collect/android/activities/FormEntryActivity.java b/src/org/odk/collect/android/activities/FormEntryActivity.java index b8dfce4..6eb6ff0 100644 --- a/src/org/odk/collect/android/activities/FormEntryActivity.java +++ b/src/org/odk/collect/android/activities/FormEntryActivity.java @@ -880,7 +880,14 @@ private void updateBadgeInfo(int requiredOnScreen, int answeredOnScreen) { badgeBorder.setVisibility(View.VISIBLE); badge.setVisibility(View.VISIBLE); - badge.setText(String.valueOf(requiredOnScreen - answeredOnScreen)); + if(requiredOnScreen - answeredOnScreen == 0) { + //Unicode checkmark + badge.setText("\u2713"); + badge.setBackgroundResource(R.drawable.badge_background_complete); + } else { + badge.setBackgroundResource(R.drawable.badge_background); + badge.setText(String.valueOf(requiredOnScreen - answeredOnScreen)); + } } /** From 304a0c9e3a0d75e7f9205d8027b66b37fbbf3e5f Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Thu, 14 Aug 2014 18:16:06 -0400 Subject: [PATCH 05/17] Fixed issues with moving progress bar out of ODK View pane --- src/org/odk/collect/android/views/ODKView.java | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/org/odk/collect/android/views/ODKView.java b/src/org/odk/collect/android/views/ODKView.java index 8900de7..2462763 100644 --- a/src/org/odk/collect/android/views/ODKView.java +++ b/src/org/odk/collect/android/views/ODKView.java @@ -191,7 +191,7 @@ public void addQuestionToIndex(QuestionWidget newQuestionWidget, int i){ if(i > 0) { dividerIndex += 2 * i - 1; } - mView.addView(divider, getViewIndex(dividerIndex)); + mView.addView(divider, dividerIndex); dividers.add(Math.max(0, i - 1), divider); QuestionWidget qw = newQuestionWidget; @@ -205,7 +205,7 @@ public void addQuestionToIndex(QuestionWidget newQuestionWidget, int i){ // } widgets.add(i, qw); - mView.addView((View) qw, getViewIndex(2 * i + mViewBannerCount), mLayout); + mView.addView((View) qw, 2 * i + mViewBannerCount, mLayout); newQuestionWidget.setChangedListener(this); } @@ -409,7 +409,7 @@ public void widgetEntryChanged() { * @param questionIndex Index in question list. */ public void removeWidget(int questionIndex){ - mView.removeViewAt(getViewIndex(questionIndex)); + mView.removeViewAt(questionIndex); } /** @@ -419,15 +419,4 @@ public void removeWidget(int questionIndex){ public void removeWidget(View v){ mView.removeView(v); } - - /** - * Translate question index to view index. - * @param questionIndex Index in the list of questions. - * @return Index of question's view in mView. - */ - private int getViewIndex(int questionIndex) { - // Account for progress bar - return questionIndex + 1; - } - } From f2956849537822c95e710008b40ab2472e629dd0 Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Mon, 18 Aug 2014 12:59:41 -0400 Subject: [PATCH 06/17] Back button now tracks appropriately for relevancy on previous screens. --- .../android/activities/FormEntryActivity.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/org/odk/collect/android/activities/FormEntryActivity.java b/src/org/odk/collect/android/activities/FormEntryActivity.java index 62bf9c4..7fc6565 100644 --- a/src/org/odk/collect/android/activities/FormEntryActivity.java +++ b/src/org/odk/collect/android/activities/FormEntryActivity.java @@ -776,6 +776,10 @@ public void updateNavigationCues() { event = mFormController.stepToPreviousEvent(); } + //keep track of whether there is a question that exists before the current screen + boolean relevantBeforeCurrentScreen = false; + boolean isFirstScreen = false; + int answeredOnScreen = 0; int requiredOnScreen = 0; @@ -799,13 +803,30 @@ public void updateNavigationCues() { if (event == FormEntryController.EVENT_QUESTION) { FormEntryPrompt[] prompts = mFormController.getQuestionPrompts(); + + + //Figure out whether we're on the last screen + if(!relevantBeforeCurrentScreen && !isFirstScreen) { + + //We got to the current screen without finding a relevant question, + //I guess we're on the first one. + if(onCurrentScreen && !relevantBeforeCurrentScreen) { + isFirstScreen = true; + } else { + //We're using the built in steps (and they take relevancy into account) + //so if there are prompts they have to be relevant + relevantBeforeCurrentScreen = true; + } + } + + totalQuestions += prompts.length; // Current questions are complete only if they're answered. // Past questions are always complete. // Future questions are never complete. if (onCurrentScreen) { for (FormEntryPrompt prompt : prompts) { - boolean isAnswered = prompt.getAnswerValue() != null; + boolean isAnswered = prompt.getAnswerValue() != null || prompt.getDataType() == Constants.DATATYPE_NULL; if(prompt.isRequired()) { requiredOnScreen++; @@ -815,7 +836,7 @@ public void updateNavigationCues() { } } - if (isAnswered || prompt.getDataType() == Constants.DATATYPE_NULL) { + if (isAnswered) { completedQuestions++; } } @@ -836,7 +857,7 @@ else if (comparison < 0) { // Set form back to correct state & actually update bar mFormController.jumpToIndex(currentFormIndex); - if(completedQuestions == 0) { + if(!relevantBeforeCurrentScreen) { prevButton.setImageResource(R.drawable.icon_exit); } else { prevButton.setImageResource(R.drawable.icon_back); From c7a9d964adac50ba902259daef6487418378150f Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Mon, 25 Aug 2014 13:41:35 -0400 Subject: [PATCH 07/17] starting to add logic for dealing with forward/back navigation around the form's edges --- .../android/activities/FormEntryActivity.java | 105 ++++++++++++++---- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/src/org/odk/collect/android/activities/FormEntryActivity.java b/src/org/odk/collect/android/activities/FormEntryActivity.java index 7fc6565..34fa0f8 100644 --- a/src/org/odk/collect/android/activities/FormEntryActivity.java +++ b/src/org/odk/collect/android/activities/FormEntryActivity.java @@ -272,7 +272,11 @@ public void onCreate(Bundle savedInstanceState) { @Override public void onClick(View v) { - FormEntryActivity.this.showNextView(); + if(!"done".equals(v.getTag())) { + FormEntryActivity.this.showNextView(); + } else { + FormEntryActivity.this.triggerUserFormComplete(); + } } }); @@ -281,7 +285,11 @@ public void onClick(View v) { @Override public void onClick(View v) { - FormEntryActivity.this.showPreviousView(); + if(!"quit".equals(v.getTag())) { + FormEntryActivity.this.showPreviousView(); + } else { + FormEntryActivity.this.triggerUserQuitInput(); + } } }); @@ -789,6 +797,8 @@ public void updateNavigationCues() { //TODO: We can probably evaluate this with a FormIndex walk that _doesn't_ //affect this form's index. while (event != FormEntryController.EVENT_END_OF_FORM) { + String toPrint = mFormController.getFormIndex().toString() + " [" + event+ "]"; + int comparison = mFormController.getFormIndex().compareTo(currentFormIndex); if (comparison == 0) { @@ -848,6 +858,21 @@ else if (comparison < 0) { //Need to test _until_ we get a question that is relevant, then we can skip the relevancy tests } } + + else if(event == FormEntryController.EVENT_PROMPT_NEW_REPEAT) { + //If we've already passed the current screen, this repeat + //junction is coming up in the future and we will need to know + //about it + if(currentScreenExit != null) { + totalQuestions++; + } else { + //Otherwise we already passed it and it no longer affects the count + } + } + + System.out.println(toPrint + ": (" + completedQuestions + " / " + totalQuestions + ")"); + + event = mFormController.stepToNextEvent(false); } @@ -859,8 +884,10 @@ else if (comparison < 0) { if(!relevantBeforeCurrentScreen) { prevButton.setImageResource(R.drawable.icon_exit); + prevButton.setTag("quit"); } else { prevButton.setImageResource(R.drawable.icon_back); + prevButton.setTag("back"); } //Apparently in Android 2.3 setting the drawable resource for the progress bar @@ -870,9 +897,17 @@ else if (comparison < 0) { if(totalQuestions == completedQuestions) { nextButton.setImageResource(R.drawable.icon_done); + + //TODO: _really_? This doesn't seem right + nextButton.setTag("done"); + progressBar.setProgressDrawable(this.getResources().getDrawable(R.drawable.progressbar_full)); } else { nextButton.setImageResource(R.drawable.icon_next); + + //TODO: _really_? This doesn't seem right + nextButton.setTag("next"); + progressBar.setProgressDrawable(this.getResources().getDrawable(R.drawable.progressbar)); } @@ -1238,18 +1273,8 @@ public CharSequence filter(CharSequence source, int start, int end, returnFilter }); - String saveName = mFormController.getFormTitle(); - if (getContentResolver().getType(getIntent().getData()) == InstanceColumns.CONTENT_ITEM_TYPE) { - Uri instanceUri = getIntent().getData(); - Cursor instance = managedQuery(instanceUri, null, null, null, null); - if (instance.getCount() == 1) { - instance.moveToFirst(); - saveName = - instance.getString(instance - .getColumnIndex(InstanceColumns.DISPLAY_NAME)); - } - } - + String saveName = getDefaultFormTitle(); + saveAs.setText(saveName); // Create 'save' button @@ -2111,19 +2136,53 @@ protected void onResume() { } + /** + * Call when the user provides input that they want to quit the form + */ + private void triggerUserQuitInput() { + //If we're just reviewing a read only form, don't worry about saving + //or what not, just quit + if(mFormController.isFormReadOnly()) { + //It's possible we just want to "finish" here, but + //I don't really wanna break any c compatibility + finishReturnInstance(); + } else { + createQuitDialog(); + } + } + + /** + * Get the default title for ODK's "Form title" field + * + * @return + */ + private String getDefaultFormTitle() { + String saveName = mFormController.getFormTitle(); + if (getContentResolver().getType(getIntent().getData()) == InstanceColumns.CONTENT_ITEM_TYPE) { + Uri instanceUri = getIntent().getData(); + Cursor instance = managedQuery(instanceUri, null, null, null, null); + if (instance.getCount() == 1) { + instance.moveToFirst(); + saveName = + instance.getString(instance + .getColumnIndex(InstanceColumns.DISPLAY_NAME)); + } + } + return saveName; + } + + /** + * Call when the user is ready to save and return the current form as complete + */ + private void triggerUserFormComplete() { + saveDataToDisk(EXIT, true, getDefaultFormTitle()); + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: - //If we're just reviewing a read only form, don't worry about saving - //or what not, just quit - if(mFormController.isFormReadOnly()) { - //It's possible we just want to "finish" here, but - //I don't really wanna break any c compatibility - finishReturnInstance(); - } else { - createQuitDialog(); - } + triggerUserQuitInput(); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (event.isAltPressed() && !mBeenSwiped) { From 9dd13e747531b3faec752a86708cd0b8e2e3919b Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Thu, 28 Aug 2014 13:34:55 -0400 Subject: [PATCH 08/17] Disabled first start screen. Fixed behavior for "Finish" button popping in too late on question lists with optional questions Updated icons to proper flatness. Introduced a depression state on the navigation buttons to signify "presses" --- res/drawable/icon_back.png | Bin 1372 -> 791 bytes res/drawable/icon_done.png | Bin 1423 -> 748 bytes res/drawable/icon_exit.png | Bin 1428 -> 718 bytes res/drawable/icon_next.png | Bin 1365 -> 800 bytes res/drawable/icon_pressed.png | Bin 0 -> 1424 bytes res/drawable/selector_button_press.xml | 17 +++++++++++++++++ res/layout/screen_form_entry.xml | 4 ++-- res/values/styles.xml | 2 +- .../android/activities/FormEntryActivity.java | 16 ++++++++++++---- 9 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 res/drawable/icon_pressed.png create mode 100644 res/drawable/selector_button_press.xml diff --git a/res/drawable/icon_back.png b/res/drawable/icon_back.png index f55636234c5439e45caa125ae4f7d32a5d8d8171..4ddc5ae00549adce26f7162d2f4d9e6d45f4855a 100644 GIT binary patch delta 766 zcmVz@;j|==^1poj532;bRa{vGh)c^nu)d4-$Sn-oy1So$3lSxEDR9Hvt*jsB8K@AD!S|39EbuiQq!O zUR*6TRB z9rqx1QUiWhsf)4`uuF8n+BY=d4`Ianoq=7UalXB#0WT2B_c{f;Kx2llXuzLJqYw5u z2d70N_OcR8;fvMoE$J_`U0etg=QSB#s?_vRXs2DaG+d9??9l@Le{il3N9J7X)bhJT-6i#T$<9D$xj+%^b6>Ec*1BDFEYT&;} zT^zB(B<*C2me0qX+&K;0Z+)jhFK7Is2L8RwrVl4go>5#{bT{Me@l5Az7ibA5k+`Zn z2Qv6vqk3kLgB!;aO=oT$U zihBryn;Q80^4LrzHQYTKN!@eeZEwdeFKC&{&WRlEdO6^FLrXZ`ePF5FcYc-N6}=2c z^t97U8}I0Dsr2FkG^>K+G|k_jE25vRg12&wmbfm? w<$8B__*Kp>R-3A<%ELID*{+CAdCG_V1?pedzBY^4(EtDd07*qoM6N<$g88suU;qFB literal 1372 zcmeAS@N?(olHy`uVBq!ia0vp^dO)nj!3-pSf14=`q*&4&eH|GXHuiJ>Nn~YUU}gyL z32_CAOT@3$O5Na9v?HQ&Pio`A?l~70Z@jf}&x8HPpPsw&`p&~o?>_thDjNl(Au#+x zKw_vb}9 zPB<`crj<~Q{Y;&2DOt|@_ujrW6qT(zK0G!d@Off>ubuEndzPmfA&8p_=UV8WFaW8`B-Asz02SEfq`C74v=tVz-V4>{?Xz``>rN;l0jYSuC%_O^- zEFK;bmgxTG*(Z}{CPt>1e{D&zXgU1ClH5}b+s*ZQo@XQ(hAsJmD)j#Ke_GH0{AfP3 z!={@K-BHZ9p`JgOk}UzhVmV?J$2HUC>$YSYINwBkL2Mz8DhH^gJXCHV)PLdGqAiz= zVDJZsJ<}1RDv6_Om8PnCWcqC}{|eaC2Q!c(CRE^wqb-LGK6c~V3h>0y*+TXu&_CnA z6Gu}S*q`|T(C1O%TF?Zye_WA^3fG1vxan{P_#f4bYeoB|QpyRS|Ej>XqkXs(Ln`o8 zpv$Gg-c@UlE2qQMp#6+Hd^ileVdzYWccJMTQw@~KY_+cQF5?YB2c4qwDkxNoToU7T zN23|)5B22{mUhAaJ*+#rTQc5sXu~sJ0KMNRIL$J3&-7i3Y09BDe^?EDR1FMvzQ%wj zwe-`q`sSdKI;(>A!Kp%r1*ZnB0!{^56|5Z{1*{bv6|4;%2do9%IXBXdDed=D(^{>m zv0)FFYF}zf@hJ{iOQvmC^gV+9|KJF-X_I)S%PVp20!~l9W6FFO=>2Q7pb0>=Z4?SE zs$jo7GBcT0tO(v?b#b|jk^5V`IMVj+7WVG8ar}zc8#_4P#re0&pH|COFKTQmP8+EO z4e<9SMB~j?^rerdCDZguE_lO5yF53De~4?u72*;>pVQVAZ5YxWPkYNJ!2{x#Rbo9+ dZl*YYa|_&4B5(8hJ9q#9002ovPDHLkV1iYcL;?T+ literal 1423 zcmeAS@N?(olHy`uVBq!ia0vp^dO)nj!3-pSf14=`q!^2X+?^QKos)S9gJ`33(U*?=MVJG&|{VmS*uB8wRq z_zr_G*ARs=V?9$nLqqq^PUb*W&pcfm zLp;2fUcJcItiZz>Q1EI-*Ps8_%X|{I@IH3BWCecsHqUc4mBR?Y>pp?%N*t;t{)Wdayw7kBt6@=ILe^O%41@!a=#f)78&qol`;+ E0F-sYT>t<8 diff --git a/res/drawable/icon_exit.png b/res/drawable/icon_exit.png index 3c9364da3c3596071f091aa77930596ab5e3247e..874388aaf450765132f1b3c90d7978a67354127f 100644 GIT binary patch delta 665 zcmV;K0%rY`3(f^0iBL{Q4GJ0x0000DNk~Le0000j0000e2nGNE0BYBBDUl%`695Tt zNLh0L01egv01egwkZ*aMlWPPhe*!&8L_t(oN7dO+OBO*K2k^_xE-!&f+d3M~{o!_$0 z17DWsVV{}L%+Aj2pD3#NW0V*(irW(D;y)W{+#0Q!97Pq-y@sw2B6@!if6=lj=+BAb zZxSV5W4nXA!uWk@V*bJ?wvFv`eBU%u%-WSJ7aM`rinmE2T8al~^+)8BR%7>lE9-Y6 zlA=-J!kMY6V^_pwA9$_kKH%diC{gTYBhh(aBl&@C-xzKjIv1?CNtXDe4>;SGe0aFP z=`y?J3noW9z)7ma?J{6ef3yRfb|jxJ3noK5!7;m21x$i=fV(;tcdLSfqupSBF9bL! z+5xs$VxJ)oebar?y4tUyL8d$ti$^8yA`0GluXA$WFvw!49}Cb77P>e?Md!hjm`^kso#C`( z^H}n~AR6FRA8^o{0N;vjJG$UImV0&7I;MRa=5y_VqxKc~fV|g=y~7Fq_TQslzVrW) zFW)kf&Df`{kx-VxSLIZFeSro&E?ilt9jl_z^WQ>Q3YQZAy-~QbP&?wT{u;*W_iSN8 zuN@+tY$iesk{~Ja6ZwVwMvjm_C%>;}ujKv$*!6rqI3UVz00000NkvXXu0mjf&>J`e literal 1428 zcmeAS@N?(olHy`uVBq!ia0vp^dO)nj!3-pSf14=`q!^2X+?^QKos)S95v-+{m9xQhu$@|GlZ|_s-To2PXbGKKJkWmH)17 z`*-*7zo!@ey}SSK+k2q;Q7{?;!zKhu?sfSA^9e&qkYDiskqsDvzq6|XBbKwkBeIx* zf$uN~Gak=hkpdKyDshb{3C>R|DNig)We7;j%q!9Ja}7}_GuAWJGc|_p9_1e?L zF~q}r>eY)vEeag07j(3@ZTj~=JJvlnyz8{W`nfW$2Nbge`^=nrnosRbHjItEqg#9D zd!f;XllL8`Etc~&yYZ^ARD+2o3>A#OZVKj3jJ@)61R1BFzcVie||qp-#IsYjgfk!wfg6!{p<&9Pn-$+d#dl( z$*sz&o2uesRF@|0P1fJe{$;`J3GQdvZQg|5e0)u8uMy`e_2BhtA$w+u=RYs>-dwyn z&#l7!iX`W(_vRa(-!HqD$Nunf(ftxzE}B$JRD^@Ff~TvW J%Q~loCII^H!+`(* diff --git a/res/drawable/icon_next.png b/res/drawable/icon_next.png index b59d39d6e8eaa634c67923a2a4c6f056ae9e7608..9a92bf46edc917cac219e61b0fd0d4f91e68f333 100644 GIT binary patch delta 775 zcmV+i1Ni*a3ZMo?iBL{Q4GJ0x0000DNk~Le0000j0000e2nGNE0BYBBDF6Tf1ZP1_ zK>z@;j|==^1poj532;bRa{vGh)c^nu)d4-$Sn-oy1So$3oJmAMR9HvN*=J{DiABiWJEO^d>mT@Gg^WUo2qFZj2t&H=xhlR95#k3y2!ue2 zj9%;oiRd?s=URfackayW+&g;*=F{vf&mPV__uR9VW#APAfhD^QBwJE2|1pWLlQ-bJ z#>(zHx~}6fGbDy9JUFph~OCUd8eZA0`MVXBZCSlvsljl#8|IjHUWTn^D|;)s8<7nmyh8-Z&@bI@_ZY(&2e$?@k_ zwYo1UTsxYBI{K)K=yhSL`0Qy?cqV8LZ!fa~qThuq&N1AaTjEAMGc*UeKJ7sC2Qj?% z$VfCt*@T`!bp5W08xYp_2XWw;MtT>N@0&i0@XsL;zZV5>3Yw#Kxv1h+kQD-7OL^v>ce(Jn;)6v9cZB!V{`%~1|vml3@sfUg;gF7&f&2>w%t z#-__ibgs;ui^ z^;zZB<6kp0f$&YNn~YUU}gyL z32_CAOT@3$O5Na9v?HQ&Pio`A?l~70Z@jf}&x8HPpPsw&`p&~o?>_thDjNl(Au#+x zKw>LeXm-g(51-{6bF`xA@5z4-U;5&!O$zwcI^h@W16 zkFE0h_Kiuq_}0!4Z!WR3Sm0-QO;X+Jp^v*?>4TVRy)BQuqV={ujFSE*eIqGFpYKg) n>4mJd!l%;`IQ4S&HD0!Va4Amgyndtr&=U-vu6{1-oD!M<*Fl}T diff --git a/res/drawable/icon_pressed.png b/res/drawable/icon_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..ac1322f9c31b997f08f6560eed76702052d640db GIT binary patch literal 1424 zcmV;B1#kL^P)N2bPDNB8 zb~7$DE-^7j^FlWO00j(5L_t(oN7b2UQxriIMM1%wKuIFzj9D?~Tq>|&`Tzfl_cZTL zJ)7RuFDkQDw`OOi!|6A--|lpejit}V#>Tj`Tbh*iO8cb)(jn=vbW}PfO-aY46Vgm* zR>!#!;=apLkNUJjd$ddY^h1C2OaE}dGoCrS@7#z21$ZzR9E?T_%-Y)8qI60+EuE3h zO6R2W(go>a=#q}Le2;RJrylibhxTZ9F$O%VzNht_{)dBC!248bYISvWR+^ViMx#p! zHiH6qS-K)!9U<;hj`9q`128=8pQ69$mtak=udnZGMqC$nNfUzQ(VS=i6Aee!QSCt0 z@U_r&9j~i?C(c8qObp5cFuWsQqF#YxC2TVRXR$^C#z!+FfQc@h5UCPXg9hZXjyFb# z``rK%ydzKh1f~T(6L#GK4PA{(%PK9Qa#J*&>SPdVTLr#|hp!0DI%Ju!(kHYwf)8f)NX z=VL}^TU;SS=pN8KN;)tw(RE~j1@gJ{q9Lw(5P(05sAq86$K#|$vXdufj&||(SVVcg z5#?+P8nlP$$iPI;urKxf71Dk5nxn7j$bG|8FN0&1;_=ERb+n7Ofv%%$FFVRiJbc%A zI3jFdBAY?qsO;M$&hr2$&p-{HJx)LPJ4d_r_8idusm>WAd)ZOO7TLpeY+#@OeJ8z_ zJ|uC@b?(28$QwL+oc8Nz!{OY$r2FM3zCgFEk-VIvj4kL05A&#P1Au`0D1DMXCvnbo z?q_i7)6QdECp|i&(4W1HMYmZ5==@{SvPS1+H9%UkEnccF&>0xmFQKpLJJ&NfUdQ9M z2^odCVsE!Ba$4m{e+wBpXAP&h+8ShwI?6nHfDHUi-}$V?k#h!OaLU^zjy97LZ?`N` zXORM3r@GqDq`C4VlB{7bGs$@DSO72pfgL1qZg9#`{!Q|>E#e7De>scT*Inw%(Eiyj z(5jeoGtk-3FLZ8eFzFm+f;&+CP3b$wfakiSO?fPZMHqbT>jF*xa7cMFmS0ChZ_6Ab zpi9=!eP;|qv+G;H^JRB=>l0*;)Um(_46d-dxg(QeWN?XUdChpWenbJ}65Hu3OmLRP8WyctZen$EN3Z3HZ%P?$!mFlx!rMD`)fB$X%}reK z%W^Mk(}aH%IPZ}EdVQKLkK?j2Yt&o7u|_=}Het(P82JC#2{17GG28cEbg_WP#GI-k z?i~JC_gwVL%z9m3AtfEN*#F0yMU2iloUGzMR;>-AylKSZN=x3N*tS8$D^#@ab!eXU zVf}?*t_=rnScR + + + + + + \ No newline at end of file diff --git a/res/layout/screen_form_entry.xml b/res/layout/screen_form_entry.xml index 815bd8d..51f110e 100644 --- a/res/layout/screen_form_entry.xml +++ b/res/layout/screen_form_entry.xml @@ -45,7 +45,7 @@ android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_marginRight="5dp" - android:background="@null" + android:background="@drawable/selector_button_press" android:padding="2dp" android:src="@drawable/icon_exit" /> @@ -70,7 +70,7 @@ android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginLeft="5dp" - android:background="@null" + android:background="@drawable/selector_button_press" android:padding="2dp" android:src="@drawable/icon_next" /> diff --git a/res/values/styles.xml b/res/values/styles.xml index 65662e1..1805662 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -26,5 +26,5 @@ the License. badge_circum_outer + badge_offset + border_depth --> 7dp - 8dp + 10dp diff --git a/src/org/odk/collect/android/activities/FormEntryActivity.java b/src/org/odk/collect/android/activities/FormEntryActivity.java index 34fa0f8..42bf145 100644 --- a/src/org/odk/collect/android/activities/FormEntryActivity.java +++ b/src/org/odk/collect/android/activities/FormEntryActivity.java @@ -791,13 +791,15 @@ public void updateNavigationCues() { int answeredOnScreen = 0; int requiredOnScreen = 0; + int relevantAfterCurrentScreen = 0; + boolean onCurrentScreen = false; FormIndex currentScreenExit = null; //TODO: We can probably evaluate this with a FormIndex walk that _doesn't_ //affect this form's index. while (event != FormEntryController.EVENT_END_OF_FORM) { - String toPrint = mFormController.getFormIndex().toString() + " [" + event+ "]"; + //String toPrint = mFormController.getFormIndex().toString() + " [" + event+ "]"; int comparison = mFormController.getFormIndex().compareTo(currentFormIndex); @@ -829,6 +831,10 @@ public void updateNavigationCues() { } } + if(!onCurrentScreen && currentScreenExit != null) { + relevantAfterCurrentScreen += prompts.length; + } + totalQuestions += prompts.length; // Current questions are complete only if they're answered. @@ -865,12 +871,14 @@ else if(event == FormEntryController.EVENT_PROMPT_NEW_REPEAT) { //about it if(currentScreenExit != null) { totalQuestions++; + relevantAfterCurrentScreen++; + } else { //Otherwise we already passed it and it no longer affects the count } } - System.out.println(toPrint + ": (" + completedQuestions + " / " + totalQuestions + ")"); + //System.out.println(toPrint + ": (" + completedQuestions + " / " + totalQuestions + ")"); event = mFormController.stepToNextEvent(false); @@ -895,7 +903,7 @@ else if(event == FormEntryController.EVENT_PROMPT_NEW_REPEAT) { //is to invalidate the view, though. Rect bounds = progressBar.getProgressDrawable().getBounds(); //Save the drawable bound - if(totalQuestions == completedQuestions) { + if(relevantAfterCurrentScreen == 0 && (requiredOnScreen == answeredOnScreen || requiredOnScreen < 1)) { nextButton.setImageResource(R.drawable.icon_done); //TODO: _really_? This doesn't seem right @@ -1483,7 +1491,7 @@ private void showPreviousView() { //check if we're at the beginning and not doing the whole "First screen" thing if(event == FormEntryController.EVENT_BEGINNING_OF_FORM && - !PreferenceManager.getDefaultSharedPreferences(this).getBoolean(PreferencesActivity.KEY_SHOW_START_SCREEN, true)) { + !PreferenceManager.getDefaultSharedPreferences(this).getBoolean(PreferencesActivity.KEY_SHOW_START_SCREEN, false)) { //If so, we can't go all the way back here, so we've gotta hit the last index that was valid mFormController.jumpToIndex(lastValidIndex); From 0b5051fef9ffe2c7dce760a716e035b0108c5b9d Mon Sep 17 00:00:00 2001 From: Clayton Sims Date: Tue, 2 Sep 2014 11:00:47 -0400 Subject: [PATCH 09/17] Updated repeat dialog to understand the status of the form to know whether it will exit the form if conditional repeats are followed --- res/drawable/icon_new.png | Bin 0 -> 309 bytes res/layout/component_repeat_new_dialog.xml | 51 +++++ res/values/strings.xml | 3 + res/values/styles.xml | 4 +- .../android/activities/FormEntryActivity.java | 214 ++++++++++++------ 5 files changed, 204 insertions(+), 68 deletions(-) create mode 100644 res/drawable/icon_new.png create mode 100644 res/layout/component_repeat_new_dialog.xml diff --git a/res/drawable/icon_new.png b/res/drawable/icon_new.png new file mode 100644 index 0000000000000000000000000000000000000000..fb3bdd0f6e7cfcffa81cdec633828131905e8e15 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^x(m{oJAo(Rp7Ff zf9B2e8s}q`cZ=J&JQVpmb-4oXOD@JYjkX)yo%yHms`cnT+xJ*9yG~#FaH?d!`k}3w zpZ1hzZm{8=)R($UckYSc@8=h_e<}GHa%t}T(%Lz4QuP + + +