Skip to content

Replace ViewPager2 with Native Morphing Carousel & Refine Touch Feedback - #20

Merged
Dhangofa merged 7 commits into
mainfrom
remove-viewpager2
Aug 18, 2026
Merged

Replace ViewPager2 with Native Morphing Carousel & Refine Touch Feedback#20
Dhangofa merged 7 commits into
mainfrom
remove-viewpager2

Conversation

@Dhangofa

Copy link
Copy Markdown
Owner

🚀 Overview

This PR significantly reduces the application's UI bloat and dependency footprint by entirely ripping out the heavyweight ViewPager2 library. In its place, we have implemented an ultra-lightweight, custom "Morphing View" container built entirely on native Android views and animation APIs.

Additionally, this PR meticulously polishes the touch feedback (ripples) across the UI, ensuring all click animations perfectly respect the custom border radiuses of their respective components without any square edge bleeding.

✨ Key Features & Improvements

🏗️ Architecture & Dependency Reduction

  • Removed ViewPager2: Dropped the androidx.viewpager2:viewpager2 library dependency, reducing the APK size and memory footprint.
  • Flattened Layout Hierarchy: Replaced complex ViewPager2 and TabLayout nodes with a single, unified LinearLayout container in both portrait and landscape configurations.
  • Deleted Boilerplate: Removed CarouselAdapter.java and item_carousel.xml. Data binding is now handled natively and directly within MainActivity.

🎨 Premium Morphing Animations

  • Color Interpolation: Integrated ArgbEvaluator to mathematically and smoothly transition the background color between carousel states.
  • Physics-Based Sliding: Implemented ViewPropertyAnimator to handle directional slide-out and slide-in animations for internal content (titles, text, and icons) mimicking a physical swipe.

🧠 Smart Auto-Cycling & Lifecycle Management

  • Intelligent Timer: Built a smart auto-cycling timer (Handler/Runnable) that cycles pages every 5 seconds.
  • Interrupt Handling: Added touch listeners to detect manual user swipes. If a user interacts with the carousel, the auto-cycler pauses to let them read, automatically resuming after 10 seconds of inactivity.
  • Lifecycle Awareness: Added onResume() and onPause() hooks to completely pause the timer and free resources when the app is backgrounded.
  • State Binding: Carousel navigation is now dynamically locked to the first setup page when unauthorized, and smoothly cycles through features when Shizuku/Root is authorized.

👆 Touch Feedback & Ripple Polish

  • Custom Pill Ripple Masking: Created a strict 20dp corner radius bounding mask (ripple_pill_mask.xml). Applied this to the Carousel "Read Guide" button so the dynamically tinted click feedback perfectly respects the pill shape.
  • Restored Native Social Ripples: Removed experimental foreground overlays from the Footer Social Links (GitHub, Telegram, FAQ), allowing them to correctly utilize their native 12dp rounded background ripples.

🗑️ Removed Files

  • app/src/main/java/com/dhangofa/networktoggle/CarouselAdapter.java
  • app/src/main/res/layout/item_carousel.xml

- Removed ViewPager2 & TabLayout: Completely excised the heavyweight androidx.viewpager2.widget.ViewPager2 and TabLayout nodes from the layout hierarchy, significantly reducing structural depth and UI bloat.
- Implemented Native Morphing Container: Introduced a custom, native LinearLayout structure with internal TextView and ImageView components (carouselTitle, carouselDesc, carouselButton, carouselIcon) to act as a unified, single-layer morphing canvas.
- Added Custom Pill Ripple Masking: Added android:foreground="@drawable/ripple_pill_mask" to the Carousel "Read Guide" button to ensure its dynamically tinted click feedback perfectly respects the 20dp pill-shaped bounding box without square edge bleeding.
- Restored Native Social Ripples: Removed experimental foreground overlays from the Footer Social Links (GitHub, Telegram, FAQ), allowing them to correctly utilize their native 12dp rounded background ripples.
- Removed ViewPager2 & TabLayout: Deleted the ViewPager2 and TabLayout definitions from the landscape layout configuration to ensure consistency with the portrait architecture.
- Implemented Native Morphing Container: Replicated the new custom LinearLayout morphing structure (containing the title, description, button, and icon elements) to maintain the lightweight UI approach in landscape.
- Added Custom Pill Ripple Masking: Applied android:foreground="@drawable/ripple_pill_mask" to the Carousel action button to enforce perfect pill-shaped touch boundaries.
- Restored Native Social Ripples: Removed experimental rectangular foreground overrides on the social links, allowing their native, perfectly clipped rounded-corner ripples to function as intended.
- Created a new XML ripple drawable containing a strict 20dp corner radius bounding mask.
- Ensures that interactive foreground touch feedback accurately conforms to the rounded bounds of pill-shaped buttons instead of bleeding into the default rectangular bounds.
- Deleted item_carousel.xml from the resource directory.
- The layout structure for individual pages has been integrated directly into activity_main.xml to facilitate the morphing animations, making this separate file obsolete.
- Removed the androidx.viewpager2:viewpager2 dependency from the build configuration.
- Eliminated unnecessary library bloat, ensuring the application remains as lightweight as possible.
- Deleted CarouselAdapter.java from the codebase entirely.
- Removed the RecyclerView.Adapter implementation, as data binding is now handled directly by MainActivity within the native view architecture.
- Removed all ViewPager2 initialization logic, page change callbacks, and adapter binding code.
- Implemented setupCarousel() and renderCarouselPage() to natively bind data and construct the UI.
- Integrated ArgbEvaluator to mathematically transition the background color between states.
- Implemented ViewPropertyAnimator to handle directional slide-out and slide-in physical animations for the internal content.
- Built a smart auto-cycling timer using Handler and Runnable that cycles every 5 seconds.
- Implemented touch listeners to detect manual user swipes, pausing the auto-cycler and resuming it after 10 seconds of inactivity.
- Connected the carousel state to updateAuthorizationUI(), dynamically locking to the first page when unauthorized, and cycling the setup steps when authorized.
- Added onResume() and onPause() lifecycle hooks to automatically pause the timer when the app is in the background.
@Dhangofa
Dhangofa merged commit dfa0cd1 into main Aug 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant