From 82c068a5f8e3217347f48f4379a1fa8dc6ec598d Mon Sep 17 00:00:00 2001 From: Marcin Szalek Date: Tue, 15 Aug 2017 12:35:36 +0200 Subject: [PATCH] Finished implementation of FullScreenDialog --- lib/WeightListItem.dart | 47 ----- lib/add_entry_dialog.dart | 242 -------------------------- lib/{HomePage.dart => home_page.dart} | 48 ++++- lib/main.dart | 2 +- lib/model/WeightSave.dart | 7 - lib/model/weight_entry.dart | 7 + lib/weight_entry_dialog.dart | 238 +++++++++++++++++++++++++ lib/weight_list_item.dart | 89 ++++++++++ 8 files changed, 374 insertions(+), 306 deletions(-) delete mode 100644 lib/WeightListItem.dart delete mode 100644 lib/add_entry_dialog.dart rename lib/{HomePage.dart => home_page.dart} (50%) delete mode 100644 lib/model/WeightSave.dart create mode 100644 lib/model/weight_entry.dart create mode 100644 lib/weight_entry_dialog.dart create mode 100644 lib/weight_list_item.dart diff --git a/lib/WeightListItem.dart b/lib/WeightListItem.dart deleted file mode 100644 index 63d00c9..0000000 --- a/lib/WeightListItem.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:weight_tracker/model/WeightSave.dart'; - -class WeightListItem extends StatelessWidget { - final WeightSave weightSave; - final double weightDifference; - - WeightListItem(this.weightSave, this.weightDifference); - - @override - Widget build(BuildContext context) { - return new Padding( - padding: new EdgeInsets.all(16.0), - child: new Row(children: [ - new Expanded( - child: new Column(children: [ - new Text( - new DateFormat.yMMMMd().format(weightSave.dateTime), - textScaleFactor: 0.9, - textAlign: TextAlign.left, - ), - new Text( - new DateFormat.EEEE().format(weightSave.dateTime), - textScaleFactor: 0.8, - textAlign: TextAlign.right, - style: new TextStyle( - color: Colors.grey, - ), - ), - ], crossAxisAlignment: CrossAxisAlignment.start)), - new Expanded( - child: new Text( - weightSave.weight.toString(), - textScaleFactor: 2.0, - textAlign: TextAlign.center, - )), - new Expanded( - child: new Text( - weightDifference.toString(), - textScaleFactor: 1.6, - textAlign: TextAlign.right, - )), - ]), - ); - } -} diff --git a/lib/add_entry_dialog.dart b/lib/add_entry_dialog.dart deleted file mode 100644 index e48b366..0000000 --- a/lib/add_entry_dialog.dart +++ /dev/null @@ -1,242 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:meta/meta.dart'; -import 'package:numberpicker/numberpicker.dart'; -import 'package:weight_tracker/model/WeightSave.dart'; - -class AddEntryDialog extends StatefulWidget { - final double initialWeight; - final WeightSave weightSaveToEdit; - - AddEntryDialog.add(this.initialWeight) : weightSaveToEdit = null; - - AddEntryDialog.edit(this.weightSaveToEdit) - : initialWeight = weightSaveToEdit.weight; - - @override - AddEntryDialogState createState() { - if (weightSaveToEdit != null) { - return new AddEntryDialogState(weightSaveToEdit.dateTime, - weightSaveToEdit.weight, weightSaveToEdit.note); - } else { - return new AddEntryDialogState(new DateTime.now(), initialWeight, null); - } - } -} - -class AddEntryDialogState extends State { - DateTime _dateTime = new DateTime.now(); - double _weight; - String _note; - - AddEntryDialogState(this._dateTime, this._weight, this._note); - - @override - Widget build(BuildContext context) { - TextStyle headerTextStyle = Theme - .of(context) - .textTheme - .subhead - .copyWith(color: Colors.black, fontSize: 16.0); - return new Scaffold( - appBar: new AppBar( - title: const Text('New entry'), - actions: [ - new FlatButton( - onPressed: () { - Navigator - .of(context) - .pop(new WeightSave(_dateTime, _weight, _note)); - }, - child: new Text('SAVE', - style: Theme - .of(context) - .textTheme - .subhead - .copyWith(color: Colors.white))), - ], - ), - body: new DefaultTextStyle( - style: headerTextStyle, - child: new Container( - padding: new EdgeInsets.all(12.0), - child: new SingleChildScrollView( - child: new Column( - children: [ - new Padding( - padding: new EdgeInsets.all(8.0), - child: new DateTimeItem( - dateTime: _dateTime, - onChanged: (dateTime) => - setState(() => _dateTime = dateTime), - ), - ), - new Padding( - padding: new EdgeInsets.symmetric(horizontal: 8.0), - child: new InkWell( - onTap: () => _showWeightPicker(context), - child: new Padding( - padding: new EdgeInsets.only(top: 8.0), - child: new Row( - children: [ - new Image.asset( - "assets/scale-bathroom.png", - color: Colors.grey[500], - height: 24.0, - width: 24.0, - ), - new Padding( - padding: new EdgeInsets.only(left: 16.0), - child: new Text( - "$_weight kg", - style: headerTextStyle, - ), - ), - ], - ), - ), - ), - ), - new Padding( - padding: new EdgeInsets.symmetric( - vertical: 0.0, horizontal: 8.0), - child: new InkWell( - onTap: () => _showWeightPicker(context), - child: new Row( - children: [ - new Padding( - padding: new EdgeInsets.only(top: 4.0), - child: new Icon( - Icons.note_add, - color: Colors.grey[500], - )), - new Expanded( - child: new Padding( - padding: new EdgeInsets.only(left: 16.0), - child: new TextField( - decoration: new InputDecoration( - labelText: 'Optional note', - labelStyle: null, - ), - focusNode: new FocusNode(), - controller: - new TextEditingController(text: _note), - onSubmitted: (string) => - setState(() => _note = string), - maxLines: null, - ), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ), - )); - } - - _showWeightPicker(BuildContext context) { - showDialog( - context: context, - child: new NumberPickerDialog.decimal( - minValue: 1, - maxValue: 150, - initialDoubleValue: _weight, - title: new Text("Enter your weight"), - ), - ).then((value) { - if (value != null) { - setState(() => _weight = value); - } - }); - } -} - -class DateTimeItem extends StatelessWidget { - DateTimeItem({Key key, DateTime dateTime, @required this.onChanged}) - : assert(onChanged != null), - date = dateTime == null - ? new DateTime.now() - : new DateTime(dateTime.year, dateTime.month, dateTime.day), - time = dateTime == null - ? new DateTime.now() - : new TimeOfDay(hour: dateTime.hour, minute: dateTime.minute), - super(key: key); - - final DateTime date; - final TimeOfDay time; - final ValueChanged onChanged; - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - - return new Row( - children: [ - new Expanded( - child: new InkWell( - onTap: () { - _showDatePicker(context); - }, - child: new Container( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: new Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - new Icon(Icons.today, color: Colors.grey[500]), - new Padding( - padding: new EdgeInsets.only(left: 16.0), - child: - new Text(new DateFormat('EEEE, MMMM d').format(date)), - ), - ], - ), - ), - ), - ), - new InkWell( - onTap: () { - _showTimePicker(context); - }, - child: new Container( - margin: const EdgeInsets.only(left: 8.0), - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: new Row( - children: [ - new Text('$time'), - ], - ), - ), - ), - ], - ); - } - - Future _showDatePicker(BuildContext context) async { - DateTime dateTimePicked = await showDatePicker( - context: context, - initialDate: date, - firstDate: date.subtract(const Duration(days: 20000)), - lastDate: new DateTime.now()); - - if (dateTimePicked != null) { - onChanged(new DateTime(dateTimePicked.year, dateTimePicked.month, - dateTimePicked.day, time.hour, time.minute)); - } - } - - Future _showTimePicker(BuildContext context) async { - TimeOfDay timeOfDay = - await showTimePicker(context: context, initialTime: time); - - if (timeOfDay != null) { - onChanged(new DateTime( - date.year, date.month, date.day, timeOfDay.hour, timeOfDay.minute)); - } - } -} diff --git a/lib/HomePage.dart b/lib/home_page.dart similarity index 50% rename from lib/HomePage.dart rename to lib/home_page.dart index 148443e..960090a 100644 --- a/lib/HomePage.dart +++ b/lib/home_page.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:weight_tracker/WeightListItem.dart'; -import 'package:weight_tracker/add_entry_dialog.dart'; -import 'package:weight_tracker/model/WeightSave.dart'; +import 'package:weight_tracker/model/weight_entry.dart'; +import 'package:weight_tracker/weight_entry_dialog.dart'; +import 'package:weight_tracker/weight_list_item.dart'; class HomePage extends StatefulWidget { HomePage({Key key, this.title}) : super(key: key); @@ -14,7 +14,9 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { - List weightSaves = new List(); + List weightSaves = new List(); + ScrollController _listViewScrollController = new ScrollController(); + double _itemExtent = 50.0; @override Widget build(BuildContext context) { @@ -23,13 +25,18 @@ class _HomePageState extends State { title: new Text(widget.title), ), body: new ListView.builder( + shrinkWrap: true, + reverse: true, + controller: _listViewScrollController, itemCount: weightSaves.length, itemBuilder: (buildContext, index) { //calculating difference double difference = index == 0 ? 0.0 : weightSaves[index].weight - weightSaves[index - 1].weight; - return new WeightListItem(weightSaves[index], difference); + return new InkWell( + onTap: () => _editEntry(weightSaves[index]), + child: new WeightListItem(weightSaves[index], difference)); }, ), floatingActionButton: new FloatingActionButton( @@ -40,17 +47,40 @@ class _HomePageState extends State { ); } - void _addWeightSave(WeightSave weightSave) { + void _addWeightSave(WeightEntry weightSave) { setState(() { weightSaves.add(weightSave); + _listViewScrollController.animateTo( + weightSaves.length * _itemExtent, + duration: const Duration(microseconds: 1), + curve: new ElasticInCurve(0.01), + ); + }); + } + + _editEntry(WeightEntry weightSave) { + Navigator + .of(context) + .push( + new MaterialPageRoute( + builder: (BuildContext context) { + return new WeightEntryDialog.edit(weightSave); + }, + fullscreenDialog: true, + ), + ) + .then((newSave) { + if (newSave != null) { + setState(() => weightSaves[weightSaves.indexOf(weightSave)] = newSave); + } }); } Future _openAddEntryDialog() async { - WeightSave save = - await Navigator.of(context).push(new MaterialPageRoute( + WeightEntry save = + await Navigator.of(context).push(new MaterialPageRoute( builder: (BuildContext context) { - return new AddEntryDialog.add( + return new WeightEntryDialog.add( weightSaves.isNotEmpty ? weightSaves.last.weight : 60.0); }, fullscreenDialog: true)); diff --git a/lib/main.dart b/lib/main.dart index 6018b31..32873da 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:weight_tracker/HomePage.dart'; +import 'package:weight_tracker/home_page.dart'; void main() { diff --git a/lib/model/WeightSave.dart b/lib/model/WeightSave.dart deleted file mode 100644 index 44f4249..0000000 --- a/lib/model/WeightSave.dart +++ /dev/null @@ -1,7 +0,0 @@ -class WeightSave { - DateTime dateTime; - double weight; - String note; - - WeightSave(this.dateTime, this.weight, this.note); -} \ No newline at end of file diff --git a/lib/model/weight_entry.dart b/lib/model/weight_entry.dart new file mode 100644 index 0000000..0be90a6 --- /dev/null +++ b/lib/model/weight_entry.dart @@ -0,0 +1,7 @@ +class WeightEntry { + DateTime dateTime; + double weight; + String note; + + WeightEntry(this.dateTime, this.weight, this.note); +} \ No newline at end of file diff --git a/lib/weight_entry_dialog.dart b/lib/weight_entry_dialog.dart new file mode 100644 index 0000000..e3d8407 --- /dev/null +++ b/lib/weight_entry_dialog.dart @@ -0,0 +1,238 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; +import 'package:numberpicker/numberpicker.dart'; +import 'package:weight_tracker/model/weight_entry.dart'; + +class WeightEntryDialog extends StatefulWidget { + final double initialWeight; + final WeightEntry weighEntryToEdit; + + WeightEntryDialog.add(this.initialWeight) : weighEntryToEdit = null; + + WeightEntryDialog.edit(this.weighEntryToEdit) + : initialWeight = weighEntryToEdit.weight; + + @override + WeightEntryDialogState createState() { + if (weighEntryToEdit != null) { + return new WeightEntryDialogState(weighEntryToEdit.dateTime, + weighEntryToEdit.weight, weighEntryToEdit.note); + } else { + return new WeightEntryDialogState( + new DateTime.now(), initialWeight, null); + } + } +} + +class WeightEntryDialogState extends State { + DateTime _dateTime = new DateTime.now(); + double _weight; + String _note; + + TextField _noteTextField; + + WeightEntryDialogState(this._dateTime, this._weight, this._note); + + @override + Widget build(BuildContext context) { + TextStyle defaultTextStyle = Theme + .of(context) + .textTheme + .subhead + .copyWith(color: Colors.black, fontSize: 16.0); + + _noteTextField = new TextField( + decoration: new InputDecoration( + labelText: 'Optional note', + ), + controller: new TextEditingController(text: _note), + onSubmitted: (string) => setState(() => _note = string), + ); + + return new Scaffold( + appBar: new AppBar( + title: widget.weighEntryToEdit == null + ? const Text("New entry") + : const Text("Edit entry"), + actions: [ + new FlatButton( + onPressed: () { + _note = _noteTextField.controller.text; + Navigator + .of(context) + .pop(new WeightEntry(_dateTime, _weight, _note)); + }, + child: new Text('SAVE', + style: Theme + .of(context) + .textTheme + .subhead + .copyWith(color: Colors.white))), + ], + ), + body: new DefaultTextStyle( + style: defaultTextStyle, + child: new Padding( + padding: new EdgeInsets.all(12.0), + child: new Column( + children: [ + new Padding( + padding: new EdgeInsets.all(8.0), + child: new DateTimeItem( + dateTime: _dateTime, + onChanged: (dateTime) => setState(() => _dateTime = dateTime), + ), + ), + new Padding( + padding: new EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 0.0), + child: new InkWell( + onTap: () => _showWeightPicker(context), + child: new Row( + children: [ + new Image.asset( + "assets/scale-bathroom.png", + color: Colors.grey[500], + height: 24.0, + width: 24.0, + ), + new Padding( + padding: new EdgeInsets.only(left: 16.0), + child: new Text( + "$_weight kg", + ), + ), + ], + ), + ), + ), + new Padding( + padding: new EdgeInsets.symmetric(horizontal: 8.0), + child: new InkWell( + onTap: () => _showWeightPicker(context), + child: new Row( + children: [ + new Padding( + padding: new EdgeInsets.only(top: 4.0), + child: new Icon( + Icons.speaker_notes, + color: Colors.grey[500], + ), + ), + new Expanded( + child: new Padding( + padding: new EdgeInsets.only(left: 16.0), + child: _noteTextField, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } + + _showWeightPicker(BuildContext context) { + showDialog( + context: context, + child: new NumberPickerDialog.decimal( + minValue: 1, + maxValue: 150, + initialDoubleValue: _weight, + title: new Text("Enter your weight"), + ), + ).then((value) { + if (value != null) { + setState(() => _weight = value); + } + }); + } +} + +class DateTimeItem extends StatelessWidget { + DateTimeItem({Key key, DateTime dateTime, @required this.onChanged}) + : assert(onChanged != null), + date = dateTime == null + ? new DateTime.now() + : new DateTime(dateTime.year, dateTime.month, dateTime.day), + time = dateTime == null + ? new DateTime.now() + : new TimeOfDay(hour: dateTime.hour, minute: dateTime.minute), + super(key: key); + + final DateTime date; + final TimeOfDay time; + final ValueChanged onChanged; + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new Expanded( + child: new InkWell( + onTap: () { + _showDatePicker(context); + }, + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: new Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + new Icon(Icons.today, color: Colors.grey[500]), + new Padding( + padding: new EdgeInsets.only(left: 16.0), + child: + new Text(new DateFormat('EEEE, MMMM d').format(date)), + ), + ], + ), + ), + ), + ), + new InkWell( + onTap: () { + _showTimePicker(context); + }, + child: new Container( + margin: const EdgeInsets.only(left: 8.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: new Row( + children: [ + new Text('$time'), + ], + ), + ), + ), + ], + ); + } + + Future _showDatePicker(BuildContext context) async { + DateTime dateTimePicked = await showDatePicker( + context: context, + initialDate: date, + firstDate: date.subtract(const Duration(days: 20000)), + lastDate: new DateTime.now()); + + if (dateTimePicked != null) { + onChanged(new DateTime(dateTimePicked.year, dateTimePicked.month, + dateTimePicked.day, time.hour, time.minute)); + } + } + + Future _showTimePicker(BuildContext context) async { + TimeOfDay timeOfDay = + await showTimePicker(context: context, initialTime: time); + + if (timeOfDay != null) { + onChanged(new DateTime( + date.year, date.month, date.day, timeOfDay.hour, timeOfDay.minute)); + } + } +} diff --git a/lib/weight_list_item.dart b/lib/weight_list_item.dart new file mode 100644 index 0000000..ab4cbe8 --- /dev/null +++ b/lib/weight_list_item.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:weight_tracker/model/weight_entry.dart'; + +class WeightListItem extends StatelessWidget { + final WeightEntry weightEntry; + final double weightDifference; + + WeightListItem(this.weightEntry, this.weightDifference); + + @override + Widget build(BuildContext context) { + return new Padding( + padding: new EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), + child: new Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + new Expanded( + child: new Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Column( + children: [ + new Text( + new DateFormat.MMMEd().format(weightEntry.dateTime), + textScaleFactor: 0.9, + textAlign: TextAlign.left, + ), + new Text( + new TimeOfDay.fromDateTime(weightEntry.dateTime) + .toString(), + textScaleFactor: 0.8, + textAlign: TextAlign.right, + style: new TextStyle( + color: Colors.grey, + ), + ), + ], + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + ), + (weightEntry.note == null || weightEntry.note.isEmpty) + ? new Container( + height: 0.0, + ) + : new Padding( + padding: new EdgeInsets.only(left: 4.0), + child: new Icon( + Icons.speaker_notes, + color: Colors.grey[300], + size: 16.0, + ), + ), + ], + ), + ), + new Text( + weightEntry.weight.toString(), + textScaleFactor: 2.0, + textAlign: TextAlign.center, + ), + new Expanded( + child: new Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + new Text( + _differenceText(weightDifference), + textScaleFactor: 1.6, + textAlign: TextAlign.right, + ), + ], + ), + ), + ], + ), + ); + } + + String _differenceText(double weightDifference) { + if (weightDifference > 0) { + return "+" + weightDifference.toStringAsFixed(1); + } else if (weightDifference < 0) { + return weightDifference.toStringAsFixed(1); + } else { + return "-"; + } + } +}