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
48 changes: 28 additions & 20 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,59 @@
# Changelog

## 2.0.0
## 2.1.0

### Breaking Changes
- **Builder signature updated**: `PlayxRoute` and `PlayxShellBranch` now use `PlayxRouteWidgetBuilder` which includes an `isInitialized` parameter:
### New Features
- **Init-aware builder (`initBuilder`)**: Added an optional `initBuilder` parameter to `PlayxRoute` and `PlayxShellBranch` that receives `(context, state, isInitialized)`. When provided, the user has full control over what to render based on the binding's initialization state. The existing `builder` with `(context, state)` signature remains unchanged — the library continues to manage loading/content switching automatically.
```dart
// Before (1.x):
builder: (context, state) => MyPage()
// After (2.0):
builder: (context, state, isInitialized) => MyPage()
```
// Standard builder — library manages loading (unchanged from 1.0.0):
PlayxRoute(
path: '/products',
builder: (context, state) => ProductsPage(),
binding: ProductsBinding(),
)

### New Features
- **Shell Builder**: Added `shellBuilder` parameter to `PlayxRoute`, `PlayxShellBranch`, and `PlayxPageConfig`. The shell (AppBar, Drawer, Scaffold) renders immediately during navigation transitions, preventing blank frames. Only the body content waits for the binding's `onEnter` to complete.
// Init-aware builder — user handles everything:
PlayxRoute(
path: '/profile',
initBuilder: (context, state, isInitialized) {
if (!isInitialized) return ProfileSkeleton();
return ProfilePage();
},
binding: ProfileBinding(),
)
```
- **Shell Builder**: Added `shellBuilder` parameter to `PlayxRoute`, `PlayxShellBranch`, and `PlayxPageConfig`. The shell (AppBar, Drawer, Scaffold) renders immediately during navigation transitions, preventing blank frames. Only the body content waits for the binding's `onEnter` to complete. Only applies when using `builder`, not `initBuilder`.
```dart
PlayxRoute(
path: '/channels',
builder: (context, state) => ChannelsListView(),
shellBuilder: (context, state, isInitialized, child) => Scaffold(
appBar: AppBar(title: Text('Channels')),
drawer: MyDrawer(),
body: child,
),
builder: (context, state, isInitialized) => ChannelsListView(),
binding: ChannelsBinding(),
)
```
- **Non-blocking initialization**: Added `waitForBinding` parameter to `PlayxRoute`, `PlayxShellBranch`, and `PlayxPageConfig`. When set to `false`, the page renders immediately with `isInitialized = false` while `onEnter` runs in the background.
- **Global page configuration via `PlayxPageConfig`**: Added `config` parameter to `PlayxNavigationBuilder` to set global defaults for `loadingWidget`, `waitForBinding`, and `shellBuilder`. Individual routes can override any of these settings.
- **Non-blocking initialization**: Added `waitForBinding` parameter to `PlayxRoute`, `PlayxShellBranch`, and `PlayxPageConfig`. When set to `false`, the page content renders immediately while `onEnter` runs in the background. Only applies when using `builder`.
- **Initialization transition animation**: Added `initTransitionDuration` parameter to `PlayxRoute`, `PlayxShellBranch`, and `PlayxPageConfig`. When set, an `AnimatedSwitcher` crossfade smoothly transitions from the loading widget to the page content. Only applies when using `builder`.
- **Global page configuration via `PlayxPageConfig`**: Added `config` parameter to `PlayxNavigationBuilder` to set global defaults for `loadingWidget`, `waitForBinding`, `shellBuilder`, and `initTransitionDuration`. Individual routes can override any of these settings.
```dart
PlayxNavigationBuilder(
router: router,
config: PlayxPageConfig(
loadingWidget: Center(child: CircularProgressIndicator()),
waitForBinding: false,
shellBuilder: (context, state, isInitialized, child) => Scaffold(
appBar: AppBar(title: Text('My App')),
body: child,
),
waitForBinding: true,
initTransitionDuration: Duration(milliseconds: 300),
),
builder: (context) => MyApp(),
)
```
- **New typedefs**: `PlayxRouteWidgetBuilder` and `PlayxShellWidgetBuilder` for type-safe builder signatures.
- **Initialization transition animation**: Added `initTransitionDuration` parameter to `PlayxRoute`, `PlayxShellBranch`, and `PlayxPageConfig`. When set, an `AnimatedSwitcher` crossfade smoothly transitions from the loading widget to the page content.

### Configuration Resolution
Route-level parameter → Global `PlayxPageConfig` → Built-in default:
Route-level parameter → Global `PlayxPageConfig` → Built-in default.
These settings only apply when using the standard `builder`, not `initBuilder`:
- `loadingWidget`: Route > Global > `SizedBox.shrink()`
- `waitForBinding`: Route > Global > `true`
- `shellBuilder`: Route > Global > `null`
Expand Down
47 changes: 32 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
- **Initialization Awaiting**: Use `PlayxNavigation.ensureInitialized` to gate startup logic until all bindings are initialized.
- **Binding Registry**: Access any registered binding by type via `PlayxNavigation.findBinding<T>()`.
- **Shell Builder**: Render page chrome (AppBar, Drawer, Scaffold) immediately during transitions — no more blank frames while bindings initialize.
- **Non-Blocking Initialization**: Optionally render pages immediately with `waitForBinding: false`, letting the builder react to `isInitialized` state.
- **Init-Aware Builder**: Use `initBuilder` with `(context, state, isInitialized)` for full control over rendering during initialization.
- **Non-Blocking Initialization**: Optionally render pages immediately with `waitForBinding: false`.
- **Global Page Configuration**: Set default loading widgets, shell builders, and initialization behavior for all routes via `PlayxPageConfig`.
- **Advanced Route Configuration**: Fine-tune the behavior of your routes with extensive configuration options, including custom transitions, modal behavior, and state management.
- **Route Management**: Easily navigate to routes, replace routes, and handle navigation stacks without the need for buildcontext.
Expand All @@ -23,7 +24,7 @@ Add `Playx Navigation` to your `pubspec.yaml`:

```yaml
dependencies:
playx_navigation: ^2.0.0
playx_navigation: ^2.1.0
```
Then, run:

Expand Down Expand Up @@ -86,19 +87,19 @@ final router = GoRouter(
PlayxRoute(
path: Paths.home,
name: Routes.home,
builder: (context, state, isInitialized) => const HomePage(),
builder: (context, state) => const HomePage(),
binding: HomeBinding(),
),
PlayxRoute(
path: Paths.products,
name: Routes.products,
builder: (context, state, isInitialized) => ProductsPage(),
builder: (context, state) => ProductsPage(),
binding: ProductsBinding(),
routes: [
PlayxRoute(
path: Paths.details,
name: Routes.details,
builder: (context, state, isInitialized) =>
builder: (context, state) =>
ProductDetailsPage(product: state.extra as Product),
binding: DetailsBinding(),
),
Expand Down Expand Up @@ -412,42 +413,57 @@ PlayxNavigationBuilder(

### Shell Builder

The `shellBuilder` renders page chrome (AppBar, Drawer, Scaffold) **immediately** during navigation transitions. Only the body content waits for the binding's `onEnter` to complete, preventing blank frames.
The `shellBuilder` renders page chrome (AppBar, Drawer, Scaffold) **immediately** during navigation transitions. Only the body content waits for the binding's `onEnter` to complete, preventing blank frames. Only applies when using the standard `builder`.

```dart
PlayxRoute(
path: '/channels',
name: 'channels',
builder: (context, state) => ChannelsListView(),
shellBuilder: (context, state, isInitialized, child) => Scaffold(
appBar: AppBar(title: Text('Channels')),
drawer: isInitialized ? MyDrawer() : null,
body: child, // loading widget or actual content
),
builder: (context, state, isInitialized) => ChannelsListView(),
binding: ChannelsBinding(),
)
```

### Non-Blocking Initialization

Set `waitForBinding: false` to render the page immediately while `onEnter` runs in the background. The builder receives `isInitialized` so it can handle its own loading state:
Set `waitForBinding: false` to render the page content immediately while `onEnter` runs in the background:

```dart
PlayxRoute(
path: '/profile',
name: 'profile',
builder: (context, state, isInitialized) {
builder: (context, state) => ProfilePage(),
binding: ProfileBinding(),
waitForBinding: false,
)
```

### Init-Aware Builder

For full control over what renders during initialization, use `initBuilder` instead of `builder`. The `initBuilder` receives `isInitialized` so the user can handle loading states:

```dart
PlayxRoute(
path: '/profile',
name: 'profile',
initBuilder: (context, state, isInitialized) {
if (!isInitialized) return ProfileSkeleton();
return ProfilePage();
},
binding: ProfileBinding(),
waitForBinding: false,
)
```

When using `initBuilder`, the library does **not** apply `shellBuilder`, `loadingWidget`, `waitForBinding`, or `initTransitionDuration` — the user handles everything.

### Initialization Animation

Set `initTransitionDuration` to smoothly crossfade from the loading widget to the page content using an `AnimatedSwitcher`:
Set `initTransitionDuration` to smoothly crossfade from the loading widget to the page content using an `AnimatedSwitcher`. Only applies when using the standard `builder`:

```dart
// Global: apply to all routes
Expand All @@ -458,7 +474,7 @@ PlayxPageConfig(
// Per-route: override for a specific route
PlayxRoute(
path: '/dashboard',
builder: (context, state, isInitialized) => DashboardPage(),
builder: (context, state) => DashboardPage(),
binding: DashboardBinding(),
initTransitionDuration: Duration(milliseconds: 500),
)
Expand All @@ -477,7 +493,8 @@ The `PlayxRoute` class extends the functionality of the `GoRoute` class, providi

- **Lifecycle Management**: Attach custom logic that runs when a route is entered or exited, enabling better control over the state and behavior of your app.
- **Shell Builder**: Render page chrome immediately during transitions to prevent blank frames.
- **Non-Blocking Initialization**: Render pages immediately with `isInitialized` state for custom loading UIs.
- **Init-Aware Builder**: Use `initBuilder` with `isInitialized` for full control over rendering during initialization.
- **Non-Blocking Initialization**: Render pages immediately with `waitForBinding: false`.
- **Page Configuration**: Customize various settings like page title, transition duration, and modal behavior.
- **Custom Transitions**: Apply predefined or custom animations for transitioning between pages.

Expand All @@ -492,7 +509,7 @@ The `PlayxRoute` class extends the functionality of the `GoRoute` class, providi
PlayxRoute(
path: '/dashboard',
name: 'dashboard',
builder: (context, state, isInitialized) => DashboardPage(),
builder: (context, state) => DashboardPage(),
binding: DashboardBinding(),
);
```
Expand Down Expand Up @@ -541,7 +558,7 @@ Example:
PlayxRoute(
path: '/custom',
name: 'customRoute',
builder: (context, state, isInitialized) => CustomPage(),
builder: (context, state) => CustomPage(),
binding: CustomBinding(),
pageConfiguration: PlayxPageConfiguration.customTransition(
transitionsBuilder: (context, animation, secondaryAnimation, child) {
Expand Down
12 changes: 6 additions & 6 deletions example/lib/navigation/pages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class AppPages {
PlayxRoute(
path: Paths.splash,
name: Routes.splash,
builder: (context, state, isInitialized) => const SplashPage(),
builder: (context, state) => const SplashPage(),
binding: SplashBinding(),
),

Expand Down Expand Up @@ -68,21 +68,21 @@ class AppPages {
PlayxShellBranch(
name: Routes.home,
path: Paths.home,
builder: (context, state, isInitialized) => const HomePage(),
builder: (context, state) => const HomePage(),
binding: HomeBinding(),
),

// Tab 2: Products → Product Details (parent-child push/pop)
PlayxShellBranch(
path: Paths.products,
name: Routes.products,
builder: (context, state, isInitialized) => const ProductsPage(),
builder: (context, state) => const ProductsPage(),
binding: ProductsBinding(),
routes: [
PlayxRoute(
path: Paths.productDetails,
name: Routes.productDetails,
builder: (context, state, isInitialized) =>
builder: (context, state) =>
ProductDetailsPage(product: state.extra as Product?),
binding: DetailsBinding(),
loadingWidget: const Center(
Expand All @@ -96,13 +96,13 @@ class AppPages {
PlayxShellBranch(
path: Paths.explore,
name: Routes.explore,
builder: (context, state, isInitialized) => const ExplorePage(),
builder: (context, state) => const ExplorePage(),
binding: ExploreBinding(),
routes: [
PlayxRoute(
path: Paths.exploreDetails,
name: Routes.exploreDetails,
builder: (context, state, isInitialized) =>
builder: (context, state) =>
ExploreDetailsPage(product: state.extra as Product?),
binding: ExploreDetailsBinding(),
),
Expand Down
Loading
Loading