Goal
Updates and manages Flutter application styling by migrating legacy Material 2 implementations to Material 3, normalizing component themes, updating deprecated button classes, and adapting UI idioms for cross-platform consistency. Assumes a Flutter environment using Dart.
Instructions
Analyze Current Theme State Review the existing Flutter codebase to identify legacy Material 2 components, deprecated button classes (FlatButton , RaisedButton , OutlineButton ), and outdated theme properties (e.g., accentColor , color in AppBarTheme ). STOP AND ASK THE USER: "What is the primary seed color for the new Material 3 ColorScheme, and which target platforms (iOS, Android, Windows, macOS, Linux, Web) should be prioritized for platform idioms?"
Decision Logic: Component Migration When encountering legacy widgets, use the following decision tree to determine the replacement:
-
IF BottomNavigationBar -> REPLACE WITH NavigationBar (uses NavigationDestination ).
-
IF Drawer -> REPLACE WITH NavigationDrawer (uses NavigationDrawerDestination ).
-
IF ToggleButtons -> REPLACE WITH SegmentedButton (uses ButtonSegment and Set for selection).
-
IF FlatButton -> REPLACE WITH TextButton .
-
IF RaisedButton -> REPLACE WITH ElevatedButton (or FilledButton for no elevation).
-
IF OutlineButton -> REPLACE WITH OutlinedButton .
Implement App-Wide Material 3 Theme Define the global ThemeData using ColorScheme.fromSeed . Ensure useMaterial3 is implicitly or explicitly true. Remove all references to deprecated accent properties (accentColor , accentColorBrightness , accentTextTheme , accentIconTheme ).
MaterialApp( title: 'App Name', theme: ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: Colors.deepPurple, brightness: Brightness.light, ), // Use colorScheme.secondary instead of accentColor ), darkTheme: ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: Colors.deepPurple, brightness: Brightness.dark, ), ), home: const MyHomePage(), );
Normalize Component Themes Update all component theme definitions in ThemeData to use their *ThemeData equivalents. Do not use the base theme classes for configuration.
-
cardTheme -> CardThemeData
-
dialogTheme -> DialogThemeData
-
tabBarTheme -> TabBarThemeData
-
appBarTheme -> AppBarThemeData (Replace color with backgroundColor )
-
bottomAppBarTheme -> BottomAppBarThemeData
-
inputDecorationTheme -> InputDecorationThemeData
ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), appBarTheme: const AppBarThemeData( backgroundColor: Colors.blue, // Do not use 'color' elevation: 4.0, ), cardTheme: const CardThemeData( elevation: 2.0, ), );
Migrate Buttons and Button Styles Replace legacy buttons. Use the styleFrom() static method for simple overrides, or ButtonStyle with MaterialStateProperty for state-dependent styling.
// Simple override using styleFrom TextButton( style: TextButton.styleFrom( foregroundColor: Colors.blue, disabledForegroundColor: Colors.red, ), onPressed: () {}, child: const Text('TextButton'), )
// State-dependent override using MaterialStateProperty OutlinedButton( style: ButtonStyle( side: MaterialStateProperty.resolveWith<BorderSide>( (Set<MaterialState> states) { if (states.contains(MaterialState.pressed)) { return const BorderSide(color: Colors.blue, width: 2); } return const BorderSide(color: Colors.grey, width: 1); } ), ), onPressed: () {}, child: const Text('OutlinedButton'), )
Decision Logic: Platform Idioms Apply platform-specific adaptations based on the host OS to reduce cognitive load and build user trust.
-
Scrollbars: IF desktop platform -> Set thumbVisibility: true (or alwaysShown ). IF mobile -> Use default auto-hiding behavior.
-
Text Selection: IF text is informational and non-interactive -> Wrap in SelectableText to allow mouse selection on Web/Desktop.
-
Button Ordering: IF Windows -> Place confirmation button on the LEFT. IF macOS/Linux/Android/iOS -> Place confirmation button on the RIGHT.
// Platform-aware button ordering TextDirection btnDirection = Platform.isWindows ? TextDirection.rtl : TextDirection.ltr;
Row( children: [ const Spacer(), Row( textDirection: btnDirection, children: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Cancel'), ), ElevatedButton( onPressed: () => Navigator.pop(context, true), child: const Text('OK'), ), ], ), ], )
Validate-and-Fix Scan the generated code to verify that no FlatButton , RaisedButton , OutlineButton , or ButtonTheme classes remain. Verify that AppBarTheme does not use the color property. Fix any instances found.
Constraints
-
Single Source of Truth: All colors must be derived from the ColorScheme (e.g., Theme.of(context).colorScheme.primary ). Do not hardcode hex colors unless explicitly requested.
-
No Legacy Buttons: Never output FlatButton , RaisedButton , or OutlineButton .
-
No Accent Properties: Never use accentColor , accentColorBrightness , accentTextTheme , or accentIconTheme . Use colorScheme.secondary and colorScheme.onSecondary instead.
-
Component Theme Suffixes: Always append Data to component themes when configuring ThemeData (e.g., CardThemeData , not CardTheme ).
-
AppBar Background: Never use the color property in AppBarTheme or AppBarThemeData ; strictly use backgroundColor .