From 1a830cf7d2b8292642fbe084be98cc9553d37f76 Mon Sep 17 00:00:00 2001 From: Adrian Torchiana Date: Sat, 2 Nov 2024 22:04:40 -0700 Subject: [PATCH 1/3] Switch to ViewPager2 (got a deprecation waring for ViewPager) --- app/build.gradle | 1 + .../java/atorch/statspuzzles/SolvePuzzle.java | 49 ++++++++++--------- .../main/res/layout/activity_solve_puzzle.xml | 4 +- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9dc316f..e8d965e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,6 +31,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.navigation:navigation-fragment:2.0.0' implementation 'androidx.navigation:navigation-ui:2.0.0' + implementation 'androidx.viewpager2:viewpager2:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java b/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java index 31de24f..196981a 100644 --- a/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java +++ b/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java @@ -21,14 +21,15 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.ShareActionProvider; import androidx.core.view.MenuItemCompat; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; -import androidx.viewpager.widget.ViewPager; import org.mariuszgromada.math.mxparser.Expression; @@ -36,6 +37,10 @@ import java.math.RoundingMode; import java.util.Random; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; + + public class SolvePuzzle extends AppCompatActivity { // Following example at https://developer.android.com/training/sharing/shareaction.html private ShareActionProvider mShareActionProvider; @@ -44,7 +49,8 @@ public class SolvePuzzle extends AppCompatActivity { public static final String LEVEL = "atorch.statspuzzles.LEVEL"; private static final int roundingScale = 4; - private ViewPager puzzlePager; // Displays puzzles one at a time + // Displays puzzles one at a time + private ViewPager2 puzzlePager; private int level; @@ -64,18 +70,14 @@ public void onCreate(Bundle savedInstanceState) { level = intent.getIntExtra(PuzzleSelection.LEVEL, 0); } - FragmentManager fragmentManager = getSupportFragmentManager(); - res = new Res(getResources()); puzzlePager = findViewById(R.id.pager); - puzzlePager.setAdapter(new AppSectionsPagerAdapter(fragmentManager, level, res)); + puzzlePager.setAdapter(new AppSectionsPagerAdapter(this, level, res)); - puzzlePager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override public void onPageScrollStateChanged(int arg0) { - } - @Override public void onPageScrolled(int arg0, float arg1, int arg2) { - } - @Override public void onPageSelected(int puzzleIndex) { + puzzlePager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int puzzleIndex) { + super.onPageSelected(puzzleIndex); prepareSharePuzzle(res.getPuzzle(level, puzzleIndex)); } }); @@ -209,30 +211,32 @@ String getFirstCongratulation(int level) { } } - public static class AppSectionsPagerAdapter extends FragmentPagerAdapter { + // TODO FragmentPagerAdapter is deprecated + public static class AppSectionsPagerAdapter extends FragmentStateAdapter { private final int level; private final Res res; - public AppSectionsPagerAdapter(FragmentManager fm, int level, Res res) { - super(fm); + public AppSectionsPagerAdapter(@NonNull FragmentActivity fa, int level, Res res) { + super(fa); this.level = level; this.res = res; } + @NonNull @Override - public Fragment getItem(int puzzleIndex) { + public Fragment createFragment(int puzzleIndex) { Fragment fragment = new SolvePuzzleFragment(); Bundle args = new Bundle(); args.putInt(LEVEL, level); args.putInt(PUZZLE_INDEX, puzzleIndex); - fragment.setArguments(args); return fragment; } + @Override - public int getCount() { + public int getItemCount() { return res.getPuzzleCount(level); } } @@ -242,7 +246,7 @@ public static class SolvePuzzleFragment extends Fragment { private int level; private int puzzleIndex; private double correctAnswer; - private ViewPager mViewPager; + private ViewPager2 mViewPager; private Res res; @Override @@ -335,7 +339,8 @@ private void onSubmit(View view) { Expression answerExpression = new Expression(answerString); double answer = answerExpression.calculate(); if (!answerExpression.checkSyntax()) { - openTroubleParsingDialog(view); // TODO Don't show if user answer is empty string? + // TODO Don't show if user answer is empty string? + openTroubleParsingDialog(); hadTroubleParsing = true; } if (!Double.isNaN(answer) && !Double.isInfinite(answer)) { @@ -349,13 +354,13 @@ private void onSubmit(View view) { if (!Double.isNaN(answer) && Math.abs(answer - correctAnswer) < 0.00001) { openCongratulationsAlert(view); } else if (!Double.isNaN(answer) && Math.abs(answer - correctAnswer) < 0.001) { - openAccuracyAlert(view); + openAccuracyAlert(); } else if (!hadTroubleParsing) { openIncorrectAnswerToast(); // User answer could parse to NaN } } - public void openTroubleParsingDialog(View view) { + public void openTroubleParsingDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage(getString(R.string.trouble_parsing_answer)); builder.setCancelable(true); @@ -443,7 +448,7 @@ public void openIncorrectAnswerToast() { Toast.makeText(context, res.getRandomIncorrect(), Toast.LENGTH_LONG).show(); } - public void openAccuracyAlert(View view) { + public void openAccuracyAlert() { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage(getString(R.string.accuracy)); builder.setCancelable(true); diff --git a/app/src/main/res/layout/activity_solve_puzzle.xml b/app/src/main/res/layout/activity_solve_puzzle.xml index 75dc9aa..bc52c22 100644 --- a/app/src/main/res/layout/activity_solve_puzzle.xml +++ b/app/src/main/res/layout/activity_solve_puzzle.xml @@ -1,8 +1,8 @@ - - \ No newline at end of file + \ No newline at end of file From 508d0df309628183294dd806c2164e604d0167f0 Mon Sep 17 00:00:00 2001 From: Adrian Torchiana Date: Tue, 26 Aug 2025 22:08:40 -0700 Subject: [PATCH 2/3] feat(test): Add swipe test for puzzles Adds a new instrumented test to verify that swiping horizontally navigates to the next puzzle. The test is configured to run on puzzle level 1 to increase test coverage across different puzzle levels. --- .../atorch/statspuzzles/PuzzleSelectionTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/androidTest/java/atorch/statspuzzles/PuzzleSelectionTest.java b/app/src/androidTest/java/atorch/statspuzzles/PuzzleSelectionTest.java index 785f739..82adc28 100644 --- a/app/src/androidTest/java/atorch/statspuzzles/PuzzleSelectionTest.java +++ b/app/src/androidTest/java/atorch/statspuzzles/PuzzleSelectionTest.java @@ -8,6 +8,7 @@ import androidx.test.espresso.assertion.ViewAssertions; import androidx.test.espresso.matcher.ViewMatchers; import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.swipeLeft; import org.junit.Rule; import org.junit.Test; @@ -34,4 +35,15 @@ public void easyPuzzlesButton_loadsEasyPuzzles() { Espresso.onView(ViewMatchers.withText(context.getString(R.string.puzzle, 1))) .check(ViewAssertions.matches(ViewMatchers.isDisplayed())); } + + @Test + public void swipeHorizontally_showsNextPuzzle() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + Espresso.onView(ViewMatchers.withText(context.getString(R.string.button_level_1))).perform(click()); + Espresso.onView(ViewMatchers.withText(context.getString(R.string.puzzle, 1))) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())); + Espresso.onView(ViewMatchers.withId(R.id.pager)).perform(swipeLeft()); + Espresso.onView(ViewMatchers.withText(context.getString(R.string.puzzle, 2))) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())); + } } From 1af4f6b5b650d12637ea50c6c4ec949edfd6f101 Mon Sep 17 00:00:00 2001 From: Adrian Torchiana Date: Tue, 26 Aug 2025 22:28:06 -0700 Subject: [PATCH 3/3] Refactor: Update dependencies and address code suggestions - Updates the androidx.viewpager2:viewpager2 dependency from 1.0.0 to 1.1.0. - Increases the minSdkVersion from 16 to 19 to support the updated ViewPager2 library. - Removes an obsolete TODO comment regarding FragmentPagerAdapter. - Refactors the mViewPager field in SolvePuzzleFragment to be a local variable, improving encapsulation. --- app/build.gradle | 4 ++-- app/src/main/java/atorch/statspuzzles/SolvePuzzle.java | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 01e6a27..360e7c4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ android { defaultConfig { applicationId "atorch.statspuzzles" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 34 versionCode 32 versionName "4.0" @@ -35,7 +35,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.navigation:navigation-fragment:2.5.3' implementation 'androidx.navigation:navigation-ui:2.5.3' - implementation 'androidx.viewpager2:viewpager2:1.0.0' + implementation 'androidx.viewpager2:viewpager2:1.1.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java b/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java index c383436..50b412c 100644 --- a/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java +++ b/app/src/main/java/atorch/statspuzzles/SolvePuzzle.java @@ -211,7 +211,6 @@ String getFirstCongratulation(int level) { } } - // TODO FragmentPagerAdapter is deprecated public static class AppSectionsPagerAdapter extends FragmentStateAdapter { private final int level; @@ -245,7 +244,6 @@ public static class SolvePuzzleFragment extends Fragment { private int level; private int puzzleIndex; - private ViewPager2 mViewPager; private Res res; @Override @@ -398,7 +396,7 @@ public void openCongratulationsAlert(View view) { editor.commit(); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - mViewPager = view.getRootView().findViewById(R.id.pager); + ViewPager2 viewPager = view.getRootView().findViewById(R.id.pager); int nPuzzles = res.getPuzzleCount(level); boolean solvedAllPuzzles = puzzles_solved >= nPuzzles; @@ -411,7 +409,7 @@ public void openCongratulationsAlert(View view) { if (next_puzzleIndex >= nPuzzles) { next_puzzleIndex = 0; } - mViewPager.setCurrentItem(next_puzzleIndex); + viewPager.setCurrentItem(next_puzzleIndex); dialog.cancel(); } );