1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 13:58:47 +00:00
Files
samples/experimental/web_dashboard/lib/src/pages/entries.dart
John Ryan 4893a24625 Migrate web dashboard to null safety (#928)
* update dependencies

* Update to cloud_firestore 2.x.x

* run dart migrate

* Fix analyzer warnings from null safety migration

* Fix errors resulting from null safety migration

* Fix info level warnings

* run flutter format

* fix tests

* remove unused import, format
2021-10-12 14:38:34 -07:00

167 lines
4.6 KiB
Dart

// Copyright 2020, the Flutter project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import 'package:provider/provider.dart';
import '../api/api.dart';
import '../app.dart';
import '../widgets/categories_dropdown.dart';
import '../widgets/dialogs.dart';
class EntriesPage extends StatefulWidget {
const EntriesPage({Key? key}) : super(key: key);
@override
_EntriesPageState createState() => _EntriesPageState();
}
class _EntriesPageState extends State<EntriesPage> {
Category? _selected;
@override
Widget build(BuildContext context) {
var appState = Provider.of<AppState>(context);
return Column(
children: [
CategoryDropdown(
api: appState.api!.categories,
onSelected: (category) => setState(() => _selected = category)),
Expanded(
child: _selected == null
? const Center(child: CircularProgressIndicator())
: EntriesList(
category: _selected,
api: appState.api!.entries,
),
),
],
);
}
}
class EntriesList extends StatefulWidget {
final Category? category;
final EntryApi api;
EntriesList({
this.category,
required this.api,
}) : super(key: ValueKey(category?.id));
@override
_EntriesListState createState() => _EntriesListState();
}
class _EntriesListState extends State<EntriesList> {
@override
Widget build(BuildContext context) {
if (widget.category == null) {
return _buildLoadingIndicator();
}
return FutureBuilder<List<Entry>>(
future: widget.api.list(widget.category!.id!),
builder: (context, futureSnapshot) {
if (!futureSnapshot.hasData) {
return _buildLoadingIndicator();
}
return StreamBuilder<List<Entry>>(
initialData: futureSnapshot.data,
stream: widget.api.subscribe(widget.category!.id!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return _buildLoadingIndicator();
}
return ListView.builder(
itemBuilder: (context, index) {
return EntryTile(
category: widget.category,
entry: snapshot.data![index],
);
},
itemCount: snapshot.data!.length,
);
},
);
},
);
}
Widget _buildLoadingIndicator() {
return const Center(child: CircularProgressIndicator());
}
}
class EntryTile extends StatelessWidget {
final Category? category;
final Entry? entry;
const EntryTile({
this.category,
this.entry,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(entry!.value.toString()),
subtitle: Text(intl.DateFormat('MM/dd/yy h:mm a').format(entry!.time)),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
child: const Text('Edit'),
onPressed: () {
showDialog<void>(
context: context,
builder: (context) {
return EditEntryDialog(category: category, entry: entry);
},
);
},
),
TextButton(
child: const Text('Delete'),
onPressed: () async {
var shouldDelete = await (showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Delete entry?'),
actions: [
TextButton(
child: const Text('Cancel'),
onPressed: () => Navigator.of(context).pop(false),
),
TextButton(
child: const Text('Delete'),
onPressed: () => Navigator.of(context).pop(true),
),
],
),
) as FutureOr<bool>);
if (shouldDelete) {
await Provider.of<AppState>(context, listen: false)
.api!
.entries
.delete(category!.id!, entry!.id!);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Entry deleted'),
),
);
}
},
),
],
),
);
}
}