hottabych

BlocSelector example

Aug 4th, 2025 (edited)
959
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 8.81 KB | None | 0 0
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_bloc/flutter_bloc.dart';
  3. import 'package:equatable/equatable.dart';
  4.  
  5. /// Represents the data model for a user profile.
  6. /// Uses Equatable for value equality comparison, which is useful for Bloc states.
  7. class UserProfile extends Equatable {
  8.   final String name;
  9.   final int age;
  10.   final bool isPremiumUser;
  11.  
  12.   const UserProfile({
  13.     required this.name,
  14.     required this.age,
  15.     required this.isPremiumUser,
  16.   });
  17.  
  18.   /// Creates a copy of this UserProfile with new values for specified properties.
  19.   UserProfile copyWith({
  20.     String? name,
  21.     int? age,
  22.     bool? isPremiumUser,
  23.   }) {
  24.     return UserProfile(
  25.       name: name ?? this.name,
  26.       age: age ?? this.age,
  27.       isPremiumUser: isPremiumUser ?? this.isPremiumUser,
  28.     );
  29.   }
  30.  
  31.   @override
  32.   List<Object> get props => [name, age, isPremiumUser];
  33. }
  34.  
  35. /// Represents the state of the UserProfileBloc.
  36. /// Contains the current UserProfile.
  37. class UserProfileState extends Equatable {
  38.   final UserProfile userProfile;
  39.  
  40.   const UserProfileState(this.userProfile);
  41.  
  42.   @override
  43.   List<Object> get props => [userProfile];
  44. }
  45.  
  46. /// Abstract base class for all UserProfile events.
  47. abstract class UserProfileEvent extends Equatable {
  48.   const UserProfileEvent();
  49.  
  50.   @override
  51.   List<Object> get props => [];
  52. }
  53.  
  54. /// Event to change the user's name.
  55. class ChangeNameEvent extends UserProfileEvent {
  56.   final String newName;
  57.   const ChangeNameEvent(this.newName);
  58.  
  59.   @override
  60.   List<Object> get props => [newName];
  61. }
  62.  
  63. /// Event to increment the user's age.
  64. class IncrementAgeEvent extends UserProfileEvent {
  65.   const IncrementAgeEvent();
  66. }
  67.  
  68. /// Event to toggle the user's premium status.
  69. class TogglePremiumEvent extends UserProfileEvent {
  70.   const TogglePremiumEvent();
  71. }
  72.  
  73. /// Bloc responsible for managing the UserProfileState.
  74. class UserProfileBloc extends Bloc<UserProfileEvent, UserProfileState> {
  75.   UserProfileBloc()
  76.       : super(
  77.           UserProfileState(
  78.             UserProfile(name: 'Alice Smith', age: 30, isPremiumUser: false),
  79.           ),
  80.         ) {
  81.     on<ChangeNameEvent>((event, emit) {
  82.       emit(UserProfileState(state.userProfile.copyWith(name: event.newName)));
  83.     });
  84.  
  85.     on<IncrementAgeEvent>((event, emit) {
  86.       emit(UserProfileState(state.userProfile.copyWith(age: state.userProfile.age + 1)));
  87.     });
  88.  
  89.     on<TogglePremiumEvent>((event, emit) {
  90.       emit(UserProfileState(state.userProfile.copyWith(isPremiumUser: !state.userProfile.isPremiumUser)));
  91.     });
  92.   }
  93. }
  94.  
  95. void main() {
  96.   runApp(const UserProfileApp());
  97. }
  98.  
  99. /// The root widget of the application.
  100. /// Provides the UserProfileBloc to its descendants using BlocProvider.
  101. class UserProfileApp extends StatelessWidget {
  102.   const UserProfileApp({super.key});
  103.  
  104.   @override
  105.   Widget build(BuildContext context) {
  106.     return MaterialApp(
  107.       title: 'User Profile Manager',
  108.       theme: ThemeData(
  109.         primarySwatch: Colors.blueGrey,
  110.         visualDensity: VisualDensity.adaptivePlatformDensity,
  111.         useMaterial3: true,
  112.       ),
  113.       home: BlocProvider<UserProfileBloc>(
  114.         create: (context) => UserProfileBloc(),
  115.         child: const UserProfileScreen(),
  116.       ),
  117.     );
  118.   }
  119. }
  120.  
  121. /// A screen to display and interact with a user's profile.
  122. /// Uses BlocSelector to selectively rebuild parts of the UI based on state changes.
  123. class UserProfileScreen extends StatelessWidget {
  124.   const UserProfileScreen({super.key});
  125.  
  126.   @override
  127.   Widget build(BuildContext context) {
  128.     return Scaffold(
  129.       appBar: AppBar(
  130.         title: const Text('User Profile'),
  131.       ),
  132.       body: Padding(
  133.         padding: const EdgeInsets.all(16.0),
  134.         child: Column(
  135.           crossAxisAlignment: CrossAxisAlignment.stretch,
  136.           children: <Widget>[
  137.             // Display User Name using BlocSelector
  138.             BlocSelector<UserProfileBloc, UserProfileState, String>(
  139.               selector: (UserProfileState state) => state.userProfile.name,
  140.               builder: (BuildContext context, String name) {
  141.                 // This widget rebuilds ONLY when the user's name changes.
  142.                 debugPrint('Rebuilding Name Widget: $name');
  143.                 return Card(
  144.                   elevation: 2,
  145.                   margin: const EdgeInsets.symmetric(vertical: 8),
  146.                   child: Padding(
  147.                     padding: const EdgeInsets.all(16.0),
  148.                     child: Row(
  149.                       children: <Widget>[
  150.                         const Icon(Icons.person, color: Colors.blueGrey),
  151.                         const SizedBox(width: 16),
  152.                         Expanded(
  153.                           child: Text(
  154.                             'Name: $name',
  155.                             style: Theme.of(context).textTheme.headlineSmall,
  156.                             overflow: TextOverflow.ellipsis,
  157.                           ),
  158.                         ),
  159.                       ],
  160.                     ),
  161.                   ),
  162.                 );
  163.               },
  164.             ),
  165.             const SizedBox(height: 10),
  166.  
  167.             // Display User Age using BlocSelector
  168.             BlocSelector<UserProfileBloc, UserProfileState, int>(
  169.               selector: (UserProfileState state) => state.userProfile.age,
  170.               builder: (BuildContext context, int age) {
  171.                 // This widget rebuilds ONLY when the user's age changes.
  172.                 debugPrint('Rebuilding Age Widget: $age');
  173.                 return Card(
  174.                   elevation: 2,
  175.                   margin: const EdgeInsets.symmetric(vertical: 8),
  176.                   child: Padding(
  177.                     padding: const EdgeInsets.all(16.0),
  178.                     child: Row(
  179.                       children: <Widget>[
  180.                         const Icon(Icons.cake, color: Colors.blueGrey),
  181.                         const SizedBox(width: 16),
  182.                         Text(
  183.                           'Age: $age',
  184.                           style: Theme.of(context).textTheme.headlineSmall,
  185.                         ),
  186.                       ],
  187.                     ),
  188.                   ),
  189.                 );
  190.               },
  191.             ),
  192.             const SizedBox(height: 10),
  193.  
  194.             // Display Premium Status using BlocSelector
  195.             BlocSelector<UserProfileBloc, UserProfileState, bool>(
  196.               selector: (UserProfileState state) => state.userProfile.isPremiumUser,
  197.               builder: (BuildContext context, bool isPremium) {
  198.                 // This widget rebuilds ONLY when the user's premium status changes.
  199.                 debugPrint('Rebuilding Premium Status Widget: $isPremium');
  200.                 return Card(
  201.                   elevation: 2,
  202.                   margin: const EdgeInsets.symmetric(vertical: 8),
  203.                   child: Padding(
  204.                     padding: const EdgeInsets.all(16.0),
  205.                     child: Row(
  206.                       children: <Widget>[
  207.                         Icon(
  208.                           isPremium ? Icons.star : Icons.star_border,
  209.                           color: isPremium ? Colors.amber : Colors.blueGrey,
  210.                         ),
  211.                         const SizedBox(width: 16),
  212.                         Text(
  213.                           'Premium User: ${isPremium ? "Yes" : "No"}',
  214.                           style: Theme.of(context).textTheme.headlineSmall,
  215.                         ),
  216.                       ],
  217.                     ),
  218.                   ),
  219.                 );
  220.               },
  221.             ),
  222.             const SizedBox(height: 20),
  223.  
  224.             // Control Buttons
  225.             Center(
  226.               child: Column(
  227.                 children: <Widget>[
  228.                   ElevatedButton.icon(
  229.                     onPressed: () {
  230.                       context.read<UserProfileBloc>().add(const ChangeNameEvent('Bob Johnson'));
  231.                     },
  232.                     icon: const Icon(Icons.edit),
  233.                     label: const Text('Change Name'),
  234.                   ),
  235.                   const SizedBox(height: 10),
  236.                   ElevatedButton.icon(
  237.                     onPressed: () {
  238.                       context.read<UserProfileBloc>().add(const IncrementAgeEvent());
  239.                     },
  240.                     icon: const Icon(Icons.add),
  241.                     label: const Text('Increment Age'),
  242.                   ),
  243.                   const SizedBox(height: 10),
  244.                   ElevatedButton.icon(
  245.                     onPressed: () {
  246.                       context.read<UserProfileBloc>().add(const TogglePremiumEvent());
  247.                     },
  248.                     icon: const Icon(Icons.toggle_on),
  249.                     label: const Text('Toggle Premium Status'),
  250.                   ),
  251.                 ],
  252.               ),
  253.             ),
  254.           ],
  255.         ),
  256.       ),
  257.     );
  258.   }
  259. }
Advertisement
Add Comment
Please, Sign In to add comment