Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions .github/actions/setup/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,38 @@ runs:
- name: 📦 Checkout the repo
uses: actions/checkout@v4

- name: 🔢 Set up version from tags
id: set-version
if: startsWith(github.ref, 'refs/tags')
shell: bash
run: |
BASE_VERSION="${GITHUB_REF#refs/tags/v}"
UNIXTIME=$(date +%s)
VERSION="${BASE_VERSION}+${UNIXTIME}"
echo "VERSION=$VERSION" >> $GITHUB_ENV
sed -i "s/^version: .*/version: ${VERSION}/" pubspec.yaml
echo "Version set to $VERSION"

- name: 🚂 Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "${{ inputs.flutter-version }}"
channel: "stable"

# Without a lockfile the pubspecs alone do not pin the resolved versions:
# the week in the key refreshes the cache regularly, and the restore keys
# start from the newest cache of the same SDK when a pubspec changes.
- name: 🗓️ Compute the cache week
id: cache-week
shell: bash
run: echo "week=$(date -u +%G-W%V)" >> "$GITHUB_OUTPUT"

- name: 📤 Restore Pub modules
id: cache-pub-restore
uses: actions/cache/restore@v4
with:
path: |
/home/runner/.pub-cache
key: ${{ runner.os }}-pub-${{ inputs.pub-cache }}-${{ hashFiles('pubspec.lock') }}
key: ${{ runner.os }}-pub-${{ inputs.pub-cache }}-flutter-${{ inputs.flutter-version }}-${{ steps.cache-week.outputs.week }}-${{ hashFiles('pubspec.yaml', 'example/pubspec.yaml') }}
restore-keys: |
${{ runner.os }}-pub-${{ inputs.pub-cache }}-flutter-${{ inputs.flutter-version }}-${{ steps.cache-week.outputs.week }}-
${{ runner.os }}-pub-${{ inputs.pub-cache }}-flutter-${{ inputs.flutter-version }}-

- name: 👷 Install Dependencies
shell: bash
run: |
echo /home/runner/.pub-cache/bin >> $GITHUB_PATH
flutter config --no-cli-animations --no-analytics
flutter pub get
flutter pub get --directory example

#- name: ⏲️ Run build runner
# shell: bash
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: Deploy

on:
# pub.dev rejects a publish started by workflow_dispatch unless
# "Enable publishing from workflow_dispatch events" is checked in the
# automated publishing settings of the package admin page on pub.dev.
workflow_dispatch:
push:
tags:
Expand Down Expand Up @@ -39,9 +42,14 @@ jobs:
flutter pub get
flutter pub get --directory example

# Also guards a manual run: it must be started from the tag of the
# version, never from a branch.
- name: 🔢 Check that the tag matches the version
if: startsWith(github.ref, 'refs/tags/')
run: |
if [ "${GITHUB_REF_TYPE}" != "tag" ]; then
echo "::error::Publish from a tag, not from ${GITHUB_REF}"
exit 1
fi
TAG="${GITHUB_REF_NAME}"
VERSION="$(awk '/^version:/ {print $2; exit}' pubspec.yaml)"
if [ "$TAG" != "$VERSION" ]; then
Expand Down
67 changes: 67 additions & 0 deletions .pubignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# pub ignores .gitignore when this file exists, so it repeats it.

# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# 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
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
.dart_tool
build/
**/doc/api/
**/ios/Flutter/.last_build_id
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/

# Pana
log.pana.json

# Test
.coverage/
coverage/
doc/api/
/test/**/*.json
/test/.test_coverage.dart
reports/

# Temp
/tmp
/temp

# FVM
.fvm/flutter_sdk

# Generated files
*.*.dart

# LLMS
.claude/
# Example
/example/pubspec.lock

# Development only
Makefile
.vscode/
.github/
100 changes: 79 additions & 21 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,86 @@

All notable changes to this project will be documented in this file.

## Unreleased
## 0.1.1

- **Fixed**: on Android with the predictive back gesture, the back button
no longer closes the application while the framework can handle the
press. The top level views report one state for the whole application:
a route to close, a visible nested view that can go back, a `PopScope`
blocking the visible route, a previous tab of a
`NavigationTabsController` or an `onBackButtonPressed` of the view. A
nested view reports again when its route becomes current again, an
inactive tab no longer speaks for the visible one, a view with
`interceptBackButton: false` no longer claims the press, and removing
the last view withdraws its claim.
- **Fixed**: a `NavigationTabsController` reports the back button when it
is created around mounted views and when it is disposed, so no stale
claim of a previous tab remains.
- **Fixed**: a page built from the context of the view (the locale, the
theme, an inherited scope read in `NavigationRoute.page`) is built again
when that context changes instead of being taken from the cache. A guard
reading the context, e.g. the size of the window, no longer rebuilds the
pages.
- **Fixed**: the default `key` of a route escapes `%`, `&`, `=` and `?` in
the name and in the arguments and writes a `null` argument without a
value, so different routes, e.g. `{'q': 'a&b=c'}` and
`{'q': 'a', 'b': 'c'}`, `null` and `'null'`, or the name `'a?b'` and the
name `'a'` with `{'b': null}`, no longer produce the same key.
- **Fixed**: observers are notified at the end of the frame, together with
the listeners, when a `ContextGuard` changes the stack during the build,
so an observer calling `setState` no longer throws. The events keep
their order when an observer changes the stack while they are delivered,
and a change made by a listener at that moment no longer notifies the
listeners once more on the next frame.
- **Fixed**: an exception in one callback of an observer no longer swallows
the remaining events of the same transition for that observer.
- **Fixed**: a guard returning an empty stack is reported to `FlutterError`
instead of throwing an assertion, which dropped the changes queued after
it in a debug build.
- **Fixed**: `pop` and `removeKey` called from a guard, an observer or a
listener are postponed instead of being checked against the stack that is
about to change, e.g. `push(route)` followed by `remove(route)`.
`maybePop` called from there decides against the stack it applies to and
no longer reports a press as handled when nothing is popped.
- **Fixed**: the result of a `pop` cancelled by a guard is dropped as soon
as the guard cancels it, instead of waiting for the end of the queued
changes.
- **Fixed**: a guard can dispose the controller: the remaining guards do
not run, the observers are not notified, and a controller disposed during
its initial validation does not subscribe to `revalidate`. Observers are
also not notified when a listener disposes the controller.
- **Docs**: a guard keeping a route closed by the user brings back a new
instance of it, use a `PopScope` to prevent the closing.
- **Docs**: the name of a class route is minified in an obfuscated build,
routes compare by instance in a plain `List`, overridden `tags` must keep
`kModalTag`, calling `pushForResult` again with the same key completes
the previous waiter with `null`, `controller.stack` while the guards run,
changes made from a guard are queued, observer events may be delivered
at the end of the frame, what the default `key` guarantees.
- **CI**: a manual publication must start from the tag of the version and
be enabled on pub.dev, the pub cache depends on the pubspecs, the Flutter
version and the week and covers the example, a `.pubignore` keeps the
development files out of the package.

## 0.1.0

- Initial release.
- `NavigationRoute` — a route is an immutable value: an `enum` value when it
has no parameters, a `sealed class` when it has.
- `NavigationController` — the owner of the stack, usable without any widget,
with guards, observers and revalidation built in.
- `NavigationView` — renders a controller with a `Navigator`, reports the
routes closed by the user and handles the system back button.
- `DialogRouteMixin` and `BottomSheetRouteMixin` — dialogs and bottom sheets
as ordinary entries of the navigation stack.
- `NavigationGuard` with the built-in `PriorityGuard`, `RootGuard`,
`LimitGuard` and `GateGuard`.
- `ContextGuard` — the rules that depend on the widget tree (the size of the
window, the theme, an inherited scope) re-run by themselves whenever what
they read changes.
- `NavigationObserver` and `NavigationLogger`.
- `NavigationTabsController` — several stacks side by side, cross tab
navigation and automatic routing of the back button.
- **Docs**: "Helpers of your application" — an extension type over
`BuildContext` with application specific shortcuts and `popModals`, which
closes the declarative and the imperative popups at once.
Expand Down Expand Up @@ -40,23 +118,3 @@ All notable changes to this project will be documented in this file.
`opened()`, the same way a closed gate falls back to `closed()`.
- **Fixed**: replacing the controller of a `NavigationView` runs its guards
with the context of the view, so a `ContextGuard` sees it immediately.

## 0.1.0

- Initial release.
- `NavigationRoute` — a route is an immutable value: an `enum` value when it
has no parameters, a `sealed class` when it has.
- `NavigationController` — the owner of the stack, usable without any widget,
with guards, observers and revalidation built in.
- `NavigationView` — renders a controller with a `Navigator`, reports the
routes closed by the user and handles the system back button.
- `DialogRouteMixin` and `BottomSheetRouteMixin` — dialogs and bottom sheets
as ordinary entries of the navigation stack.
- `NavigationGuard` with the built-in `PriorityGuard`, `RootGuard`,
`LimitGuard` and `GateGuard`.
- `ContextGuard` — the rules that depend on the widget tree (the size of the
window, the theme, an inherited scope) re-run by themselves whenever what
they read changes.
- `NavigationObserver` and `NavigationLogger`.
- `NavigationTabsController` — several stacks side by side, cross tab
navigation and automatic routing of the back button.
Loading
Loading