Skip to content

Instantly share code, notes, and snippets.

@cloverrose
Last active May 7, 2022 05:55
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 cloverrose/1bbc69c9a3c749c2aa9228a856534b17 to your computer and use it in GitHub Desktop.
Save cloverrose/1bbc69c9a3c749c2aa9228a856534b17 to your computer and use it in GitHub Desktop.
[Flutter] Realtime ListView Demo with Provider and FutureBuilder
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Message {
const Message({required this.id, required this.text, required this.create});
final int id;
final String text;
final DateTime create;
}
var _i = 0;
void mylog(String msg) {
_i++;
log('$_i: ${DateTime.now()} $msg');
}
class MessageModel extends ChangeNotifier {
final MyDatabase db = MyDatabase();
Future<int> add(Message message) async {
var x = await db.add(message);
notifyListeners();
return x;
}
Future<List<Message>> get() async {
mylog('call MessageModel.get');
var x = await db.get();
return x;
}
}
// fake db
class MyDatabase {
final List<Message> _data = [];
Future<int> add(Message message) async {
await Future.delayed(const Duration(milliseconds: 100));
_data.add(message);
return _data.length;
}
Future<List<Message>> get() async {
await Future.delayed(const Duration(seconds: 5));
return [..._data];
}
}
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => MessageModel()),
],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Realtime ListView Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Realtime ListView Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future: Provider.of<MessageModel>(context, listen: true).get(),
initialData: const <Message>[],
builder: (BuildContext context, AsyncSnapshot<List<Message>> snapshot) {
mylog('call FutureBuilder.builder');
if (snapshot.connectionState == ConnectionState.waiting) {
if (!snapshot.hasData) {
mylog('waiting & not hasData');
return const Center(child: CircularProgressIndicator());
} else {
mylog('waiting & hasData');
}
}
if (snapshot.hasData) {
mylog('ready');
var messages = snapshot.data!;
return ListView.separated(
itemBuilder: (_, index) {
return ListTile(
title: Text(messages[index].text),
subtitle: Text(messages[index].create.toString()),
trailing: Text(messages[index].id.toString()),
);
},
separatorBuilder: (_, __) => const Divider(),
itemCount: messages.length,
);
}
mylog('not ready');
return Container(color: Colors.yellow);
},
),
floatingActionButton: Consumer<MessageModel>(
builder: (context, messageModel, child) {
return FloatingActionButton(
onPressed: () async {
_counter++;
await messageModel.add(
Message(id: _counter, text: 'Hi!', create: DateTime.now()));
},
tooltip: 'Post',
child: const Icon(Icons.add),
);
},
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment