Skip to content

Commit

Permalink
Merge branch 'release/1.11.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
SchabanBo committed Jul 23, 2024
2 parents 5b9ea3c + 04aba6f commit 557ee05
Show file tree
Hide file tree
Showing 47 changed files with 1,044 additions and 317 deletions.
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"cSpell.words": [
"fullscreen",
"notfound",
"qhistory",
"qlevar",
"qobserver",
"qpage",
"qroute",
"qrouter"
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

# 1.11.0

- Add `TemporaryQRouter` to use the router in n popups or dialogs. #126
- Fix #139
- Set min SDK to 2.17.0

# 1.10.3

- Fixes #148
Expand Down
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
- [Page Transition](#page-transition)
- [Mix it up](#mix-it-up)
- [App Page Transition](#app-page-transition)
- [Temporary router](#temporary-router)
- [Limitations](#limitations)
- [waiting for page result](#waiting-for-page-result)
- [Restoration management](#restoration-management)
- [Other features](#other-features)
Expand Down Expand Up @@ -401,13 +403,39 @@ in this case `QFadePage.transitionDurationMilliseconds (1000)` will be used and

you can define the Transition for all pages in the app with setting the page type in `QR.settings.pagesType`

## Temporary router

It creates a new navigator that is only active while the widget is in view. This is useful for displaying nested routes within a modal or popup without affecting the main navigation stack. and is automatically removed when the widget is removed from the tree, ensuring that there are no lingering navigators consuming resources.

The temporary routes are the same as those defined in the main application, ensuring consistency and reuse of route definitions.

```dart
final storeRoutes = StoreRoutes().route;
showModalBottomSheet(
context: context,
builder: (_) {
return TemporaryQRouter(
name: 'temp Store',
path: '/temp-store',
routes: [storeRoutes],
initPath: storeRoutes.path,
);
},
);
```
This example will show the store page in a bottom sheet. the same routes are defined in the main app routes. and the sane pages will be displayed.

To Check if the temporary router is active or not you can use `QR.navigator.isTemporary`.

### Limitations
- URL Navigation: The temporary router will not function if the user directly types the path into the URL. This limitation arises because the temporary router is designed to exist only within the widget tree and is destroyed when the widget is removed.

## waiting for page result

If you need to wait for a result from another page, you can do so by setting `waitForResult` to true before navigating to the page.
More info: [example](https://qlevar-router.netlify.app/#/await-result) | [example code](example\lib\pages\await_result\await_result_view.dart) | [tests](test\waiting_results_test.dart).

```dart
/// navigate to the page using
final result = await QR.to<String>('/page', waitForResult: true);
// or by name
Expand Down
52 changes: 27 additions & 25 deletions example/lib/pages/store/stores_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,33 @@ class StoresView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Store'),
),
body: ListView(
children: storage.stores
.map(
(e) => ListTile(
title: Text(e.name),
leading: const Icon(
Icons.store,
color: Colors.indigo,
),
trailing: Text(e.products.length.toString()),
// Navigate to the store page with the route name
// and give the id of the store as parameter
onTap: () => QR.toName(
fromDashboard
? DashboardRoutes.dashboardStoresId
: StoreRoutes.storeId,
params: {'id': storage.stores.indexOf(e)},
),
),
)
.toList(),
),
appBar: AppBar(title: const Text('Store')),
body: ListView(children: [
for (final e in storage.stores)
ListTile(
title: Text(e.name),
leading: const Icon(
Icons.store,
color: Colors.indigo,
),
trailing: Text(e.products.length.toString()),
// Navigate to the store page with the route name
// and give the id of the store as parameter
onTap: () => QR.toName(
fromDashboard
? DashboardRoutes.dashboardStoresId
: StoreRoutes.storeId,
params: {'id': storage.stores.indexOf(e)},
),
),
if (QR.navigator.isTemporary)
Center(
child: ElevatedButton(
onPressed: QR.back,
child: const Text('Close'),
),
),
]),
floatingActionButton: const DebugTools(),
);
}
Expand Down
30 changes: 30 additions & 0 deletions example/lib/pages/welcome/temporary_router_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:qlevar_router/qlevar_router.dart';

import '../../routes/store_routes.dart';
import 'node_widget.dart';

class SingleNavigatorRouterExample extends StatelessWidget {
const SingleNavigatorRouterExample({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return NodeWidget(
name: 'Temporary QRouter Example',
onPressed: () async {
final storeRoutes = StoreRoutes().route;
showModalBottomSheet(
context: context,
builder: (_) {
return TemporaryQRouter(
name: 'temp Store',
path: '/temp-store',
routes: [storeRoutes],
initPath: storeRoutes.path,
);
},
);
},
);
}
}
2 changes: 2 additions & 0 deletions example/lib/pages/welcome/welcome_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import '../../routes/mobile_routes.dart';
import '../../routes/store_routes.dart';
import 'debug_tools.dart';
import 'node_widget.dart';
import 'temporary_router_widget.dart';

class WelcomeView extends StatelessWidget {
const WelcomeView({Key? key}) : super(key: key);
Expand Down Expand Up @@ -51,6 +52,7 @@ class WelcomeView extends StatelessWidget {
name: 'Editable Routes',
onPressed: () => QR.to('/editable-routes'),
),
const SingleNavigatorRouterExample(),
],
),
),
Expand Down
49 changes: 25 additions & 24 deletions example/lib/routes/mobile_routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,29 @@ class MobileRoutes {
];

final route = QRoute.withChild(
path: '/mobile',
name: mobile,
initRoute: '/stores',
builderChild: (router) => MobileView(router),
children: [
QRoute(
path: '/stores',
name: tabs[0],
pageType: const QFadePage(),
builder: () => MobileStoresView(),
),
QRoute(
path: '/products',
name: tabs[1],
pageType: const QFadePage(),
builder: () => MobileProductsView(),
),
QRoute(
path: '/settings',
name: tabs[2],
pageType: const QFadePage(),
builder: () => const MobileSettingsView(),
),
]);
path: '/mobile',
name: mobile,
initRoute: '/stores',
builderChild: (router) => MobileView(router),
children: [
QRoute(
path: '/stores',
name: tabs[0],
pageType: const QFadePage(),
builder: () => MobileStoresView(),
),
QRoute(
path: '/products',
name: tabs[1],
pageType: const QFadePage(),
builder: () => MobileProductsView(),
),
QRoute(
path: '/settings',
name: tabs[2],
pageType: const QFadePage(),
builder: () => const MobileSettingsView(),
),
],
);
}
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
sdk: '>=2.15.0 <3.0.0'
sdk: '>=2.17.0 <3.0.0'
flutter: ">=1.12.0"

dependencies:
Expand Down
7 changes: 6 additions & 1 deletion example/windows/flutter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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")

Expand Down Expand Up @@ -91,7 +96,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG>
${FLUTTER_TARGET_PLATFORM} $<CONFIG>
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
Expand Down
10 changes: 5 additions & 5 deletions example/windows/runner/Runner.rc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/qlevar_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export 'src/qr.dart';
export 'src/routers/qdeclarative._router.dart';
export 'src/routers/qrouter.dart';
export 'src/routers/router_delegate.dart';
export 'src/routers/temporary_router.dart';
export 'src/routes/qdeclarative_route.dart';
export 'src/routes/qmiddleware.dart';
export 'src/routes/qroute.dart';
Expand Down
7 changes: 5 additions & 2 deletions lib/src/controllers/controller_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ControllerManager {
QRouteChildren? cRoutes,
String? initPath,
QRouteInternal? initRoute,
bool isTemporary,
) async {
if (hasController(name)) {
QR.log('A navigator with name [$name] already exist', isDebug: true);
Expand All @@ -29,7 +30,7 @@ class ControllerManager {
cRoutes =
QRouteChildren.from(routes!, key, routePath == '/' ? '' : routePath);
}
final controller = QRouterController(key, cRoutes);
final controller = QRouterController(key, cRoutes, isTemporary);
await controller.initialize(initPath: initPath, initRoute: initRoute);
controllers.add(controller);
return controller;
Expand Down Expand Up @@ -62,9 +63,10 @@ class ControllerManager {
QKey(name),
'/',
),
false,
);
}
throw Exception('No router was set in the app');
throw Exception('No navigator with name $name was found');
}

bool hasController(String name) =>
Expand All @@ -77,6 +79,7 @@ class ControllerManager {
final controller = withName(name);
await controller.disposeAsync();
controllers.remove(controller);
QR.history.removeWithNavigator(name);
QR.log('Navigator with name [$name] was removed');
return true;
}
Expand Down
7 changes: 1 addition & 6 deletions lib/src/controllers/pages_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,7 @@ class PagesController {

await middleware.runOnExit(); // run on exit
middleware.scheduleOnExited(); // schedule on exited

if (await QR.removeNavigator(route.name)) {
// if this route has navigator then remove it to remove this route too.
// and remove all histories to this route
QR.history.removeWithNavigator(route.name);
}
await QR.removeNavigator(route.name); // remove navigator if exist
QR.history.removeLast(); // remove history for this route
if (QR.history.hasLast && QR.history.current.path == route.activePath) {
QR.history.removeLast();
Expand Down
13 changes: 11 additions & 2 deletions lib/src/controllers/qrouter_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ abstract class QNavigator extends ChangeNotifier {
/// Get if the current [QNavigator] can pop or not
bool get canPop;

bool get isTemporary;

/// Get the current route for this navigator
QRoute get currentRoute;

Expand Down Expand Up @@ -119,10 +121,12 @@ class QRouterController extends QNavigator {
late GlobalKey<NavigatorState> navKey;
late final observer = QNavigatorObserver(key.name);
final QRouteChildren routes;
@override
final bool isTemporary;

final _pagesController = PagesController();

QRouterController(this.key, this.routes);
QRouterController(this.key, this.routes, this.isTemporary);

@override
void addRoutes(List<QRoute> routes) => this.routes.add(routes);
Expand Down Expand Up @@ -268,8 +272,13 @@ class QRouterController extends QNavigator {
}

Future<void> disposeAsync() async {
await _pagesController.removeAll();
if (!isTemporary) await _pagesController.removeAll();
isDisposed = true;
if (isTemporary) {
// remove routes from the tree
final routesNames = routes.routes.map((e) => e.name).toList();
removeRoutes(routesNames);
}
super.dispose();
}

Expand Down
3 changes: 1 addition & 2 deletions lib/src/helpers/widgets/browser_address_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ class BrowserAddressBar extends StatefulWidget {

final Function(String) setNewRoute;
final QRouterController _controller;
const BrowserAddressBar(this.setNewRoute, this._controller, {Key? key})
: super(key: key);
const BrowserAddressBar(this.setNewRoute, this._controller, {super.key});
@override
State createState() => _BrowserAddressBarState();
}
Expand Down
Loading

0 comments on commit 557ee05

Please sign in to comment.