From 2c84ec07cd17daa7a869edd289a173514fd3f58c Mon Sep 17 00:00:00 2001 From: simonpoole Date: Mon, 25 Nov 2024 12:35:51 +0100 Subject: [PATCH] Fix regression where changes in OH mode wouldn't update the value And some code cleanup and simplifications. --- .github/workflows/android.yml | 2 +- README.md | 2 +- build.gradle | 1 + lib/build.gradle | 2 +- .../DefaultTextWatcher.java | 15 ++ .../OpeningHoursFragment.java | 164 +++++++++--------- 6 files changed, 102 insertions(+), 84 deletions(-) create mode 100644 lib/src/main/java/ch/poole/openinghoursfragment/DefaultTextWatcher.java diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 9be433a..6b7021a 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -42,7 +42,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: Test output - path: /Users/runner/work/OpeningHoursFragment/OpeningHoursFragment/lib/build/reports/androidTests/connected/flavors/debugAndroidTest + path: /Users/runner/work/OpeningHoursFragment/OpeningHoursFragment/lib/build/reports/androidTests/connected - name: Generate coverage report run: ./gradlew jacocoTestReport - name: SonarCloud Scan diff --git a/README.md b/README.md index 6b3dbef..ffd67a9 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,6 @@ repositories { ``` groovy dependencies { - compile "ch.poole:OpeningHoursFragment:0.13.5" + compile "ch.poole:OpeningHoursFragment:0.14.1" } ``` diff --git a/build.gradle b/build.gradle index bc3e8d2..858bd63 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,7 @@ buildscript { mavenCentral() maven { url "https://maven.google.com" } google() + mavenLocal() } dependencies { classpath 'com.android.tools.build:gradle:7.0.2' diff --git a/lib/build.gradle b/lib/build.gradle index f30e6ea..fdfdd50 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -22,7 +22,7 @@ apply plugin: 'signing' apply plugin: "jacoco" apply plugin: "com.github.breadmoirai.github-release" -version = '0.14.0' +version = '0.14.1' def libName = "OpeningHoursFragment" task updateTranslations(type: Exec) { diff --git a/lib/src/main/java/ch/poole/openinghoursfragment/DefaultTextWatcher.java b/lib/src/main/java/ch/poole/openinghoursfragment/DefaultTextWatcher.java new file mode 100644 index 0000000..3706d03 --- /dev/null +++ b/lib/src/main/java/ch/poole/openinghoursfragment/DefaultTextWatcher.java @@ -0,0 +1,15 @@ +package ch.poole.openinghoursfragment; + +import android.text.TextWatcher; + +abstract class DefaultTextWatcher implements TextWatcher { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // empty + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // empty + } +} \ No newline at end of file diff --git a/lib/src/main/java/ch/poole/openinghoursfragment/OpeningHoursFragment.java b/lib/src/main/java/ch/poole/openinghoursfragment/OpeningHoursFragment.java index c438faf..1be216c 100644 --- a/lib/src/main/java/ch/poole/openinghoursfragment/OpeningHoursFragment.java +++ b/lib/src/main/java/ch/poole/openinghoursfragment/OpeningHoursFragment.java @@ -20,7 +20,6 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; -import android.text.TextWatcher; import android.text.style.ForegroundColorSpan; import android.util.Log; import android.util.TypedValue; @@ -391,7 +390,6 @@ public void onCreate(Bundle savedInstanceState) { @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { Dialog dialog = super.onCreateDialog(savedInstanceState); - // request a window without the title dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); return dialog; @@ -405,27 +403,11 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa int initialRule = -1; if (savedInstanceState != null) { Log.d(DEBUG_TAG, "Restoring from saved state"); - key = (ValueWithDescription) savedInstanceState.getSerializable(KEY_KEY); - region = savedInstanceState.getString(REGION_KEY); - object = savedInstanceState.getString(OBJECT_KEY); - openingHoursValue = savedInstanceState.getString(VALUE_KEY); - originalOpeningHoursValue = savedInstanceState.getString(ORIGINAL_VALUE_KEY); - styleRes = savedInstanceState.getInt(STYLE_KEY); - useFragmentCallback = savedInstanceState.getBoolean(FRAGMENT_KEY); - textValues = (List) savedInstanceState.getSerializable(TEXTVALUES_KEY); - locale = (Locale) savedInstanceState.getSerializable(LOCALE_KEY); + getStateFromBundle(savedInstanceState); } else { - key = (ValueWithDescription) getArguments().getSerializable(KEY_KEY); - region = getArguments().getString(REGION_KEY); - object = getArguments().getString(OBJECT_KEY); - openingHoursValue = getArguments().getString(VALUE_KEY); - originalOpeningHoursValue = openingHoursValue; - styleRes = getArguments().getInt(STYLE_KEY); + getStateFromBundle(getArguments()); initialRule = getArguments().getInt(RULE_KEY); showTemplates = getArguments().getBoolean(SHOWTEMPLATES_KEY); - useFragmentCallback = getArguments().getBoolean(FRAGMENT_KEY); - textValues = (List) getArguments().getSerializable(TEXTVALUES_KEY); - locale = (Locale) getArguments().getSerializable(LOCALE_KEY); } if (styleRes == 0) { styleRes = R.style.AlertDialog_AppCompat_Light; // fallback @@ -443,6 +425,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa final LinearLayout openingHoursLayout = (LinearLayout) inflater.inflate(R.layout.openinghours, null); final ScrollView sv = (ScrollView) openingHoursLayout.findViewById(R.id.openinghours_view); + text = (AutoCompleteTextView) openingHoursLayout.findViewById(R.id.openinghours_string_edit); watcher = new OhTextWatcher(sv); textWatcher = new TextTextWatcher(); rebuilder = new Rebuilder(sv); @@ -450,53 +433,51 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // set parser locale singleton I18n.setLocale(locale != null ? locale : Locale.getDefault()); - // check if this is a mixed value tag - final LinearLayout modeContainer = (LinearLayout) openingHoursLayout.findViewById(R.id.modeContainer); + final View modeContainer = openingHoursLayout.findViewById(R.id.modeContainer); headerLine = openingHoursLayout.findViewById(R.id.headerLine); errorMessages = (LinearLayout) openingHoursLayout.findViewById(R.id.openinghours_error_messages); - if (textValues != null) { + + // check if this is a mixed value tag + final boolean hasTextValues = textValues != null; + textMode = hasTextValues + && (textValues.contains(new ValueWithDescription(openingHoursValue, null)) || openingHoursValue == null || "".equals(openingHoursValue)); + buildLayout(openingHoursLayout, openingHoursValue == null ? "" : openingHoursValue, initialRule); + if (hasTextValues) { final RadioGroup modeGroup = (RadioGroup) openingHoursLayout.findViewById(R.id.modeGroup); final RadioButton useOH = (RadioButton) modeGroup.findViewById(R.id.use_oh); final RadioButton useText = (RadioButton) modeGroup.findViewById(R.id.use_text); - if (textValues.contains(new ValueWithDescription(openingHoursValue, null)) || openingHoursValue == null || "".equals(openingHoursValue)) { + if (textMode) { useText.setChecked(true); - textMode = true; - headerLine.setVisibility(View.VISIBLE); + setUpTextMode(); } else { useOH.setChecked(true); - headerLine.setVisibility(View.GONE); + rebuilder.rebuild(); } modeGroup.setOnCheckedChangeListener((group, checkedId) -> { openingHoursValue = text.getText().toString(); - text.removeTextChangedListener(watcher); - text.removeTextChangedListener(textWatcher); - text.removeCallbacks(updateStringRunnable); - text.setOnEditorActionListener(null); removeHighlight(text); errorMessages.removeAllViews(); - final FloatingActionButton fab = (FloatingActionButton) openingHoursLayout.findViewById(R.id.more); + final View fab = openingHoursLayout.findViewById(R.id.more); if (checkedId == useText.getId()) { + textMode = true; buildLayout(openingHoursLayout, openingHoursValue, -1); fab.setVisibility(View.GONE); - headerLine.setVisibility(View.VISIBLE); + setUpTextMode(); } else if (checkedId == useOH.getId()) { + textMode = false; text.setText(openingHoursValue); - text.setOnEditorActionListener(editorActionListener); - text.addTextChangedListener(watcher); rebuilder.rebuild(); fab.setVisibility(View.VISIBLE); - headerLine.setVisibility(View.GONE); + setUpOHMode(); } }); modeContainer.setVisibility(View.VISIBLE); } else { modeContainer.setVisibility(View.GONE); - headerLine.setVisibility(View.GONE); } - buildLayout(openingHoursLayout, openingHoursValue == null ? "" : openingHoursValue, initialRule); // add callbacks for the buttons - AppCompatButton cancel = (AppCompatButton) openingHoursLayout.findViewById(R.id.cancel); + View cancel = openingHoursLayout.findViewById(R.id.cancel); cancel.setOnClickListener(v -> dismiss()); Object listener = null; @@ -526,6 +507,49 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa return openingHoursLayout; } + /** + * Get state/arguments from a bundle + * + * @param bundle the Bundle + */ + private void getStateFromBundle(@NonNull Bundle bundle) { + key = (ValueWithDescription) bundle.getSerializable(KEY_KEY); + region = bundle.getString(REGION_KEY); + object = bundle.getString(OBJECT_KEY); + openingHoursValue = bundle.getString(VALUE_KEY); + originalOpeningHoursValue = bundle.getString(ORIGINAL_VALUE_KEY); + styleRes = bundle.getInt(STYLE_KEY); + useFragmentCallback = bundle.getBoolean(FRAGMENT_KEY); + textValues = (List) bundle.getSerializable(TEXTVALUES_KEY); + locale = (Locale) bundle.getSerializable(LOCALE_KEY); + } + + /** + * Setup listeners for text mode + */ + private void setUpTextMode() { + text.removeCallbacks(updateStringRunnable); + headerLine.setVisibility(View.VISIBLE); + text.setOnEditorActionListener(null); + text.removeTextChangedListener(watcher); + text.removeTextChangedListener(textWatcher); + text.addTextChangedListener(textWatcher); + } + + /** + * Setup listeners for OH mode + */ + private void setUpOHMode() { + text.removeCallbacks(updateStringRunnable); + text.setAdapter(null); + text.setOnClickListener(null); + headerLine.setVisibility(View.GONE); + text.setOnEditorActionListener(editorActionListener); + text.removeTextChangedListener(watcher); + text.removeTextChangedListener(textWatcher); + text.addTextChangedListener(watcher); + } + /** * Try to locate a reasonable default value */ @@ -549,18 +573,6 @@ public void onStart() { } } - private abstract class DefaultTextWatcher implements TextWatcher { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // empty - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - // empty - } - } - /** * Enable the save button if the text has changed * @@ -637,8 +649,12 @@ private class Rebuilder { this.scrollView = scrollView; } + /** + * Actually rebuild + */ private void rebuild() { Runnable rebuildRunnable = () -> { + System.out.println("rebuild"); text.removeTextChangedListener(watcher); OpeningHoursParser parser = new OpeningHoursParser(new ByteArrayInputStream(text.getText().toString().getBytes())); try { @@ -660,6 +676,11 @@ private void rebuild() { } } + /** + * Display any parse errors + * + * @param pex a parse exceptions + */ private void displayParseErrors(@NonNull OpeningHoursParseException pex) { Log.d(DEBUG_TAG, pex.getMessage()); highlightParseError(text, pex); @@ -699,7 +720,6 @@ private void displayParseErrors(@NonNull OpeningHoursParseException pex) { */ @Nullable private ScrollView buildLayout(final @NonNull LinearLayout openingHoursLayout, @NonNull String openingHoursValue, final int initialRule) { - text = (AutoCompleteTextView) openingHoursLayout.findViewById(R.id.openinghours_string_edit); if (text != null) { String keyDescription = key.getDescription(); if (keyDescription != null && !"".equals(keyDescription)) { @@ -714,8 +734,7 @@ private ScrollView buildLayout(final @NonNull LinearLayout openingHoursLayout, @ if (textValues != null) { final RadioGroup modeGroup = (RadioGroup) openingHoursLayout.findViewById(R.id.modeGroup); final RadioButton useText = (RadioButton) modeGroup.findViewById(R.id.use_text); - if (useText.isChecked()) { - text.removeCallbacks(updateStringRunnable); + if (textMode) { ValueArrayAdapter adapter = new ValueArrayAdapter(getContext(), android.R.layout.simple_spinner_item, textValues); text.setAdapter(adapter); text.setOnClickListener(autocompleteOnClick); @@ -727,23 +746,14 @@ private ScrollView buildLayout(final @NonNull LinearLayout openingHoursLayout, @ text.setText((String) o); } }); - text.setText(openingHoursValue); - text.setOnEditorActionListener(null); - text.removeTextChangedListener(textWatcher); - text.addTextChangedListener(textWatcher); + setUpTextMode(); fab.setVisibility(View.GONE); setupFab(sv, fab); - headerLine.setVisibility(View.VISIBLE); - textMode = true; return sv; } else { - text.setOnEditorActionListener(editorActionListener); - text.removeTextChangedListener(watcher); - text.addTextChangedListener(watcher); - text.setAdapter(null); - text.setOnClickListener(null); - textMode = false; + System.out.println("build layout mixed OH"); + setUpOHMode(); if ("".equals(openingHoursValue)) { if (!showTemplates) { loadDefault(); @@ -755,15 +765,13 @@ private ScrollView buildLayout(final @NonNull LinearLayout openingHoursLayout, @ TemplateMangementDialog.showDialog(this, false, key, null, null, text.getText().toString()); } } - headerLine.setVisibility(View.GONE); } } else { - text.setOnEditorActionListener(editorActionListener); - text.removeTextChangedListener(watcher); - text.addTextChangedListener(watcher); + System.out.println("build layout OH"); + setUpOHMode(); } + textMode = false; text.setText(openingHoursValue); - text.removeTextChangedListener(textWatcher); fab.setVisibility(View.VISIBLE); OpeningHoursParser parser = new OpeningHoursParser(new ByteArrayInputStream(openingHoursValue.getBytes())); @@ -2563,16 +2571,7 @@ private boolean justOneDay(@NonNull List ranges) { * @param listener listener to call when afterTextChanged is called */ private void setTextWatcher(@NonNull final EditText edit, @NonNull final SetValue listener) { - edit.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // Empty - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - // Empty - } + edit.addTextChangedListener(new DefaultTextWatcher() { @Override public void afterTextChanged(Editable s) { @@ -3106,11 +3105,13 @@ private Menu addStandardMenuItems(@NonNull LinearLayout row, @Nullable final Del * Runnable that updates the OH string */ Runnable updateStringRunnable = () -> { + System.out.println("updateString"); if (rules != null) { text.removeTextChangedListener(watcher); int pos = text.getSelectionStart(); int prevLen = text.length(); String oh = ch.poole.openinghoursparser.Util.rulesToOpeningHoursString(rules); + System.out.println("updateString oh " + oh); text.setText(oh); text.setSelection(prevLen < text.length() ? text.length() : Math.min(pos, text.length())); enableSaveButton(oh); @@ -3162,6 +3163,7 @@ private void checkNth(@NonNull RelativeLayout container, int nth) { private void setWeekDayListeners(@NonNull final RelativeLayout container, @NonNull final List days, @NonNull final List inContainer, final boolean justOne, @NonNull final MenuItem nthMenuItem) { OnCheckedChangeListener listener = (buttonView, isChecked) -> { + System.out.println("weekday listener"); if (justOne) { // Nth exists if (isChecked) { WeekDayRange range = inContainer.get(0);