Skip to content

Ux updates - #36

Merged
khlebobul merged 3 commits into
mainfrom
ux_updates
Jul 11, 2026
Merged

khlebobul merged 3 commits into
mainfrom
ux_updates

Conversation

@khlebobul

@khlebobul khlebobul commented Jul 11, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added subtle fading edges to scrollable content.
    • Added spring-style press animations to buttons, menus, level tiles, and game controls.
  • Bug Fixes

    • Improved app bar appearance by preventing unwanted tinting and elevation while scrolling.
  • Technical Improvements

    • Updated Android and iOS build tooling.
    • iOS now requires version 15 or later.
    • Improved level discovery and validation during testing.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Release, platform, and interface updates

Layer / File(s) Summary
Release metadata and build tooling
CHANGELOG.md, README.md, analysis_options.yaml, android/..., pubspec.yaml
Updates version 1.11.2, dependencies, analyzer exclusions, Android Gradle settings, and release documentation.
iOS Swift Package Manager migration
ios/Flutter/..., ios/Runner.xcodeproj/..., ios/Runner.xcworkspace/...
Removes CocoaPods references, updates Flutter Swift package references, raises the iOS deployment target to 15.0, and updates build versions.
Riverpod generated lifecycle updates
lib/presentation/providers/**/*.g.dart
Regenerates provider instances and changes notifier initialization to return WhenComplete through handleCreate.
Press and scroll-edge widget implementation
lib/presentation/widgets/common/..., lib/presentation/widgets/game/game_bottom_bar.dart
Adds animated Pressable and scroll-aware Edgy widgets and applies them to app-bar and game controls.
Screen integration and asset discovery
lib/presentation/screens/..., test/levels_*_test.dart
Uses the new widgets across screens and updates level tests to discover assets through AssetManifest.listAssets().
Estimated code review effort: 4 (Complex) ~45 minutes

Possibly related PRs

Suggested labels: feature

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided, so the required checklist section is missing. Add the template checklist and mark the appropriate change type: bugfix, new lvl, new feature, or other.
Title check ❓ Inconclusive The title is too vague and generic to describe the main change in the pull request. Use a specific title that names the primary update, such as the new UI widgets and iOS/Android build changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ux_updates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@khlebobul
khlebobul merged commit a6b9248 into main Jul 11, 2026
1 of 2 checks passed
@khlebobul
khlebobul deleted the ux_updates branch July 11, 2026 06:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
test/levels_uniqueness_test.dart (1)

11-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract duplicated asset discovery logic into a shared test helper.

The AssetManifest.loadFromAssetBundle + listAssets() filtering and level ID extraction pattern appears 3 times across both test files (levels_solvability_test.dart lines 11-24, and here at lines 11-25 and 88-93). Extracting this into a shared helper (e.g., loadLevelIds() in a test_helpers.dart file) would eliminate duplication and ensure consistent asset discovery if the path convention changes.

♻️ Suggested shared helper
// test/test_helpers.dart
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

Future<List<String>> loadLevelIds() async {
  final manifest = await AssetManifest.loadFromAssetBundle(rootBundle);
  final levelPaths = manifest
      .listAssets()
      .where((String key) => key.contains('lib/data/levels/level_'))
      .toList();

  final levelIds = levelPaths.map((path) {
    return path
        .split('/')
        .last
        .replaceAll('level_', '')
        .replaceAll('.json', '');
  }).toList();

  levelIds.sort((a, b) {
    final aNum = double.tryParse(a) ?? 0;
    final bNum = double.tryParse(b) ?? 0;
    return aNum.compareTo(bNum);
  });

  return levelIds;
}

Future<List<String>> loadLevelPaths() async {
  final manifest = await AssetManifest.loadFromAssetBundle(rootBundle);
  return manifest
      .listAssets()
      .where((String key) => key.contains('lib/data/levels/level_'))
      .toList();
}

Also applies to: 88-93

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/levels_uniqueness_test.dart` around lines 11 - 25, Extract the
duplicated manifest asset filtering and level ID parsing from the affected tests
and levels_solvability_test.dart into shared helpers such as loadLevelIds() and
loadLevelPaths() in test_helpers.dart. Update all three call sites, including
the logic around the levelPaths and levelIds declarations, to use these helpers
and preserve the existing sorting and assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/Runner.xcodeproj/project.pbxproj`:
- Around line 480-481: Replace the invalid AppIcon value assigned to
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS in the Debug and
Release build configurations with the boolean value YES, matching the existing
Profile configuration. Keep ASSETCATALOG_COMPILER_APPICON_NAME set to AppIcon.

In `@lib/presentation/screens/home/side_menu_screen.dart`:
- Around line 77-88: Increase the Pressable touch target in the side-menu item
builder by enforcing a minimum height of at least 48px while preserving the
existing padding and alignment; update the widget containing onTap, title, and
theme.menuTextStyle rather than relying solely on its current vertical padding.

In `@lib/presentation/widgets/common/edgy.dart`:
- Around line 22-23: Initialize _canScrollEnd to false in the Edgy widget state,
allowing layout/metrics notifications to enable the end fade only when the
content actually overflows.

In `@lib/presentation/widgets/common/pressable.dart`:
- Line 2: Update the motion configuration in the pressable widget to reference
the constant directly: replace `CupertinoMotion.smooth()` with
`CupertinoMotion.smooth` in the relevant `Pressable` configuration.

---

Nitpick comments:
In `@test/levels_uniqueness_test.dart`:
- Around line 11-25: Extract the duplicated manifest asset filtering and level
ID parsing from the affected tests and levels_solvability_test.dart into shared
helpers such as loadLevelIds() and loadLevelPaths() in test_helpers.dart. Update
all three call sites, including the logic around the levelPaths and levelIds
declarations, to use these helpers and preserve the existing sorting and
assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a947e18-cb02-4353-b343-f5b8439de544

📥 Commits

Reviewing files that changed from the base of the PR and between a84b23d and 9f48446.

⛔ Files ignored due to path filters (8)
  • ios/Podfile.lock is excluded by !**/*.lock
  • lib/generated/intl/messages_de.dart is excluded by !**/generated/**
  • lib/generated/intl/messages_en.dart is excluded by !**/generated/**
  • lib/generated/intl/messages_es.dart is excluded by !**/generated/**
  • lib/generated/intl/messages_fr.dart is excluded by !**/generated/**
  • lib/generated/intl/messages_it.dart is excluded by !**/generated/**
  • lib/generated/intl/messages_ru.dart is excluded by !**/generated/**
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (25)
  • CHANGELOG.md
  • README.md
  • analysis_options.yaml
  • android/gradle.properties
  • android/gradle/wrapper/gradle-wrapper.properties
  • android/settings.gradle.kts
  • ios/Flutter/Debug.xcconfig
  • ios/Flutter/Release.xcconfig
  • ios/Podfile
  • ios/Runner.xcodeproj/project.pbxproj
  • ios/Runner.xcworkspace/contents.xcworkspacedata
  • lib/presentation/providers/game_provider.g.dart
  • lib/presentation/providers/settings/language_provider.g.dart
  • lib/presentation/providers/settings/theme_provider.g.dart
  • lib/presentation/screens/home/home_screen.dart
  • lib/presentation/screens/home/side_menu_screen.dart
  • lib/presentation/screens/info/about_screen.dart
  • lib/presentation/screens/info/story_screen.dart
  • lib/presentation/widgets/common/app_bar_widget.dart
  • lib/presentation/widgets/common/edgy.dart
  • lib/presentation/widgets/common/pressable.dart
  • lib/presentation/widgets/game/game_bottom_bar.dart
  • pubspec.yaml
  • test/levels_solvability_test.dart
  • test/levels_uniqueness_test.dart
💤 Files with no reviewable changes (4)
  • ios/Flutter/Release.xcconfig
  • ios/Runner.xcworkspace/contents.xcworkspacedata
  • ios/Flutter/Debug.xcconfig
  • ios/Podfile

Comment on lines +480 to 481
"ARCHS[sdk=iphonesimulator*]" = arm64;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Fix invalid ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS value in Debug and Release configs.

This build setting expects a boolean (YES/NO), but both the Debug (line 481) and Release (line 541) configs now have AppIcon — likely a copy-paste error from ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon. The Profile config (line 354, unchanged) correctly retains YES. This inconsistency could produce build warnings or disable Swift asset symbol extensions in Debug/Release builds.

🔧 Proposed fix for both Debug and Release configs
 // Debug config (line 481)
-				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;

 // Release config (line 541)
-				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
+				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;

Also applies to: 540-541

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/Runner.xcodeproj/project.pbxproj` around lines 480 - 481, Replace the
invalid AppIcon value assigned to
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS in the Debug and
Release build configurations with the boolean value YES, matching the existing
Profile configuration. Keep ASSETCATALOG_COMPILER_APPICON_NAME set to AppIcon.

Comment on lines +77 to 88
return Pressable(
onTap: onTap,
contentPadding: const EdgeInsets.symmetric(
horizontal: GeneralConsts.horizontalPadding,
vertical: GeneralConsts.verticalPadding,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: GeneralConsts.horizontalPadding,
vertical: GeneralConsts.verticalPadding,
),
child: Align(
alignment: Alignment.centerLeft,
child: Text(title, style: theme.menuTextStyle),
),
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Touch target height may fall below accessibility minimum.

The previous ListTile enforced a minimum height (~48–56px via materialTapTargetSize). The new Pressable + Padding + Text layout has an estimated height of ~32–40px (16px text + 16px vertical padding), which is below the 48px minimum recommended by WCAG and Material Design guidelines.

♿ Proposed fix: enforce minimum touch target height
     return Pressable(
       onTap: onTap,
-      child: Padding(
+      child: ConstrainedBox(
+        constraints: const BoxConstraints(minHeight: 48),
+        child: Padding(
           padding: const EdgeInsets.symmetric(
             horizontal: GeneralConsts.horizontalPadding,
             vertical: GeneralConsts.verticalPadding,
           ),
           child: Align(
             alignment: Alignment.centerLeft,
             child: Text(title, style: theme.menuTextStyle),
           ),
         ),
       ),
     );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return Pressable(
onTap: onTap,
contentPadding: const EdgeInsets.symmetric(
horizontal: GeneralConsts.horizontalPadding,
vertical: GeneralConsts.verticalPadding,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: GeneralConsts.horizontalPadding,
vertical: GeneralConsts.verticalPadding,
),
child: Align(
alignment: Alignment.centerLeft,
child: Text(title, style: theme.menuTextStyle),
),
),
return Pressable(
onTap: onTap,
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 48),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: GeneralConsts.horizontalPadding,
vertical: GeneralConsts.verticalPadding,
),
child: Align(
alignment: Alignment.centerLeft,
child: Text(title, style: theme.menuTextStyle),
),
),
),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/presentation/screens/home/side_menu_screen.dart` around lines 77 - 88,
Increase the Pressable touch target in the side-menu item builder by enforcing a
minimum height of at least 48px while preserving the existing padding and
alignment; update the widget containing onTap, title, and theme.menuTextStyle
rather than relying solely on its current vertical padding.

Comment on lines +22 to +23
bool _canScrollStart = false;
bool _canScrollEnd = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Default _canScrollEnd = true may show end fade for non-overflowing content.

If the wrapped scrollable content fits entirely within the viewport, no ScrollNotification fires, so _canScrollEnd remains true and the end fade displays incorrectly. Defaulting to false is safer — ScrollMetricsNotification (dispatched on initial layout and metric changes) will set it to true when content actually overflows.

🛡️ Proposed fix
   bool _canScrollStart = false;
-  bool _canScrollEnd = true;
+  bool _canScrollEnd = false;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool _canScrollStart = false;
bool _canScrollEnd = true;
bool _canScrollStart = false;
bool _canScrollEnd = false;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/presentation/widgets/common/edgy.dart` around lines 22 - 23, Initialize
_canScrollEnd to false in the Edgy widget state, allowing layout/metrics
notifications to enable the end fade only when the content actually overflows.

@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import 'package:motor/motor.dart';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify motor package is declared and locked, then inspect its API surface.
rg -n 'motor' pubspec.yaml pubspec.lock
# If source is available, check for SingleMotionBuilder and CupertinoMotion
fd -t f 'motor' --exec rg -l 'SingleMotionBuilder|CupertinoMotion' {} \; 2>/dev/null || \
  find . -path '*/motor/*' -name '*.dart' -exec rg -l 'SingleMotionBuilder|CupertinoMotion' {} \; 2>/dev/null

Repository: khlebobul/pegma

Length of output: 246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== pressable.dart =="
if [ -f lib/presentation/widgets/common/pressable.dart ]; then
  cat -n lib/presentation/widgets/common/pressable.dart | sed -n '1,220p'
else
  echo "missing: lib/presentation/widgets/common/pressable.dart"
fi

echo
echo "== motor dependency =="
rg -n '^\s*motor:|name: motor|version:' pubspec.yaml pubspec.lock || true

echo
echo "== motor API usage in repo =="
rg -n 'SingleMotionBuilder|CupertinoMotion\.smooth\(|CupertinoMotion|MotionBuilder' lib . || true

Repository: khlebobul/pegma

Length of output: 8685


🌐 Web query:

motor 1.1.0 SingleMotionBuilder CupertinoMotion.smooth API pub.dev

💡 Result:

In the motor package (version 1.1.0), CupertinoMotion.smooth is a static constant that provides a smooth spring animation configuration [1][2]. This configuration is designed to match Apple's SwiftUI animation presets, specifically offering a smooth motion with no bounce, which is ideal for subtle UI transitions [1][2]. The SingleMotionBuilder widget is used within the motor package for basic, one-dimensional animations [1][2]. When using CupertinoMotion.smooth, it triggers a physics-based spring animation whenever the target value changes [1][2]. Example usage: SingleMotionBuilder( motion: CupertinoMotion.smooth, value: targetValue, builder: (context, value, child) { return Container( width: value, height: value, color: Colors.blue,); },) CupertinoMotion is a subclass of SpringMotion that offers several other predefined constants mirroring iOS design, including CupertinoMotion, CupertinoMotion.bouncy, CupertinoMotion.snappy, and CupertinoMotion.interactive [1][2].

Citations:


Use CupertinoMotion.smooth without ()
motor 1.1.0 exposes CupertinoMotion.smooth as a constant, so const CupertinoMotion.smooth() is invalid here. Update lib/presentation/widgets/common/pressable.dart:36-37 to motion: CupertinoMotion.smooth.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/presentation/widgets/common/pressable.dart` at line 2, Update the motion
configuration in the pressable widget to reference the constant directly:
replace `CupertinoMotion.smooth()` with `CupertinoMotion.smooth` in the relevant
`Pressable` configuration.

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