๐ญ EventModule: Like a Magic Telephone Central!
Imagine that EventModule is like a magic telephone central in your city! ๐โจ
๐ What is an EventModule?
Think of EventModule as different houses in your city. Each house (module) can:
- ๐ Listen to special phone calls
- ๐ข Send messages to other houses
- ๐ Receive important notifications
class LoginEventModule extends EventModule {
@override
void listen() {
// This house listens when someone logs in! ๐
on<LoginEvent>((event, context) {
print('๐ Welcome, ${event.username}!');
if (context != null) {
context.go('/home'); // Go to home page
}
});
}
}๐ How Does the Telephone Central Work?
1. ๐ข Sending Messages (Firing Events)
When something important happens, you "shout" to the whole city:
// ๐ฃ๏ธ "HEY EVERYONE! John just logged in!"
ModularEvent.fire(LoginEvent(username: 'John'));
// ๐ฃ๏ธ "ATTENTION! A new message arrived!"
ModularEvent.fire(NotificationEvent(message: 'You have a gift!'));
// ๐ฃ๏ธ "WATCH OUT! Something went wrong!"
ModularEvent.fire(ErrorEvent(error: 'Slow internet'));2. ๐ Listening to Messages (Listening Events)
Each house can choose which types of "shouts" it wants to listen to:
class NotificationModule extends EventModule {
@override
void listen() {
// ๐ This house listens to notifications
on<NotificationEvent>((event, context) {
showDialog(
context: context!,
builder: (context) => AlertDialog(
title: Text('๐ฌ New Message!'),
content: Text(event.message),
),
);
});
// โ This house also listens to errors
on<ErrorEvent>((event, context) {
ScaffoldMessenger.of(context!).showSnackBar(
SnackBar(
content: Text('๐ฅ Oops! ${event.error}'),
backgroundColor: Colors.red,
),
);
});
}
}๐ต The Exclusive System: Like a Special Radio
Imagine you have a very special radio that can only play one song at a time! ๐ต
๐ป Normal Mode (Non-Exclusive)
// ๐ถ ALL houses listen to the same song at the same time
on<MusicEvent>((event, context) {
print('๐ต Playing: ${event.songName}');
}); // exclusive: false (default)What happens:
- John's House: ๐ต "Playing: Happy Birthday"
- Maria's House: ๐ต "Playing: Happy Birthday"
- Peter's House: ๐ต "Playing: Happy Birthday"
๐ป Exclusive Mode (Radio Queue)
// ๐ฏ Only ONE house can listen at a time!
on<MusicEvent>((event, context) {
print('๐ต Only I listen: ${event.songName}');
}, exclusive: true);What happens:
- ๐ John's House enters queue first โ ๐ต He listens to the song
- ๐ Maria's House enters queue โ โณ Waits
- ๐ Peter's House enters queue โ โณ Waits
๐ RADIO QUEUE:
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ต John (playing now) โ โ Active
โ โณ Maria (waiting) โ โ Next
โ โณ Peter (waiting) โ โ After
โโโโโโโโโโโโโโโโโโโโโโโโโโโ๐โโ๏ธ When Someone Leaves the Queue
If John leaves home (dispose), the radio automatically goes to Maria:
๐ AFTER JOHN LEAVES:
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ต Maria (playing now) โ โ Now active!
โ โณ Peter (waiting) โ โ Next
โโโโโโโโโโโโโโโโโโโโโโโโโโโ๐ช Real World Examples
๐ Login System
class LoginModule extends EventModule {
@override
void listen() {
// When someone logs in
on<LoginEvent>((event, context) {
print('๐ Hello, ${event.username}!');
// Go to main screen
context?.go('/dashboard');
});
// When someone logs out
on<LogoutEvent>((event, context) {
print('๐ Bye, ${event.username}!');
// Go back to login screen
context?.go('/login');
});
}
}
// How to use:
ModularEvent.fire(LoginEvent(username: 'Ana'));
ModularEvent.fire(LogoutEvent(username: 'Ana'));๐ Shopping Cart
class ShoppingModule extends EventModule {
@override
void listen() {
// When adding product
on<AddToCartEvent>((event, context) {
print('๐ Added: ${event.productName}');
ScaffoldMessenger.of(context!).showSnackBar(
SnackBar(content: Text('โ
${event.productName} in cart!'))
);
});
// When finishing purchase
on<PurchaseEvent>((event, context) {
print('๐ณ Purchase of \$${event.total} completed!');
context?.go('/success');
});
}
}
// How to use:
ModularEvent.fire(AddToCartEvent(productName: 'Bicycle', price: 500.0));
ModularEvent.fire(PurchaseEvent(total: 500.0));๐ฎ Game System
class GameModule extends EventModule {
@override
void listen() {
// Score system (exclusive - only one counter)
on<ScoreEvent>((event, context) {
print('๐ New score: ${event.points}');
updateScoreboard(event.points);
}, exclusive: true);
// Sound effects (normal - everyone listens)
on<SoundEvent>((event, context) {
print('๐ Sound: ${event.soundName}');
playSound(event.soundName);
});
}
}
// How to use:
ModularEvent.fire(ScoreEvent(points: 1000));
ModularEvent.fire(SoundEvent(soundName: 'coin.wav'));๐ฏ Important Rules
1. ๐ Automatic Cleanup
When a house is demolished (dispose()), it automatically:
- ๐งน Stops listening to all events
- ๐๏ธ Cleans all memory
- ๐ป If it was on exclusive radio, passes to the next
2. ๐ Magic Context
The context is like a magic GPS that shows you where you are:
on<NavigationEvent>((event, context) {
if (context != null) {
// ๐บ๏ธ You know where you are! Can navigate
context.go('/new-page');
} else {
// ๐คทโโ๏ธ You don't know where you are...
print('Oops! I don't know where I am');
}
});3. ๐ AutoDispose
// ๐ This listener goes away when the house is demolished
on<MyEvent>((event, context) {
// do something...
}, autoDispose: true); // default
// ๐ This listener stays forever (careful!)
on<MyEvent>((event, context) {
// do something...
}, autoDispose: false); // dangerous!๐จ Creating Your Own Events
// ๐ Birthday event
class BirthdayEvent {
final String personName;
final int age;
BirthdayEvent({required this.personName, required this.age});
}
// ๐ Module that listens to birthdays
class BirthdayModule extends EventModule {
@override
void listen() {
on<BirthdayEvent>((event, context) {
print('๐ Happy Birthday ${event.personName}! ${event.age} years old!');
if (context != null) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('๐ Birthday!'),
content: Text('${event.personName} is ${event.age} years old!'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('๐ Cool!'),
),
],
),
);
}
});
}
}
// How to use:
ModularEvent.fire(BirthdayEvent(personName: 'Maria', age: 10));๐ Golden Tips
โจ Best Practices
// โ
GOOD: Always check context
on<NavigationEvent>((event, context) {
if (context != null) {
context.go(event.route);
}
});
// โ
GOOD: Clear names for events
class UserLoginSuccessEvent { ... }
class ShoppingCartUpdatedEvent { ... }
class GameOverEvent { ... }
// โ BAD: Don't check context
on<NavigationEvent>((event, context) {
context!.go(event.route); // Can cause error!
});๐ช Complete Example: Shop App
// ๐ฑ Complete app with events
class ShopApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GoRouterModularApp(
title: '๐๏ธ My Shop',
modules: [
LoginModule(), // Handles login
ShoppingModule(), // Handles shopping
NotificationModule(), // Handles notifications
],
);
}
}
// ๐ช Shop module
class ShoppingModule extends EventModule {
@override
List<ModularRoute> get routes => [
ChildRoute('/shop', child: (context, state) => ShopPage()),
ChildRoute('/cart', child: (context, state) => CartPage()),
];
@override
void listen() {
// When adding to cart
on<AddToCartEvent>((event, context) {
print('๐ ${event.productName} added!');
// Show notification
ModularEvent.fire(NotificationEvent(
message: '${event.productName} in your cart!'
));
});
// When removing from cart
on<RemoveFromCartEvent>((event, context) {
print('๐๏ธ ${event.productName} removed!');
});
// When finishing purchase (exclusive - only one at a time)
on<CheckoutEvent>((event, context) {
print('๐ณ Processing purchase...');
// Go to success page
context?.go('/success');
}, exclusive: true);
}
}๐ Conclusion
EventModule is like a magic city where:
- ๐ Houses (modules) can listen to events
- ๐ข Shouts (events) spread information
- ๐ Telephone central (EventBus) connects everything
- ๐ป Exclusive radio ensures order in queues
- ๐งน Automatic cleanup prevents mess
Now you can create your own events and make your app talk like a happy city! ๐๏ธโจ
"With great power comes great responsibility... always dispose your modules!" ๐ท๏ธ