Created
April 24, 2023 14:56
-
-
Save hotdang-ca/624b42b0e9a6192e4a9d9f3d73e8bb69 to your computer and use it in GitHub Desktop.
Using ChangeNotifier as a Singleton
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:provider/provider.dart'; | |
void main() { | |
runApp(const SampleApp()); | |
} | |
class SampleApp extends StatelessWidget { | |
const SampleApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return ChangeNotifierProvider( | |
create: (context) => NotificationHandler(), | |
child: const MaterialApp( | |
home: ListOfContactsPage(), | |
), | |
); | |
} | |
} | |
class ListOfContactsPage extends StatefulWidget { | |
const ListOfContactsPage({super.key}); | |
@override | |
State<ListOfContactsPage> createState() => _ListOfContactsPageState(); | |
} | |
class _ListOfContactsPageState extends State<ListOfContactsPage> { | |
List<Contact> contacts = [ | |
Contact( | |
name: 'John', | |
userId: '[email protected]', | |
), | |
Contact( | |
name: 'Jane', | |
userId: '[email protected]', | |
), | |
Contact( | |
name: 'Bob', | |
userId: '[email protected]', | |
), | |
]; | |
@override | |
void initState() { | |
super.initState(); | |
Provider.of<NotificationHandler>(context, listen: false) | |
.addListener(_onNotification); | |
} | |
void _onNotification() { | |
// Deep-copy the existing list of contacts. | |
List<Contact> newContacts = List.from(contacts); | |
// This is another way to access the ChangeNotifier. | |
// This is synatically idential to | |
// Provider.of<NotificationHandler>(context, listen: false) | |
final userId = context.read<NotificationHandler>().userId; | |
// Check to see which member in the list this email is | |
// identical to. This is the one who will get the alert | |
// badge | |
for (var contact in contacts) { | |
if (contact.userId == userId) { | |
contact.isAlert = true; | |
} | |
} | |
setState(() { | |
// we are assigning a new value to contacts, | |
// which will trigger a rebuild of the widget tree. | |
// Just modifying the list will not trigger a rebuild. | |
contacts = List.from(newContacts); | |
}); | |
} | |
void _simulateNotification() { | |
/// access the notification handler singleton | |
NotificationHandler().setUnreadForUserId('[email protected]'); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Contacts'), | |
), | |
body: Center( | |
child: ListView.builder( | |
itemCount: contacts.length, | |
itemBuilder: (context, index) { | |
Contact contact = contacts[index]; | |
return ContactListCard(contact); | |
}, | |
), | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: _simulateNotification, | |
tooltip: 'Increment', | |
child: const Icon(Icons.add), | |
), | |
); | |
} | |
} | |
/// A simple contact with name and email, as well as a boolean | |
/// to indicate if there is an unread alert for this user | |
class Contact { | |
final String name; | |
final String userId; | |
bool isAlert = false; | |
Contact({required this.name, required this.userId}); | |
} | |
class ContactListCard extends StatelessWidget { | |
final Contact contact; | |
const ContactListCard(this.contact, {super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return Container( | |
color: Colors.white, | |
child: ListTile( | |
trailing: Stack( | |
children: [ | |
const Icon(Icons.add_ic_call), | |
// only if this contact has an alert, display the alert indicator | |
if (contact.isAlert) const AlertIndicator(), | |
], | |
), | |
title: Text(contact.name), | |
subtitle: Text(contact.userId), | |
), | |
); | |
} | |
} | |
/// A simple alert indicator that will be displayed | |
class AlertIndicator extends StatelessWidget { | |
const AlertIndicator({ | |
Key? key, | |
}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return Positioned( | |
right: 0, | |
child: Container( | |
padding: const EdgeInsets.all(1), | |
decoration: const BoxDecoration( | |
color: Colors.red, | |
borderRadius: BorderRadius.all(Radius.circular(8)), | |
), | |
constraints: const BoxConstraints( | |
minWidth: 16, | |
minHeight: 16, | |
), | |
child: const Text( | |
'1', | |
style: TextStyle( | |
color: Colors.white, | |
fontSize: 8, | |
), | |
textAlign: TextAlign.center, | |
), | |
), | |
); | |
} | |
} | |
/// A simple notification handler, but modified | |
/// to be a singleton. You can access the singleton | |
/// to set the message and email outside of the widget tree. | |
class NotificationHandler extends ChangeNotifier { | |
static final NotificationHandler _notificationHandler = | |
NotificationHandler._internal(); | |
factory NotificationHandler() { | |
return _notificationHandler; | |
} | |
NotificationHandler._internal(); | |
// the above code creates this as a singleton, when accessing | |
// like a standard class, eg, NotificationHandler() | |
String _userId = ''; | |
String get userId => _userId; | |
void setUnreadForUserId(String userId) { | |
_userId = userId; | |
notifyListeners(); // important, to trigger listeners | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment