{"id":13491337,"url":"https://github.com/gurleensethi/sailor","last_synced_at":"2025-05-07T15:47:30.639Z","repository":{"id":34871207,"uuid":"185814983","full_name":"gurleensethi/sailor","owner":"gurleensethi","description":"Easy page navigation and management in Flutter apps.","archived":false,"fork":false,"pushed_at":"2022-02-11T12:11:00.000Z","size":166,"stargazers_count":145,"open_issues_count":30,"forks_count":23,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-19T02:07:48.464Z","etag":null,"topics":["android","dart","dart2","dartlang","flutter","flutter-app","flutter-apps","flutter-demo","flutter-package","flutter-widget","ios","navigation"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/sailor","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gurleensethi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-09T14:26:22.000Z","updated_at":"2024-11-01T12:27:59.000Z","dependencies_parsed_at":"2022-08-08T02:15:18.924Z","dependency_job_id":null,"html_url":"https://github.com/gurleensethi/sailor","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gurleensethi%2Fsailor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gurleensethi%2Fsailor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gurleensethi%2Fsailor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gurleensethi%2Fsailor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gurleensethi","download_url":"https://codeload.github.com/gurleensethi/sailor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231449739,"owners_count":18378431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","dart","dart2","dartlang","flutter","flutter-app","flutter-apps","flutter-demo","flutter-package","flutter-widget","ios","navigation"],"created_at":"2024-07-31T19:00:55.788Z","updated_at":"2024-12-27T07:09:08.508Z","avatar_url":"https://github.com/gurleensethi.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"# sailor\n\n![anchor_image](https://raw.githubusercontent.com/gurleensethi/sailor/master/images/anchor-icon.png)\n\n![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)\n[![pub_package](https://img.shields.io/pub/vpre/sailor.svg)](https://pub.dev/packages/sailor)\n\nA Flutter package for easy navigation management.\n\n#### Warning: Package is still under development, there might be breaking changes in future.\n\n## Index\n\n- [Setup and Usage](#setup-and-usage)\n- [Passing Parameters](#passing-parameters)\n- [Passing Arguments](#passing-arguments)\n- [Route Guards (Experimental)](#route-guards-experimental)\n- [Transitions](#transitions)\n- [Pushing Multiple Routes](#pushing-multiple-routes)\n- [Log Navigation](#log-navigation)\n- [Support](#support)\n\n## Setup and Usage\n\n1. Create an instance of `Sailor` and add routes.\n\n```dart\n// Routes class is created by you.\nclass Routes {\n  static final sailor = Sailor();\n\n  static void createRoutes() {\n    sailor.addRoute(SailorRoute(\n        name: \"/secondPage\",\n        builder: (context, args, params) {\n          return SecondPage();\n        },\n      ));\n  }\n}\n```\n\n2. Register the routes in `onGenerateRoute` using the `generate` function of `Sailor` and also `Sailor`'s `navigatorKey`.\n\n```dart\nclass App extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Sailor Example',\n      home: Home(),\n      navigatorKey: Routes.sailor.navigatorKey,  // important\n      onGenerateRoute: Routes.sailor.generator(),  // important\n    );\n  }\n}\n```\n\n3. Make sure to create routes before starting the application.\n\n```dart\nvoid main() async {\n  Routes.createRoutes();\n  runApp(App());\n}\n```\n\n4. Use the instance of `Sailor` to navigate.\n\n```dart\nRoutes.sailor.navigate(\"/secondPage\");\n```\n\n- TIP: `Sailor` is a callable class, so you can omit `navigate` and directly call the method.\n\n```dart\nRoutes.sailor(\"/secondPage\");\n```\n\n## Passing Parameters\n\n`Sailor` allows you to pass parameters to the page that you are navigating to.\n\n- Before passing the parameter itself, you need to declare it while declaring your route. Let's declare a parameter named `id` that has a default value of `1234`.\n\n```dart\nsailor.addRoutes([\n  SailorRoute(\n    name: \"/secondPage\",\n    builder: (context, args, params) =\u003e SecondPage(),\n    params: [\n      SailorParam\u003cint\u003e(\n        name: 'id',\n        defaultValue: 1234,\n      ),\n    ],\n  ),\n);\n```\n\n- Pass the actual parameter when navigating to the new route.\n\n```dart\nRoutes.sailor.navigate\u003cbool\u003e(\"/secondPage\", params: {\n  'id': 4321,\n});\n```\n\n- Parameters can be retrieved from two places, first, the route builder and second, the opened page itself.\n\n**Route Builder:**\n\n```dart\nsailor.addRoutes([\n  SailorRoute(\n    name: \"/secondPage\",\n    builder: (context, args, params) {\n      // Getting a param\n      final id = params.param\u003cint\u003e('id');\n      return SecondPage();\n    },\n    params: [\n      SailorParam(\n        name: 'id',\n        defaultValue: 1234,\n      ),\n    ],\n  ),\n);\n```\n\n**Opened page:**\n\n```dart\nclass SecondPage extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    final id = Sailor.param\u003cint\u003e(context, 'id');\n\n    ...\n\n  }\n}\n```\n\nMake sure to specify the type of paramter when declaring `SailorParam\u003cT\u003e`. This type is used to make sure when the route is being opened, it is passed the correct param type. Right now `Sailor` logs a warning if the type of declared and passed param is not same. In future version this might throw an error.\n\n## Passing Arguments\n\n`Sailor` allows you to pass arguments to the page that you are navigating to.\n\n- Create a class that extends from `BaseArguments`.\n\n```dart\nclass SecondPageArgs extends BaseArguments {\n  final String text;\n\n  SecondPageArgs(this.text);\n}\n```\n\n- When calling the `navigate` method pass these arguments.\n\n```dart\nfinal response = Routes.sailor.navigate(\n  \"/secondPage\",\n  args: SecondPageArgs('Hey there'),\n);\n```\n\n- When in the SecondPage, use `Sailor.args` to get the passed arguments.\n\n```dart\nclass SecondPage extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    final args = Sailor.args\u003cSecondPageArgs\u003e(context);\n\n    return Scaffold(\n      appBar: AppBar(\n        title: Text('Compass Example'),\n      ),\n      body: Center(\n        child: Text(args.text),\n      ),\n    );\n  }\n}\n```\n\n## Route Guards (Experimental)\n\nRoutes can be protected from being opened when `navigate` is called using `route guard`.\n\nA route guard can be added when declaring a `SailorRoute`.\n\n```dart\nsailor.addRoutes([\n  SailorRoute(\n    name: \"/secondPage\",\n    builder: (context, args, params) =\u003e SecondPage(),\n    routeGuards: [\n      SailorRouteGuard.simple((context, args, params) async {\n        // Can open logic goes here.\n        if (sharedPreferences.getToken() != null) {\n          return true;\n        }\n        return false;\n      }),\n    ],\n  ),\n);\n```\n\n`routeGuards` takes an array of `SailorRouteGuard`.\n\nThere are two ways to create a route guard:\n\n- Using `SailorRouteGuard.simple`, as shown above.\n```dart\nSailorRouteGuard.simple((context, args, params) async {\n  // Can open logic goes here.\n  if (sharedPreferences.getToken() != null) {\n    return true;\n  }\n  return false;\n});\n```\n- Extending `SailorRouteGuard` class.\n```dart\nclass CustomRouteGuard extends SailorRouteGuard {\n  @override\n  Future\u003cbool\u003e canOpen(\n    BuildContext context,\n    BaseArguments args,\n    ParamMap paramMap,\n  ) async {\n    return false;\n  }\n}\n```\n\nThe result from each route guard is `Future\u003cbool\u003e`. If the value returned __by each route__ is `true` the route is accepted and opened, anything else will result in route being rejected and not being opened.\n\n## Transitions\n\nSailor has inbuilt support for page transitions. A transition is specified using `SailorTransition`.\n\nTransition can be specified at 3 levels (ordered in priority from highest to lowest):\n\n- When Navigating (using `Sailor.navigate`).\n- While adding routes (`SailorRoute`).\n- Global transitions (`SailorOptions`).\n\n### When navigating\n\nSpecify which transitions to use when calling the `navigate` method.\n\n```dart\nRoutes.sailor.navigate(\n  \"/secondPage\",\n  transitions: [SailorTransition.fade_in],\n);\n```\n\nMore than one transition can be provided when navigating a single route. These transitions are composed on top of each other, so in some cases changing the order will change the animation.\n\n```dart\nRoutes.sailor.navigate(\n  \"/secondPage\",\n  transitions: [\n    SailorTransition.fade_in,\n    SailorTransition.slide_from_right,\n  ],\n  transitionDuration: Duration(milliseconds: 500),\n  transitionCurve: Curves.bounceOut,\n);\n```\n\n`Duration` and `Curve` can be provided using `transitionDuration` and `transitionCurve` respectively.\n\n```dart\nRoutes.sailor.navigate(\n  \"/secondPage\",\n  transitions: [\n    SailorTransition.fade_in,\n    SailorTransition.slide_from_right,\n  ],\n  transitionDuration: Duration(milliseconds: 500),\n  transitionCurve: Curves.bounceOut,\n);\n```\n\nIn the above example the page will slide in from right with a fade in animation. You can specify as many transitions as you want.\n\n### When adding routes\n\nYou can specify the default transition for a route, so you don't have to specify it again and again when navigating.\n\n```dart\nsailor.addRoute(SailorRoute(\n  name: \"/secondPage\",\n  defaultTransitions: [\n    SailorTransition.slide_from_bottom,\n    SailorTransition.zoom_in,\n  ],\n  defaultTransitionCurve: Curves.decelerate,\n  defaultTransitionDuration: Duration(milliseconds: 500),\n  builder: (context, args) =\u003e SecondPage(),\n));\n```\n\nPriority: Transitions provided in `Sailor.navigate` while navigating to this route, will override these transitions.\n\n### Global transitions\n\nYou can specify default transition to be used for all routes in `Sailor`.\n\n```dart\nSailorOptions(\n  defaultTransitions: [\n    SailorTransition.slide_from_bottom,\n    SailorTransition.zoom_in,\n  ],\n  defaultTransitionCurve: Curves.decelerate,\n  defaultTransitionDuration: Duration(milliseconds: 500),\n)\n```\n\nPriority: Transitions provided while adding a route or when navigating using `navigate`, will override these transitions.\n\n### Custom Transitions\n\nAlthough `sailor` provides you with a number of out of the box transitions, you can still provide your own custom transitions.\n\n- To create a custom transition, extend the class `CustomSailorTransition` and implement `buildTransition` method.\n\n```dart\nclass MyCustomTransition extends CustomSailorTransition {\n  @override\n  Widget buildTransition(\n    BuildContext context,\n    Animation\u003cdouble\u003e animation,\n    Animation\u003cdouble\u003e secondaryAnimation,\n    Widget child,\n  ) {\n    return FadeTransition(\n      opacity: animation,\n      child: child,\n    );\n  }\n}\n```\n\nThis transition can now be provided at 3 places:\n\n- While calling `navigate`.\n\n```dart\nRoutes.sailor.navigate\u003cbool\u003e(\n  \"/secondPage\",\n  customTransition: MyCustomTransition(),\n);\n```\n\n- When declaring a `SailorRoute`.\n\n```dart\nSailorRoute(\n  name: \"/secondPage\",\n  builder: (context, args, params) =\u003e SecondPage(),\n  customTransition: MyCustomTransition(),\n),\n```\n\n- In `SailorOptions`:\n\n```dart\nstatic final sailor = Sailor(\n  options: SailorOptions(\n    customTransition: MyCustomTransition(),\n  ),\n);\n```\n\n#### Custom Transition Priority\n\n_NOTE: Custom transitions have the highest priority, if you provide a custom transition, they will be used over Sailor's inbuilt transitions._\n\nThe same priority rules apply to custom transitions as inbuilt sailor transitions, with the added rule that at any step if both transitions are provided (i.e. Sailor's inbuilt transitions and a CustomSailorTransition), the custom transition will be used over inbuilt one.\n\nFor example, in the below code, `MyCustomTransition` will be used instead of `SailorTransition.slide_from_top`.\n\n```dart\nRoutes.sailor.navigate\u003cbool\u003e(\n  \"/secondPage\",\n  transitions: [\n    SailorTransition.slide_from_top,\n  ],\n  customTransition: MyCustomTransition(),\n);\n```\n\n## Pushing Multiple Routes\n\nSailor allows you to push multiple pages at the same time and get collected response from all.\n\n```dart\nfinal responses = await Routes.sailor.navigateMultiple(context, [\n  RouteArgsPair(\"/secondPage\", SecondPageArgs(\"Multi Page!\")),\n  RouteArgsPair(\"/thirdPage\", ThirdPageArgs(10)),\n]);\n\nprint(\"Second Page Response ${responses[0]}\");\nprint(\"Third Page Response ${responses[1]}\");\n```\n\n## Log Navigation\n\nUse `SailorLoggingObserver` to log the `push`/`pop` navigation inside the application.\nAdd the `SailorLoggingObserver` to the `navigatorObservers` list inside your `MaterialApp`.\n\n```dart\nclass App extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Compass Example',\n      home: Home(),\n      onGenerateRoute: Routes.sailor.generator(),\n      navigatorObservers: [\n        SailorLoggingObserver(),\n      ],\n    );\n  }\n}\n```\n\nOnce added, start navigating in your app and check the logs. You will see something like this.\n\n```\nflutter: [Sailor] Route Pushed: (Pushed Route='/', Previous Route='null', New Route Args=null, Previous Route Args=null)\nflutter: [Sailor] Route Pushed: (Pushed Route='/secondPage', Previous Route='/', New Route Args=Instance of 'SecondPageArgs', Previous Route Args=null)\nflutter: [Sailor] Route Popped: (New Route='/', Popped Route='/secondPage', New Route Args=null, Previous Route Args=Instance of 'SecondPageArgs')\n```\n\n## Support\n\nIf you face any issue or want a new feature to be added to the package, please [create an issue](https://github.com/gurleensethi/sailor/issues/new).\nI will be more than happy to resolve your queries.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgurleensethi%2Fsailor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgurleensethi%2Fsailor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgurleensethi%2Fsailor/lists"}