diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9b01303..f6785c8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,13 +4,16 @@ on:
pull_request:
push:
branches: [master]
+ schedule:
+ - cron: '0 6 * * 1' # Mondays 06:00 UTC: catch breakage from new Flutter releases
+ workflow_dispatch:
jobs:
test:
name: Test & Analyze
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: subosito/flutter-action@v2
with:
@@ -27,3 +30,24 @@ jobs:
- name: Test
run: flutter test --coverage --test-randomize-ordering-seed random
+
+ test-beta:
+ # Early warning for upcoming deprecations and breaking changes. Allowed to fail.
+ name: Test & Analyze (beta)
+ runs-on: ubuntu-latest
+ continue-on-error: true
+ steps:
+ - uses: actions/checkout@v5
+
+ - uses: subosito/flutter-action@v2
+ with:
+ channel: beta
+
+ - name: Install dependencies
+ run: flutter pub get
+
+ - name: Analyze
+ run: flutter analyze lib/ test/ example/
+
+ - name: Test
+ run: flutter test --test-randomize-ordering-seed random
diff --git a/.github/workflows/code-quality-tests.yml b/.github/workflows/code-quality-tests.yml
deleted file mode 100644
index ca938a7..0000000
--- a/.github/workflows/code-quality-tests.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Code Quality
-
-on: [push]
-
-jobs:
- format-and-fix:
- if: ${{ !github.event.pull_request.draft }}
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v2
-
- - name: Setup flutter
- uses: subosito/flutter-action@v2
- with:
- channel: stable
-
- - name: Get packages
- run: flutter pub get
-
- - name: Check format errors
- run: flutter format --set-exit-if-changed .
-
- - name: Check lint errors
- run: flutter analyze .
-
- - name: Run tests
- run: flutter test --coverage --test-randomize-ordering-seed random
-
- - name: Very Good Coverage
- uses: VeryGoodOpenSource/very_good_coverage@v2.1.0
- with:
- min_coverage: 35
diff --git a/.github/workflows/conventional-pr-title.yml b/.github/workflows/conventional-pr-title.yml
index dfb7f4f..aa0f51b 100644
--- a/.github/workflows/conventional-pr-title.yml
+++ b/.github/workflows/conventional-pr-title.yml
@@ -12,11 +12,9 @@ jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
+ permissions:
+ pull-requests: read
steps:
- - uses: deepakputhraya/action-pr-title@master
- with:
- max_length: 100
- github_token: ${{ secrets.GITHUB_TOKEN }}
- - uses: amannn/action-semantic-pull-request@v4
+ - uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 27029f1..13c372a 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,19 +1,21 @@
+# Automated publishing: https://dart.dev/tools/pub/automated-publishing
+# Needs, on pub.dev (Admin tab): automated publishing enabled for this repository,
+# tag pattern `v{{version}}` and required environment `pub.dev`. On GitHub: an
+# environment named `pub.dev`. Release by pushing a tag that matches the pubspec
+# version, e.g. `git tag v3.3.0 && git push origin v3.3.0`.
name: Publish to pub.dev
on:
push:
tags:
- - 'v*'
+ - 'v[0-9]+.[0-9]+.[0-9]+' # tag pattern on pub.dev: 'v{{version}}'
jobs:
- publish:
- name: Publish
+ test:
+ name: Test & Analyze
runs-on: ubuntu-latest
- permissions:
- id-token: write # required for OIDC pub.dev publishing
-
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: subosito/flutter-action@v2
with:
@@ -28,5 +30,29 @@ jobs:
- name: Test
run: flutter test --test-randomize-ordering-seed random
+ publish:
+ # Separate job so the short-lived OIDC token is created right before publishing.
+ name: Publish
+ needs: test
+ runs-on: ubuntu-latest
+ environment: pub.dev
+ permissions:
+ contents: read
+ id-token: write # Required for authentication using OIDC
+ steps:
+ - uses: actions/checkout@v5
+
+ # Creates the GitHub-signed OIDC token and registers it with pub for pub.dev.
+ - uses: dart-lang/setup-dart@v1
+
+ # Flutter's `dart` shadows the one from setup-dart; publishing a Flutter
+ # package needs the Flutter SDK.
+ - uses: subosito/flutter-action@v2
+ with:
+ channel: stable
+
+ - name: Install dependencies
+ run: flutter pub get
+
- name: Publish
run: flutter pub publish --force
diff --git a/.gitignore b/.gitignore
index c2853e0..a7e6824 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ version
**/doc/api/
.dart_tool/
.flutter-plugins
+.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
@@ -47,6 +48,7 @@ unlinked_spec.ds
# Android related
#**/android/**/gradle-wrapper.jar
**/android/.gradle
+**/android/.kotlin/
**/android/captures/
#**/android/gradlew
#**/android/gradlew.bat
@@ -85,3 +87,14 @@ unlinked_spec.ds
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
+
+# Generated / local-only files
+coverage/
+migrate_working_dir/
+.build/
+.swiftpm/
+**/ios/Flutter/ephemeral/
+**/ios/Flutter/Flutter.podspec
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/Flutter/.last_build_id
+**/windows/flutter/ephemeral/
diff --git a/.pubignore b/.pubignore
new file mode 100644
index 0000000..52a1f48
--- /dev/null
+++ b/.pubignore
@@ -0,0 +1,117 @@
+# pub ignores .gitignore in a directory that has a .pubignore, so the rules below
+# start as a copy of .gitignore. Keep them in sync.
+
+# Miscellaneous
+*.class
+*.lock
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# Visual Studio Code related
+.vscode/
+
+# Flutter repo-specific
+/bin/cache/
+/bin/mingit/
+/dev/benchmarks/mega_gallery/
+/dev/bots/.recipe_deps
+/dev/bots/android_tools/
+/dev/docs/doc/
+/dev/docs/lib/
+/dev/docs/pubspec.yaml
+/packages/flutter/coverage/
+version
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+build/
+flutter_*.png
+linked_*.ds
+unlinked.ds
+unlinked_spec.ds
+
+# Android related
+#**/android/**/gradle-wrapper.jar
+**/android/.gradle
+**/android/.kotlin/
+**/android/captures/
+#**/android/gradlew
+#**/android/gradlew.bat
+**/android/local.properties
+**/android/**/GeneratedPluginRegistrant.java
+
+# iOS/XCode related
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/flutter_assets/
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!**/ios/**/default.mode1v3
+!**/ios/**/default.mode2v3
+!**/ios/**/default.pbxuser
+!**/ios/**/default.perspectivev3
+!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
+
+# Generated / local-only files
+coverage/
+migrate_working_dir/
+.build/
+.swiftpm/
+**/ios/Flutter/ephemeral/
+**/ios/Flutter/Flutter.podspec
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/Flutter/.last_build_id
+**/windows/flutter/ephemeral/
+
+# Not part of the published package
+AGENTS.md
+CLAUDE.md
+PLAN.md
+/coverage/
+/example/coverage/
+/example/ios/Flutter/ephemeral/
+.history/
+.idea/
+
+# README loads these from GitHub URLs. Only the pubspec `screenshots:` image ships.
+/images/*
+!/images/pub_dev_preview.png
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..d524238
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,67 @@
+# AGENTS.md
+
+Guidance for coding agents (Claude Code, Codex, ...) working in this repository.
+
+## Commands
+
+```bash
+# Get dependencies
+flutter pub get
+
+# Run all tests (with randomized ordering)
+flutter test --coverage --test-randomize-ordering-seed random
+
+# Run a single test file
+flutter test test/badges_test.dart
+
+# Lint (CI runs exactly this; infos fail it)
+flutter analyze lib/ test/ example/
+
+# Format (CI enforces this — run before committing)
+dart format .
+```
+
+## Architecture
+
+This is a Flutter package (`badges`) that provides a single `Badge` widget for overlaying notification-style badges on any widget.
+
+### Public API (`lib/badges.dart`)
+
+All public exports go through `lib/badges.dart`. Consumers import as:
+```dart
+import 'package:badges/badges.dart' as badges;
+```
+The `as badges` alias is required because Flutter 3.7+ added a `Badge` widget to Material that conflicts.
+
+### Core widget (`lib/src/badge.dart`)
+
+`Badge` is a `StatefulWidget` with `TickerProviderStateMixin`. It manages two `AnimationController`s:
+- `_animationController` — drives the content-change animation (slide, scale, fade, size, rotation)
+- `_appearanceController` — drives the fade in/out when `showBadge` toggles
+
+The `didUpdateWidget` override is where animation re-triggering logic lives: it watches for changes to `badgeContent` (Text/Icon data), `badgeColor`, `showBadge`, and `loopAnimation`.
+
+When `child` is null, the badge renders standalone. When `child` is provided, it uses a `Stack` with `BadgePositioned` to overlay the badge. When `onTap` is set, extra padding is added to the child and the position is recalculated via `CalculationUtils` to keep the full badge tappable.
+
+### Configuration objects
+
+- **`BadgeStyle`** — visual properties: shape, color, gradient, border, padding, elevation
+- **`BadgeAnimation`** — named constructors per animation type (`.slide()`, `.fade()`, `.scale()`, `.size()`, `.rotation()`); each sets the `animationType` field and relevant defaults
+- **`BadgePosition`** — named constructors (`topEnd`, `topStart`, `bottomEnd`, `bottomStart`, `center`) plus custom offsets
+- **`BadgeGradient`** — named constructors (`.linear()`, `.radial()`, `.sweep()`) wrapping Flutter gradient types
+- **`BadgeShape`** — enum: `circle`, `square`, `twitter`, `instagram`
+
+### Custom shapes
+
+`BadgeShape.twitter` and `BadgeShape.instagram` bypass the `Material`/`AnimatedContainer` path and use `CustomPaint` with their respective painters in `lib/src/painters/`. The `DrawingUtils.drawBadgeShape()` helper selects the correct painter.
+
+### Internal utilities (not exported)
+
+- `lib/src/utils/calculation_utils.dart` — computes padding and position adjustments for tappable badges
+- `lib/src/utils/gradient_utils.dart` — gradient rendering helpers
+- `lib/src/badge_border_gradient.dart` — custom `BoxBorder` subclass that paints a gradient border
+- `lib/src/badge_gradient_type.dart` — internal enum used by `BadgeGradient`
+
+### Tests (`test/`)
+
+`badges_test.dart` is the entry point; it imports and calls group functions from `test/badge_animations_tests/`. Tests use `flutter_test` and wrap widgets in `MaterialApp` + `Scaffold`. Animation tests pump specific durations and check `hasRunningAnimations` to assert controller state.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77b9a59..1e35e42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,29 @@
-## [4.0.0] - [September 23, 2026]
+## [4.0.0] - [Unreleased]
### Breaking Changes
-* **Migrated to `package:material_ui`** — Material and Cupertino were decoupled from the Flutter SDK in Flutter 3.47 and now ship as standalone packages. This package now imports `package:material_ui/material_ui.dart` instead of `package:flutter/material.dart`.
+* **Migrated to `package:material_ui`** (#135, thanks @mayainle) — Material and Cupertino were decoupled from the Flutter SDK in Flutter 3.47 and now ship as standalone packages. This package now imports `package:material_ui/material_ui.dart` instead of `package:flutter/material.dart`.
* In apps that use `material_ui`, badge content now gets the app's theme text style without `MaterialUiCompatibilityBridge`. Apps still on `package:flutter/material.dart` keep working, but badge text uses the default Material text style until they migrate. This is a major version bump, as the Flutter team recommends for this migration.
* To hide the ambiguous `Badge`, use `import 'package:material_ui/material_ui.dart' hide Badge;` instead of the Flutter Material equivalent.
* **Minimum SDK raised** to Dart `3.13.0` / Flutter `3.47.0`, the floor required by `material_ui`.
+### Bug Fixes
+* **Issue #133** — The `ignorePointer` docs said the opposite of what it does. `true` lets taps pass through the badge; `false` (default) lets the badge get taps.
+* **`BadgeStyle.elevation` works again.** It has drawn no shadow since 3.0.3. The default is now `0`, so badges that don't set it look the same as before.
+* **`BadgePosition.center()` with `onTap`** no longer moves the badge to the top-left corner.
+* **`BadgePosition.centerStart()` / `centerEnd()`** are now vertically centered, as documented.
+* **Right-to-left layouts with `onTap`** no longer shift the badge. The tap padding is now directional.
+* **Hidden badges (`showBadge: false`)** no longer catch taps or call `onTap`; taps reach the widget below.
+* **Twitter / Instagram shapes** no longer crash with gradients of 3+ colors. Gradient `stops`, `tileMode`, sweep angles and directional alignments are now used.
+* **Turning `toAnimate` on at runtime** no longer leaves the badge invisible.
+* Fixed a listener leak: every rebuild added a listener to the appearance controller.
+* Removed a no-op `ConstrainedBox`. The 3.2.0 "minimum-square sizing" note was wrong: badge sizing did not change in 3.2.0 and does not change now.
+
### Maintenance
* Replaced `SizeTransition.axisAlignment`, deprecated after Flutter v3.41, with `alignment`. `BadgeAnimation.sizeTransitionAxisAlignment` is unchanged and still takes a `double`.
+* CI: removed the broken "Code Quality" workflow, set up pub.dev automated publishing in the publish workflow, updated actions, added a weekly run on Flutter beta.
+* Example app: regenerated Android / iOS / Windows projects so it builds again, and fixed the test screen overflowing on phone widths.
+* Smaller pub.dev archive (`.pubignore`).
+* README: fixed build and downloads badges, documented `onTap` padding and `ignorePointer`.
## [3.2.0] - [April 9, 2026]
diff --git a/CLAUDE.md b/CLAUDE.md
index 92aace5..43c994c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,67 +1 @@
-# CLAUDE.md
-
-This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
-
-## Commands
-
-```bash
-# Get dependencies
-flutter pub get
-
-# Run all tests (with randomized ordering)
-flutter test --coverage --test-randomize-ordering-seed random
-
-# Run a single test file
-flutter test test/badges_test.dart
-
-# Lint
-flutter analyze .
-
-# Format (CI enforces this — run before committing)
-flutter format .
-```
-
-## Architecture
-
-This is a Flutter package (`badges`) that provides a single `Badge` widget for overlaying notification-style badges on any widget.
-
-### Public API (`lib/badges.dart`)
-
-All public exports go through `lib/badges.dart`. Consumers import as:
-```dart
-import 'package:badges/badges.dart' as badges;
-```
-The `as badges` alias is required because Flutter 3.7+ added a `Badge` widget to Material that conflicts.
-
-### Core widget (`lib/src/badge.dart`)
-
-`Badge` is a `StatefulWidget` with `TickerProviderStateMixin`. It manages two `AnimationController`s:
-- `_animationController` — drives the content-change animation (slide, scale, fade, size, rotation)
-- `_appearanceController` — drives the fade in/out when `showBadge` toggles
-
-The `didUpdateWidget` override is where animation re-triggering logic lives: it watches for changes to `badgeContent` (Text/Icon data), `badgeColor`, `showBadge`, and `loopAnimation`.
-
-When `child` is null, the badge renders standalone. When `child` is provided, it uses a `Stack` with `BadgePositioned` to overlay the badge. When `onTap` is set, extra padding is added to the child and the position is recalculated via `CalculationUtils` to keep the full badge tappable.
-
-### Configuration objects
-
-- **`BadgeStyle`** — visual properties: shape, color, gradient, border, padding, elevation
-- **`BadgeAnimation`** — named constructors per animation type (`.slide()`, `.fade()`, `.scale()`, `.size()`, `.rotation()`); each sets the `animationType` field and relevant defaults
-- **`BadgePosition`** — named constructors (`topEnd`, `topStart`, `bottomEnd`, `bottomStart`, `center`) plus custom offsets
-- **`BadgeGradient`** — named constructors (`.linear()`, `.radial()`, `.sweep()`) wrapping Flutter gradient types
-- **`BadgeShape`** — enum: `circle`, `square`, `twitter`, `instagram`
-
-### Custom shapes
-
-`BadgeShape.twitter` and `BadgeShape.instagram` bypass the `Material`/`AnimatedContainer` path and use `CustomPaint` with their respective painters in `lib/src/painters/`. The `DrawingUtils.drawBadgeShape()` helper selects the correct painter.
-
-### Internal utilities (not exported)
-
-- `lib/src/utils/calculation_utils.dart` — computes padding and position adjustments for tappable badges
-- `lib/src/utils/gradient_utils.dart` — gradient rendering helpers
-- `lib/src/badge_border_gradient.dart` — custom `BoxBorder` subclass that paints a gradient border
-- `lib/src/badge_gradient_type.dart` — internal enum used by `BadgeGradient`
-
-### Tests (`test/`)
-
-`badges_test.dart` is the entry point; it imports and calls group functions from `test/badge_animations_tests/`. Tests use `flutter_test` and wrap widgets in `MaterialApp` + `Scaffold`. Animation tests pump specific durations and check `hasRunningAnimations` to assert controller state.
+@AGENTS.md
diff --git a/README.md b/README.md
index 1005b58..2175a5b 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
[](https://pub.dev/packages/badges)
-[](https://pub.dev/packages/badges/score)
+[](https://pub.dev/packages/badges/score)
[](https://pub.dev/packages/badges/score)
-
+[](https://github.com/yako-dev/flutter_badges/actions/workflows/ci.yml)
[](https://pub.dev/packages/flutter_lints)
[](https://youtu.be/_CIHLJHVoN8)
@@ -82,6 +82,10 @@ import 'package:material_ui/material_ui.dart' hide Badge;
),
```
+`onTap`: when the badge sits outside its child (negative `position` values), the badge adds padding around the child so the whole badge can be tapped. Flutter only delivers taps inside a widget's bounds. The padding makes the widget bigger, so leave `onTap` null if you don't need it.
+
+`ignorePointer: true` lets taps pass through the badge to the widgets below it (and `onTap` is not called).
+
---
@@ -136,6 +140,6 @@ From left to right:
[Diagonal decoration](https://pub.dev/packages/diagonal_decoration)
-[Yako Yheme Switch](https://pub.dev/packages/yako_theme_switch)
+[Yako Theme Switch](https://pub.dev/packages/yako_theme_switch)
and more to come!
\ No newline at end of file
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 57346b5..9c66398 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,3 +1,6 @@
+analyzer:
+ exclude:
+ - build/**
include: package:flutter_lints/flutter.yaml
linter:
rules:
diff --git a/coverage/lcov.info b/coverage/lcov.info
deleted file mode 100644
index 963f609..0000000
--- a/coverage/lcov.info
+++ /dev/null
@@ -1,472 +0,0 @@
-SF:lib/src/badge_border_gradient.dart
-DA:7,1
-DA:9,1
-DA:12,1
-DA:15,1
-DA:16,2
-DA:18,1
-DA:21,0
-DA:30,0
-DA:31,0
-DA:33,0
-DA:35,0
-DA:37,0
-DA:44,0
-DA:45,0
-DA:46,0
-DA:49,0
-DA:50,0
-DA:51,0
-DA:52,0
-DA:55,1
-DA:60,0
-DA:61,0
-DA:62,0
-DA:63,0
-DA:64,0
-LF:25
-LH:7
-end_of_record
-SF:lib/src/painters/instagram_badge_shape_painter.dart
-DA:11,1
-DA:19,0
-DA:21,0
-DA:22,0
-DA:24,0
-DA:25,0
-DA:26,0
-DA:28,0
-DA:29,0
-DA:30,0
-DA:36,0
-DA:37,0
-DA:38,0
-DA:39,0
-DA:41,0
-DA:42,0
-DA:43,0
-DA:49,0
-DA:50,0
-DA:51,0
-DA:52,0
-DA:53,0
-DA:54,0
-DA:55,0
-DA:56,0
-DA:57,0
-DA:58,0
-DA:59,0
-DA:60,0
-DA:61,0
-DA:62,0
-DA:63,0
-DA:64,0
-DA:65,0
-DA:66,0
-DA:67,0
-DA:68,0
-DA:69,0
-DA:70,0
-DA:71,0
-DA:72,0
-DA:73,0
-DA:75,0
-DA:76,0
-DA:77,0
-DA:78,0
-DA:82,1
-LF:47
-LH:2
-end_of_record
-SF:lib/src/painters/twitter_badge_shape_painter.dart
-DA:11,1
-DA:19,0
-DA:21,0
-DA:22,0
-DA:24,0
-DA:25,0
-DA:26,0
-DA:28,0
-DA:29,0
-DA:30,0
-DA:36,0
-DA:37,0
-DA:38,0
-DA:39,0
-DA:41,0
-DA:42,0
-DA:43,0
-DA:49,0
-DA:50,0
-DA:51,0
-DA:52,0
-DA:53,0
-DA:54,0
-DA:55,0
-DA:56,0
-DA:57,0
-DA:58,0
-DA:59,0
-DA:60,0
-DA:61,0
-DA:62,0
-DA:63,0
-DA:64,0
-DA:65,0
-DA:67,0
-DA:68,0
-DA:69,0
-DA:70,0
-DA:74,1
-LF:39
-LH:2
-end_of_record
-SF:lib/src/utils/calculation_utils.dart
-DA:7,1
-DA:9,1
-DA:12,1
-DA:16,1
-DA:19,1
-DA:20,2
-DA:21,2
-DA:22,2
-DA:23,2
-DA:29,1
-DA:34,1
-DA:38,1
-DA:39,1
-DA:42,1
-DA:45,2
-DA:46,1
-DA:47,2
-DA:48,2
-DA:50,1
-DA:51,2
-DA:52,2
-DA:53,2
-DA:54,2
-DA:58,1
-DA:63,1
-DA:64,3
-DA:65,1
-DA:66,3
-DA:67,1
-DA:68,3
-DA:69,1
-DA:70,3
-DA:71,1
-DA:72,3
-DA:73,1
-DA:74,3
-DA:75,1
-DA:76,3
-DA:77,1
-DA:78,3
-DA:79,1
-DA:80,3
-DA:82,1
-LF:43
-LH:43
-end_of_record
-SF:lib/src/utils/drawing_utils.dart
-DA:7,1
-DA:15,1
-DA:16,1
-DA:22,1
-DA:23,1
-DA:29,1
-DA:30,1
-LF:7
-LH:7
-end_of_record
-SF:lib/src/badge.dart
-DA:8,2
-DA:19,1
-DA:56,1
-DA:57,1
-DA:66,1
-DA:68,1
-DA:69,1
-DA:70,5
-DA:71,2
-DA:72,3
-DA:73,3
-DA:76,2
-DA:77,3
-DA:78,3
-DA:82,2
-DA:83,1
-DA:84,3
-DA:87,5
-DA:88,2
-DA:89,2
-DA:91,4
-DA:92,2
-DA:93,2
-DA:100,1
-DA:102,2
-DA:103,2
-DA:104,0
-DA:105,4
-DA:107,1
-DA:108,2
-DA:110,1
-DA:113,2
-DA:114,2
-DA:115,1
-DA:116,3
-DA:117,2
-DA:119,1
-DA:122,2
-DA:123,2
-DA:124,3
-DA:125,2
-DA:126,2
-DA:127,4
-DA:134,1
-DA:135,3
-DA:136,2
-DA:140,1
-DA:141,2
-DA:144,2
-DA:147,1
-DA:148,4
-DA:149,1
-DA:150,3
-DA:151,3
-DA:153,1
-DA:154,3
-DA:155,3
-DA:157,3
-DA:159,4
-DA:160,4
-DA:162,3
-DA:163,1
-DA:164,4
-DA:165,4
-DA:169,1
-DA:170,1
-DA:171,1
-DA:172,1
-DA:173,1
-DA:174,1
-DA:175,1
-DA:177,1
-DA:178,1
-DA:179,3
-DA:180,3
-DA:181,3
-DA:182,3
-DA:183,3
-DA:185,1
-DA:186,3
-DA:187,2
-DA:190,1
-DA:192,3
-DA:193,1
-DA:194,3
-DA:195,3
-DA:196,3
-DA:198,4
-DA:199,1
-DA:200,3
-DA:203,3
-DA:206,1
-DA:207,3
-DA:209,4
-DA:211,3
-DA:214,1
-DA:215,3
-DA:216,2
-DA:225,3
-DA:226,4
-DA:227,1
-DA:228,3
-DA:229,1
-DA:230,2
-DA:231,1
-DA:232,4
-DA:234,3
-DA:235,4
-DA:237,3
-DA:238,4
-DA:240,1
-DA:241,1
-DA:242,3
-DA:244,3
-DA:245,1
-DA:247,4
-DA:249,1
-DA:250,1
-DA:251,1
-DA:256,1
-DA:259,1
-DA:261,1
-DA:262,3
-DA:263,6
-DA:264,2
-DA:265,3
-DA:266,2
-DA:267,2
-DA:270,4
-DA:271,2
-DA:272,2
-DA:273,2
-DA:278,5
-DA:279,2
-DA:280,1
-DA:281,3
-DA:282,2
-DA:283,3
-DA:284,2
-DA:285,2
-DA:286,4
-DA:287,0
-DA:288,0
-DA:295,5
-DA:296,2
-DA:297,1
-DA:298,3
-DA:299,0
-DA:300,0
-DA:301,0
-DA:302,0
-DA:303,0
-DA:309,3
-DA:310,2
-DA:311,1
-DA:312,0
-DA:313,0
-DA:317,3
-DA:318,2
-DA:319,1
-DA:320,2
-DA:322,3
-DA:323,0
-DA:324,0
-DA:325,3
-DA:326,2
-DA:327,2
-DA:332,1
-DA:334,2
-DA:335,2
-DA:336,1
-LF:171
-LH:159
-end_of_record
-SF:lib/src/badge_position.dart
-DA:23,2
-DA:33,1
-DA:39,1
-DA:40,1
-DA:45,1
-DA:46,1
-DA:51,1
-DA:52,1
-DA:57,1
-DA:58,1
-DA:61,1
-DA:68,1
-LF:12
-LH:12
-end_of_record
-SF:lib/src/badge_positioned.dart
-DA:20,1
-DA:21,1
-DA:23,1
-DA:25,1
-DA:27,1
-DA:28,1
-DA:29,1
-DA:30,1
-DA:31,1
-DA:35,1
-DA:36,0
-DA:37,0
-DA:39,0
-DA:44,1
-DA:45,1
-DA:46,1
-DA:47,1
-DA:48,1
-DA:49,1
-LF:19
-LH:16
-end_of_record
-SF:lib/src/badge_style.dart
-DA:36,3
-LF:1
-LH:1
-end_of_record
-SF:lib/src/badge_animation.dart
-DA:70,3
-DA:88,2
-DA:103,2
-DA:118,2
-DA:133,2
-DA:153,2
-DA:155,1
-DA:156,3
-LF:8
-LH:8
-end_of_record
-SF:lib/src/badge_gradient.dart
-DA:20,1
-DA:35,1
-DA:50,1
-DA:65,1
-DA:66,1
-DA:67,1
-DA:68,1
-DA:69,1
-DA:70,1
-DA:71,1
-DA:72,1
-DA:73,1
-DA:74,1
-DA:76,1
-DA:77,1
-DA:78,1
-DA:79,1
-DA:80,1
-DA:81,1
-DA:82,1
-DA:83,1
-DA:84,1
-DA:85,1
-DA:87,1
-DA:88,1
-DA:89,1
-DA:90,1
-DA:91,1
-DA:92,1
-DA:93,1
-DA:94,1
-DA:95,1
-LF:32
-LH:32
-end_of_record
-SF:lib/src/utils/gradient_utils.dart
-DA:8,0
-DA:13,0
-DA:14,0
-DA:15,0
-DA:16,0
-DA:17,0
-DA:21,0
-DA:22,0
-DA:26,0
-DA:28,0
-DA:29,0
-DA:30,0
-DA:31,0
-DA:35,0
-DA:36,0
-DA:38,0
-DA:39,0
-DA:40,0
-DA:41,0
-DA:45,0
-LF:20
-LH:0
-end_of_record
diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies
deleted file mode 100644
index 4df3bd1..0000000
--- a/example/.flutter-plugins-dependencies
+++ /dev/null
@@ -1 +0,0 @@
-{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"/Users/yadaniyil/flutter/packages/integration_test/","native_build":true,"dependencies":[]}],"android":[{"name":"integration_test","path":"/Users/yadaniyil/flutter/packages/integration_test/","native_build":true,"dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]}],"date_created":"2023-08-28 11:18:31.970160","version":"3.13.1"}
\ No newline at end of file
diff --git a/example/.gitignore b/example/.gitignore
index dce2403..79f7eca 100644
--- a/example/.gitignore
+++ b/example/.gitignore
@@ -1,14 +1,16 @@
# Miscellaneous
*.class
-*.lock
*.log
*.pyc
*.swp
.DS_Store
.atom/
+.build/
.buildlog/
.history
.svn/
+.swiftpm/
+migrate_working_dir/
# IntelliJ related
*.iml
@@ -16,72 +18,31 @@
*.iws
.idea/
-# Visual Studio Code related
-.vscode/
-
-# Flutter repo-specific
-/bin/cache/
-/bin/mingit/
-/dev/benchmarks/mega_gallery/
-/dev/bots/.recipe_deps
-/dev/bots/android_tools/
-/dev/docs/doc/
-/dev/docs/lib/
-/dev/docs/pubspec.yaml
-/packages/flutter/coverage/
-version
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
+**/ios/Flutter/.last_build_id
.dart_tool/
-.flutter-plugins
-.packages
+.flutter-plugins-dependencies
.pub-cache/
.pub/
-build/
-flutter_*.png
-linked_*.ds
-unlinked.ds
-unlinked_spec.ds
+/build/
+/coverage/
+
+# Symbolication related
+app.*.symbols
-# Android related
-#**/android/**/gradle-wrapper.jar
-**/android/.gradle
-**/android/captures/
-#**/android/gradlew
-#**/android/gradlew.bat
-**/android/local.properties
-**/android/**/GeneratedPluginRegistrant.java
+# Obfuscation related
+app.*.map.json
-# iOS/XCode related
-**/ios/**/*.mode1v3
-**/ios/**/*.mode2v3
-**/ios/**/*.moved-aside
-**/ios/**/*.pbxuser
-**/ios/**/*.perspectivev3
-**/ios/**/*sync/
-**/ios/**/.sconsign.dblite
-**/ios/**/.tags*
-**/ios/**/.vagrant/
-**/ios/**/DerivedData/
-**/ios/**/Icon?
-**/ios/**/Pods/
-**/ios/**/.symlinks/
-**/ios/**/profile
-**/ios/**/xcuserdata
-**/ios/.generated/
-**/ios/Flutter/App.framework
-**/ios/Flutter/Flutter.framework
-**/ios/Flutter/Generated.xcconfig
-**/ios/Flutter/app.flx
-**/ios/Flutter/app.zip
-**/ios/Flutter/flutter_assets/
-**/ios/ServiceDefinitions.json
-**/ios/Runner/GeneratedPluginRegistrant.*
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
-# Exceptions to above rules.
-!**/ios/**/default.mode1v3
-!**/ios/**/default.mode2v3
-!**/ios/**/default.pbxuser
-!**/ios/**/default.perspectivev3
-!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
\ No newline at end of file
+# Widget Preview related
+.widget_preview/
diff --git a/example/.metadata b/example/.metadata
index 82403ed..a54e41f 100644
--- a/example/.metadata
+++ b/example/.metadata
@@ -4,5 +4,33 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: c7ea3ca377e909469c68f2ab878a5bc53d3cf66b
- channel: beta
+ revision: "d3b14c876900e553bc736ca19295fc09e3853e8e"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+ base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+ - platform: android
+ create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+ base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+ - platform: ios
+ create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+ base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+ - platform: windows
+ create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+ base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/example/README.md b/example/README.md
index 64a12f6..cfab0dd 100644
--- a/example/README.md
+++ b/example/README.md
@@ -1,8 +1,7 @@
-# example
+# badges example
-A new Flutter project.
+A demo app for the [badges](https://pub.dev/packages/badges) package. It shows badges on
+app bar icons, tabs, the bottom navigation bar and avatars, plus the Twitter and Instagram
+shapes, gradients and the slide animation on the cart badge (tap + / - to change it).
-## Getting Started
-
-For help getting started with Flutter, view our online
-[documentation](https://flutter.io/).
+Run it with `flutter run` from this `example/` directory (Android, iOS or Windows).
diff --git a/example/android/.gitignore b/example/android/.gitignore
index 6f56801..be3943c 100644
--- a/example/android/.gitignore
+++ b/example/android/.gitignore
@@ -5,9 +5,10 @@ gradle-wrapper.jar
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
+.cxx/
# Remember to never publicly share your keystore.
-# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
deleted file mode 100644
index 5fe3c92..0000000
--- a/example/android/app/build.gradle
+++ /dev/null
@@ -1,68 +0,0 @@
-def localProperties = new Properties()
-def localPropertiesFile = rootProject.file('local.properties')
-if (localPropertiesFile.exists()) {
- localPropertiesFile.withReader('UTF-8') { reader ->
- localProperties.load(reader)
- }
-}
-
-def flutterRoot = localProperties.getProperty('flutter.sdk')
-if (flutterRoot == null) {
- throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
-}
-
-def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
-if (flutterVersionCode == null) {
- flutterVersionCode = '1'
-}
-
-def flutterVersionName = localProperties.getProperty('flutter.versionName')
-if (flutterVersionName == null) {
- flutterVersionName = '1.0'
-}
-
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
-
-android {
- compileSdkVersion flutter.compileSdkVersion
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
-
- kotlinOptions {
- jvmTarget = '1.8'
- }
-
- sourceSets {
- main.java.srcDirs += 'src/main/kotlin'
- }
-
- defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId "com.example.example"
- minSdkVersion flutter.minSdkVersion
- targetSdkVersion flutter.targetSdkVersion
- versionCode flutterVersionCode.toInteger()
- versionName flutterVersionName
- }
-
- buildTypes {
- release {
- // TODO: Add your own signing config for the release build.
- // Signing with the debug keys for now, so `flutter run --release` works.
- signingConfig signingConfigs.debug
- }
- }
-}
-
-flutter {
- source '../..'
-}
-
-dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-}
diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts
new file mode 100644
index 0000000..74caf01
--- /dev/null
+++ b/example/android/app/build.gradle.kts
@@ -0,0 +1,49 @@
+plugins {
+ id("com.android.application")
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id("dev.flutter.flutter-gradle-plugin")
+}
+
+android {
+ namespace = "com.example.example"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.example.example"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
+ minSdk = flutter.minSdkVersion
+ targetSdk = flutter.targetSdkVersion
+ // Uses the version code from pubspec.yaml. When using split APKs, 1000 * ABI_VERSION
+ // is added automatically by Flutter. (https://developer.android.com/studio/build/configure-apk-splits#configure-APK-versions)
+ // You can force using the value of versionCode by specifying the `-P force-version-code-ignoring-abi=true`
+ // flag during build.
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.getByName("debug")
+ }
+ }
+}
+
+kotlin {
+ compilerOptions {
+ jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml
index c208884..399f698 100644
--- a/example/android/app/src/debug/AndroidManifest.xml
+++ b/example/android/app/src/debug/AndroidManifest.xml
@@ -1,6 +1,6 @@
-
-
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index 3f41384..74a78b9 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
-
+
@@ -8,6 +7,7 @@
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
+ android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
@@ -31,4 +31,15 @@
android:name="flutterEmbedding"
android:value="2" />
+
+
+
+
+
+
+
diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt
index e793a00..ac81bae 100644
--- a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt
+++ b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt
@@ -2,5 +2,4 @@ package com.example.example
import io.flutter.embedding.android.FlutterActivity
-class MainActivity: FlutterActivity() {
-}
+class MainActivity : FlutterActivity()
diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml
index 3db14bb..06952be 100644
--- a/example/android/app/src/main/res/values-night/styles.xml
+++ b/example/android/app/src/main/res/values-night/styles.xml
@@ -3,7 +3,7 @@
diff --git a/example/android/build.gradle b/example/android/build.gradle
deleted file mode 100644
index 4256f91..0000000
--- a/example/android/build.gradle
+++ /dev/null
@@ -1,31 +0,0 @@
-buildscript {
- ext.kotlin_version = '1.6.10'
- repositories {
- google()
- mavenCentral()
- }
-
- dependencies {
- classpath 'com.android.tools.build:gradle:4.1.0'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- }
-}
-
-allprojects {
- repositories {
- google()
- mavenCentral()
- }
-}
-
-rootProject.buildDir = '../build'
-subprojects {
- project.buildDir = "${rootProject.buildDir}/${project.name}"
-}
-subprojects {
- project.evaluationDependsOn(':app')
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts
new file mode 100644
index 0000000..dbee657
--- /dev/null
+++ b/example/android/build.gradle.kts
@@ -0,0 +1,24 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+val newBuildDir: Directory =
+ rootProject.layout.buildDirectory
+ .dir("../../build")
+ .get()
+rootProject.layout.buildDirectory.value(newBuildDir)
+
+subprojects {
+ val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
+ project.layout.buildDirectory.value(newSubprojectBuildDir)
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean") {
+ delete(rootProject.layout.buildDirectory)
+}
diff --git a/example/android/gradle.properties b/example/android/gradle.properties
index 94adc3a..e96108c 100644
--- a/example/android/gradle.properties
+++ b/example/android/gradle.properties
@@ -1,3 +1,6 @@
-org.gradle.jvmargs=-Xmx1536M
+org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
-android.enableJetifier=true
+# This newDsl flag was added by the Flutter template
+android.newDsl=false
+# This builtInKotlin flag was added by the Flutter template
+android.builtInKotlin=false
diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties
index bc6a58a..a20f2c4 100644
--- a/example/android/gradle/wrapper/gradle-wrapper.properties
+++ b/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip
diff --git a/example/android/settings.gradle b/example/android/settings.gradle
deleted file mode 100644
index 44e62bc..0000000
--- a/example/android/settings.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
-include ':app'
-
-def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
-def properties = new Properties()
-
-assert localPropertiesFile.exists()
-localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
-
-def flutterSdkPath = properties.getProperty("flutter.sdk")
-assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
-apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts
new file mode 100644
index 0000000..b28021a
--- /dev/null
+++ b/example/android/settings.gradle.kts
@@ -0,0 +1,26 @@
+pluginManagement {
+ val flutterSdkPath =
+ run {
+ val properties = java.util.Properties()
+ file("local.properties").inputStream().use { properties.load(it) }
+ val flutterSdkPath = properties.getProperty("flutter.sdk")
+ require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
+ flutterSdkPath
+ }
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id("dev.flutter.flutter-plugin-loader") version "1.0.0"
+ id("com.android.application") version "9.1.0" apply false
+ id("org.jetbrains.kotlin.android") version "2.4.0" apply false
+}
+
+include(":app")
diff --git a/example/coverage/lcov.info b/example/coverage/lcov.info
deleted file mode 100644
index e69de29..0000000
diff --git a/example/ios/.gitignore b/example/ios/.gitignore
index c096a2d..7a7f987 100644
--- a/example/ios/.gitignore
+++ b/example/ios/.gitignore
@@ -1,46 +1,34 @@
-.idea/
-.vagrant/
-.sconsign.dblite
-.svn/
-
-.DS_Store
-*.swp
-profile
-
-DerivedData/
-build/
-GeneratedPluginRegistrant.h
-GeneratedPluginRegistrant.m
-
-.generated/
-
-*.pbxuser
+**/dgph
*.mode1v3
*.mode2v3
+*.moved-aside
+*.pbxuser
*.perspectivev3
-
-!default.pbxuser
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
+!default.pbxuser
!default.perspectivev3
-
-xcuserdata
-
-*.moved-aside
-
-*.pyc
-*sync/
-Icon?
-.tags*
-
-/Flutter/app.flx
-/Flutter/app.zip
-/Flutter/flutter_assets/
-/Flutter/App.framework
-/Flutter/Flutter.framework
-/Flutter/Generated.xcconfig
-/ServiceDefinitions.json
-/Flutter/flutter_export_environment.sh
-
-Pods/
-.symlinks/
diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist
index 9625e10..391a902 100644
--- a/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/example/ios/Flutter/AppFrameworkInfo.plist
@@ -20,7 +20,5 @@
????
CFBundleVersion
1.0
- MinimumOSVersion
- 11.0
diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig
index ec97fc6..592ceee 100644
--- a/example/ios/Flutter/Debug.xcconfig
+++ b/example/ios/Flutter/Debug.xcconfig
@@ -1,2 +1 @@
-#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
diff --git a/example/ios/Flutter/Flutter.podspec b/example/ios/Flutter/Flutter.podspec
deleted file mode 100644
index 29758b7..0000000
--- a/example/ios/Flutter/Flutter.podspec
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# This podspec is NOT to be published. It is only used as a local source!
-# This is a generated file; do not edit or check into version control.
-#
-
-Pod::Spec.new do |s|
- s.name = 'Flutter'
- s.version = '1.0.0'
- s.summary = 'A UI toolkit for beautiful and fast apps.'
- s.homepage = 'https://flutter.dev'
- s.license = { :type => 'BSD' }
- s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
- s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
- s.ios.deployment_target = '11.0'
- # Framework linking is handled by Flutter tooling, not CocoaPods.
- # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
- s.vendored_frameworks = 'path/to/nothing'
-end
diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig
index c4855bf..592ceee 100644
--- a/example/ios/Flutter/Release.xcconfig
+++ b/example/ios/Flutter/Release.xcconfig
@@ -1,2 +1 @@
-#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
diff --git a/example/ios/Podfile b/example/ios/Podfile
deleted file mode 100644
index d207307..0000000
--- a/example/ios/Podfile
+++ /dev/null
@@ -1,38 +0,0 @@
-# Uncomment this line to define a global platform for your project
-# platform :ios, '11.0'
-
-# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
-ENV['COCOAPODS_DISABLE_STATS'] = 'true'
-
-project 'Runner', {
- 'Debug' => :debug,
- 'Profile' => :release,
- 'Release' => :release,
-}
-
-def flutter_root
- generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
- unless File.exist?(generated_xcode_build_settings_path)
- raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
- end
-
- File.foreach(generated_xcode_build_settings_path) do |line|
- matches = line.match(/FLUTTER_ROOT\=(.*)/)
- return matches[1].strip if matches
- end
- raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
-end
-
-require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
-
-flutter_ios_podfile_setup
-
-target 'Runner' do
- flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
-end
-
-post_install do |installer|
- installer.pods_project.targets.each do |target|
- flutter_additional_ios_build_settings(target)
- end
-end
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index 1c9a969..25942dc 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -8,17 +8,26 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
- 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
- 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
- 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
- 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
+ 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
- D40517F33D6344040707842E /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DD1FA343129FC7FF5F84D57 /* libPods-Runner.a */; };
/* End PBXBuildFile section */
+/* Begin PBXContainerItemProxy section */
+ 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
@@ -35,17 +44,17 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
- 3869DA7265273353387147B5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
- 7AEFC2AAAD1E41FEC8612C57 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
+ 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
- 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
- 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
- 7DD1FA343129FC7FF5F84D57 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
@@ -57,26 +66,25 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- D40517F33D6344040707842E /* libPods-Runner.a in Frameworks */,
+ 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- 040983FC55ACDB1E2FD95D0D /* Pods */ = {
+ 331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
- 7AEFC2AAAD1E41FEC8612C57 /* Pods-Runner.debug.xcconfig */,
- 3869DA7265273353387147B5 /* Pods-Runner.release.xcconfig */,
+ 331C807B294A618700263BE5 /* RunnerTests.swift */,
);
- name = Pods;
- path = Pods;
+ path = RunnerTests;
sourceTree = "";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
+ 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
@@ -91,8 +99,7 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
- 040983FC55ACDB1E2FD95D0D /* Pods */,
- 985BF9FFF7CA805928065D6C /* Frameworks */,
+ 331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "";
};
@@ -100,6 +107,7 @@
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "";
@@ -107,43 +115,43 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
- 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
- 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
- 97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "";
};
- 97C146F11CF9000F007C117D /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- 97C146F21CF9000F007C117D /* main.m */,
- );
- name = "Supporting Files";
- sourceTree = "";
- };
- 985BF9FFF7CA805928065D6C /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 7DD1FA343129FC7FF5F84D57 /* libPods-Runner.a */,
- );
- name = Frameworks;
- sourceTree = "";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
+ 331C8080294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+ buildPhases = (
+ 331C807D294A63A400263BE5 /* Sources */,
+ 331C807F294A63A400263BE5 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */,
+ );
+ name = RunnerTests;
+ productName = RunnerTests;
+ productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
- 57FBAE60819E5B5ADE59FB98 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
@@ -156,6 +164,9 @@
dependencies = (
);
name = Runner;
+ packageProductDependencies = (
+ 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
+ );
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
@@ -166,43 +177,56 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1430;
- ORGANIZATIONNAME = "The Chromium Authors";
+ BuildIndependentTargetsInParallel = YES;
+ LastUpgradeCheck = 1510;
+ ORGANIZATIONNAME = "";
TargetAttributes = {
+ 331C8080294A63A400263BE5 = {
+ CreatedOnToolsVersion = 14.0;
+ TestTargetID = 97C146ED1CF9000F007C117D;
+ };
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
- DevelopmentTeam = 2B9L42U8WK;
+ LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
- compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
- English,
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
+ packageReferences = (
+ 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
+ );
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
+ 331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
+ 331C807F294A63A400263BE5 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
- 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
- 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
@@ -227,28 +251,6 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
- 57FBAE60819E5B5ADE59FB98 /* [CP] Check Pods Manifest.lock */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
- );
- name = "[CP] Check Pods Manifest.lock";
- outputFileListPaths = (
- );
- outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- showEnvVarsInLog = 0;
- };
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -267,18 +269,34 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 331C807D294A63A400263BE5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
- 97C146F31CF9000F007C117D /* main.m in Sources */,
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
+/* Begin PBXTargetDependency section */
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97C146ED1CF9000F007C117D /* Runner */;
+ targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
@@ -299,10 +317,133 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 2B9L42U8WK;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 331C8088294A63A400263BE5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Debug;
+ };
+ 331C8089294A63A400263BE5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Release;
+ };
+ 331C808A294A63A400263BE5 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.example.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Profile;
+ };
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -312,12 +453,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -330,6 +473,7 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@@ -344,10 +488,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
@@ -356,6 +501,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -365,12 +511,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -383,6 +531,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -391,9 +540,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
+ STRING_CATALOG_GENERATE_SYMBOLS = YES;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
@@ -404,24 +557,20 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CURRENT_PROJECT_VERSION = 1;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 2B9L42U8WK;
ENABLE_BITCODE = NO;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/Flutter",
- );
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- LIBRARY_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/Flutter",
- );
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@@ -431,24 +580,19 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CURRENT_PROJECT_VERSION = 1;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 2B9L42U8WK;
ENABLE_BITCODE = NO;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/Flutter",
- );
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
- LIBRARY_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/Flutter",
- );
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
@@ -456,11 +600,22 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 331C8088294A63A400263BE5 /* Debug */,
+ 331C8089294A63A400263BE5 /* Release */,
+ 331C808A294A63A400263BE5 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@@ -470,11 +625,26 @@
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
+
+/* Begin XCLocalSwiftPackageReference section */
+ 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
+ };
+/* End XCLocalSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = FlutterGeneratedPluginSwiftPackage;
+ };
+/* End XCSwiftPackageProductDependency section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index 327eb3b..c3fedb2 100644
--- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,10 +1,28 @@
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
@@ -63,11 +91,9 @@
ReferencedContainer = "container:Runner.xcodeproj">
-
-
-
-
diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/example/ios/Runner/AppDelegate.h b/example/ios/Runner/AppDelegate.h
deleted file mode 100644
index 36e21bb..0000000
--- a/example/ios/Runner/AppDelegate.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#import
-#import
-
-@interface AppDelegate : FlutterAppDelegate
-
-@end
diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m
deleted file mode 100644
index 59a72e9..0000000
--- a/example/ios/Runner/AppDelegate.m
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "AppDelegate.h"
-#include "GeneratedPluginRegistrant.h"
-
-@implementation AppDelegate
-
-- (BOOL)application:(UIApplication *)application
- didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- [GeneratedPluginRegistrant registerWithRegistry:self];
- // Override point for customization after application launch.
- return [super application:application didFinishLaunchingWithOptions:launchOptions];
-}
-
-@end
diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..c30b367
--- /dev/null
+++ b/example/ios/Runner/AppDelegate.swift
@@ -0,0 +1,16 @@
+import Flutter
+import UIKit
+
+@main
+@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+
+ func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
+ GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
+ }
+}
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
index 3d43d11..dc9ada4 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
index 28c6bf0..7353c41 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
index 2ccbfd9..797d452 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
index f091b6b..6ed2d93 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
index 4cde121..4cd7b00 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
index d0ef06e..fe73094 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
index dcdc230..321773c 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
index 2ccbfd9..797d452 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
index c8f9ed8..502f463 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
index a6d6b86..0ec3034 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
index a6d6b86..0ec3034 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
index 75b2d16..e9f5fea 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
index c4df70d..84ac32a 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
index 6a84f41..8953cba 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
index d0e1f58..0467bf1 100644
Binary files a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist
index 8e5ff92..cd88d65 100644
--- a/example/ios/Runner/Info.plist
+++ b/example/ios/Runner/Info.plist
@@ -2,8 +2,12 @@
+ CADisableMinimumFrameDurationOnPhone
+
CFBundleDevelopmentRegion
- en
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Example
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
@@ -15,13 +19,36 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.0
+ $(FLUTTER_BUILD_NAME)
CFBundleSignature
????
CFBundleVersion
- 1
+ $(FLUTTER_BUILD_NUMBER)
LSRequiresIPhoneOS
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneClassName
+ UIWindowScene
+ UISceneConfigurationName
+ flutter
+ UISceneDelegateClassName
+ $(PRODUCT_MODULE_NAME).SceneDelegate
+ UISceneStoryboardFile
+ Main
+
+
+
+
+ UIApplicationSupportsIndirectInputEvents
+
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
@@ -39,11 +66,5 @@
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
- UIViewControllerBasedStatusBarAppearance
-
- CADisableMinimumFrameDurationOnPhone
-
- UIApplicationSupportsIndirectInputEvents
-
diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..308a2a5
--- /dev/null
+++ b/example/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/example/ios/Runner/SceneDelegate.swift b/example/ios/Runner/SceneDelegate.swift
new file mode 100644
index 0000000..b9ce8ea
--- /dev/null
+++ b/example/ios/Runner/SceneDelegate.swift
@@ -0,0 +1,6 @@
+import Flutter
+import UIKit
+
+class SceneDelegate: FlutterSceneDelegate {
+
+}
diff --git a/example/ios/Runner/main.m b/example/ios/Runner/main.m
deleted file mode 100644
index dff6597..0000000
--- a/example/ios/Runner/main.m
+++ /dev/null
@@ -1,9 +0,0 @@
-#import
-#import
-#import "AppDelegate.h"
-
-int main(int argc, char* argv[]) {
- @autoreleasepool {
- return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
- }
-}
diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000..86a7c3b
--- /dev/null
+++ b/example/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+ func testExample() {
+ // If you add code to the Runner application, consider adding tests here.
+ // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+ }
+
+}
diff --git a/example/lib/test_screen.dart b/example/lib/test_screen.dart
index 95503d1..20e5862 100644
--- a/example/lib/test_screen.dart
+++ b/example/lib/test_screen.dart
@@ -46,378 +46,405 @@ class _TestScreenState extends State {
return Scaffold(
appBar: AppBar(title: Text('Test Badge Screen')),
body: Padding(
- padding: const EdgeInsets.symmetric(vertical: 30.0),
+ padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
/// Circle Badge with button
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 20.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- _showCircleBadge = !_showCircleBadge;
- }),
- child: Text('Circle size'),
- ),
- ),
- badges.Badge(
- key: const Key('CircleBadge'),
- badgeAnimation: badges.BadgeAnimation.size(
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
- ),
- showBadge: _showCircleBadge,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: Colors.green,
+ // Scales the row down on narrow phones instead of overflowing.
+ FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 20.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ _showCircleBadge = !_showCircleBadge;
+ }),
+ child: Text('Circle size'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Text(
- 'circle',
- style: TextStyle(color: Colors.white),
+ badges.Badge(
+ key: const Key('CircleBadge'),
+ badgeAnimation: badges.BadgeAnimation.size(
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ showBadge: _showCircleBadge,
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.circle,
+ badgeColor: Colors.green,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Text(
+ 'circle',
+ style: TextStyle(color: Colors.white),
+ ),
),
),
- ),
- /// Square Badge with button
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 20.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- _showSquareBadge = !_showSquareBadge;
- }),
- child: Text('Square fade'),
- ),
- ),
- badges.Badge(
- key: const Key('SquareBadge'),
- badgeAnimation: badges.BadgeAnimation.fade(
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
- ),
- showBadge: _showSquareBadge,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.square,
- badgeColor: Colors.black,
+ /// Square Badge with button
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 20.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ _showSquareBadge = !_showSquareBadge;
+ }),
+ child: Text('Square fade'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Text('1111', style: TextStyle(color: Colors.white)),
+ badges.Badge(
+ key: const Key('SquareBadge'),
+ badgeAnimation: badges.BadgeAnimation.fade(
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ showBadge: _showSquareBadge,
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.square,
+ badgeColor: Colors.black,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Text(
+ '1111',
+ style: TextStyle(color: Colors.white),
+ ),
+ ),
),
- ),
- ],
+ ],
+ ),
),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- /// Twitter Badge with button
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- _showTwitterBadge = !_showTwitterBadge;
- }),
- child: Text('Twitter rotation'),
- ),
- ),
- badges.Badge(
- key: const Key('TwitterBadge'),
- badgeAnimation: badges.BadgeAnimation.rotation(
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
- ),
- showBadge: _showTwitterBadge,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.twitter,
- badgeColor: Colors.blue,
+ // Scales the row down on narrow phones instead of overflowing.
+ FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ /// Twitter Badge with button
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ _showTwitterBadge = !_showTwitterBadge;
+ }),
+ child: Text('Twitter rotation'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Icon(Icons.check, color: Colors.white),
+ badges.Badge(
+ key: const Key('TwitterBadge'),
+ badgeAnimation: badges.BadgeAnimation.rotation(
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ showBadge: _showTwitterBadge,
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.twitter,
+ badgeColor: Colors.blue,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Icon(Icons.check, color: Colors.white),
+ ),
),
- ),
- /// Instagram Badge with button
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- _showInstagramBadge = !_showInstagramBadge;
- }),
- child: Text('Instagram scale'),
- ),
- ),
- badges.Badge(
- key: const Key('InstagramBadge'),
- badgeAnimation: badges.BadgeAnimation.scale(
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
- ),
- showBadge: _showInstagramBadge,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.instagram,
- badgeColor: Colors.red,
+ /// Instagram Badge with button
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ _showInstagramBadge = !_showInstagramBadge;
+ }),
+ child: Text('Instagram scale'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Icon(Icons.camera, color: Colors.white),
+ badges.Badge(
+ key: const Key('InstagramBadge'),
+ badgeAnimation: badges.BadgeAnimation.scale(
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ showBadge: _showInstagramBadge,
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.instagram,
+ badgeColor: Colors.red,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Icon(Icons.camera, color: Colors.white),
+ ),
),
- ),
- ],
+ ],
+ ),
),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- /// Change Color Badge with button
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- if (_changeBadgeColor == Colors.purple) {
- _changeBadgeColor = Colors.orange;
- } else {
- _changeBadgeColor = Colors.purple;
- }
- }),
- child: Text('Change color'),
- ),
- ),
- badges.Badge(
- key: const Key('ChangeColorBadge'),
- badgeAnimation: badges.BadgeAnimation.scale(
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
- ),
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: _changeBadgeColor,
+ // Scales the row down on narrow phones instead of overflowing.
+ FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ /// Change Color Badge with button
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ if (_changeBadgeColor == Colors.purple) {
+ _changeBadgeColor = Colors.orange;
+ } else {
+ _changeBadgeColor = Colors.purple;
+ }
+ }),
+ child: Text('Change color'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Icon(Icons.ac_unit_sharp, color: Colors.white),
+ badges.Badge(
+ key: const Key('ChangeColorBadge'),
+ badgeAnimation: badges.BadgeAnimation.scale(
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.circle,
+ badgeColor: _changeBadgeColor,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Icon(Icons.ac_unit_sharp, color: Colors.white),
+ ),
),
- ),
- /// Change Icon Badge with button
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- if (_showChangeIconBadge) {
- if (_badgeIcon == Icons.account_balance_rounded) {
- _badgeIcon = Icons.add;
- _showChangeIconBadge = !_showChangeIconBadge;
+ /// Change Icon Badge with button
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ if (_showChangeIconBadge) {
+ if (_badgeIcon == Icons.account_balance_rounded) {
+ _badgeIcon = Icons.add;
+ _showChangeIconBadge = !_showChangeIconBadge;
+ } else {
+ _badgeIcon = Icons.account_balance_rounded;
+ _showChangeIconBadge = !_showChangeIconBadge;
+ }
} else {
- _badgeIcon = Icons.account_balance_rounded;
_showChangeIconBadge = !_showChangeIconBadge;
}
- } else {
- _showChangeIconBadge = !_showChangeIconBadge;
- }
- }),
- child: Text('Change icon'),
- ),
- ),
- badges.Badge(
- key: const Key('ChangeIconBadge'),
- badgeAnimation: badges.BadgeAnimation.scale(
- appearanceDisappearanceFadeAnimationEnabled: false,
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
+ }),
+ child: Text('Change icon'),
+ ),
),
- showBadge: _showChangeIconBadge,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: Colors.yellow,
+ badges.Badge(
+ key: const Key('ChangeIconBadge'),
+ badgeAnimation: badges.BadgeAnimation.scale(
+ appearanceDisappearanceFadeAnimationEnabled: false,
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ showBadge: _showChangeIconBadge,
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.circle,
+ badgeColor: Colors.yellow,
+ ),
+ badgeContent: Icon(_badgeIcon, color: Colors.white),
),
- badgeContent: Icon(_badgeIcon, color: Colors.white),
- ),
- ],
+ ],
+ ),
),
/// Change Amount Badge with button
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- ElevatedButton.icon(
- onPressed: () => setState(() {
- _badgeAmount++;
- }),
- icon: Icon(Icons.add),
- label: Text('Add'),
- ),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton.icon(
- onPressed: _badgeAmount != 0
- ? () => setState(() {
- _badgeAmount--;
- })
- : null,
- icon: Icon(Icons.remove),
- label: Text('Remove'),
- ),
- ),
- badges.Badge(
- key: const Key('ChangeAmountBadge'),
- badgeAnimation: badges.BadgeAnimation.slide(
- toAnimate: false,
- colorChangeAnimationDuration: Duration(milliseconds: 200),
- curve: Curves.easeInCubic,
- ),
- showBadge: _showBadgeAmount,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: Colors.pink,
- ),
- badgeContent: Text(_badgeAmount.toString()),
- ),
- ],
- ),
-
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- /// Animation Duration More Appearance Duration
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton(
+ // Scales the row down on narrow phones instead of overflowing.
+ FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ ElevatedButton.icon(
onPressed: () => setState(() {
- _showAnimMoreAppear = !_showAnimMoreAppear;
+ _badgeAmount++;
}),
- child: Text('anim>appear'),
- ),
- ),
- badges.Badge(
- showBadge: _showAnimMoreAppear,
- key: const Key('AnimationMoreAppearance'),
- badgeAnimation: badges.BadgeAnimation.scale(
- animationDuration: Duration(milliseconds: 500),
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
- ),
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: Colors.green,
+ icon: Icon(Icons.add),
+ label: Text('Add'),
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton.icon(
+ onPressed: _badgeAmount != 0
+ ? () => setState(() {
+ _badgeAmount--;
+ })
+ : null,
+ icon: Icon(Icons.remove),
+ label: Text('Remove'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Icon(Icons.cloud, color: Colors.white),
+ badges.Badge(
+ key: const Key('ChangeAmountBadge'),
+ badgeAnimation: badges.BadgeAnimation.slide(
+ toAnimate: false,
+ colorChangeAnimationDuration: Duration(milliseconds: 200),
+ curve: Curves.easeInCubic,
+ ),
+ showBadge: _showBadgeAmount,
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.circle,
+ badgeColor: Colors.pink,
+ ),
+ badgeContent: Text(_badgeAmount.toString()),
),
- ),
+ ],
+ ),
+ ),
- /// Animation Duration Less Appearance Duration
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- _showAnimLessAppear = !_showAnimLessAppear;
- }),
- child: Text('anim setState(() {
+ _showAnimMoreAppear = !_showAnimMoreAppear;
+ }),
+ child: Text('anim>appear'),
+ ),
),
- ),
- badges.Badge(
- key: const Key('AnimationLessAppearance'),
- badgeAnimation: badges.BadgeAnimation.scale(
- animationDuration: Duration(milliseconds: 200),
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 500,
- ),
- curve: Curves.easeInCubic,
+ badges.Badge(
+ showBadge: _showAnimMoreAppear,
+ key: const Key('AnimationMoreAppearance'),
+ badgeAnimation: badges.BadgeAnimation.scale(
+ animationDuration: Duration(milliseconds: 500),
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.circle,
+ badgeColor: Colors.green,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Icon(Icons.cloud, color: Colors.white),
+ ),
),
- showBadge: _showAnimLessAppear,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: Colors.purple,
+
+ /// Animation Duration Less Appearance Duration
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ _showAnimLessAppear = !_showAnimLessAppear;
+ }),
+ child: Text('anim setState(() {
- _showAnimZero = !_showAnimZero;
- }),
- child: Text('anim=zero'),
- ),
- ),
- badges.Badge(
- showBadge: _showAnimZero,
- key: const Key('AnimationZero'),
- badgeAnimation: badges.BadgeAnimation.scale(
- animationDuration: Duration.zero,
- disappearanceFadeAnimationDuration: Duration(
- milliseconds: 200,
- ),
- curve: Curves.easeInCubic,
- ),
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: Colors.black38,
+ // Scales the row down on narrow phones instead of overflowing.
+ FittedBox(
+ fit: BoxFit.scaleDown,
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ /// Animation Duration Zero
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ _showAnimZero = !_showAnimZero;
+ }),
+ child: Text('anim=zero'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Icon(Icons.adb, color: Colors.white),
+ badges.Badge(
+ showBadge: _showAnimZero,
+ key: const Key('AnimationZero'),
+ badgeAnimation: badges.BadgeAnimation.scale(
+ animationDuration: Duration.zero,
+ disappearanceFadeAnimationDuration: Duration(
+ milliseconds: 200,
+ ),
+ curve: Curves.easeInCubic,
+ ),
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.circle,
+ badgeColor: Colors.black38,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Icon(Icons.adb, color: Colors.white),
+ ),
),
- ),
- /// Appearance Duration Zero
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 10.0),
- child: ElevatedButton(
- onPressed: () => setState(() {
- _showAppearZero = !_showAppearZero;
- }),
- child: Text('appear=zero'),
- ),
- ),
- badges.Badge(
- key: const Key('AppearanceZero'),
- badgeAnimation: badges.BadgeAnimation.scale(
- animationDuration: Duration(milliseconds: 200),
- disappearanceFadeAnimationDuration: Duration.zero,
- curve: Curves.easeInCubic,
- ),
- showBadge: _showAppearZero,
- badgeStyle: badges.BadgeStyle(
- shape: badges.BadgeShape.circle,
- badgeColor: Colors.brown,
+ /// Appearance Duration Zero
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10.0),
+ child: ElevatedButton(
+ onPressed: () => setState(() {
+ _showAppearZero = !_showAppearZero;
+ }),
+ child: Text('appear=zero'),
+ ),
),
- badgeContent: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Icon(Icons.access_time, color: Colors.white),
+ badges.Badge(
+ key: const Key('AppearanceZero'),
+ badgeAnimation: badges.BadgeAnimation.scale(
+ animationDuration: Duration(milliseconds: 200),
+ disappearanceFadeAnimationDuration: Duration.zero,
+ curve: Curves.easeInCubic,
+ ),
+ showBadge: _showAppearZero,
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.circle,
+ badgeColor: Colors.brown,
+ ),
+ badgeContent: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Icon(Icons.access_time, color: Colors.white),
+ ),
),
- ),
- ],
+ ],
+ ),
),
],
),
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 6cb1d9c..124d1e7 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -1,5 +1,7 @@
name: example
-description: A new Flutter project.
+description: Demo app for the badges package.
+publish_to: 'none'
+version: 1.0.0+1
environment:
sdk: ">=3.13.0 <4.0.0"
diff --git a/example/windows/CMakeLists.txt b/example/windows/CMakeLists.txt
index 55ab02e..d960948 100644
--- a/example/windows/CMakeLists.txt
+++ b/example/windows/CMakeLists.txt
@@ -1,13 +1,16 @@
+# Project-level configuration.
cmake_minimum_required(VERSION 3.14)
-project(examlpe LANGUAGES CXX)
+project(example LANGUAGES CXX)
-set(BINARY_NAME "examlpe")
+# The name of the executable created for the application. Change this to change
+# the on-disk name of your application.
+set(BINARY_NAME "example")
-cmake_policy(SET CMP0063 NEW)
+# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
+# versions of CMake.
+cmake_policy(VERSION 3.14...3.25)
-set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
-
-# Configure build options.
+# Define build configuration option.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
@@ -20,7 +23,7 @@ else()
"Debug" "Profile" "Release")
endif()
endif()
-
+# Define settings for the Profile build mode.
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
@@ -30,6 +33,10 @@ set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets.
+#
+# Be cautious about adding new options here, as plugins use this function by
+# default. In most cases, you should add new options to specific targets instead
+# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
@@ -38,14 +45,14 @@ function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>")
endfunction()
-set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
-
# Flutter library and tool build rules.
+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
-# Application build
+# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
+
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
@@ -80,6 +87,12 @@ if(PLUGIN_BUNDLED_LIBRARIES)
COMPONENT Runtime)
endif()
+# Copy the native assets provided by the build.dart from all packages.
+set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
+install(DIRECTORY "${NATIVE_ASSETS_DIR}"
+ DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+ COMPONENT Runtime)
+
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
diff --git a/example/windows/flutter/CMakeLists.txt b/example/windows/flutter/CMakeLists.txt
index b2e4bd8..903f489 100644
--- a/example/windows/flutter/CMakeLists.txt
+++ b/example/windows/flutter/CMakeLists.txt
@@ -1,3 +1,4 @@
+# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.14)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
@@ -9,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake)
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
+# Set fallback configurations for older versions of the flutter tool.
+if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
+ set(FLUTTER_TARGET_PLATFORM "windows-x64")
+endif()
+
# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
@@ -91,7 +97,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
- windows-x64 $
+ ${FLUTTER_TARGET_PLATFORM} $
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
diff --git a/example/windows/runner/CMakeLists.txt b/example/windows/runner/CMakeLists.txt
index de2d891..394917c 100644
--- a/example/windows/runner/CMakeLists.txt
+++ b/example/windows/runner/CMakeLists.txt
@@ -1,6 +1,11 @@
cmake_minimum_required(VERSION 3.14)
project(runner LANGUAGES CXX)
+# Define the application target. To change its name, change BINARY_NAME in the
+# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
+# work.
+#
+# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp"
"main.cpp"
@@ -10,8 +15,26 @@ add_executable(${BINARY_NAME} WIN32
"Runner.rc"
"runner.exe.manifest"
)
+
+# Apply the standard set of build settings. This can be removed for applications
+# that need different build settings.
apply_standard_settings(${BINARY_NAME})
+
+# Add preprocessor definitions for the build version.
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
+
+# Disable Windows macros that collide with C++ standard library functions.
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
+
+# Add dependency libraries and include directories. Add any application-specific
+# dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
+target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
+
+# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble)
diff --git a/example/windows/runner/Runner.rc b/example/windows/runner/Runner.rc
index 7bb917a..0e3e27b 100644
--- a/example/windows/runner/Runner.rc
+++ b/example/windows/runner/Runner.rc
@@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico"
// Version
//
-#ifdef FLUTTER_BUILD_NUMBER
-#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
+#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
+#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
#else
-#define VERSION_AS_NUMBER 1,0,0
+#define VERSION_AS_NUMBER 1,0,0,0
#endif
-#ifdef FLUTTER_BUILD_NAME
-#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
+#if defined(FLUTTER_VERSION)
+#define VERSION_AS_STRING FLUTTER_VERSION
#else
#define VERSION_AS_STRING "1.0.0"
#endif
@@ -90,12 +90,12 @@ BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "com.example" "\0"
- VALUE "FileDescription", "examlpe" "\0"
+ VALUE "FileDescription", "example" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
- VALUE "InternalName", "examlpe" "\0"
- VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0"
- VALUE "OriginalFilename", "examlpe.exe" "\0"
- VALUE "ProductName", "examlpe" "\0"
+ VALUE "InternalName", "example" "\0"
+ VALUE "LegalCopyright", "Copyright (C) 2026 com.example. All rights reserved." "\0"
+ VALUE "OriginalFilename", "example.exe" "\0"
+ VALUE "ProductName", "example" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
END
END
diff --git a/example/windows/runner/flutter_window.cpp b/example/windows/runner/flutter_window.cpp
index b43b909..955ee30 100644
--- a/example/windows/runner/flutter_window.cpp
+++ b/example/windows/runner/flutter_window.cpp
@@ -26,6 +26,16 @@ bool FlutterWindow::OnCreate() {
}
RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow());
+
+ flutter_controller_->engine()->SetNextFrameCallback([&]() {
+ this->Show();
+ });
+
+ // Flutter can complete the first frame before the "show window" callback is
+ // registered. The following call ensures a frame is pending to ensure the
+ // window is shown. It is a no-op if the first frame hasn't completed yet.
+ flutter_controller_->ForceRedraw();
+
return true;
}
diff --git a/example/windows/runner/main.cpp b/example/windows/runner/main.cpp
index 5a0b3ea..a61bf80 100644
--- a/example/windows/runner/main.cpp
+++ b/example/windows/runner/main.cpp
@@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
- if (!window.CreateAndShow(L"examlpe", origin, size)) {
+ if (!window.Create(L"example", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
diff --git a/example/windows/runner/runner.exe.manifest b/example/windows/runner/runner.exe.manifest
index c977c4a..153653e 100644
--- a/example/windows/runner/runner.exe.manifest
+++ b/example/windows/runner/runner.exe.manifest
@@ -7,14 +7,8 @@
-
+
-
-
-
-
-
-
diff --git a/example/windows/runner/utils.cpp b/example/windows/runner/utils.cpp
index d19bdbb..3cb7146 100644
--- a/example/windows/runner/utils.cpp
+++ b/example/windows/runner/utils.cpp
@@ -45,18 +45,23 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) {
if (utf16_string == nullptr) {
return std::string();
}
+ // First, find the length of the string with a safe upper bound (CWE-126).
+ // UNICODE_STRING_MAX_CHARS (32767) is the maximum length of a UNICODE_STRING.
+ int input_length = static_cast(wcsnlen(utf16_string, UNICODE_STRING_MAX_CHARS));
+ // Now use that bounded length to determine the required buffer size.
+ // When an explicit length is passed, WideCharToMultiByte does not include
+ // the null terminator in its returned size.
int target_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
- -1, nullptr, 0, nullptr, nullptr);
- if (target_length == 0) {
- return std::string();
- }
+ input_length, nullptr, 0, nullptr, nullptr);
std::string utf8_string;
+ if (target_length == 0 || static_cast(target_length) > utf8_string.max_size()) {
+ return utf8_string;
+ }
utf8_string.resize(target_length);
int converted_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
- -1, utf8_string.data(),
- target_length, nullptr, nullptr);
+ input_length, utf8_string.data(), target_length, nullptr, nullptr);
if (converted_length == 0) {
return std::string();
}
diff --git a/example/windows/runner/win32_window.cpp b/example/windows/runner/win32_window.cpp
index c10f08d..60608d0 100644
--- a/example/windows/runner/win32_window.cpp
+++ b/example/windows/runner/win32_window.cpp
@@ -1,13 +1,31 @@
#include "win32_window.h"
+#include
#include
#include "resource.h"
namespace {
+/// Window attribute that enables dark mode window decorations.
+///
+/// Redefined in case the developer's machine has a Windows SDK older than
+/// version 10.0.22000.0.
+/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
+#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
+#endif
+
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
+/// Registry key for app theme preference.
+///
+/// A value of 0 indicates apps should use dark mode. A non-zero or missing
+/// value indicates apps should use light mode.
+constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
+constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
+
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
@@ -31,8 +49,8 @@ void EnableFullDpiSupportIfAvailable(HWND hwnd) {
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr) {
enable_non_client_dpi_scaling(hwnd);
- FreeLibrary(user32_module);
}
+ FreeLibrary(user32_module);
}
} // namespace
@@ -42,7 +60,7 @@ class WindowClassRegistrar {
public:
~WindowClassRegistrar() = default;
- // Returns the singleton registar instance.
+ // Returns the singleton registrar instance.
static WindowClassRegistrar* GetInstance() {
if (!instance_) {
instance_ = new WindowClassRegistrar();
@@ -102,9 +120,9 @@ Win32Window::~Win32Window() {
Destroy();
}
-bool Win32Window::CreateAndShow(const std::wstring& title,
- const Point& origin,
- const Size& size) {
+bool Win32Window::Create(const std::wstring& title,
+ const Point& origin,
+ const Size& size) {
Destroy();
const wchar_t* window_class =
@@ -117,7 +135,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
double scale_factor = dpi / 96.0;
HWND window = CreateWindow(
- window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
nullptr, nullptr, GetModuleHandle(nullptr), this);
@@ -126,9 +144,15 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
return false;
}
+ UpdateTheme(window);
+
return OnCreate();
}
+bool Win32Window::Show() {
+ return ShowWindow(window_handle_, SW_SHOWNORMAL);
+}
+
// static
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
UINT const message,
@@ -188,6 +212,10 @@ Win32Window::MessageHandler(HWND hwnd,
SetFocus(child_content_);
}
return 0;
+
+ case WM_DWMCOLORIZATIONCOLORCHANGED:
+ UpdateTheme(hwnd);
+ return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
@@ -243,3 +271,18 @@ bool Win32Window::OnCreate() {
void Win32Window::OnDestroy() {
// No-op; provided for subclasses.
}
+
+void Win32Window::UpdateTheme(HWND const window) {
+ DWORD light_mode;
+ DWORD light_mode_size = sizeof(light_mode);
+ LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
+ kGetPreferredBrightnessRegValue,
+ RRF_RT_REG_DWORD, nullptr, &light_mode,
+ &light_mode_size);
+
+ if (result == ERROR_SUCCESS) {
+ BOOL enable_dark_mode = light_mode == 0;
+ DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
+ &enable_dark_mode, sizeof(enable_dark_mode));
+ }
+}
diff --git a/example/windows/runner/win32_window.h b/example/windows/runner/win32_window.h
index 17ba431..e901dde 100644
--- a/example/windows/runner/win32_window.h
+++ b/example/windows/runner/win32_window.h
@@ -28,15 +28,16 @@ class Win32Window {
Win32Window();
virtual ~Win32Window();
- // Creates and shows a win32 window with |title| and position and size using
+ // Creates a win32 window with |title| that is positioned and sized using
// |origin| and |size|. New windows are created on the default monitor. Window
// sizes are specified to the OS in physical pixels, hence to ensure a
- // consistent size to will treat the width height passed in to this function
- // as logical pixels and scale to appropriate for the default monitor. Returns
- // true if the window was created successfully.
- bool CreateAndShow(const std::wstring& title,
- const Point& origin,
- const Size& size);
+ // consistent size this function will scale the inputted width and height as
+ // as appropriate for the default monitor. The window is invisible until
+ // |Show| is called. Returns true if the window was created successfully.
+ bool Create(const std::wstring& title, const Point& origin, const Size& size);
+
+ // Show the current window. Returns true if the window was successfully shown.
+ bool Show();
// Release OS resources associated with window.
void Destroy();
@@ -76,7 +77,7 @@ class Win32Window {
// OS callback called by message pump. Handles the WM_NCCREATE message which
// is passed when the non-client area is being created and enables automatic
// non-client DPI scaling so that the non-client area automatically
- // responsponds to changes in DPI. All other messages are handled by
+ // responds to changes in DPI. All other messages are handled by
// MessageHandler.
static LRESULT CALLBACK WndProc(HWND const window,
UINT const message,
@@ -86,6 +87,9 @@ class Win32Window {
// Retrieves a class instance pointer for |window|
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
+ // Update the window frame's theme to match the system theme.
+ static void UpdateTheme(HWND const window);
+
bool quit_on_close_ = false;
// window handle for top level window.
diff --git a/lib/src/badge.dart b/lib/src/badge.dart
index 9874fd9..caa3eeb 100644
--- a/lib/src/badge.dart
+++ b/lib/src/badge.dart
@@ -34,10 +34,12 @@ class Badge extends StatefulWidget {
/// Content inside badge.
final Widget? badgeContent;
- /// Can make your [badgeContent] interactive.
+ /// Whether the badge ignores taps.
/// The default value is false.
- /// Make it true to make badge intercept all taps
- /// Make it false and all taps will be passed through the badge
+ /// Keep it false so the badge receives taps ([onTap] and any interactive
+ /// [badgeContent] work).
+ /// Make it true and all taps will pass through the badge to the widgets
+ /// below it. [onTap] is not called then.
final bool ignorePointer;
/// Allows to edit fit parameter to [Stack] widget.
@@ -50,7 +52,9 @@ class Badge extends StatefulWidget {
/// Will be called when you tap on the badge
/// Important: if the badge is outside of the child
- /// the additional padding will be applied to make the full badge clickable
+ /// the additional padding will be applied to make the full badge clickable.
+ /// This padding makes the whole widget bigger, so it can move the widgets
+ /// around it.
final Function()? onTap;
@override
@@ -103,12 +107,18 @@ class BadgeState extends State with TickerProviderStateMixin {
}
}
+ /// A hidden badge must not catch taps meant for the widgets below it.
+ Widget _getTappableBadge() {
+ return IgnorePointer(
+ ignoring: widget.ignorePointer || !widget.showBadge,
+ child: GestureDetector(onTap: widget.onTap, child: _getBadge()),
+ );
+ }
+
@override
Widget build(BuildContext context) {
if (widget.child == null) {
- return widget.ignorePointer
- ? IgnorePointer(child: _getBadge())
- : GestureDetector(onTap: widget.onTap, child: _getBadge());
+ return _getTappableBadge();
} else {
return Stack(
fit: widget.stackFit,
@@ -128,9 +138,7 @@ class BadgeState extends State with TickerProviderStateMixin {
position: widget.onTap == null
? widget.position
: CalculationUtils.calculatePosition(widget.position),
- child: widget.ignorePointer
- ? IgnorePointer(child: _getBadge())
- : GestureDetector(onTap: widget.onTap, child: _getBadge()),
+ child: _getTappableBadge(),
),
],
);
@@ -206,6 +214,22 @@ class BadgeState extends State with TickerProviderStateMixin {
if (!widget.badgeAnimation.toAnimate) return;
+ // Animations were off, so the controllers never ran. Jump them to the
+ // end so the badge doesn't turn invisible.
+ if (!oldWidget.badgeAnimation.toAnimate) {
+ if (widget.showBadge) {
+ _animationController.value = 1;
+ _appearanceController.value = 1;
+ if (widget.badgeAnimation.loopAnimation && enableLoopAnimation) {
+ _animationController.repeat(
+ period: _animationController.duration,
+ reverse: true,
+ );
+ }
+ }
+ return;
+ }
+
// --- showBadge changes are handled FIRST (fixes issue #114) ---
// Badge became visible.
@@ -357,49 +381,57 @@ class _BadgeVisual extends StatelessWidget {
);
}
+ Widget container = AnimatedContainer(
+ curve: badgeAnimation.colorChangeAnimationCurve,
+ duration: badgeAnimation.toAnimate
+ ? badgeAnimation.colorChangeAnimationDuration
+ : Duration.zero,
+ decoration: badgeStyle.shape == BadgeShape.circle
+ ? BoxDecoration(
+ color: badgeStyle.badgeColor,
+ border: boxBorder,
+ gradient: badgeStyle.badgeGradient?.gradient(),
+ shape: BoxShape.circle,
+ )
+ : BoxDecoration(
+ color: badgeStyle.badgeColor,
+ gradient: badgeStyle.badgeGradient?.gradient(),
+ shape: BoxShape.rectangle,
+ borderRadius: badgeStyle.borderRadius,
+ border: boxBorder,
+ ),
+ // IntrinsicWidth sizes the badge to its content's natural width.
+ child: IntrinsicWidth(
+ child: Padding(padding: badgeStyle.padding, child: badgeContent),
+ ),
+ );
+
+ // MaterialType.transparency never paints a shadow, so the elevation
+ // shadow is drawn here instead.
+ if (badgeStyle.elevation > 0) {
+ container = PhysicalShape(
+ clipper: ShapeBorderClipper(shape: materialShape),
+ elevation: badgeStyle.elevation,
+ color: Colors.transparent,
+ shadowColor: Colors.black,
+ child: container,
+ );
+ }
+
return Material(
shape: materialShape,
- elevation: badgeStyle.elevation,
// Without this Colors.transparent will be ignored
type: MaterialType.transparency,
- child: AnimatedContainer(
- curve: badgeAnimation.colorChangeAnimationCurve,
- duration: badgeAnimation.toAnimate
- ? badgeAnimation.colorChangeAnimationDuration
- : Duration.zero,
- decoration: badgeStyle.shape == BadgeShape.circle
- ? BoxDecoration(
- color: badgeStyle.badgeColor,
- border: boxBorder,
- gradient: badgeStyle.badgeGradient?.gradient(),
- shape: BoxShape.circle,
- )
- : BoxDecoration(
- color: badgeStyle.badgeColor,
- gradient: badgeStyle.badgeGradient?.gradient(),
- shape: BoxShape.rectangle,
- borderRadius: badgeStyle.borderRadius,
- border: boxBorder,
- ),
- // ConstrainedBox ensures the badge is at least as wide as it is tall,
- // so single-character / small-icon badges stay circular (PR #111).
- child: ConstrainedBox(
- constraints: const BoxConstraints(minWidth: 0),
- child: IntrinsicWidth(
- child: Padding(padding: badgeStyle.padding, child: badgeContent),
- ),
- ),
- ),
+ child: container,
);
}
@override
Widget build(BuildContext context) {
+ // Listen to the controller directly: a new CurvedAnimation per build
+ // would add a listener to the controller every time and never remove it.
final inner = AnimatedBuilder(
- animation: CurvedAnimation(
- parent: appearanceController,
- curve: Curves.linear,
- ),
+ animation: appearanceController,
builder: (context, child) {
return Opacity(opacity: _getOpacity(), child: child);
},
diff --git a/lib/src/badge_position.dart b/lib/src/badge_position.dart
index 36ea473..d0da1bc 100644
--- a/lib/src/badge_position.dart
+++ b/lib/src/badge_position.dart
@@ -16,7 +16,9 @@ class BadgePosition {
/// Distance to the bottom side of a parent widget.
final double? bottom;
- /// Indicates that the badge is in center of parent widget
+ /// Indicates that the badge is centered in the parent widget.
+ /// If [start] or [end] is set, the badge is only centered vertically
+ /// and keeps that horizontal offset.
final bool isCenter;
/// This creates a new instance of this widget
@@ -77,12 +79,12 @@ class BadgePosition {
/// Factory method that creates a new instance of this widget
/// vertically centered on the start (left) side.
factory BadgePosition.centerStart({double start = -10}) {
- return BadgePosition._(start: start);
+ return BadgePosition._(start: start, isCenter: true);
}
/// Factory method that creates a new instance of this widget
/// vertically centered on the end (right) side.
factory BadgePosition.centerEnd({double end = -10}) {
- return BadgePosition._(end: end);
+ return BadgePosition._(end: end, isCenter: true);
}
}
diff --git a/lib/src/badge_positioned.dart b/lib/src/badge_positioned.dart
index 2d4f87e..7e7b010 100644
--- a/lib/src/badge_positioned.dart
+++ b/lib/src/badge_positioned.dart
@@ -31,6 +31,17 @@ class BadgePositioned extends StatelessWidget {
);
}
+ if (position.isCenter && (position.start != null || position.end != null)) {
+ // centerStart / centerEnd: centered vertically, offset horizontally.
+ return PositionedDirectional(
+ top: 0,
+ bottom: 0,
+ start: position.start,
+ end: position.end,
+ child: Align(widthFactor: 1, child: child),
+ );
+ }
+
if (position.isCenter) {
return Positioned.fill(
child: Align(alignment: Alignment.center, child: child),
diff --git a/lib/src/badge_shape.dart b/lib/src/badge_shape.dart
index d9b271b..869ed16 100644
--- a/lib/src/badge_shape.dart
+++ b/lib/src/badge_shape.dart
@@ -16,10 +16,10 @@ enum BadgeShape {
square,
/// To make the twitter badge .
- /// See [TwitterBadgeShapePainter] for more details.
+ /// Drawn with a custom painter.
twitter,
/// To make the instagram badge .
- /// See [InstagramBadgeShapePainter] for more details.
+ /// Drawn with a custom painter.
instagram,
}
diff --git a/lib/src/badge_style.dart b/lib/src/badge_style.dart
index b376998..1eab815 100644
--- a/lib/src/badge_style.dart
+++ b/lib/src/badge_style.dart
@@ -11,7 +11,7 @@ class BadgeStyle {
final BorderRadius borderRadius;
/// Background color of the badge.
- /// If [gradient] is not null, this property will be ignored.
+ /// If [badgeGradient] is not null, this property will be ignored.
final Color badgeColor;
/// Allows to set border side to this [badgeContent].
@@ -19,6 +19,8 @@ class BadgeStyle {
final BorderSide borderSide;
/// The size of the shadow below the badge.
+ /// The default value is 0 (no shadow).
+ /// Ignored for [BadgeShape.twitter] and [BadgeShape.instagram].
final double elevation;
/// Background gradient color of the badge.
@@ -38,7 +40,7 @@ class BadgeStyle {
this.borderRadius = BorderRadius.zero,
this.badgeColor = Colors.red,
this.borderSide = BorderSide.none,
- this.elevation = 2,
+ this.elevation = 0,
this.badgeGradient,
this.borderGradient,
this.padding = const EdgeInsets.all(5.0),
diff --git a/lib/src/utils/calculation_utils.dart b/lib/src/utils/calculation_utils.dart
index 83a00b1..f9068e9 100644
--- a/lib/src/utils/calculation_utils.dart
+++ b/lib/src/utils/calculation_utils.dart
@@ -1,5 +1,5 @@
import 'package:badges/badges.dart';
-import 'package:material_ui/material_ui.dart';
+import 'package:flutter/widgets.dart';
class CalculationUtils {
/// When the onTap is specified the additional padding is added
@@ -16,6 +16,14 @@ class CalculationUtils {
return !digit.isNegative ? digit : 0;
}
+ if (position.isCenter) {
+ return BadgePosition.custom(
+ start: getUpdatedPosition(position.start),
+ end: getUpdatedPosition(position.end),
+ isCenter: true,
+ );
+ }
+
return BadgePosition.custom(
start: getUpdatedPosition(position.start),
end: getUpdatedPosition(position.end),
@@ -26,13 +34,11 @@ class CalculationUtils {
/// When the onTap is specified, we need to add some padding
/// to make the full badge tappable.
- static EdgeInsets calculatePadding(BadgePosition? position) {
+ /// The padding is directional because the badge is positioned with
+ /// start/end, so it stays correct in right-to-left layouts.
+ static EdgeInsetsDirectional calculatePadding(BadgePosition? position) {
if (position == null) {
- return const EdgeInsets.only(top: 8, right: 10);
- }
-
- if (position.isCenter) {
- return EdgeInsets.zero;
+ return const EdgeInsetsDirectional.only(top: 8, end: 10);
}
double getUpdatedPadding(double? digit) {
@@ -42,17 +48,24 @@ class CalculationUtils {
return digit.abs();
}
+ if (position.isCenter) {
+ return EdgeInsetsDirectional.only(
+ start: getUpdatedPadding(position.start),
+ end: getUpdatedPadding(position.end),
+ );
+ }
+
if (position.top != null && position.start != null) {
- return EdgeInsets.only(
+ return EdgeInsetsDirectional.only(
top: getUpdatedPadding(position.top),
- left: getUpdatedPadding(position.start),
+ start: getUpdatedPadding(position.start),
);
}
- return EdgeInsets.only(
+ return EdgeInsetsDirectional.only(
top: getUpdatedPadding(position.top),
bottom: getUpdatedPadding(position.bottom),
- left: getUpdatedPadding(position.start),
- right: getUpdatedPadding(position.end),
+ start: getUpdatedPadding(position.start),
+ end: getUpdatedPadding(position.end),
);
}
@@ -80,6 +93,10 @@ class CalculationUtils {
} else if (alignment == Alignment.topRight) {
return Offset(width * 0.809, height * 0.191);
}
- return Offset(width, height);
+ // Any other alignment (e.g. AlignmentDirectional) maps to its point in
+ // the badge rect.
+ return alignment
+ .resolve(TextDirection.ltr)
+ .withinRect(Offset.zero & Size(width, height));
}
}
diff --git a/lib/src/utils/gradient_utils.dart b/lib/src/utils/gradient_utils.dart
index 67cb4ff..4127f3b 100644
--- a/lib/src/utils/gradient_utils.dart
+++ b/lib/src/utils/gradient_utils.dart
@@ -11,6 +11,9 @@ class GradientUtils {
required double width,
required double height,
}) {
+ final colors = badgeGradient.colors;
+ final stops = badgeGradient.stops ?? _evenStops(colors.length);
+ final tileMode = badgeGradient.tileMode;
switch (badgeGradient.gradientType) {
case BadgeGradientType.linear:
return ui.Gradient.linear(
@@ -24,7 +27,9 @@ class GradientUtils {
width: width,
height: height,
),
- badgeGradient.colors,
+ colors,
+ stops,
+ tileMode,
);
case BadgeGradientType.radial:
return ui.Gradient.radial(
@@ -34,7 +39,9 @@ class GradientUtils {
height: height,
),
width * badgeGradient.radius!,
- badgeGradient.colors,
+ colors,
+ stops,
+ tileMode,
);
case BadgeGradientType.sweep:
return ui.Gradient.sweep(
@@ -43,8 +50,19 @@ class GradientUtils {
width: width,
height: height,
),
- badgeGradient.colors,
+ colors,
+ stops,
+ tileMode,
+ badgeGradient.startAngle!,
+ badgeGradient.endAngle!,
);
}
}
+
+ /// dart:ui gradients need explicit stops when there are more than two
+ /// colors, so spread them evenly like [Gradient.createShader] does.
+ static List? _evenStops(int count) {
+ if (count <= 2) return null;
+ return List.generate(count, (i) => i / (count - 1));
+ }
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 012dd97..d9abe1d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,6 +3,11 @@ description: A package for creating badges. Badges can be used for an additional
version: 4.0.0
repository: https://github.com/yako-dev/flutter_badges
issue_tracker: https://github.com/yako-dev/flutter_badges/issues
+topics:
+ - badge
+ - notification
+ - widget
+ - ui
dependencies:
flutter:
diff --git a/test/badges_test.dart b/test/badges_test.dart
index 2a06e0c..b5e9a70 100644
--- a/test/badges_test.dart
+++ b/test/badges_test.dart
@@ -488,7 +488,7 @@ void main() {
expect(badgeWidget.badgeStyle.borderRadius, BorderRadius.zero);
expect(badgeWidget.badgeStyle.badgeColor, Colors.red);
expect(badgeWidget.badgeStyle.borderSide, BorderSide.none);
- expect(badgeWidget.badgeStyle.elevation, 2);
+ expect(badgeWidget.badgeStyle.elevation, 0);
expect(badgeWidget.badgeStyle.badgeGradient, null);
expect(badgeWidget.badgeStyle.borderGradient, null);
expect(badgeWidget.badgeStyle.padding, const EdgeInsets.all(5.0));
@@ -1190,6 +1190,293 @@ void main() {
},
);
});
+
+ // ---------------------------------------------------------------------------
+ // Elevation (MaterialType.transparency ignores Material.elevation)
+ // ---------------------------------------------------------------------------
+ group('Elevation', () {
+ Finder shadowFinder() => find.descendant(
+ of: find.byType(badges.Badge),
+ matching: find.byType(PhysicalShape),
+ );
+
+ testWidgets('no shadow by default', (tester) async {
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(const badges.Badge(badgeContent: Text('1'))),
+ );
+ expect(shadowFinder(), findsNothing);
+ });
+
+ testWidgets('elevation draws a shadow', (tester) async {
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(
+ const badges.Badge(
+ badgeContent: Text('1'),
+ badgeStyle: badges.BadgeStyle(elevation: 4),
+ ),
+ ),
+ );
+ final shape = tester.widget(shadowFinder());
+ expect(shape.elevation, 4);
+ expect(shape.color, Colors.transparent);
+ });
+
+ testWidgets('square shape shadow follows the border radius', (
+ tester,
+ ) async {
+ final radius = BorderRadius.circular(6);
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(
+ badges.Badge(
+ badgeContent: const Text('1'),
+ badgeStyle: badges.BadgeStyle(
+ shape: badges.BadgeShape.square,
+ borderRadius: radius,
+ elevation: 2,
+ ),
+ ),
+ ),
+ );
+ final clipper =
+ tester.widget(shadowFinder()).clipper
+ as ShapeBorderClipper;
+ expect(clipper.shape, RoundedRectangleBorder(borderRadius: radius));
+ });
+ });
+
+ // ---------------------------------------------------------------------------
+ // Positioning with onTap
+ // ---------------------------------------------------------------------------
+ group('Positioning', () {
+ const childKey = Key('child');
+ const contentKey = Key('content');
+
+ Widget badgeWith(badges.BadgePosition position, {VoidCallback? onTap}) {
+ return Center(
+ child: badges.Badge(
+ position: position,
+ onTap: onTap,
+ badgeAnimation: const badges.BadgeAnimation.fade(toAnimate: false),
+ badgeContent: const SizedBox(key: contentKey, width: 10, height: 10),
+ child: const SizedBox(key: childKey, width: 100, height: 100),
+ ),
+ );
+ }
+
+ Offset contentCenterInChild(WidgetTester tester) {
+ return tester.getCenter(find.byKey(contentKey)) -
+ tester.getTopLeft(find.byKey(childKey));
+ }
+
+ testWidgets('center() stays centered when onTap is set', (tester) async {
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(
+ badgeWith(badges.BadgePosition.center(), onTap: () {}),
+ ),
+ );
+ expect(contentCenterInChild(tester), const Offset(50, 50));
+ });
+
+ for (final withTap in [false, true]) {
+ testWidgets('centerStart() is vertically centered (onTap: $withTap)', (
+ tester,
+ ) async {
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(
+ badgeWith(
+ badges.BadgePosition.centerStart(),
+ onTap: withTap ? () {} : null,
+ ),
+ ),
+ );
+ final center = contentCenterInChild(tester);
+ expect(center.dy, 50);
+ // Badge box is 20 wide (10 + 2 * 5 padding), 10 px left of the child.
+ expect(center.dx, 0);
+ });
+
+ testWidgets('centerEnd() is vertically centered (onTap: $withTap)', (
+ tester,
+ ) async {
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(
+ badgeWith(
+ badges.BadgePosition.centerEnd(),
+ onTap: withTap ? () {} : null,
+ ),
+ ),
+ );
+ final center = contentCenterInChild(tester);
+ expect(center.dy, 50);
+ expect(center.dx, 100);
+ });
+ }
+
+ testWidgets('onTap does not move the badge in right-to-left layouts', (
+ tester,
+ ) async {
+ Future measure({VoidCallback? onTap}) async {
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Directionality(
+ textDirection: TextDirection.rtl,
+ child: Scaffold(
+ body: badgeWith(badges.BadgePosition.topEnd(), onTap: onTap),
+ ),
+ ),
+ ),
+ );
+ return contentCenterInChild(tester);
+ }
+
+ final withoutTap = await measure();
+ final withTap = await measure(onTap: () {});
+ expect(withTap, withoutTap);
+ // topEnd in RTL is the top-left corner: the 20 px wide badge sits
+ // 10 px past the child's left edge.
+ expect(withoutTap.dx, 0);
+ });
+ });
+
+ // ---------------------------------------------------------------------------
+ // Hidden badge must not catch taps
+ // ---------------------------------------------------------------------------
+ group('Hidden badge taps', () {
+ for (final animation in const [
+ badges.BadgeAnimation.fade(),
+ badges.BadgeAnimation.rotation(),
+ badges.BadgeAnimation.fade(toAnimate: false),
+ ]) {
+ testWidgets(
+ 'taps reach the child and onTap is not called '
+ '(${animation.animationType.name}, toAnimate: ${animation.toAnimate})',
+ (tester) async {
+ var childTaps = 0;
+ var badgeTaps = 0;
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(
+ Center(
+ child: badges.Badge(
+ showBadge: false,
+ position: badges.BadgePosition.center(),
+ badgeAnimation: animation,
+ onTap: () => badgeTaps++,
+ badgeContent: const SizedBox(width: 40, height: 40),
+ child: GestureDetector(
+ behavior: HitTestBehavior.opaque,
+ onTap: () => childTaps++,
+ child: const SizedBox(width: 100, height: 100),
+ ),
+ ),
+ ),
+ ),
+ );
+ await tester.pumpAndSettle();
+ // Tap where the (invisible) badge actually is.
+ await tester.tap(
+ find.descendant(
+ of: find.byType(badges.Badge),
+ matching: find.byType(AnimatedContainer),
+ ),
+ );
+ expect(childTaps, 1);
+ expect(badgeTaps, 0);
+ },
+ );
+ }
+ });
+
+ // ---------------------------------------------------------------------------
+ // Custom shapes with gradients
+ // ---------------------------------------------------------------------------
+ group('Custom shape gradients', () {
+ for (final shape in [
+ badges.BadgeShape.twitter,
+ badges.BadgeShape.instagram,
+ ]) {
+ for (final gradient in const [
+ badges.BadgeGradient.linear(
+ colors: [Colors.red, Colors.green, Colors.blue],
+ begin: AlignmentDirectional.topStart,
+ end: AlignmentDirectional.bottomEnd,
+ ),
+ badges.BadgeGradient.radial(
+ colors: [Colors.red, Colors.green, Colors.blue],
+ ),
+ badges.BadgeGradient.sweep(
+ colors: [Colors.red, Colors.green, Colors.blue],
+ stops: [0, 0.3, 1],
+ ),
+ ]) {
+ testWidgets('${shape.name} paints a 3-color '
+ '${gradient.gradientType.name} gradient', (tester) async {
+ await tester.pumpWidget(
+ _wrapWithMaterialApp(
+ badges.Badge(
+ badgeStyle: badges.BadgeStyle(
+ shape: shape,
+ badgeGradient: gradient,
+ borderGradient: gradient,
+ borderSide: const BorderSide(width: 2),
+ ),
+ badgeContent: const Icon(Icons.check, size: 12),
+ ),
+ ),
+ );
+ await tester.pumpAndSettle();
+ expect(tester.takeException(), isNull);
+ });
+ }
+ }
+ });
+
+ // ---------------------------------------------------------------------------
+ // Turning animations on at runtime
+ // ---------------------------------------------------------------------------
+ group('toAnimate false -> true', () {
+ for (final type in badges.BadgeAnimationType.values) {
+ testWidgets('badge stays visible (${type.name})', (tester) async {
+ Widget build(bool toAnimate) {
+ final animation = switch (type) {
+ badges.BadgeAnimationType.slide => badges.BadgeAnimation.slide(
+ toAnimate: toAnimate,
+ ),
+ badges.BadgeAnimationType.fade => badges.BadgeAnimation.fade(
+ toAnimate: toAnimate,
+ ),
+ badges.BadgeAnimationType.scale => badges.BadgeAnimation.scale(
+ toAnimate: toAnimate,
+ ),
+ badges.BadgeAnimationType.size => badges.BadgeAnimation.size(
+ toAnimate: toAnimate,
+ ),
+ badges.BadgeAnimationType.rotation =>
+ badges.BadgeAnimation.rotation(toAnimate: toAnimate),
+ };
+ return _wrapWithMaterialApp(
+ badges.Badge(badgeAnimation: animation, badgeContent: Text('1')),
+ );
+ }
+
+ await tester.pumpWidget(build(false));
+ await tester.pumpWidget(build(true));
+ await tester.pumpAndSettle();
+
+ final state = tester.state(
+ find.byType(badges.Badge),
+ );
+ expect(state.animationController.value, 1);
+ expect(state.appearanceController.value, 1);
+ final opacity = tester.widget(
+ find.descendant(
+ of: find.byType(badges.Badge),
+ matching: find.byType(Opacity),
+ ),
+ );
+ expect(opacity.opacity, 1);
+ });
+ }
+ });
}
Widget _wrapWithMaterialApp(Widget testWidget) {
diff --git a/test/utils_tests.dart b/test/utils_tests.dart
index 8f867a2..9d70d3f 100644
--- a/test/utils_tests.dart
+++ b/test/utils_tests.dart
@@ -54,9 +54,9 @@ void testUtils() {
test('Passing null', () {
final padding = CalculationUtils.calculatePadding(null);
expect(padding.top, 8);
- expect(padding.right, 10);
+ expect(padding.end, 10);
expect(padding.bottom, 0);
- expect(padding.left, 0);
+ expect(padding.start, 0);
});
test('isCenter = true', () {
@@ -64,8 +64,8 @@ void testUtils() {
BadgePosition.custom(isCenter: true, top: -10, end: 20),
);
expect(padding.top, 0);
- expect(padding.right, 0);
- expect(padding.left, 0);
+ expect(padding.end, 0);
+ expect(padding.start, 0);
expect(padding.bottom, 0);
});
@@ -74,9 +74,9 @@ void testUtils() {
BadgePosition.custom(top: null, end: null, bottom: null, start: null),
);
expect(padding.top, 0);
- expect(padding.left, 0);
+ expect(padding.start, 0);
expect(padding.bottom, 0);
- expect(padding.right, 0);
+ expect(padding.end, 0);
});
test('Top and start values', () {
@@ -84,9 +84,9 @@ void testUtils() {
BadgePosition.custom(top: -5, end: -5, bottom: -5, start: -5),
);
expect(padding.top, 5);
- expect(padding.left, 5);
+ expect(padding.start, 5);
expect(padding.bottom, 0);
- expect(padding.right, 0);
+ expect(padding.end, 0);
});
test('Without top and start values and negative end bottom values', () {
@@ -94,9 +94,9 @@ void testUtils() {
BadgePosition.custom(end: -5, bottom: -5),
);
expect(padding.top, 0);
- expect(padding.left, 0);
+ expect(padding.start, 0);
expect(padding.bottom, 5);
- expect(padding.right, 5);
+ expect(padding.end, 5);
});
test('Without top and start values and normal end bottom values', () {
@@ -104,9 +104,9 @@ void testUtils() {
BadgePosition.custom(end: 5, bottom: 5),
);
expect(padding.top, 0);
- expect(padding.left, 0);
+ expect(padding.start, 0);
expect(padding.bottom, 0);
- expect(padding.right, 0);
+ expect(padding.end, 0);
});
});
@@ -174,7 +174,13 @@ void testUtils() {
});
test('Custom alignment ', () {
- final offset = getOffset(const Alignment(2, 2));
+ final offset = getOffset(const Alignment(0.5, -0.5));
+ expect(offset.dx, 75);
+ expect(offset.dy, 25);
+ });
+
+ test('Directional alignment resolves left-to-right', () {
+ final offset = getOffset(AlignmentDirectional.bottomEnd);
expect(offset.dx, 100);
expect(offset.dy, 100);
});