mirror of
https://github.com/flutter/samples.git
synced 2025-11-13 00:08:24 +00:00
Flutter 3.29 beta (#2571)
This commit is contained in:
@@ -86,12 +86,14 @@ class Entry {
|
||||
|
||||
static DateTime _timestampToDateTime(Timestamp timestamp) {
|
||||
return DateTime.fromMillisecondsSinceEpoch(
|
||||
timestamp.millisecondsSinceEpoch);
|
||||
timestamp.millisecondsSinceEpoch,
|
||||
);
|
||||
}
|
||||
|
||||
static Timestamp _dateTimeToTimestamp(DateTime dateTime) {
|
||||
return Timestamp.fromMillisecondsSinceEpoch(
|
||||
dateTime.millisecondsSinceEpoch);
|
||||
dateTime.millisecondsSinceEpoch,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -11,14 +11,12 @@ part of 'api.dart';
|
||||
// **************************************************************************
|
||||
|
||||
Category _$CategoryFromJson(Map<String, dynamic> json) {
|
||||
return Category(
|
||||
json['name'] as String,
|
||||
);
|
||||
return Category(json['name'] as String);
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$CategoryToJson(Category instance) => <String, dynamic>{
|
||||
'name': instance.name,
|
||||
};
|
||||
'name': instance.name,
|
||||
};
|
||||
|
||||
Entry _$EntryFromJson(Map<String, dynamic> json) {
|
||||
return Entry(
|
||||
@@ -28,6 +26,6 @@ Entry _$EntryFromJson(Map<String, dynamic> json) {
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$EntryToJson(Entry instance) => <String, dynamic>{
|
||||
'value': instance.value,
|
||||
'time': Entry._dateTimeToTimestamp(instance.time),
|
||||
};
|
||||
'value': instance.value,
|
||||
'time': Entry._dateTimeToTimestamp(instance.time),
|
||||
};
|
||||
|
||||
@@ -14,8 +14,8 @@ class FirebaseDashboardApi implements DashboardApi {
|
||||
final CategoryApi categories;
|
||||
|
||||
FirebaseDashboardApi(FirebaseFirestore firestore, String userId)
|
||||
: entries = FirebaseEntryApi(firestore, userId),
|
||||
categories = FirebaseCategoryApi(firestore, userId);
|
||||
: entries = FirebaseEntryApi(firestore, userId),
|
||||
categories = FirebaseCategoryApi(firestore, userId);
|
||||
}
|
||||
|
||||
class FirebaseEntryApi implements EntryApi {
|
||||
@@ -24,7 +24,7 @@ class FirebaseEntryApi implements EntryApi {
|
||||
final CollectionReference<Map<String, dynamic>> _categoriesRef;
|
||||
|
||||
FirebaseEntryApi(this.firestore, this.userId)
|
||||
: _categoriesRef = firestore.collection('users/$userId/categories');
|
||||
: _categoriesRef = firestore.collection('users/$userId/categories');
|
||||
|
||||
@override
|
||||
Stream<List<Entry>> subscribe(String categoryId) {
|
||||
@@ -62,9 +62,10 @@ class FirebaseEntryApi implements EntryApi {
|
||||
Future<List<Entry>> list(String categoryId) async {
|
||||
var entriesRef = _categoriesRef.doc(categoryId).collection('entries');
|
||||
var querySnapshot = await entriesRef.get();
|
||||
var entries = querySnapshot.docs
|
||||
.map((doc) => Entry.fromJson(doc.data())..id = doc.id)
|
||||
.toList();
|
||||
var entries =
|
||||
querySnapshot.docs
|
||||
.map((doc) => Entry.fromJson(doc.data())..id = doc.id)
|
||||
.toList();
|
||||
|
||||
return entries;
|
||||
}
|
||||
@@ -91,7 +92,7 @@ class FirebaseCategoryApi implements CategoryApi {
|
||||
final CollectionReference<Map<String, dynamic>> _categoriesRef;
|
||||
|
||||
FirebaseCategoryApi(this.firestore, this.userId)
|
||||
: _categoriesRef = firestore.collection('users/$userId/categories');
|
||||
: _categoriesRef = firestore.collection('users/$userId/categories');
|
||||
|
||||
@override
|
||||
Stream<List<Category>> subscribe() {
|
||||
@@ -131,9 +132,10 @@ class FirebaseCategoryApi implements CategoryApi {
|
||||
@override
|
||||
Future<List<Category>> list() async {
|
||||
var querySnapshot = await _categoriesRef.get();
|
||||
var categories = querySnapshot.docs
|
||||
.map((doc) => Category.fromJson(doc.data())..id = doc.id)
|
||||
.toList();
|
||||
var categories =
|
||||
querySnapshot.docs
|
||||
.map((doc) => Category.fromJson(doc.data())..id = doc.id)
|
||||
.toList();
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
@@ -104,11 +104,12 @@ class MockEntryApi implements EntryApi {
|
||||
|
||||
@override
|
||||
Future<List<Entry>> list(String categoryId) async {
|
||||
var list = _storage.keys
|
||||
.where((k) => k.startsWith(categoryId))
|
||||
.map((k) => _storage[k])
|
||||
.nonNulls
|
||||
.toList();
|
||||
var list =
|
||||
_storage.keys
|
||||
.where((k) => k.startsWith(categoryId))
|
||||
.map((k) => _storage[k])
|
||||
.nonNulls
|
||||
.toList();
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -127,10 +128,11 @@ class MockEntryApi implements EntryApi {
|
||||
}
|
||||
|
||||
void _emit(String categoryId) {
|
||||
var entries = _storage.keys
|
||||
.where((k) => k.startsWith(categoryId))
|
||||
.map((k) => _storage[k]!)
|
||||
.toList();
|
||||
var entries =
|
||||
_storage.keys
|
||||
.where((k) => k.startsWith(categoryId))
|
||||
.map((k) => _storage[k]!)
|
||||
.toList();
|
||||
|
||||
_streamController.add(_EntriesEvent(categoryId, entries));
|
||||
}
|
||||
|
||||
@@ -40,13 +40,13 @@ class DashboardApp extends StatefulWidget {
|
||||
|
||||
/// Runs the app using Firebase
|
||||
DashboardApp.firebase({super.key})
|
||||
: auth = FirebaseAuthService(),
|
||||
apiBuilder = _apiBuilder;
|
||||
: auth = FirebaseAuthService(),
|
||||
apiBuilder = _apiBuilder;
|
||||
|
||||
/// Runs the app using mock data
|
||||
DashboardApp.mock({super.key})
|
||||
: auth = MockAuthService(),
|
||||
apiBuilder = _mockApiBuilder;
|
||||
: auth = MockAuthService(),
|
||||
apiBuilder = _mockApiBuilder;
|
||||
|
||||
@override
|
||||
State<DashboardApp> createState() => _DashboardAppState();
|
||||
@@ -82,11 +82,7 @@ class SignInSwitcher extends StatefulWidget {
|
||||
final AppState? appState;
|
||||
final ApiBuilder? apiBuilder;
|
||||
|
||||
const SignInSwitcher({
|
||||
this.appState,
|
||||
this.apiBuilder,
|
||||
super.key,
|
||||
});
|
||||
const SignInSwitcher({this.appState, this.apiBuilder, super.key});
|
||||
|
||||
@override
|
||||
State<SignInSwitcher> createState() => _SignInSwitcherState();
|
||||
@@ -101,14 +97,13 @@ class _SignInSwitcherState extends State<SignInSwitcher> {
|
||||
switchInCurve: Curves.easeOut,
|
||||
switchOutCurve: Curves.easeOut,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: _isSignedIn
|
||||
? HomePage(
|
||||
onSignOut: _handleSignOut,
|
||||
)
|
||||
: SignInPage(
|
||||
auth: widget.appState!.auth,
|
||||
onSuccess: _handleSignIn,
|
||||
),
|
||||
child:
|
||||
_isSignedIn
|
||||
? HomePage(onSignOut: _handleSignOut)
|
||||
: SignInPage(
|
||||
auth: widget.appState!.auth,
|
||||
onSuccess: _handleSignIn,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ class FirebaseAuthService implements Auth {
|
||||
var googleAuth = await googleUser!.authentication;
|
||||
|
||||
var credential = GoogleAuthProvider.credential(
|
||||
accessToken: googleAuth.accessToken, idToken: googleAuth.idToken);
|
||||
accessToken: googleAuth.accessToken,
|
||||
idToken: googleAuth.idToken,
|
||||
);
|
||||
|
||||
var authResult = await _auth.signInWithCredential(credential);
|
||||
|
||||
@@ -44,10 +46,7 @@ class FirebaseAuthService implements Auth {
|
||||
|
||||
@override
|
||||
Future<void> signOut() async {
|
||||
await Future.wait([
|
||||
_auth.signOut(),
|
||||
_googleSignIn.signOut(),
|
||||
]);
|
||||
await Future.wait([_auth.signOut(), _googleSignIn.signOut()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,18 +19,14 @@ class DashboardPage extends StatelessWidget {
|
||||
future: appState.api!.categories.list(),
|
||||
builder: (context, futureSnapshot) {
|
||||
if (!futureSnapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return StreamBuilder<List<Category>>(
|
||||
initialData: futureSnapshot.data,
|
||||
stream: appState.api!.categories.subscribe(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
return Dashboard(snapshot.data);
|
||||
},
|
||||
@@ -56,13 +52,9 @@ class Dashboard extends StatelessWidget {
|
||||
),
|
||||
children: [
|
||||
...categories!.map(
|
||||
(category) => Card(
|
||||
child: CategoryChart(
|
||||
category: category,
|
||||
api: api,
|
||||
),
|
||||
),
|
||||
)
|
||||
(category) =>
|
||||
Card(child: CategoryChart(category: category, api: api)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -27,15 +27,17 @@ class _EntriesPageState extends State<EntriesPage> {
|
||||
return Column(
|
||||
children: [
|
||||
CategoryDropdown(
|
||||
api: appState.api!.categories,
|
||||
onSelected: (category) => setState(() => _selected = category)),
|
||||
api: appState.api!.categories,
|
||||
onSelected: (category) => setState(() => _selected = category),
|
||||
),
|
||||
Expanded(
|
||||
child: _selected == null
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: EntriesList(
|
||||
category: _selected,
|
||||
api: appState.api!.entries,
|
||||
),
|
||||
child:
|
||||
_selected == null
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: EntriesList(
|
||||
category: _selected,
|
||||
api: appState.api!.entries,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -46,10 +48,8 @@ class EntriesList extends StatefulWidget {
|
||||
final Category? category;
|
||||
final EntryApi api;
|
||||
|
||||
EntriesList({
|
||||
this.category,
|
||||
required this.api,
|
||||
}) : super(key: ValueKey(category?.id));
|
||||
EntriesList({this.category, required this.api})
|
||||
: super(key: ValueKey(category?.id));
|
||||
|
||||
@override
|
||||
State<EntriesList> createState() => _EntriesListState();
|
||||
@@ -99,11 +99,7 @@ class EntryTile extends StatelessWidget {
|
||||
final Category? category;
|
||||
final Entry? entry;
|
||||
|
||||
const EntryTile({
|
||||
this.category,
|
||||
this.entry,
|
||||
super.key,
|
||||
});
|
||||
const EntryTile({this.category, this.entry, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -131,26 +127,25 @@ class EntryTile extends StatelessWidget {
|
||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||
final bool? 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),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('Delete'),
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (shouldDelete != null && shouldDelete) {
|
||||
await appState.api!.entries.delete(category!.id!, entry!.id!);
|
||||
scaffoldMessenger.showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Entry deleted'),
|
||||
),
|
||||
const SnackBar(content: Text('Entry deleted')),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,10 +14,7 @@ import 'entries.dart';
|
||||
class HomePage extends StatefulWidget {
|
||||
final VoidCallback onSignOut;
|
||||
|
||||
const HomePage({
|
||||
required this.onSignOut,
|
||||
super.key,
|
||||
});
|
||||
const HomePage({required this.onSignOut, super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
@@ -38,7 +35,7 @@ class _HomePageState extends State<HomePage> {
|
||||
onPressed: () => _handleSignOut(),
|
||||
child: const Text('Sign Out'),
|
||||
),
|
||||
)
|
||||
),
|
||||
],
|
||||
currentIndex: _pageIndex,
|
||||
destinations: const [
|
||||
@@ -90,23 +87,24 @@ class _HomePageState extends State<HomePage> {
|
||||
Future<void> _handleSignOut() async {
|
||||
var shouldSignOut = await (showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Are you sure you want to sign out?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('No'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: const Text('Are you sure you want to sign out?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('No'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('Yes'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('Yes'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
|
||||
if (shouldSignOut == null || !shouldSignOut) {
|
||||
|
||||
@@ -10,18 +10,12 @@ class SignInPage extends StatelessWidget {
|
||||
final Auth auth;
|
||||
final ValueChanged<User> onSuccess;
|
||||
|
||||
const SignInPage({
|
||||
required this.auth,
|
||||
required this.onSuccess,
|
||||
super.key,
|
||||
});
|
||||
const SignInPage({required this.auth, required this.onSuccess, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: SignInButton(auth: auth, onSuccess: onSuccess),
|
||||
),
|
||||
body: Center(child: SignInButton(auth: auth, onSuccess: onSuccess)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -30,11 +24,7 @@ class SignInButton extends StatefulWidget {
|
||||
final Auth auth;
|
||||
final ValueChanged<User> onSuccess;
|
||||
|
||||
const SignInButton({
|
||||
required this.auth,
|
||||
required this.onSuccess,
|
||||
super.key,
|
||||
});
|
||||
const SignInButton({required this.auth, required this.onSuccess, super.key});
|
||||
|
||||
@override
|
||||
State<SignInButton> createState() => _SignInButtonState();
|
||||
@@ -97,10 +87,8 @@ class _SignInButtonState extends State<SignInButton> {
|
||||
}
|
||||
|
||||
void _showError() {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Unable to sign in.'),
|
||||
),
|
||||
);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('Unable to sign in.')));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,20 @@ class EntryTotal {
|
||||
|
||||
/// Returns a list of [EntryTotal] objects. Each [EntryTotal] is the sum of
|
||||
/// the values of all the entries on a given day.
|
||||
List<EntryTotal> entryTotalsByDay(List<Entry>? entries, int daysAgo,
|
||||
{DateTime? today}) {
|
||||
List<EntryTotal> entryTotalsByDay(
|
||||
List<Entry>? entries,
|
||||
int daysAgo, {
|
||||
DateTime? today,
|
||||
}) {
|
||||
today ??= DateTime.now();
|
||||
return _entryTotalsByDay(entries, daysAgo, today).toList();
|
||||
}
|
||||
|
||||
Iterable<EntryTotal> _entryTotalsByDay(
|
||||
List<Entry>? entries, int daysAgo, DateTime today) sync* {
|
||||
List<Entry>? entries,
|
||||
int daysAgo,
|
||||
DateTime today,
|
||||
) sync* {
|
||||
var start = today.subtract(Duration(days: daysAgo));
|
||||
var entriesByDay = _entriesInRange(start, today, entries);
|
||||
|
||||
@@ -42,11 +48,16 @@ Iterable<EntryTotal> _entryTotalsByDay(
|
||||
/// lists. The outer list represents the number of days since [start], and the
|
||||
/// inner list is the group of entries on that day.
|
||||
List<List<Entry>> _entriesInRange(
|
||||
DateTime start, DateTime end, List<Entry>? entries) =>
|
||||
_entriesInRangeImpl(start, end, entries).toList();
|
||||
DateTime start,
|
||||
DateTime end,
|
||||
List<Entry>? entries,
|
||||
) => _entriesInRangeImpl(start, end, entries).toList();
|
||||
|
||||
Iterable<List<Entry>> _entriesInRangeImpl(
|
||||
DateTime start, DateTime end, List<Entry>? entries) sync* {
|
||||
DateTime start,
|
||||
DateTime end,
|
||||
List<Entry>? entries,
|
||||
) sync* {
|
||||
start = start.atMidnight;
|
||||
end = end.atMidnight;
|
||||
var d = start;
|
||||
|
||||
@@ -105,6 +105,8 @@ class _CategoryDropdownState extends State<CategoryDropdown> {
|
||||
|
||||
DropdownMenuItem<Category> _buildDropdownItem(Category category) {
|
||||
return DropdownMenuItem<Category>(
|
||||
value: category, child: Text(category.name));
|
||||
value: category,
|
||||
child: Text(category.name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ class CategoryChart extends StatelessWidget {
|
||||
final Category category;
|
||||
final DashboardApi? api;
|
||||
|
||||
const CategoryChart({
|
||||
required this.category,
|
||||
required this.api,
|
||||
super.key,
|
||||
});
|
||||
const CategoryChart({required this.category, required this.api, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -75,9 +71,7 @@ class CategoryChart extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildLoadingIndicator() {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,10 +82,7 @@ class _BarChart extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return charts.BarChart(
|
||||
[_seriesData()],
|
||||
animate: false,
|
||||
);
|
||||
return charts.BarChart([_seriesData()], animate: false);
|
||||
}
|
||||
|
||||
charts.Series<utils.EntryTotal, String> _seriesData() {
|
||||
|
||||
@@ -60,9 +60,7 @@ class _EditCategoryFormState extends State<EditCategoryForm> {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
initialValue: widget.category.name,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Name',
|
||||
),
|
||||
decoration: const InputDecoration(labelText: 'Name'),
|
||||
onChanged: (newValue) {
|
||||
widget.category.name = newValue;
|
||||
},
|
||||
|
||||
@@ -17,9 +17,7 @@ class NewCategoryDialog extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return const SimpleDialog(
|
||||
title: Text('New Category'),
|
||||
children: [
|
||||
NewCategoryForm(),
|
||||
],
|
||||
children: [NewCategoryForm()],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -27,10 +25,7 @@ class NewCategoryDialog extends StatelessWidget {
|
||||
class EditCategoryDialog extends StatelessWidget {
|
||||
final Category category;
|
||||
|
||||
const EditCategoryDialog({
|
||||
required this.category,
|
||||
super.key,
|
||||
});
|
||||
const EditCategoryDialog({required this.category, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -65,9 +60,7 @@ class _NewEntryDialogState extends State<NewEntryDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
return const SimpleDialog(
|
||||
title: Text('New Entry'),
|
||||
children: [
|
||||
NewEntryForm(),
|
||||
],
|
||||
children: [NewEntryForm()],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -76,11 +69,7 @@ class EditEntryDialog extends StatelessWidget {
|
||||
final Category? category;
|
||||
final Entry? entry;
|
||||
|
||||
const EditEntryDialog({
|
||||
this.category,
|
||||
this.entry,
|
||||
super.key,
|
||||
});
|
||||
const EditEntryDialog({this.category, this.entry, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -97,7 +86,7 @@ class EditEntryDialog extends StatelessWidget {
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,11 +58,7 @@ class EditEntryForm extends StatefulWidget {
|
||||
final Entry? entry;
|
||||
final ValueChanged<bool> onDone;
|
||||
|
||||
const EditEntryForm({
|
||||
required this.entry,
|
||||
required this.onDone,
|
||||
super.key,
|
||||
});
|
||||
const EditEntryForm({required this.entry, required this.onDone, super.key});
|
||||
|
||||
@override
|
||||
State<EditEntryForm> createState() => _EditEntryFormState();
|
||||
@@ -107,11 +103,13 @@ class _EditEntryFormState extends State<EditEntryForm> {
|
||||
child: const Text('Edit'),
|
||||
onPressed: () async {
|
||||
var result = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: widget.entry!.time,
|
||||
firstDate:
|
||||
DateTime.now().subtract(const Duration(days: 365)),
|
||||
lastDate: DateTime.now());
|
||||
context: context,
|
||||
initialDate: widget.entry!.time,
|
||||
firstDate: DateTime.now().subtract(
|
||||
const Duration(days: 365),
|
||||
),
|
||||
lastDate: DateTime.now(),
|
||||
);
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
@@ -119,7 +117,7 @@ class _EditEntryFormState extends State<EditEntryForm> {
|
||||
widget.entry!.time = result;
|
||||
});
|
||||
},
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -147,7 +145,7 @@ class _EditEntryFormState extends State<EditEntryForm> {
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -17,10 +17,7 @@ class AdaptiveScaffoldDestination {
|
||||
final String title;
|
||||
final IconData icon;
|
||||
|
||||
const AdaptiveScaffoldDestination({
|
||||
required this.title,
|
||||
required this.icon,
|
||||
});
|
||||
const AdaptiveScaffoldDestination({required this.title, required this.icon});
|
||||
}
|
||||
|
||||
/// A widget that adapts to the current display size, displaying a [Drawer],
|
||||
@@ -60,11 +57,7 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
|
||||
Drawer(
|
||||
child: Column(
|
||||
children: [
|
||||
DrawerHeader(
|
||||
child: Center(
|
||||
child: widget.title,
|
||||
),
|
||||
),
|
||||
DrawerHeader(child: Center(child: widget.title)),
|
||||
for (var d in widget.destinations)
|
||||
ListTile(
|
||||
leading: Icon(d.icon),
|
||||
@@ -76,16 +69,10 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
|
||||
],
|
||||
),
|
||||
),
|
||||
VerticalDivider(
|
||||
width: 1,
|
||||
thickness: 1,
|
||||
color: Colors.grey[300],
|
||||
),
|
||||
VerticalDivider(width: 1, thickness: 1, color: Colors.grey[300]),
|
||||
Expanded(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
actions: widget.actions,
|
||||
),
|
||||
appBar: AppBar(actions: widget.actions),
|
||||
body: widget.body,
|
||||
floatingActionButton: widget.floatingActionButton,
|
||||
),
|
||||
@@ -97,10 +84,7 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
|
||||
// Show a navigation rail
|
||||
if (_isMediumScreen(context)) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: widget.title,
|
||||
actions: widget.actions,
|
||||
),
|
||||
appBar: AppBar(title: widget.title, actions: widget.actions),
|
||||
body: Row(
|
||||
children: [
|
||||
NavigationRail(
|
||||
@@ -116,14 +100,8 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
|
||||
selectedIndex: widget.currentIndex,
|
||||
onDestinationSelected: widget.onNavigationIndexChange ?? (_) {},
|
||||
),
|
||||
VerticalDivider(
|
||||
width: 1,
|
||||
thickness: 1,
|
||||
color: Colors.grey[300],
|
||||
),
|
||||
Expanded(
|
||||
child: widget.body!,
|
||||
),
|
||||
VerticalDivider(width: 1, thickness: 1, color: Colors.grey[300]),
|
||||
Expanded(child: widget.body!),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -132,17 +110,11 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
|
||||
// Show a bottom app bar
|
||||
return Scaffold(
|
||||
body: widget.body,
|
||||
appBar: AppBar(
|
||||
title: widget.title,
|
||||
actions: widget.actions,
|
||||
),
|
||||
appBar: AppBar(title: widget.title, actions: widget.actions),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
items: [
|
||||
...widget.destinations.map(
|
||||
(d) => BottomNavigationBarItem(
|
||||
icon: Icon(d.icon),
|
||||
label: d.title,
|
||||
),
|
||||
(d) => BottomNavigationBarItem(icon: Icon(d.icon), label: d.title),
|
||||
),
|
||||
],
|
||||
currentIndex: widget.currentIndex,
|
||||
|
||||
Reference in New Issue
Block a user