Skip to content

Instantly share code, notes, and snippets.

@wingkit-leung
Last active February 13, 2022 13:13
Show Gist options
  • Save wingkit-leung/9f61acbc03aa3358ff8be78d16929797 to your computer and use it in GitHub Desktop.
Save wingkit-leung/9f61acbc03aa3358ff8be78d16929797 to your computer and use it in GitHub Desktop.
CustomCounter: badges, shared_preferences, state_notifier, riverpod
import 'package:flutter/material.dart';
import 'package:flutter_app_badger/flutter_app_badger.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:badges/badges.dart';
// A CustomCounter example implemented with riverpod and shared_preferences
// using StateNotifier
// using Badges
class CustomCounter {
final int value;
final DateTime dateTime;
const CustomCounter(this.value, this.dateTime);
String get counter {
return (value < 0) ? '-' : value.toString();
}
String get lastUpdatedAt {
return dateTime.toIso8601String();
}
String get lastUpdatedAtFormatted {
return "${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}:${dateTime.second.toString().padLeft(2, '0')}";
}
}
class CounterStateNotifier extends StateNotifier<CustomCounter> {
final SharedPreferences prefs;
CounterStateNotifier(this.prefs) : super(CustomCounter(0, DateTime.now())) {
init();
}
void init() {
final counter = prefs.getInt('counter');
final lastUpdatedAt = prefs.getString('lastUpdatedAt');
if (counter == null || lastUpdatedAt == null) {
state = CustomCounter(0, DateTime.now());
} else {
state = CustomCounter(counter, DateTime.parse(lastUpdatedAt));
}
}
Future<void> increment() async {
final countPref = state.value + 1;
state = CustomCounter(countPref, DateTime.now());
prefs.setInt('counter', state.value);
prefs.setString('lastUpdatedAt', state.lastUpdatedAt);
try {
bool res = await FlutterAppBadger.isAppBadgeSupported();
if (res) {
FlutterAppBadger.updateBadgeCount(countPref);
}
} on Exception catch (_) {}
}
}
/// Providers are declared globally and specify how to create a state
final sharedPrefs = Provider<SharedPreferences>((ref) {
throw UnimplementedError();
});
final counterStateNotifier =
StateNotifierProvider<CounterStateNotifier, CustomCounter>(
(ref) => CounterStateNotifier(ref.watch(sharedPrefs)));
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final sharedPreferences = await SharedPreferences.getInstance();
runApp(
// Adding ProviderScope enables Riverpod for the entire project
ProviderScope(overrides: [
sharedPrefs.overrideWithValue(sharedPreferences),
], child: const MyApp()),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(home: Home());
}
}
class Home extends ConsumerWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
leading: Badge(
shape: BadgeShape.circle,
position: BadgePosition.topEnd(top: 0, end: 5),
borderRadius: BorderRadius.circular(5),
child: const Icon(Icons.menu),
badgeContent: Consumer(builder: (context, ref, _) {
final myCounter = ref.watch(counterStateNotifier);
return Text(
myCounter.counter,
style: const TextStyle(color: Colors.white),
);
}),
),
title: const Text('Flutter101')),
body: Center(
child: Consumer(builder: (context, ref, _) {
final myCounter = ref.watch(counterStateNotifier);
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Counter',
style: DefaultTextStyle.of(context)
.style
.apply(fontSizeFactor: 3.0),
),
const SizedBox(height: 30),
Chip(
padding: const EdgeInsets.all(5),
backgroundColor: Colors.deepPurple,
label: Text(myCounter.counter,
style: const TextStyle(color: Colors.white)),
labelStyle: DefaultTextStyle.of(context)
.style
.apply(fontSizeFactor: 3.0),
),
const SizedBox(height: 50),
Text(
myCounter.lastUpdatedAtFormatted,
style: DefaultTextStyle.of(context)
.style
.apply(fontSizeFactor: 3.0),
),
],
),
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
ref.read(counterStateNotifier.notifier).increment();
},
child: const Icon(Icons.add),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment