๐ŸŽญ Event Module
๐Ÿ‘ถ Event Module for Kids

๐ŸŽญ 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:

  1. ๐Ÿ  John's House enters queue first โ†’ ๐ŸŽต He listens to the song
  2. ๐Ÿ  Maria's House enters queue โ†’ โณ Waits
  3. ๐Ÿ  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!" ๐Ÿ•ท๏ธ