import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:equatable/equatable.dart'; /// Represents the data model for a user profile. /// Uses Equatable for value equality comparison, which is useful for Bloc states. class UserProfile extends Equatable { final String name; final int age; final bool isPremiumUser; const UserProfile({ required this.name, required this.age, required this.isPremiumUser, }); /// Creates a copy of this UserProfile with new values for specified properties. UserProfile copyWith({ String? name, int? age, bool? isPremiumUser, }) { return UserProfile( name: name ?? this.name, age: age ?? this.age, isPremiumUser: isPremiumUser ?? this.isPremiumUser, ); } @override List get props => [name, age, isPremiumUser]; } /// Represents the state of the UserProfileBloc. /// Contains the current UserProfile. class UserProfileState extends Equatable { final UserProfile userProfile; const UserProfileState(this.userProfile); @override List get props => [userProfile]; } /// Abstract base class for all UserProfile events. abstract class UserProfileEvent extends Equatable { const UserProfileEvent(); @override List get props => []; } /// Event to change the user's name. class ChangeNameEvent extends UserProfileEvent { final String newName; const ChangeNameEvent(this.newName); @override List get props => [newName]; } /// Event to increment the user's age. class IncrementAgeEvent extends UserProfileEvent { const IncrementAgeEvent(); } /// Event to toggle the user's premium status. class TogglePremiumEvent extends UserProfileEvent { const TogglePremiumEvent(); } /// Bloc responsible for managing the UserProfileState. class UserProfileBloc extends Bloc { UserProfileBloc() : super( UserProfileState( UserProfile(name: 'Alice Smith', age: 30, isPremiumUser: false), ), ) { on((event, emit) { emit(UserProfileState(state.userProfile.copyWith(name: event.newName))); }); on((event, emit) { emit(UserProfileState(state.userProfile.copyWith(age: state.userProfile.age + 1))); }); on((event, emit) { emit(UserProfileState(state.userProfile.copyWith(isPremiumUser: !state.userProfile.isPremiumUser))); }); } } void main() { runApp(const UserProfileApp()); } /// The root widget of the application. /// Provides the UserProfileBloc to its descendants using BlocProvider. class UserProfileApp extends StatelessWidget { const UserProfileApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'User Profile Manager', theme: ThemeData( primarySwatch: Colors.blueGrey, visualDensity: VisualDensity.adaptivePlatformDensity, useMaterial3: true, ), home: BlocProvider( create: (context) => UserProfileBloc(), child: const UserProfileScreen(), ), ); } } /// A screen to display and interact with a user's profile. /// Uses BlocSelector to selectively rebuild parts of the UI based on state changes. class UserProfileScreen extends StatelessWidget { const UserProfileScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('User Profile'), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Display User Name using BlocSelector BlocSelector( selector: (UserProfileState state) => state.userProfile.name, builder: (BuildContext context, String name) { // This widget rebuilds ONLY when the user's name changes. debugPrint('Rebuilding Name Widget: $name'); return Card( elevation: 2, margin: const EdgeInsets.symmetric(vertical: 8), child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ const Icon(Icons.person, color: Colors.blueGrey), const SizedBox(width: 16), Expanded( child: Text( 'Name: $name', style: Theme.of(context).textTheme.headlineSmall, overflow: TextOverflow.ellipsis, ), ), ], ), ), ); }, ), const SizedBox(height: 10), // Display User Age using BlocSelector BlocSelector( selector: (UserProfileState state) => state.userProfile.age, builder: (BuildContext context, int age) { // This widget rebuilds ONLY when the user's age changes. debugPrint('Rebuilding Age Widget: $age'); return Card( elevation: 2, margin: const EdgeInsets.symmetric(vertical: 8), child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ const Icon(Icons.cake, color: Colors.blueGrey), const SizedBox(width: 16), Text( 'Age: $age', style: Theme.of(context).textTheme.headlineSmall, ), ], ), ), ); }, ), const SizedBox(height: 10), // Display Premium Status using BlocSelector BlocSelector( selector: (UserProfileState state) => state.userProfile.isPremiumUser, builder: (BuildContext context, bool isPremium) { // This widget rebuilds ONLY when the user's premium status changes. debugPrint('Rebuilding Premium Status Widget: $isPremium'); return Card( elevation: 2, margin: const EdgeInsets.symmetric(vertical: 8), child: Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ Icon( isPremium ? Icons.star : Icons.star_border, color: isPremium ? Colors.amber : Colors.blueGrey, ), const SizedBox(width: 16), Text( 'Premium User: ${isPremium ? "Yes" : "No"}', style: Theme.of(context).textTheme.headlineSmall, ), ], ), ), ); }, ), const SizedBox(height: 20), // Control Buttons Center( child: Column( children: [ ElevatedButton.icon( onPressed: () { context.read().add(const ChangeNameEvent('Bob Johnson')); }, icon: const Icon(Icons.edit), label: const Text('Change Name'), ), const SizedBox(height: 10), ElevatedButton.icon( onPressed: () { context.read().add(const IncrementAgeEvent()); }, icon: const Icon(Icons.add), label: const Text('Increment Age'), ), const SizedBox(height: 10), ElevatedButton.icon( onPressed: () { context.read().add(const TogglePremiumEvent()); }, icon: const Icon(Icons.toggle_on), label: const Text('Toggle Premium Status'), ), ], ), ), ], ), ), ); } }