diff --git a/.github/actions/setup_flutter/action.yaml b/.github/actions/setup_flutter/action.yaml new file mode 100644 index 00000000..a57cbfd1 --- /dev/null +++ b/.github/actions/setup_flutter/action.yaml @@ -0,0 +1,27 @@ +name: Setup Flutter +description: Setup flutter project and toolchains for subsequent actions. + +inputs: + target: + description: "The working directory where the Flutter project is located." + required: false + default: "." + +runs: + using: "composite" + steps: + - name: Install Flutter SDK + uses: subosito/flutter-action@v2 + with: + channel: stable + flutter-version: 3.x + cache: true + + - name: Flutter version + run: flutter --version + shell: bash + + - name: Install dependencies + run: flutter pub get + shell: bash + working-directory: ${{ inputs.target }} diff --git a/.github/workflows/code_check.yaml b/.github/workflows/code_check.yaml new file mode 100644 index 00000000..f04f451d --- /dev/null +++ b/.github/workflows/code_check.yaml @@ -0,0 +1,84 @@ +name: Code Check +on: + push: + branches: main + pull_request: + +env: + FLUTTER_TEST_REPORT: ${{github.workspace}}/flutter-test-report.json + PATTERN_CHECKER: ${{github.workspace}}/scripts/pattern_checker.sh + +jobs: + # Change detection + changes: + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + dart-files: ${{ steps.filter.outputs.dart-files }} + steps: + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + dart-files: + - '**.dart' + + # Static code analysis + analysis: + needs: changes + if: ${{ needs.changes.outputs.dart-files == 'true' }} + runs-on: ubuntu-latest + strategy: + matrix: + target: [package, cookbook] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: ./.github/actions/setup_flutter + with: + target: ${{ matrix.target }} + + - name: Format + run: dart format . -o none --set-exit-if-changed + working-directory: ${{ matrix.target }} + + - name: Analyze + run: dart analyze + working-directory: ${{ matrix.target }} + + - name: Disallowed patterns check + run: bash ${{ env.PATTERN_CHECKER }} "*.dart" "--" "debugPrint" + working-directory: ${{ matrix.target }} + + # Unit testing + testing: + needs: changes + if: ${{ needs.changes.outputs.dart-files == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: read + actions: read + checks: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: ./.github/actions/setup_flutter + with: + target: package + + - name: Run unit tests + run: flutter test --file-reporter="json:${{ env.FLUTTER_TEST_REPORT }}" + working-directory: package + + - name: Write test report + uses: dorny/test-reporter@v1 + if: success() || failure() + with: + name: Test Report + path: ${{ env.FLUTTER_TEST_REPORT }} + reporter: flutter-json diff --git a/.github/workflows/code_check.yml b/.github/workflows/code_check.yml deleted file mode 100644 index 0c12e945..00000000 --- a/.github/workflows/code_check.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Code Checking -on: - push: - branches: main - pull_request: - paths: - - "**.dart" - -jobs: - code-check: - name: Code Checking - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install cargo-make - uses: taiki-e/install-action@cargo-make - - - name: Install Flutter SDK - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version: 3.x - - - name: Flutter version - run: flutter --version - - - name: Run task 'check-all' - run: cargo make check-all diff --git a/.github/workflows/dry_publish.yaml b/.github/workflows/dry_publish.yaml index 927461d5..5462fca3 100644 --- a/.github/workflows/dry_publish.yaml +++ b/.github/workflows/dry_publish.yaml @@ -1,36 +1,27 @@ name: Dry Publish on: push: - branches: [main, "release/*"] - -env: - package_dir: ./package + branches: main + pull_request: + branches: main jobs: dry-publish: - name: Dry Publish runs-on: ubuntu-latest - defaults: - run: - working-directory: ${{ env.package_dir }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Install Flutter SDK - uses: subosito/flutter-action@v2 + - name: Setup Flutter + uses: ./.github/actions/setup_flutter with: - channel: stable - flutter-version: 3.x - - - run: flutter --version - - run: flutter pub get + target: package - uses: axel-op/dart-package-analyzer@master id: analysis with: githubToken: ${{ secrets.GITHUB_TOKEN }} - relativePath: ${{ env.package_dir }} + relativePath: package - uses: fujidaiti/dart-package-inspector@v1 with: @@ -42,3 +33,4 @@ jobs: supported-platforms: ios, android - run: flutter pub publish --dry-run + working-directory: package diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yaml similarity index 58% rename from .github/workflows/publish.yml rename to .github/workflows/publish.yaml index b6d84709..9327f568 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yaml @@ -5,7 +5,6 @@ on: jobs: publish: - name: Publish runs-on: ubuntu-latest permissions: id-token: write @@ -13,14 +12,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install Flutter SDK - uses: subosito/flutter-action@v2 + - name: Setup Flutter + uses: ./.github/actions/setup_flutter with: - channel: stable - flutter-version: 3.x - - - name: Flutter version - run: flutter --version + target: package - name: Publish to pub.dev run: flutter pub publish --force + working-directory: package diff --git a/.github/workflows/unit_testing.yaml b/.github/workflows/unit_testing.yaml deleted file mode 100644 index 52b793da..00000000 --- a/.github/workflows/unit_testing.yaml +++ /dev/null @@ -1,47 +0,0 @@ -name: Unit Testing - -on: - pull_request: - paths: - - "package/lib/**" - - "package/test/**" - -jobs: - test: - name: Unit Tests - runs-on: ubuntu-latest - permissions: - contents: read - actions: read - checks: write - defaults: - run: - working-directory: package/ - env: - FLUTTER_TEST_REPORT: ${{github.workspace}}/flutter-test-report.json - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: stable - flutter-version: 3.x - - - name: Flutter version - run: flutter --version - - - name: Get dependencies - run: flutter pub get - - - name: Run unit tests - run: flutter test --file-reporter="json:${{ env.FLUTTER_TEST_REPORT }}" - - - name: Write test report - uses: dorny/test-reporter@v1 - if: success() || failure() - with: - name: Test Report - path: ${{ env.FLUTTER_TEST_REPORT }} - reporter: flutter-json diff --git a/package/test/foundation/sheet_physics_test.dart b/package/test/foundation/sheet_physics_test.dart index 30c42313..f652a9b8 100644 --- a/package/test/foundation/sheet_physics_test.dart +++ b/package/test/foundation/sheet_physics_test.dart @@ -47,7 +47,7 @@ void main() { ); }); - test('does not apply any resistance if the position is in bounds', () { + test('does not apply any resistance if position is in bounds', () { final positionAtNearTopEdge = _referenceSheetMetrics.copyWith( pixels: _referenceSheetMetrics.maxPixels - 10); final positionAtNearBottomEdge = _referenceSheetMetrics.copyWith( @@ -78,7 +78,7 @@ void main() { ); }); - test('creates no ballistic simulation if the position is in bounds', () { + test('creates no ballistic simulation if position is in bounds', () { expect( physicsUnderTest.createBallisticSimulation(0, _positionAtMiddle), isNull, @@ -141,7 +141,7 @@ void main() { ); }); - test('creates settling simulation which ends at the nearest edge', () { + test('creates settling simulation which ends at nearest edge', () { final moreOverDraggedPosition = _referenceSheetMetrics.copyWith( pixels: _referenceSheetMetrics.maxPixels + 200, ); @@ -186,7 +186,7 @@ void main() { behaviorUnderTest = const SnapToNearestEdge(minFlingSpeed: 50); }); - test('snaps to the nearest edge if the velocity is small enough', () { + test('snaps to nearest edge if velocity is small enough', () { final positionAtNearTopEdge = _referenceSheetMetrics.copyWith( pixels: _referenceSheetMetrics.maxPixels - 50, ); @@ -215,6 +215,92 @@ void main() { ); }); + test('is disabled if position is out of bounds', () { + final overDraggedPosition = _referenceSheetMetrics.copyWith( + pixels: _referenceSheetMetrics.maxPixels + 10, + ); + final underDraggedPosition = _referenceSheetMetrics.copyWith( + pixels: _referenceSheetMetrics.minPixels - 10, + ); + + expect( + behaviorUnderTest.findSnapPixels(0, overDraggedPosition), + isNull, + ); + expect( + behaviorUnderTest.findSnapPixels(0, underDraggedPosition), + isNull, + ); + }); + }); + group('$SnapToNearest', () { + late SnapToNearest behaviorUnderTest; + + setUp(() { + behaviorUnderTest = SnapToNearest( + minFlingSpeed: 50, + snapTo: [ + Extent.pixels(_positionAtBottomEdge.pixels), + Extent.pixels(_positionAtMiddle.pixels), + Extent.pixels(_positionAtTopEdge.pixels), + ], + ); + }); + + test('snaps to nearest edge if velocity is small enough', () { + final positionAtNearTopEdge = _referenceSheetMetrics.copyWith( + pixels: _referenceSheetMetrics.maxPixels - 50, + ); + final positionAtNearMiddle = _referenceSheetMetrics.copyWith( + pixels: _positionAtMiddle.pixels + 50, + ); + final positionAtNearBottomEdge = _referenceSheetMetrics.copyWith( + pixels: _referenceSheetMetrics.minPixels + 50, + ); + + expect( + behaviorUnderTest.findSnapPixels(0, positionAtNearTopEdge), + moreOrLessEquals(_referenceSheetMetrics.maxPixels), + ); + expect( + behaviorUnderTest.findSnapPixels(0, positionAtNearMiddle), + moreOrLessEquals(_positionAtMiddle.pixels), + ); + expect( + behaviorUnderTest.findSnapPixels(0, positionAtNearBottomEdge), + moreOrLessEquals(_referenceSheetMetrics.minPixels), + ); + }); + + test('is aware of fling gesture direction', () { + final positionAtAboveMiddle = _positionAtMiddle.copyWith( + pixels: _positionAtMiddle.pixels + 10, + ); + final positionAtBelowMiddle = _positionAtMiddle.copyWith( + pixels: _positionAtMiddle.pixels - 10, + ); + // Flings up at the bottom edge + expect( + behaviorUnderTest.findSnapPixels(50, _positionAtBottomEdge), + moreOrLessEquals(_positionAtMiddle.pixels), + ); + // Flings up at the slightly above the middle position + expect( + behaviorUnderTest.findSnapPixels(50, positionAtAboveMiddle), + moreOrLessEquals(_positionAtTopEdge.pixels), + ); + // Flings down at the top edge + expect( + behaviorUnderTest.findSnapPixels(-50, _positionAtTopEdge), + moreOrLessEquals(_positionAtMiddle.pixels), + ); + // Flings down at the slightly below the middle position + expect( + behaviorUnderTest.findSnapPixels(-50, positionAtBelowMiddle), + moreOrLessEquals(_positionAtBottomEdge.pixels), + ); + }); + test('is disabled if position is out of bounds', () { final overDraggedPosition = _referenceSheetMetrics.copyWith( pixels: _referenceSheetMetrics.maxPixels + 10,