diff --git a/packages/wyatt_go_router/.gitignore b/packages/wyatt_go_router/.gitignore
new file mode 120000
index 00000000..6ef08f9d
--- /dev/null
+++ b/packages/wyatt_go_router/.gitignore
@@ -0,0 +1 @@
+../../.gitignore
\ No newline at end of file
diff --git a/packages/wyatt_go_router/.pubignore b/packages/wyatt_go_router/.pubignore
new file mode 120000
index 00000000..52b2f28d
--- /dev/null
+++ b/packages/wyatt_go_router/.pubignore
@@ -0,0 +1 @@
+../../.pubignore
\ No newline at end of file
diff --git a/packages/wyatt_go_router/.vscode/launch.json b/packages/wyatt_go_router/.vscode/launch.json
new file mode 100644
index 00000000..653eabc8
--- /dev/null
+++ b/packages/wyatt_go_router/.vscode/launch.json
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 WYATT GROUP
+ * Please see the AUTHORS file for details.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch Example",
+ "request": "launch",
+ "type": "dart",
+ "cwd": "example/",
+ "program": "lib/main.dart",
+ "flutterMode": "debug"
+ },
+ ]
+}
\ No newline at end of file
diff --git a/packages/wyatt_go_router/.vscode/settings.json b/packages/wyatt_go_router/.vscode/settings.json
new file mode 100644
index 00000000..a29d370a
--- /dev/null
+++ b/packages/wyatt_go_router/.vscode/settings.json
@@ -0,0 +1,72 @@
+{
+ "dart.runPubGetOnPubspecChanges": "never",
+ "bloc.newCubitTemplate.type": "equatable",
+ "psi-header.changes-tracking": {
+ "isActive": true
+ },
+ "psi-header.config": {
+ "blankLinesAfter": 1,
+ "forceToTop": true
+ },
+ "psi-header.lang-config": [
+ {
+ "beforeHeader": [
+ "# -*- coding:utf-8 -*-",
+ "#!/usr/bin/env python3"
+ ],
+ "begin": "###",
+ "end": "###",
+ "language": "python",
+ "prefix": "# "
+ },
+ {
+ "beforeHeader": [
+ "#!/usr/bin/env sh",
+ ""
+ ],
+ "language": "shellscript",
+ "begin": "",
+ "end": "",
+ "prefix": "# "
+ },
+ {
+ "begin": "",
+ "end": "",
+ "language": "dart",
+ "prefix": "// "
+ },
+ {
+ "begin": "",
+ "end": "",
+ "language": "yaml",
+ "prefix": "# "
+ },
+ {
+ "begin": "",
+ "language": "markdown",
+ },
+ ],
+ "psi-header.templates": [
+ {
+ "language": "*",
+ "template": [
+ "Copyright (C) <> WYATT GROUP",
+ "Please see the AUTHORS file for details.",
+ "",
+ "This program is free software: you can redistribute it and/or modify",
+ "it under the terms of the GNU General Public License as published by",
+ "the Free Software Foundation, either version 3 of the License, or",
+ "any later version.",
+ "",
+ "This program is distributed in the hope that it will be useful,",
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of",
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
+ "GNU General Public License for more details.",
+ "",
+ "You should have received a copy of the GNU General Public License",
+ "along with this program. If not, see ."
+ ],
+ }
+ ],
+}
diff --git a/packages/wyatt_go_router/AUTHORS b/packages/wyatt_go_router/AUTHORS
new file mode 120000
index 00000000..f04b7e8a
--- /dev/null
+++ b/packages/wyatt_go_router/AUTHORS
@@ -0,0 +1 @@
+../../AUTHORS
\ No newline at end of file
diff --git a/packages/wyatt_go_router/CHANGELOG.md b/packages/wyatt_go_router/CHANGELOG.md
new file mode 100644
index 00000000..effe43c8
--- /dev/null
+++ b/packages/wyatt_go_router/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 1.0.0
+
+- Initial version.
diff --git a/packages/wyatt_go_router/LICENSE b/packages/wyatt_go_router/LICENSE
new file mode 120000
index 00000000..30cff740
--- /dev/null
+++ b/packages/wyatt_go_router/LICENSE
@@ -0,0 +1 @@
+../../LICENSE
\ No newline at end of file
diff --git a/packages/wyatt_go_router/README.md b/packages/wyatt_go_router/README.md
new file mode 100644
index 00000000..9c9537ae
--- /dev/null
+++ b/packages/wyatt_go_router/README.md
@@ -0,0 +1,68 @@
+
+
+# Flutter - Wyatt Go Router
+
+
+
+
+
+
+GoRouter Enhancements for Flutter
+
+This package provides a set of utilities to help you use the [GoRouter](https://pub.dev/packages/go_router) package.
+
+## Features
+
+* PageProtection extension to add a protection to a page
+* currentRoute method to get the current route anywhere in the app
+* GoRouterRefreshStream to refresh the router when needed
+* RouteBase flattenization to get a list of all the routes in the router
+
+## Usage
+
+If you want to protect a page, you can use the PageProtection extension:
+
+```dart
+GoRoute(
+ path: '/sign_in',
+ ...
+)..setPublic(),
+```
+
+If you want to get the current route, you can use the currentRoute method:
+
+```dart
+final route = GoRouter.of(context).currentRoute;
+// or
+final route = context.currentRoute;
+```
+
+If you want to refresh the router, you can use the GoRouterRefreshStream:
+
+```dart
+GoRouterRefreshStream(
+ context.read>().stream,
+)
+```
+
+If you want to get a list of all the routes in the router, you can use the RouteBase flattenization:
+
+```dart
+final routes = GoRouter.of(context).flattenedRoutes;
+```
diff --git a/packages/wyatt_go_router/analysis_options.yaml b/packages/wyatt_go_router/analysis_options.yaml
new file mode 100644
index 00000000..bd347efb
--- /dev/null
+++ b/packages/wyatt_go_router/analysis_options.yaml
@@ -0,0 +1,27 @@
+include: package:wyatt_analysis/analysis_options.flutter.yaml
+
+analyzer:
+ plugins:
+ - dart_code_linter
+
+dart_code_linter:
+ anti-patterns:
+ - long-method
+ - long-parameter-list
+ metrics:
+ cyclomatic-complexity: 20
+ maximum-nesting-level: 5
+ number-of-parameters: 10
+ source-lines-of-code: 400
+ metrics-exclude:
+ - test/**
+ rules:
+ - newline-before-return
+ - no-boolean-literal-compare
+ - no-empty-block
+ - prefer-trailing-comma
+ - prefer-conditional-expressions
+ - no-equal-then-else
+ - avoid-border-all
+ - prefer-const-border-radius
+ - prefer-using-list-view
diff --git a/packages/wyatt_go_router/example/.gitignore b/packages/wyatt_go_router/example/.gitignore
new file mode 100644
index 00000000..24476c5d
--- /dev/null
+++ b/packages/wyatt_go_router/example/.gitignore
@@ -0,0 +1,44 @@
+# 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
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/packages/wyatt_go_router/example/.metadata b/packages/wyatt_go_router/example/.metadata
new file mode 100644
index 00000000..a072c7d9
--- /dev/null
+++ b/packages/wyatt_go_router/example/.metadata
@@ -0,0 +1,30 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "d211f42860350d914a5ad8102f9ec32764dc6d06"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
+ base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
+ - platform: android
+ create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
+ base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
+
+ # 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/packages/wyatt_go_router/example/README.md b/packages/wyatt_go_router/example/README.md
new file mode 100644
index 00000000..2b3fce4c
--- /dev/null
+++ b/packages/wyatt_go_router/example/README.md
@@ -0,0 +1,16 @@
+# example
+
+A new Flutter project.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/packages/wyatt_go_router/example/analysis_options.yaml b/packages/wyatt_go_router/example/analysis_options.yaml
new file mode 100644
index 00000000..0939257e
--- /dev/null
+++ b/packages/wyatt_go_router/example/analysis_options.yaml
@@ -0,0 +1,7 @@
+
+include: package:wyatt_analysis/analysis_options.flutter.yaml
+
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/.gitignore b/packages/wyatt_go_router/example/android/.gitignore
new file mode 100644
index 00000000..6f568019
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/packages/wyatt_go_router/example/android/app/build.gradle b/packages/wyatt_go_router/example/android/app/build.gradle
new file mode 100644
index 00000000..118ee1d9
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/build.gradle
@@ -0,0 +1,67 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+android {
+ namespace "com.example.example"
+ compileSdkVersion flutter.compileSdkVersion
+ ndkVersion flutter.ndkVersion
+
+ 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"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+ 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 {}
diff --git a/packages/wyatt_go_router/example/android/app/src/debug/AndroidManifest.xml b/packages/wyatt_go_router/example/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 00000000..399f6981
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/app/src/main/AndroidManifest.xml b/packages/wyatt_go_router/example/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..19b862ec
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/wyatt_go_router/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt
new file mode 100644
index 00000000..e793a000
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt
@@ -0,0 +1,6 @@
+package com.example.example
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/wyatt_go_router/example/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 00000000..f74085f3
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/drawable/launch_background.xml b/packages/wyatt_go_router/example/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 00000000..304732f8
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..db77bb4b
Binary files /dev/null and b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..17987b79
Binary files /dev/null and b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..09d43914
Binary files /dev/null and b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..d5f1c8d3
Binary files /dev/null and b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..4d6372ee
Binary files /dev/null and b/packages/wyatt_go_router/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/values-night/styles.xml b/packages/wyatt_go_router/example/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 00000000..06952be7
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/app/src/main/res/values/styles.xml b/packages/wyatt_go_router/example/android/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..cb1ef880
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/app/src/profile/AndroidManifest.xml b/packages/wyatt_go_router/example/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 00000000..399f6981
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/packages/wyatt_go_router/example/android/build.gradle b/packages/wyatt_go_router/example/android/build.gradle
new file mode 100644
index 00000000..f7eb7f63
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/build.gradle
@@ -0,0 +1,31 @@
+buildscript {
+ ext.kotlin_version = '1.7.10'
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.3.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')
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/packages/wyatt_go_router/example/android/gradle.properties b/packages/wyatt_go_router/example/android/gradle.properties
new file mode 100644
index 00000000..94adc3a3
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/packages/wyatt_go_router/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/wyatt_go_router/example/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..3c472b99
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
diff --git a/packages/wyatt_go_router/example/android/settings.gradle b/packages/wyatt_go_router/example/android/settings.gradle
new file mode 100644
index 00000000..55c4ca8b
--- /dev/null
+++ b/packages/wyatt_go_router/example/android/settings.gradle
@@ -0,0 +1,20 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }
+ settings.ext.flutterSdkPath = flutterSdkPath()
+
+ includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
+
+ plugins {
+ id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
+ }
+}
+
+include ":app"
+
+apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/packages/wyatt_go_router/example/lib/app_router.dart b/packages/wyatt_go_router/example/lib/app_router.dart
new file mode 100644
index 00000000..9f0f0e5b
--- /dev/null
+++ b/packages/wyatt_go_router/example/lib/app_router.dart
@@ -0,0 +1,108 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:wyatt_go_router/wyatt_go_router.dart';
+import 'package:wyatt_go_router_example/bottom_bar.dart';
+import 'package:wyatt_go_router_example/page_a.dart';
+import 'package:wyatt_go_router_example/page_b.dart';
+import 'package:wyatt_go_router_example/page_c.dart';
+
+abstract class AppRouter {
+ /// Default transition for all pages
+ static Page defaultTransition(
+ BuildContext context,
+ GoRouterState state,
+ Widget child,
+ ) =>
+ CupertinoPage(key: state.pageKey, child: child);
+
+ /// Disable transition animation
+ static Page noTransition(
+ BuildContext context,
+ GoRouterState state,
+ Widget child,
+ ) =>
+ NoTransitionPage(key: state.pageKey, child: child);
+
+ static final GlobalKey rootNavigatorKey =
+ GlobalKey();
+ static final GlobalKey shellNavigatorKey =
+ GlobalKey();
+
+ /// Defines GoRoute routes.
+ static final List routes = [
+ ShellRoute(
+ navigatorKey: shellNavigatorKey,
+ builder: (context, state, child) {
+ final currentRoute = context.currentRoute;
+
+ return Scaffold(
+ appBar: AppBar(
+ title: Text(
+ currentRoute.name ?? 'Unknown',
+ ),
+ ),
+ body: child,
+ bottomNavigationBar: BottomBar(
+ currentRoute: currentRoute,
+ ),
+ );
+ },
+ routes: [
+ GoRoute(
+ path: '/page-a',
+ name: 'A',
+ pageBuilder: (context, state) => noTransition(
+ context,
+ state,
+ const PageA(),
+ ),
+ ),
+ GoRoute(
+ path: '/page-b',
+ name: 'B',
+ pageBuilder: (context, state) => noTransition(
+ context,
+ state,
+ const PageB(),
+ ),
+ ),
+ ],
+ ),
+ GoRoute(
+ path: '/page-c',
+ name: 'C',
+ parentNavigatorKey: rootNavigatorKey,
+ pageBuilder: (context, state) => defaultTransition(
+ context,
+ state,
+ const PageC(),
+ ),
+ ),
+ ];
+
+ static GoRouter? _router;
+
+ /// Returns the router.
+ static GoRouter routerOf(BuildContext context) => _router ??= GoRouter(
+ initialLocation: '/page-a',
+ routes: AppRouter.routes,
+ navigatorKey: rootNavigatorKey,
+ debugLogDiagnostics: true,
+ );
+}
diff --git a/packages/wyatt_go_router/example/lib/bottom_bar.dart b/packages/wyatt_go_router/example/lib/bottom_bar.dart
new file mode 100644
index 00000000..e3f45e9e
--- /dev/null
+++ b/packages/wyatt_go_router/example/lib/bottom_bar.dart
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:flutter/material.dart';
+import 'package:wyatt_go_router/wyatt_go_router.dart';
+
+class BottomBar extends StatelessWidget {
+ const BottomBar({
+ required this.currentRoute,
+ super.key,
+ });
+
+ final GoRoute currentRoute;
+
+ @override
+ Widget build(BuildContext context) => BottomNavigationBar(
+ items: const [
+ BottomNavigationBarItem(
+ icon: Icon(Icons.home),
+ label: 'Home',
+ ),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.settings),
+ label: 'Settings',
+ ),
+ ],
+ currentIndex: (currentRoute.name == 'A') ? 0 : 1,
+ onTap: (index) => switch (index) {
+ 0 => context.goNamed('A'),
+ 1 => context.goNamed('B'),
+ _ => throw Exception('Invalid index: $index'),
+ },
+ );
+}
diff --git a/packages/wyatt_go_router/example/lib/main.dart b/packages/wyatt_go_router/example/lib/main.dart
new file mode 100644
index 00000000..bd224ab6
--- /dev/null
+++ b/packages/wyatt_go_router/example/lib/main.dart
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:flutter/material.dart';
+import 'package:wyatt_go_router_example/app_router.dart';
+
+void main(List args) {
+ runApp(const App());
+}
+
+class App extends StatelessWidget {
+ const App({super.key});
+
+ static const String title = 'Wyatt Go Router Example';
+
+ @override
+ Widget build(BuildContext context) => MaterialApp.router(
+ title: title,
+ routerConfig: AppRouter.routerOf(context),
+ );
+}
diff --git a/packages/wyatt_go_router/example/lib/page_a.dart b/packages/wyatt_go_router/example/lib/page_a.dart
new file mode 100644
index 00000000..10dedd4d
--- /dev/null
+++ b/packages/wyatt_go_router/example/lib/page_a.dart
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:flutter/material.dart';
+import 'package:wyatt_go_router/wyatt_go_router.dart';
+
+class PageA extends StatelessWidget {
+ const PageA({super.key});
+
+ @override
+ Widget build(BuildContext context) => Center(
+ child: Text(
+ 'Page A: ${context.currentRoute}',
+ style: Theme.of(context).textTheme.headlineMedium,
+ ),
+ );
+}
diff --git a/packages/wyatt_go_router/example/lib/page_b.dart b/packages/wyatt_go_router/example/lib/page_b.dart
new file mode 100644
index 00000000..fae9089d
--- /dev/null
+++ b/packages/wyatt_go_router/example/lib/page_b.dart
@@ -0,0 +1,40 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:flutter/material.dart';
+import 'package:wyatt_go_router/wyatt_go_router.dart';
+
+class PageB extends StatelessWidget {
+ const PageB({super.key});
+
+ @override
+ Widget build(BuildContext context) => Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ 'Page B: ${context.currentRoute}',
+ style: Theme.of(context).textTheme.headlineMedium,
+ ),
+ const SizedBox(height: 16),
+ ElevatedButton(
+ onPressed: () => context.pushNamed('C'),
+ child: const Text('Go to Page C'),
+ ),
+ ],
+ ),
+ );
+}
diff --git a/packages/wyatt_go_router/example/lib/page_c.dart b/packages/wyatt_go_router/example/lib/page_c.dart
new file mode 100644
index 00000000..6bf8d15a
--- /dev/null
+++ b/packages/wyatt_go_router/example/lib/page_c.dart
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:flutter/material.dart';
+import 'package:wyatt_go_router/wyatt_go_router.dart';
+
+class PageC extends StatelessWidget {
+ const PageC({super.key});
+
+ @override
+ Widget build(BuildContext context) => Scaffold(
+ appBar: AppBar(
+ title: const Text('Page C'),
+ ),
+ body: Center(
+ child: Text(
+ 'Page C: ${context.currentRoute}',
+ style: Theme.of(context).textTheme.headlineMedium,
+ ),
+ ),
+ );
+}
diff --git a/packages/wyatt_go_router/example/pubspec.yaml b/packages/wyatt_go_router/example/pubspec.yaml
new file mode 100644
index 00000000..29b14025
--- /dev/null
+++ b/packages/wyatt_go_router/example/pubspec.yaml
@@ -0,0 +1,25 @@
+name: wyatt_go_router_example
+description: A new Flutter project.
+version: 1.0.0
+
+publish_to: "none"
+
+environment:
+ sdk: ">=3.0.0 <4.0.0"
+
+dependencies:
+ flutter: { sdk: flutter }
+
+ wyatt_go_router:
+ path: "../"
+
+dev_dependencies:
+ flutter_test: { sdk: flutter }
+
+ wyatt_analysis:
+ hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub
+ version: ^2.6.1
+
+# The following section is specific to Flutter.
+flutter:
+ uses-material-design: true
diff --git a/packages/wyatt_go_router/example/test/widget_test.dart b/packages/wyatt_go_router/example/test/widget_test.dart
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/packages/wyatt_go_router/example/test/widget_test.dart
@@ -0,0 +1 @@
+
diff --git a/packages/wyatt_go_router/example/web/favicon.png b/packages/wyatt_go_router/example/web/favicon.png
new file mode 100644
index 00000000..8aaa46ac
Binary files /dev/null and b/packages/wyatt_go_router/example/web/favicon.png differ
diff --git a/packages/wyatt_go_router/example/web/icons/Icon-192.png b/packages/wyatt_go_router/example/web/icons/Icon-192.png
new file mode 100644
index 00000000..b749bfef
Binary files /dev/null and b/packages/wyatt_go_router/example/web/icons/Icon-192.png differ
diff --git a/packages/wyatt_go_router/example/web/icons/Icon-512.png b/packages/wyatt_go_router/example/web/icons/Icon-512.png
new file mode 100644
index 00000000..88cfd48d
Binary files /dev/null and b/packages/wyatt_go_router/example/web/icons/Icon-512.png differ
diff --git a/packages/wyatt_go_router/example/web/icons/Icon-maskable-192.png b/packages/wyatt_go_router/example/web/icons/Icon-maskable-192.png
new file mode 100644
index 00000000..eb9b4d76
Binary files /dev/null and b/packages/wyatt_go_router/example/web/icons/Icon-maskable-192.png differ
diff --git a/packages/wyatt_go_router/example/web/icons/Icon-maskable-512.png b/packages/wyatt_go_router/example/web/icons/Icon-maskable-512.png
new file mode 100644
index 00000000..d69c5669
Binary files /dev/null and b/packages/wyatt_go_router/example/web/icons/Icon-maskable-512.png differ
diff --git a/packages/wyatt_go_router/example/web/index.html b/packages/wyatt_go_router/example/web/index.html
new file mode 100644
index 00000000..be820e83
--- /dev/null
+++ b/packages/wyatt_go_router/example/web/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ example
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/wyatt_go_router/example/web/manifest.json b/packages/wyatt_go_router/example/web/manifest.json
new file mode 100644
index 00000000..096edf8f
--- /dev/null
+++ b/packages/wyatt_go_router/example/web/manifest.json
@@ -0,0 +1,35 @@
+{
+ "name": "example",
+ "short_name": "example",
+ "start_url": ".",
+ "display": "standalone",
+ "background_color": "#0175C2",
+ "theme_color": "#0175C2",
+ "description": "A new Flutter project.",
+ "orientation": "portrait-primary",
+ "prefer_related_applications": false,
+ "icons": [
+ {
+ "src": "icons/Icon-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "icons/Icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ },
+ {
+ "src": "icons/Icon-maskable-192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "maskable"
+ },
+ {
+ "src": "icons/Icon-maskable-512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "maskable"
+ }
+ ]
+}
diff --git a/packages/wyatt_go_router/lib/src/core/enums/page_protection.dart b/packages/wyatt_go_router/lib/src/core/enums/page_protection.dart
new file mode 100644
index 00000000..154ab5cf
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/core/enums/page_protection.dart
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+/// {@template}
+/// A enum that defines the protection of a page.
+/// {@endtemplate}
+enum PageProtection {
+ /// The page can be accessed without authentication.
+ public,
+
+ /// The page can only be accessed with authentication.
+ protected,
+
+ /// The page protection is unknown, and the default one should be used.
+ none,
+}
diff --git a/packages/wyatt_go_router/lib/src/core/extensions/build_context_extension.dart b/packages/wyatt_go_router/lib/src/core/extensions/build_context_extension.dart
new file mode 100644
index 00000000..7bb14b9a
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/core/extensions/build_context_extension.dart
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:flutter/widgets.dart';
+import 'package:wyatt_go_router/wyatt_go_router.dart';
+
+extension BuildContextExtension on BuildContext {
+ GoRoute get currentRoute => GoRouter.of(this).currentRoute;
+}
diff --git a/packages/wyatt_go_router/lib/src/core/extensions/go_route_extension.dart b/packages/wyatt_go_router/lib/src/core/extensions/go_route_extension.dart
new file mode 100644
index 00000000..4f7bfb64
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/core/extensions/go_route_extension.dart
@@ -0,0 +1,69 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:go_router/go_router.dart';
+import 'package:wyatt_go_router/src/core/enums/page_protection.dart';
+
+/// Defines if a GoRoute is public or not.
+///
+/// By default, all routes are in the [PageProtection.none] state.
+extension GoRouteExtension on GoRoute {
+ static final _protection = Expando();
+
+ /// Returns `true` if the route is public.
+ bool get isPublic => _protection[this] == PageProtection.public;
+
+ /// Returns `true` if the route is protected.
+ bool get isProtected => _protection[this] == PageProtection.protected;
+
+ /// Returns `true` if the route is neither public nor protected.
+ /// This is the default state.
+ bool get isNone => _protection[this] == PageProtection.none;
+
+ /// Sets the route to be public.
+ /// This is useful for routes that should be accessible
+ /// without authentication.
+ /// ```dart
+ /// GoRoute(
+ /// path: '/sign_in',
+ /// ...
+ /// )..setPublic(),
+ /// ```
+ void setPublic() => _protection[this] = PageProtection.public;
+
+ /// Sets the route to be protected.
+ /// This is useful for routes that should only be accessible
+ /// with authentication.
+ void setProtected() => _protection[this] = PageProtection.protected;
+
+ PageProtection get protection => _protection[this] ?? PageProtection.none;
+}
diff --git a/packages/wyatt_go_router/lib/src/core/extensions/go_route_iterable_extension.dart b/packages/wyatt_go_router/lib/src/core/extensions/go_route_iterable_extension.dart
new file mode 100644
index 00000000..3fbacf78
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/core/extensions/go_route_iterable_extension.dart
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:go_router/go_router.dart';
+import 'package:wyatt_go_router/src/core/extensions/go_route_extension.dart';
+
+extension GoRouteIterableExtension on Iterable {
+ /// Returns a list of public routes.
+ List get publicRoutes =>
+ where((route) => route.isPublic).toList(growable: false);
+
+ /// Returns a list of protected routes.
+ List get protectedRoutes =>
+ where((route) => route.isProtected).toList(growable: false);
+
+ /// Returns a list of routes that are neither public nor protected.
+ List get noneRoutes =>
+ where((route) => route.isNone).toList(growable: false);
+
+ /// Returns a go route from its name.
+ ///
+ /// If no route is found, a [StateError] is thrown.
+ GoRoute fromName(String name) => firstWhere((route) => route.name == name);
+
+ /// Returns a go route from its path.
+ ///
+ /// If no route is found, a [StateError] is thrown.
+ GoRoute fromPath(String path) => firstWhere((route) => route.path == path);
+
+ /// Returns a go route from its name or null if no route is found.
+ GoRoute? fromNameOrNull(String name) {
+ if (any((route) => route.name == name)) {
+ return fromName(name);
+ }
+
+ return null;
+ }
+
+ /// Returns a go route from its path or null if no route is found.
+ GoRoute? fromPathOrNull(String path) {
+ if (any((route) => route.path == path)) {
+ return fromPath(path);
+ }
+
+ return null;
+ }
+
+ /// Returns a go route from its name, or null if no route is found.
+ ///
+ /// This is a shorthand for [fromNameOrNull].
+ GoRoute? operator [](String name) => fromNameOrNull(name);
+}
diff --git a/packages/wyatt_go_router/lib/src/core/extensions/go_router_extension.dart b/packages/wyatt_go_router/lib/src/core/extensions/go_router_extension.dart
new file mode 100644
index 00000000..8211e2d1
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/core/extensions/go_router_extension.dart
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:wyatt_go_router/wyatt_go_router.dart';
+
+extension GoRouterExtension on GoRouter {
+ List get flattenedRoutes => configuration.routes
+ .map((route) => route.flatten())
+ .expand(
+ (routeList) => routeList,
+ )
+ .toList();
+
+ /// Returns the current route.
+ GoRoute get currentRoute =>
+ flattenedRoutes.fromPath(routeInformationProvider.value.uri.path);
+}
diff --git a/packages/wyatt_go_router/lib/src/core/extensions/route_base_extension.dart b/packages/wyatt_go_router/lib/src/core/extensions/route_base_extension.dart
new file mode 100644
index 00000000..3a24b375
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/core/extensions/route_base_extension.dart
@@ -0,0 +1,40 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'package:go_router/go_router.dart';
+
+/// Flatten the [GoRoute] tree.
+extension RouteBaseExtension on RouteBase {
+ /// Flatten a [GoRoute] or [ShellRoute] into a list of [GoRoute]s.
+ /// - If the current route is a [GoRoute], it is added to the list.
+ /// - If the current route is a [ShellRoute], all of its child routes are
+ /// flattened and added to the list.
+ List flatten() {
+ final List routes = [];
+ if (this is GoRoute) {
+ routes.add(this as GoRoute);
+ } else if (this is ShellRoute) {
+ routes.addAll(
+ (this as ShellRoute)
+ .routes
+ .map((route) => route.flatten())
+ .expand((routeList) => routeList),
+ );
+ }
+
+ return routes;
+ }
+}
diff --git a/packages/wyatt_go_router/lib/src/core/go_router_refresh_stream.dart b/packages/wyatt_go_router/lib/src/core/go_router_refresh_stream.dart
new file mode 100644
index 00000000..b37ca831
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/core/go_router_refresh_stream.dart
@@ -0,0 +1,40 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+
+/// {@template go_router_refresh_stream}
+/// A [ChangeNotifier] that notifies its listeners when a stream emits a value.
+/// {@endtemplate}
+class GoRouterRefreshStream extends ChangeNotifier {
+ /// {@macro go_router_refresh_stream}
+ GoRouterRefreshStream(Stream stream) {
+ notifyListeners();
+ _subscription = stream.asBroadcastStream().listen(
+ (dynamic _) => notifyListeners(),
+ );
+ }
+
+ late final StreamSubscription _subscription;
+
+ @override
+ void dispose() {
+ _subscription.cancel();
+ super.dispose();
+ }
+}
diff --git a/packages/wyatt_go_router/lib/src/wyatt_go_router.dart b/packages/wyatt_go_router/lib/src/wyatt_go_router.dart
new file mode 100644
index 00000000..93ba60c0
--- /dev/null
+++ b/packages/wyatt_go_router/lib/src/wyatt_go_router.dart
@@ -0,0 +1,23 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+export 'core/enums/page_protection.dart';
+export 'core/extensions/build_context_extension.dart';
+export 'core/extensions/go_route_extension.dart';
+export 'core/extensions/go_route_iterable_extension.dart';
+export 'core/extensions/go_router_extension.dart';
+export 'core/extensions/route_base_extension.dart';
+export 'core/go_router_refresh_stream.dart';
diff --git a/packages/wyatt_go_router/lib/wyatt_go_router.dart b/packages/wyatt_go_router/lib/wyatt_go_router.dart
new file mode 100644
index 00000000..1b3952c1
--- /dev/null
+++ b/packages/wyatt_go_router/lib/wyatt_go_router.dart
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 WYATT GROUP
+// Please see the AUTHORS file for details.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+/// GoRouter enhancements
+///
+/// This library provides enhancements to the GoRouter package.
+/// It also exports the GoRouter package.
+library wyatt_go_router;
+
+export 'package:go_router/go_router.dart';
+
+export 'src/wyatt_go_router.dart';
diff --git a/packages/wyatt_go_router/pubspec.yaml b/packages/wyatt_go_router/pubspec.yaml
new file mode 100644
index 00000000..c42f8d07
--- /dev/null
+++ b/packages/wyatt_go_router/pubspec.yaml
@@ -0,0 +1,18 @@
+name: wyatt_go_router
+description: GoRouter Enhancements.
+repository: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages/src/branch/master/packages/wyatt_go_router
+version: 1.0.0
+
+environment:
+ sdk: ">=3.0.0 <4.0.0"
+
+dependencies:
+ flutter: { sdk: flutter }
+ go_router: ^12.1.1
+
+dev_dependencies:
+ flutter_test: { sdk: flutter }
+ dart_code_linter: ^1.1.1
+ wyatt_analysis:
+ hosted: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub
+ version: ^2.6.1
diff --git a/packages/wyatt_go_router/test/wyatt_go_router_test.dart b/packages/wyatt_go_router/test/wyatt_go_router_test.dart
new file mode 100644
index 00000000..3a06c0e1
--- /dev/null
+++ b/packages/wyatt_go_router/test/wyatt_go_router_test.dart
@@ -0,0 +1 @@
+// TODO(wyatt): add some tests