Flutter
āđāļĄāđāļāļĢāđāļāļĢāļĄāđāļ§āļīāļĢāđāļ
āļŠāļģāļŦāļĢāļąāļāđāļāļāļŠāļĄāļąāļĒāđāļŦāļĄāđ
āļĢāļēāļāļāļēāļāļāļĩāđāđāļāđāļāđāļāļĢāđāļāļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāļĢāđāļēāļāđāļāļ Flutter āļĢāļ°āļāļāđāļŠāđāļāļāļēāļ āļāļēāļĢāļāļąāļāļāļēāļĢāļŠāļāļēāļāļ° āđāļāļĢāļ·āļāļāđāļēāļĒ āđāļĨāļ°āļāļ·āđāļāđ āļāļĩāļāļĄāļēāļāļĄāļēāļĒ â āļāļąāđāļāļŦāļĄāļāđāļāđāļāđāļāđāļāļāđāļāļĩāļĒāļ§āļāļĩāđāļŠāļ§āļĒāļāļēāļĄ
āļāļļāļāļŠāļīāđāļāļāļĩāđāļāļļāļāļāđāļāļāļāļēāļĢāļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāļĢāđāļēāļ
Nylo āļĄāļāļāđāļāļĢāļ·āđāļāļāļĄāļ·āļāļāļąāđāļāļŦāļĄāļāļāļĩāđāļāļļāļāļāđāļāļāļāļēāļĢāđāļāļ·āđāļāļŠāļĢāđāļēāļāđāļāļāļāļĨāļīāđāļāļāļąāļ Flutter āļāļĩāđāļāļĢāđāļāļĄāđāļāđāļāļēāļāļāļĢāļīāļāļāļĒāđāļēāļāļĄāļąāđāļāđāļ
āļĢāļ°āļāļāđāļŠāđāļāļāļēāļ
āļĢāļ°āļāļāđāļŠāđāļāļāļēāļāđāļāļāļāļĢāļ°āļāļēāļĻāļāļĩāđāđāļĢāļĩāļĒāļāļāđāļēāļĒ āļāļĢāđāļāļĄāļāļēāļĢāļāđāļāļāļāļąāļāđāļŠāđāļāļāļēāļ āļāļēāļĢāļēāļĄāļīāđāļāļāļĢāđ āđāļĨāļ°āļĢāļāļāļĢāļąāļ Deep Linking
āļāļēāļĢāļāļąāļāļāļēāļĢāļŠāļāļēāļāļ°
āļāļēāļĢāļāļąāļāļāļēāļĢāļŠāļāļēāļāļ°āđāļāļ Reactive āđāļāļāļąāļ§ āļāļĢāđāļāļĄāļāļāļāđāļāļĢāļĨāđāļĨāļāļĢāđāđāļĨāļ°āļāļēāļĢāļāļāļŠāļāļēāļāļ°āļāļĩāđāļāđāļēāļĒāļāļēāļĒ
āđāļāļĢāļ·āļāļāđāļēāļĒ
āļāļĨāļēāļŠāļāļĢāļīāļāļēāļĢ API āļāļĩāđāļŠāļ§āļĒāļāļēāļĄ āļāļĢāđāļāļĄāļāļēāļĢāđāļāļĨāļāđāļĄāđāļāļĨāļāļąāļāđāļāļĄāļąāļāļīāđāļĨāļ°āļāļąāļ§āļāļąāļāļāļąāļ
āļāļāļĢāđāļĄ
āļāļēāļĢāļāļąāļāļāļēāļĢāļāļāļĢāđāļĄāļāļĩāđāļāļĢāļāļāļĨāļąāļ āļāļĢāđāļāļĄāļāļēāļĢāļāļĢāļ§āļāļŠāļāļ āļāļēāļĢāđāļāļĨāļāļāļāļīāļāļāđāļāļĄāļđāļĨ āđāļĨāļ°āļāļēāļĢāļāļđāļāļāđāļāļĄāļđāļĨāļāļąāļāđāļāļĄāļąāļāļī
āļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļ
āļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāļāļĩāđāļāļĨāļāļāļ āļąāļĒ āļāļĢāđāļāļĄāļāļēāļĢāļāđāļāļāļāļąāļāđāļŠāđāļāļāļēāļ āļāļēāļĢāļāļąāļāđāļāđāļāđāļāđāļāđāļ āđāļĨāļ°āļāļēāļĢāļāļąāļāļāļēāļĢāđāļāļŠāļāļąāļ
Metro CLI
āļŠāļĢāđāļēāļāļŦāļāđāļē āđāļĄāđāļāļĨ āļāļāļāđāļāļĢāļĨāđāļĨāļāļĢāđ āđāļĨāļ°āļāļ·āđāļāđ āļāđāļ§āļĒāļāļģāļŠāļąāđāļ CLI āļāļĩāđāļāļĢāļāļāļĨāļąāļ
āļŠāļĢāđāļēāļāļāļļāļāļāļĒāđāļēāļāļāļēāļāđāļāļāļĢāđāļĄāļīāļāļąāļĨ
Metro āļāļ·āļāđāļāļĢāļ·āđāļāļāļĄāļ·āļ CLI āļāļāļ Nylo āļāļĩāđāļāđāļ§āļĒāđāļŦāđāļāļļāļāļŠāļĢāđāļēāļāđāļāļĢāļāļŠāļĢāđāļēāļāļŦāļāđāļē āđāļĄāđāļāļĨ āļāļāļāđāļāļĢāļĨāđāļĨāļāļĢāđ āļ§āļīāļāđāļāđāļ āđāļĨāļ°āļāļ·āđāļāđ āļāđāļ§āļĒāļāļģāļŠāļąāđāļāđāļāļĩāļĒāļ§
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄāđāļāļĩāđāļĒāļ§āļāļąāļ Metrometro make:page HomePage
# Creates a new page called HomePage
metro make:api_service User
# Creates a new API Service called UserApiService
metro make:model User
# Creates a new model called User
metro make:stateful_widget FavouriteWidget
# Creates a new stateful widget called FavouriteWidget
class ApiService extends NyApiService {
@override
String get baseUrl => "https://api.example.com/v1";
Future<List<Post>> posts() async {
return await network(
request: (request) => request.get("/posts"),
);
}
}
// Usage in your page
final posts = await api<ApiService>((request) => request.posts());
āļāļēāļĢāđāļāļ·āđāļāļĄāļāđāļ API āļāļĒāđāļēāļāļāđāļēāļĒāļāļēāļĒ
āđāļāļĩāļĒāļāļāļĢāļīāļāļēāļĢ API āļāļĩāđāļŠāļ°āļāļēāļāđāļĨāļ°āļāļđāđāļĨāļĢāļąāļāļĐāļēāļāđāļēāļĒ āļāļĢāđāļāļĄāļāļēāļĢāđāļĒāļāļ§āļīāđāļāļĢāļēāļ°āļŦāđ JSON āļāļąāļāđāļāļĄāļąāļāļī āļāļēāļĢāļāļąāļāļāļēāļĢāļāđāļāļāļīāļāļāļĨāļēāļ āđāļĨāļ°āļāļąāļ§āļāļąāļāļāļąāļāļāļģāļāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄāđāļāļĩāđāļĒāļ§āļāļąāļāđāļāļĢāļ·āļāļāđāļēāļĒāđāļāļĢāļ·āđāļāļāļĄāļ·āļāļāļĩāđāļāļĢāļāļāļĨāļąāļāļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāļĢāđāļēāļ
āļāļļāļāļŠāļīāđāļāļāļĩāđāļāļļāļāļāđāļāļāļāļēāļĢāļŠāļģāļŦāļĢāļąāļāļŠāļĢāđāļēāļāđāļāļ Flutter āļāļąāļāđāļāļāļāļāļāļļāļ
appRouter() => nyRoutes((router) {
router.add(HomePage.path).initialRoute();
router.add(DiscoverPage.path);
router.add(LoginPage.path,
transitionType: TransitionType.bottomToTop());
router.add(ProfilePage.path,
routeGuard: [
AuthGuard()
]
);
});
āļŠāļĢāđāļēāļāđāļŠāđāļāļāļēāļ āļāļīāļāđāļāļāļĢāđāđāļāļ āđāļĨāļ°āļŦāļāđāļē UI āļāļĩāđāļāļąāļāļāđāļāļāļŠāļģāļŦāļĢāļąāļāđāļāļāļāļĨāļīāđāļāļāļąāļ Flutter āļāļāļāļāļļāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāļāļđāđāđāļāđ
String userToken = "eyJhbG123...";
await Auth.authenticate(data: {"token": userToken});
āļāļāļāļāļĩāđ āđāļĄāļ·āđāļāļāļđāđāđāļāđāļāļāļāļāļļāļāđāļāļīāļāđāļāļ āļāļ§āļāđāļāļēāļāļ°āđāļāđāļĢāļąāļāļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāđāļĨāđāļ§
final userData = Auth.data();
// {"token": "eyJhbG123..."}
bool isAuthenticated = await Auth.isAuthenticated();
// true
āļŦāļēāļāļāļļāļāđāļāđāļāļąāđāļāļāđāļē authenticatedRoute āđāļāđāļĢāļēāđāļāļāļĢāđāļāļāļāļāļļāļ āļŦāļāđāļēāļāļĩāđāļāļ°āļāļđāļāđāļŠāļāļāđāļĄāļ·āđāļāļāļđāđāđāļāđāđāļāļīāļāđāļāļāļāļĩāļāļāļĢāļąāđāļ
appRouter() => nyRoutes((router) {
...
router.add(LandingPage.path).initialRoute();
router.add(DashboardPage.path).authenticatedRoute();
// overrides the initial route when a user is authenticated
āļāļāļāļāļēāļāļĢāļ°āļāļāļāļđāđāđāļāđ
await Auth.logout();
āļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāļāļđāđāđāļāđāđāļāđāļāļāļāļĨāļīāđāļāļāļąāļ Flutter āļāļāļāļāļļāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļŠāļĢāđāļēāļāļāļāļĢāđāļĄ
metro make:form RegisterForm
āđāļāđāđāļāļāļāļĢāđāļĄāļāļāļāļāļļāļ
class RegisterForm extends NyFormWidget {
RegisterForm({super.key, super.submitButton, super.onSubmit, super.onFailure});
// Add your fields here
@override
fields() => [
Field.capitalizeWords("name",
label: "Name",
validator: FormValidator.notEmpty(),
),
Field.email("email_address",
label: "Email",
validator: FormValidator.email()
),
Field.password("password",
label: "Password",
validator: FormValidator.password(),
),
];
static NyFormActions get actions => const NyFormActions("RegisterForm");
}
āđāļāđāļāļāļĢāđāļĄāļāļāļāļāļļāļāđāļāļ§āļīāļāđāļāđāļ
@override
Widget build(BuildContext context) {
return Scaffold(
body: RegisterForm(
submitButton: Button.primary(text: "Submit"),
onSubmit: (data) {
printInfo(data);
},
),
);
}
āļāļąāļāļāļēāļĢ āļāļĢāļ§āļāļŠāļāļ āđāļĨāļ°āļŠāđāļāļāđāļāļĄāļđāļĨāļāļąāđāļāļŦāļĄāļāđāļāļāļĩāđāđāļāļĩāļĒāļ§āļāđāļ§āļĒ Nylo Forms
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļŠāļĢāđāļēāļāļ§āļīāļāđāļāđāļāļāļĩāđāļāļąāļāļāļēāļĢāļŠāļāļēāļāļ°
metro make:stateful_widget CartIcon
class _CartIconState extends NyState<CartIcon> {
...
@override
Map<String, Function> get stateActions => {
"clear_cart": () {
_items = 0;
},
...
};
@override
Widget view(BuildContext context) {
return Container(child: Text("Items in cart: ${_items}"));
}
}
Use CartIcon.action("clear_cart")
Button.primary(text: "Add to cart",
onPressed: () {
CartIcon.action("clear_cart");
}
)
āļāļēāļĢāļāļąāļāļāļēāļĢāļŠāļāļēāļāļ°āļāļĩāđāļāļĢāļāļāļĨāļąāļāļŠāļģāļŦāļĢāļąāļāļ§āļīāļāđāļāđāļāđāļāđāļāļāļāļĨāļīāđāļāļāļąāļ Flutter āļāļāļāļāļļāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļŠāļĢāđāļēāļāđāļŦāļāļļāļāļēāļĢāļāđāļāļāļāļāļļāļ
metro make:event Logout
class LogoutEvent implements NyEvent {
@override
final listeners = {
DefaultListener: DefaultListener(),
};
}
class DefaultListener extends NyListener {
@override
handle(dynamic event) async {
// logout user
await Auth.logout();
// redirect to home page
routeTo(HomePage.path,
navigationType: NavigationType.pushAndForgetAll
);
}
}
āļŠāđāļāđāļŦāļāļļāļāļēāļĢāļāđ
MaterialButton(child: Text("Logout"),
onPressed: () {
event<LogoutEvent>();
},
)
āļŠāđāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļĨāļ°āļĢāļąāļāļāļąāļāđāļŦāļāļļāļāļēāļĢāļāđāđāļāđāļāļāļāļĨāļīāđāļāļāļąāļāļāļāļāļāļļāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļāļģāļŦāļāļāđāļ§āļĨāļēāđāļŦāđāļāļēāļāļāļģāļāļēāļāļāļĢāļąāđāļāđāļāļĩāļĒāļ§
Nylo.scheduleOnce("onboarding_info", () {
print("Perform code here to run once");
});
āļāļģāļŦāļāļāđāļ§āļĨāļēāđāļŦāđāļāļēāļāļāļģāļāļēāļāļāļĢāļąāđāļāđāļāļĩāļĒāļ§āļŦāļĨāļąāļāļāļēāļāļ§āļąāļāļāļĩāđāļĢāļ°āļāļļ
Nylo.scheduleOnceAfterDate("app_review_rating", () {
print("Perform code to run once after DateTime(2025, 04, 10)");
}, date: DateTime(2025, 04, 10));
āļāļģāļŦāļāļāđāļ§āļĨāļēāđāļŦāđāļāļēāļāļāļģāļāļēāļāļ§āļąāļāļĨāļ°āļāļĢāļąāđāļ
Nylo.scheduleOnceDaily("free_daily_coins", () {
print("Perform code to run once daily");
});
āļāļģāļŦāļāļāđāļ§āļĨāļēāđāļŦāđāļāļēāļāļāļģāļāļēāļāļāļĢāļąāđāļāđāļāļĩāļĒāļ§āļŦāļĢāļ·āļāļĢāļēāļĒāļ§āļąāļāđāļāđāļāļāļāļĨāļīāđāļāļāļąāļ Flutter āļāļāļāļāļļāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļŠāļĢāđāļēāļāļāļĢāļīāļāļēāļĢ API
metro make:api_service User
class UserApiService extends NyApiService {
@override
String get baseUrl => getEnv("API_BASE_URL");
Future<User?> fetchUser(int id) async {
return await get<User>(
"/users/$id",
queryParameters: {"include": "profile"},
);
}
Future<User?> createUser(Map<String, dynamic> data) async {
return await post<User>("/users", data: data);
}
}
āđāļĢāļĩāļĒāļāđāļāđ API āļāļēāļāļŦāļāđāļēāļāļāļāļāļļāļ
User? user = await api<UserApiService>(
(request) => request.fetchUser(1),
);
āļāļĢāļīāļāļēāļĢ API āļāļĩāđāļŠāļ§āļĒāļāļēāļĄ āļāļĢāđāļāļĄāļāļēāļĢāđāļĒāļāļ§āļīāđāļāļĢāļēāļ°āļŦāđ JSON āļāļąāļāđāļāļĄāļąāļāļī āđāļāļ āđāļĨāļ°āļāļąāļ§āļāļąāļāļāļąāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļāļąāļāļāļķāļāļāđāļāļĄāļđāļĨāļāļĒāđāļēāļāļāļĨāļāļāļ āļąāļĒ
// Save values to secure storage
await NyStorage.save("coins", 100);
await NyStorage.save("username", "Anthony");
await NyStorage.save("isPremium", true);
// Save with TTL (auto-expires)
await NyStorage.save("session", "abc123",
expiry: Duration(hours: 1),
);
āļāđāļēāļāļāļĢāđāļāļĄāļāļēāļĢāđāļāļĨāļāļāļāļīāļāļāđāļāļĄāļđāļĨ
// Automatic type casting
String? username = await NyStorage.read("username");
int? coins = await NyStorage.read<int>("coins");
bool? isPremium = await NyStorage.read<bool>("isPremium");
// Delete a value
await NyStorage.delete("coins");
āļāļ·āđāļāļāļĩāđāļāļąāļāđāļāđāļāļ āļēāļĒāđāļāļāļĩāđāļāļĨāļāļāļ āļąāļĒ āļāļĢāđāļāļĄāļāļēāļĢāđāļāļĨāļāļāļāļīāļāļāđāļāļĄāļđāļĨ āļāļēāļĢāļŦāļĄāļāļāļēāļĒāļļ TTL āđāļĨāļ°āļāļāļĨāđāļĨāļāļāļąāļ
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āđāļāļīāđāļĄāđāļāļĨāđāļ āļēāļĐāļēāļāļāļāļāļļāļ
{
"welcome": "Welcome",
"greeting": "Hello {{name}}",
"navigation": {
"home": "Home",
"profile": "Profile"
}
}
āđāļāļĨāļāđāļāļāļ§āļēāļĄāđāļāļ§āļīāļāđāļāđāļāļāļāļāļāļļāļ
// Simple translation
Text("welcome".tr()) // "Welcome"
// With arguments
Text("greeting".tr(arguments: {"name": "Anthony"}))
// "Hello Anthony"
// Nested keys
Text("navigation.home".tr()) // "Home"
āļĢāļāļāļĢāļąāļāļŦāļĨāļēāļĒāļ āļēāļĐāļēāļāđāļ§āļĒāđāļāļĨāđ JSON āļāļēāļĢāđāļāļīāļ§āđāļĄāļāļāđ āđāļĨāļ° RTL
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āļŠāļĢāđāļēāļāļĻāļđāļāļĒāđāļāļĨāļēāļāļāļēāļĢāļāļģāļāļēāļ
metro make:navigation_hub base
class _BaseNavigationHubState extends NavigationHub<BaseNavigationHub> {
NavigationHubLayout? layout = NavigationHubLayout.bottomNav();
@override
bool get maintainState => true;
_BaseNavigationHubState() : super(() async {
return {
0: NavigationTab(
title: "Home",
page: HomeTab(),
icon: Icon(Icons.home),
),
1: NavigationTab(
title: "Settings",
page: SettingsTab(),
icon: Icon(Icons.settings),
),
};
});
}
āļŠāļĨāļąāļāđāļĨāļĒāđāđāļāļēāļāđāđāļāđāļāđāļēāļĒāđ
// Bottom navigation
NavigationHubLayout.bottomNav()
// Top navigation
NavigationHubLayout.topNav()
// Journey / wizard flow
NavigationHubLayout.journey()
āļŠāļĢāđāļēāļāđāļāļāļāļģāļāļēāļāļāđāļēāļāļĨāđāļēāļ āđāļāļāļāļģāļāļēāļāļāđāļēāļāļāļ āļŦāļĢāļ·āļāđāļāļĨāļ§āđāļāļēāļĢāđāļāļīāļāļāļēāļ āļāļĢāđāļāļĄāļĢāļąāļāļĐāļēāļŠāļāļēāļāļ°
āđāļĢāļĩāļĒāļāļĢāļđāđāđāļāļīāđāļĄāđāļāļīāļĄ
āđāļāđāļāļāļĩāđāļāļ·āđāļāļāļāļāļāļāļāļāļļāļĄāļāļ
āļŠāļīāđāļāļāļĩāđāļāļąāļāļāļąāļāļāļēāļāļđāļāļāļķāļ Nylo Website
āđāļāđāļēāļĢāđāļ§āļĄāļāļēāļĢāļŠāļāļāļāļēI'm new to Dart and new to your framework (which I love)
Peter Senior Director of Heroku Global
I wanted to thank you guys for the great job you are doing.
@youssefKadaouiAbbassi
Just to say that I am in love with @nylo_dev's website!! Definitely gonna explore it!
@esfoliante_txt
Really love the concept of this framework
@Chrisvidal
Nylo is the best framework for flutter, which makes developing easy
@higakijin
This is incredible. Very well done!
FireflyDaniel
Very nice Framework! Thank you so much!
@ChaoChao2509
I just discovered this framework and I'm very impressed. Thank you
@lepresk
Great work on Nylo
@dylandamsma
This is by far the best framework out there. Amazing quality and features. Thanks so much.
@2kulfi
It's interesting and very amazing. It makes the work more easier and less time consuming. Great work. Thank you
darkreader01
Salut. Je viens juste de dÃĐcouvrir votre outils et je le trouve vraiment super. Une belle dÃĐcouverte pour moi ððĪ
ojean-01