# Flutter App Template ## Basic App Structure Complete starter template for Flutter applications. ```dart // main.dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'app/theme/app_theme.dart'; import 'app/screens/home_screen.dart'; import 'app/screens/detail_screen.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter App', debugShowCheckedModeBanner: false, theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, themeMode: ThemeMode.system, home: HomeScreen(), routes: { '/detail': (context) => DetailScreen(), }, ); } } ``` ## Responsive App Template Mobile-first responsive design. ```dart // main.dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'app/theme/responsive_theme.dart'; import 'app/screens/home_screen.dart'; import 'app/widgets/responsive_layout.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Responsive Flutter App', debugShowCheckedModeBanner: false, theme: ResponsiveTheme.lightTheme, darkTheme: ResponsiveTheme.darkTheme, themeMode: ThemeMode.system, home: ResponsiveLayout( mobile: HomeScreen(), tablet: HomeScreen(), desktop: HomeScreen(), ), ); } } // app/widgets/responsive_layout.dart import 'package:flutter/material.dart'; class ResponsiveLayout extends StatelessWidget { final Widget mobile; final Widget? tablet; final Widget? desktop; const ResponsiveLayout({ required this.mobile, this.tablet, this.desktop, }); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth >= 1200 && desktop != null) { return desktop!; } else if (constraints.maxWidth >= 800 && tablet != null) { return tablet!; } else { return mobile; } }, ); } } ``` ## Navigation Template Structured navigation with routes. ```dart // app/routes/app_routes.dart class AppRoutes { static const String home = '/'; static const String detail = '/detail'; static const String settings = '/settings'; static const String profile = '/profile'; } class RouteGenerator { static Route generateRoute(RouteSettings settings) { switch (settings.name) { case AppRoutes.home: return MaterialPageRoute( builder: (_) => HomeScreen(), settings: settings, ); case AppRoutes.detail: final String id = settings.arguments as String; return MaterialPageRoute( builder: (_) => DetailScreen(id: id), settings: settings, ); case AppRoutes.settings: return MaterialPageRoute( builder: (_) => SettingsScreen(), settings: settings, ); default: return MaterialPageRoute( builder: (_) => NotFoundScreen(), ); } } } // app/navigation/navigation_service.dart import 'package:flutter/material.dart'; class NavigationService { static final GlobalKey navigatorKey = GlobalKey(); static Future navigateTo(String routeName, {Object? arguments}) { return navigatorKey.currentState!.pushNamed(routeName, arguments: arguments); } static void goBack() { return navigatorKey.currentState!.pop(); } static Future replaceWith(String routeName, {Object? arguments}) { return navigatorKey.currentState!.pushReplacementNamed( routeName, arguments: arguments, ); } static Future navigateToAndClearStack(String routeName, {Object? arguments}) { return navigatorKey.currentState!.pushNamedAndRemoveUntil( routeName, (route) => false, arguments: arguments, ); } } ``` ## State Management Template Provider-based state management. ```dart // app/providers/app_state_provider.dart import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; class AppState extends ChangeNotifier { bool _isLoading = false; String? _errorMessage; bool get isLoading => _isLoading; String? get errorMessage => _errorMessage; void setLoading(bool loading) { _isLoading = loading; notifyListeners(); } void setError(String? error) { _errorMessage = error; notifyListeners(); } void clearError() { _errorMessage = null; notifyListeners(); } } // app/providers/user_provider.dart import 'package:flutter/foundation.dart'; class UserProvider extends ChangeNotifier { User? _user; bool _isLoggedIn = false; User? get user => _user; bool get isLoggedIn => _isLoggedIn; Future login(String email, String password) async { try { // Login logic here _user = User(id: '1', email: email); _isLoggedIn = true; notifyListeners(); } catch (e) { // Handle error } } void logout() { _user = null; _isLoggedIn = false; notifyListeners(); } } class User { final String id; final String email; User({required this.id, required this.email}); } // app/widgets/stateful_builder.dart import 'package:flutter/material.dart'; class StatefulBuilder extends StatefulWidget { final T initialValue; final Widget Function( T value, void Function(T) updateValue, ) builder; const StatefulBuilder({ required this.initialValue, required this.builder, }); @override _StatefulBuilderState createState() => _StatefulBuilderState(); } class _StatefulBuilderState extends State> { late T _value; @override void initState() { super.initState(); _value = widget.initialValue; } void _updateValue(T newValue) { setState(() { _value = newValue; }); } @override Widget build(BuildContext context) { return widget.builder(_value, _updateValue); } } ``` ## API Service Template Structured API communication. ```dart // app/services/api_service.dart import 'dart:convert'; import 'package:http/http.dart' as http; class ApiService { static const String baseUrl = 'https://api.example.com'; static const Duration timeout = Duration(seconds: 30); static Map get headers => { 'Content-Type': 'application/json', 'Accept': 'application/json', }; static Future> get(String endpoint) async { try { final response = await http.get( Uri.parse('$baseUrl$endpoint'), headers: headers, ).timeout(timeout); return _handleResponse(response); } catch (e) { throw _handleError(e); } } static Future> post( String endpoint, Map data, ) async { try { final response = await http.post( Uri.parse('$baseUrl$endpoint'), headers: headers, body: json.encode(data), ).timeout(timeout); return _handleResponse(response); } catch (e) { throw _handleError(e); } } static Future> put( String endpoint, Map data, ) async { try { final response = await http.put( Uri.parse('$baseUrl$endpoint'), headers: headers, body: json.encode(data), ).timeout(timeout); return _handleResponse(response); } catch (e) { throw _handleError(e); } } static Future delete(String endpoint) async { try { final response = await http.delete( Uri.parse('$baseUrl$endpoint'), headers: headers, ).timeout(timeout); _handleResponse(response); } catch (e) { throw _handleError(e); } } static Map _handleResponse(http.Response response) { if (response.statusCode >= 200 && response.statusCode < 300) { return json.decode(response.body); } else { throw ApiException( 'API Error: ${response.statusCode}', response.statusCode, ); } } static Exception _handleError(dynamic error) { if (error is http.TimeoutException) { return ApiException('Request timeout', 408); } else if (error is http.ClientException) { return ApiException('Network error', 0); } else { return ApiException('Unknown error', 0); } } } class ApiException implements Exception { final String message; final int statusCode; ApiException(this.message, this.statusCode); @override String toString() => 'ApiException: $message ($statusCode)'; } ``` ## Widget Templates Common reusable widgets. ```dart // app/widgets/custom_button.dart import 'package:flutter/material.dart'; class CustomButton extends StatelessWidget { final String text; final VoidCallback onPressed; final bool isLoading; final Color? color; final Color? textColor; final double? width; final double? height; const CustomButton({ required this.text, required this.onPressed, this.isLoading = false, this.color, this.textColor, this.width, this.height, }); @override Widget build(BuildContext context) { return SizedBox( width: width, height: height ?? 48, child: ElevatedButton( onPressed: isLoading ? null : onPressed, style: ElevatedButton.styleFrom( backgroundColor: color ?? Theme.of(context).primaryColor, foregroundColor: textColor ?? Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: isLoading ? SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( textColor ?? Colors.white, ), ), ) : Text(text), ), ); } } // app/widgets/custom_text_field.dart import 'package:flutter/material.dart'; class CustomTextField extends StatelessWidget { final String? label; final String? hint; final String? errorText; final TextEditingController? controller; final bool obscureText; final TextInputType keyboardType; final Function(String)? onChanged; final Function(String)? onSubmitted; final Widget? prefixIcon; final Widget? suffixIcon; const CustomTextField({ this.label, this.hint, this.errorText, this.controller, this.obscureText = false, this.keyboardType = TextInputType.text, this.onChanged, this.onSubmitted, this.prefixIcon, this.suffixIcon, }); @override Widget build(BuildContext context) { return TextField( controller: controller, obscureText: obscureText, keyboardType: keyboardType, onChanged: onChanged, onSubmitted: onSubmitted, decoration: InputDecoration( labelText: label, hintText: hint, errorText: errorText, prefixIcon: prefixIcon, suffixIcon: suffixIcon, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( color: Theme.of(context).primaryColor, width: 2, ), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: BorderSide( color: Theme.of(context).errorColor, width: 2, ), ), contentPadding: EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), ), ); } } // app/widgets/loading_widget.dart import 'package:flutter/material.dart'; class LoadingWidget extends StatelessWidget { final String? message; final double? size; const LoadingWidget({ this.message, this.size = 24, }); @override Widget build(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: size, height: size, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( Theme.of(context).primaryColor, ), ), ), if (message != null) ...[ SizedBox(height: 16), Text( message!, style: Theme.of(context).textTheme.bodyMedium, ), ], ], ), ); } } // app/widgets/empty_state_widget.dart import 'package:flutter/material.dart'; class EmptyStateWidget extends StatelessWidget { final String title; final String? subtitle; final Widget? action; final IconData? icon; const EmptyStateWidget({ required this.title, this.subtitle, this.action, this.icon, }); @override Widget build(BuildContext context) { return Center( child: Padding( padding: EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ if (icon != null) ...[ Icon( icon!, size: 64, color: Theme.of(context).disabledColor, ), SizedBox(height: 16), ], Text( title, style: Theme.of(context).textTheme.headlineSmall?.copyWith( color: Theme.of(context).disabledColor, ), textAlign: TextAlign.center, ), if (subtitle != null) ...[ SizedBox(height: 8), Text( subtitle!, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).disabledColor, ), textAlign: TextAlign.center, ), ], if (action != null) ...[ SizedBox(height: 24), action!, ], ], ), ), ); } } ``` ## Screen Templates Common screen patterns. ```dart // app/screens/base_screen.dart import 'package:flutter/material.dart'; class BaseScreen extends StatelessWidget { final Widget body; final String? title; final List? actions; final Widget? floatingActionButton; final Widget? bottomNavigationBar; final bool showAppBar; const BaseScreen({ required this.body, this.title, this.actions, this.floatingActionButton, this.bottomNavigationBar, this.showAppBar = true, }); @override Widget build(BuildContext context) { return Scaffold( appBar: showAppBar ? AppBar( title: title != null ? Text(title!) : null, actions: actions, ) : null, body: SafeArea(child: body), floatingActionButton: floatingActionButton, bottomNavigationBar: bottomNavigationBar, ); } } // app/screens/list_screen.dart import 'package:flutter/material.dart'; class ListScreen extends StatelessWidget { final List items; final Widget Function(BuildContext, T) itemBuilder; final String? title; final Function(T)? onItemTap; final Widget? emptyState; final bool isLoading; const ListScreen({ required this.items, required this.itemBuilder, this.title, this.onItemTap, this.emptyState, this.isLoading = false, }); @override Widget build(BuildContext context) { if (isLoading) { return LoadingWidget(); } if (items.isEmpty) { return emptyState ?? EmptyStateWidget( title: 'No items found', icon: Icons.inbox_outlined, ); } return BaseScreen( title: title, body: ListView.builder( itemCount: items.length, itemBuilder: (context, index) { final item = items[index]; return GestureDetector( onTap: () => onItemTap?.call(item), child: itemBuilder(context, item), ); }, ), ); } } ``` ## Usage Example Complete app using all templates. ```dart // main.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'app/providers/user_provider.dart'; import 'app/services/api_service.dart'; import 'app/widgets/custom_button.dart'; import 'app/screens/base_screen.dart'; void main() { runApp( ChangeNotifierProvider( create: (_) => UserProvider(), child: MyApp(), ), ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Template App', theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, themeMode: ThemeMode.system, home: HomeScreen(), ); } } class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer( builder: (context, userProvider, child) { return BaseScreen( title: 'Home', body: Column( children: [ if (userProvider.isLoggedIn) ...[ Text('Welcome ${userProvider.user?.email}'), CustomButton( text: 'Logout', onPressed: () => userProvider.logout(), ), ] else ...[ Text('Please login'), CustomButton( text: 'Login', onPressed: () => _showLoginDialog(context), ), ], ], ), ); }, ); } void _showLoginDialog(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Login'), content: CustomTextField( label: 'Email', hint: 'Enter your email', ), actions: [ CustomButton( text: 'Cancel', onPressed: () => Navigator.pop(context), ), CustomButton( text: 'Login', onPressed: () { // Login logic Navigator.pop(context); }, ), ], ), ); } }