Skip to content

Instantly share code, notes, and snippets.

@hotdang-ca
Created April 24, 2023 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hotdang-ca/624b42b0e9a6192e4a9d9f3d73e8bb69 to your computer and use it in GitHub Desktop.
Save hotdang-ca/624b42b0e9a6192e4a9d9f3d73e8bb69 to your computer and use it in GitHub Desktop.
Using ChangeNotifier as a Singleton
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: 'john@gmail.com',
),
Contact(
name: 'Jane',
userId: 'jane@gmail.com',
),
Contact(
name: 'Bob',
userId: 'bob@gmail.com',
),
];
@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('bob@gmail.com');
}
@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