Flutter
рдорд╛рдЗрдХреНрд░реЛ-рдлреНрд░реЗрдорд╡рд░реНрдХ
рдЖрдзреБрдирд┐рдХ рдРрдкреНрд╕ рдХреЗ рд▓рд┐рдП
Flutter рдРрдкреНрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдордЬрдмреВрдд рдЖрдзрд╛рд░ред рд░рд╛рдЙрдЯрд┐рдВрдЧ, рд╕реНрдЯреЗрдЯ рдореИрдиреЗрдЬрдореЗрдВрдЯ, рдиреЗрдЯрд╡рд░реНрдХрд┐рдВрдЧ, рдФрд░ рдмрд╣реБрдд рдХреБрдЫ тАФ рд╕рдм рдПрдХ рд╕реБрдВрджрд░ рдкреИрдХреЗрдЬ рдореЗрдВред
рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЬреЛ рдХреБрдЫ рднреА рдЪрд╛рд╣рд┐рдП
Nylo рдЖрдкрдХреЛ рдЖрддреНрдорд╡рд┐рд╢реНрд╡рд╛рд╕ рдХреЗ рд╕рд╛рде рдкреНрд░реЛрдбрдХреНрд╢рди-рд░реЗрдбреА Flutter рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдЯреВрд▓ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
рд░рд╛рдЙрдЯрд┐рдВрдЧ
рд░реВрдЯ рдЧрд╛рд░реНрдбреНрд╕, рдкреИрд░рд╛рдореАрдЯрд░реНрд╕ рдФрд░ рдбреАрдк рд▓рд┐рдВрдХрд┐рдВрдЧ рд╕рдкреЛрд░реНрдЯ рдХреЗ рд╕рд╛рде рд╕рд░рд▓, рдШреЛрд╖рдгрд╛рддреНрдордХ рд░рд╛рдЙрдЯрд┐рдВрдЧред
рд╕реНрдЯреЗрдЯ рдореИрдиреЗрдЬрдореЗрдВрдЯ
рдХрдВрдЯреНрд░реЛрд▓рд░реНрд╕ рдФрд░ рдЖрд╕рд╛рди рд╕реНрдЯреЗрдЯ рдкрд░реНрд╕рд┐рд╕реНрдЯреЗрдВрд╕ рдХреЗ рд╕рд╛рде рдмрд┐рд▓реНрдЯ-рдЗрди рд░рд┐рдПрдХреНрдЯрд┐рд╡ рд╕реНрдЯреЗрдЯ рдореИрдиреЗрдЬрдореЗрдВрдЯред
рдиреЗрдЯрд╡рд░реНрдХрд┐рдВрдЧ
рдСрдЯреЛрдореИрдЯрд┐рдХ рдореЙрдбрд▓ рд╕реАрд░рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдФрд░ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯрд░реНрд╕ рдХреЗ рд╕рд╛рде рд╕реБрдВрджрд░ API рд╕рд░реНрд╡рд┐рд╕ рдХреНрд▓рд╛рд╕реЗрд╕ред
рдлреЙрд░реНрдореНрд╕
рд╡реИрд▓рд┐рдбреЗрд╢рди, рдХрд╛рд╕реНрдЯрд┐рдВрдЧ рдФрд░ рдСрдЯреЛрдореИрдЯрд┐рдХ рдбреЗрдЯрд╛ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдлреЙрд░реНрдо рд╣реИрдВрдбрд▓рд┐рдВрдЧред
рдкреНрд░рдорд╛рдгреАрдХрд░рдг
рд░реВрдЯ рдЧрд╛рд░реНрдбреНрд╕, рдЯреЛрдХрди рд╕реНрдЯреЛрд░реЗрдЬ рдФрд░ рд╕реЗрд╢рди рдореИрдиреЗрдЬрдореЗрдВрдЯ рдХреЗ рд╕рд╛рде рд╕реБрд░рдХреНрд╖рд┐рдд рдкреНрд░рдорд╛рдгреАрдХрд░рдгред
Metro CLI
рд╢рдХреНрддрд┐рд╢рд╛рд▓реА CLI рдХрдорд╛рдВрдбреНрд╕ рдХреЗ рд╕рд╛рде рдкреЗрдЬ, рдореЙрдбрд▓, рдХрдВрдЯреНрд░реЛрд▓рд░ рдФрд░ рдмрд╣реБрдд рдХреБрдЫ рдЬрдирд░реЗрдЯ рдХрд░реЗрдВред
рдЯрд░реНрдорд┐рдирд▓ рд╕реЗ рдХреБрдЫ рднреА рдмрдирд╛рдПрдВ
Metro Nylo рдХрд╛ CLI рдЯреВрд▓ рд╣реИ рдЬреЛ рдПрдХ рдХрдорд╛рдВрдб рд╕реЗ рдкреЗрдЬ, рдореЙрдбрд▓, рдХрдВрдЯреНрд░реЛрд▓рд░, рд╡рд┐рдЬреЗрдЯ рдФрд░ рдмрд╣реБрдд рдХреБрдЫ рд╕реНрдХреИрдлреЛрд▓реНрдб рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред
Metro рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдЬрд╛рдиреЗрдВmetro 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 рдЗрдВрдЯреАрдЧреНрд░реЗрд╢рди
рдСрдЯреЛрдореИрдЯрд┐рдХ JSON рдкрд╛рд░реНрд╕рд┐рдВрдЧ, рдПрд░рд░ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рдФрд░ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯрд░реНрд╕ рдХреЗ рд╕рд╛рде рд╕рд╛рдл, рдореЗрдВрдЯреЗрди рдХрд░рдиреЗ рдпреЛрдЧреНрдп API рд╕рд░реНрд╡рд┐рд╕реЗрдЬ рд▓рд┐рдЦреЗрдВред
рдиреЗрдЯрд╡рд░реНрдХрд┐рдВрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдЬрд╛рдиреЗрдВрдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдЯреВрд▓реНрд╕
рдЕрдкрдирд╛ рдЕрдЧрд▓рд╛ 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()
]
);
});
рдЕрдкрдиреЗ Flutter рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдЬрдЯрд┐рд▓ рд░реВрдЯ, рдЗрдВрдЯрд░рдлреЗрд╕ рдФрд░ UI рдкреЗрдЬ рдмрдирд╛рдПрдВред
рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВ
рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреНрд░рдорд╛рдгрд┐рдд рдХрд░реЗрдВ
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),
);
рдСрдЯреЛрдореИрдЯрд┐рдХ JSON рдкрд╛рд░реНрд╕рд┐рдВрдЧ, рдХреИрд╢рд┐рдВрдЧ рдФрд░ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯрд░реНрд╕ рдХреЗ рд╕рд╛рде рд╕реБрдВрджрд░ API рд╕рд░реНрд╡рд┐рд╕реЗрдЬред
рдЕрдзрд┐рдХ рдЬрд╛рдиреЗрдВ
рдбреЗрдЯрд╛ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рд╕реЗрд╡ рдХрд░реЗрдВ
// 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