1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 22:09:06 +00:00
Files
samples/experimental/web_dashboard/lib/src/pages/entries.dart
2021-06-05 12:24:28 +10:00

162 lines
4.5 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 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart' as intl;
import '../api/api.dart';
import '../app.dart';
import '../widgets/categories_dropdown.dart';
import '../widgets/dialogs.dart';
class EntriesPage extends StatefulWidget {
@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({
@required 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,
});
@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),
),
],
),
);
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'),
),
);
}
},
),
],
),
);
}
}