From b6c38dde3cdbfc6d3a4c031bea2751315a5ac009 Mon Sep 17 00:00:00 2001 From: Vishesh Handa Date: Thu, 24 May 2018 12:33:46 +0200 Subject: [PATCH] Use an InheritedWidget instead of passing the callbacks This simplifies the code quite a bit, at the cost of using this strange flutter magic of an 'InheritedWidget'. It basically make a class a global variable. --- lib/app.dart | 72 +-------------------- lib/file_storage.dart | 2 +- lib/main.dart | 23 ++----- lib/note_editor.dart | 11 ++-- lib/screens/home_screen.dart | 20 ++---- lib/state_container.dart | 117 ++++++++++++++++++++++++++++++++++ lib/widgets/journal_list.dart | 7 +- 7 files changed, 139 insertions(+), 113 deletions(-) create mode 100644 lib/state_container.dart diff --git a/lib/app.dart b/lib/app.dart index ab4a8986..959e4555 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,51 +1,14 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:uuid/uuid.dart'; - -import 'package:journal/file_storage.dart'; -import 'package:journal/note.dart'; import 'package:journal/screens/home_screen.dart'; -class JournalApp extends StatefulWidget { - final FileStorage fileStorage; - - JournalApp({@required this.fileStorage}); - - @override - JournalAppState createState() { - return new JournalAppState(); - } -} - -class JournalAppState extends State { - AppState appState = AppState.loading(); - - @override - void initState() { - super.initState(); - - widget.fileStorage.loadNotes().then((loadedNotes) { - setState(() { - appState = AppState(notes: loadedNotes); - }); - }).catchError((err) { - setState(() { - print("Got Error"); - print(err); - appState.isLoading = false; - }); - }); - } +class JournalApp extends StatelessWidget { + JournalApp(); @override Widget build(BuildContext context) { return new MaterialApp( title: 'Journal', - home: new HomeScreen( - appState: appState, - noteAdder: addNote, - noteRemover: removeNote, - ), + home: new HomeScreen(), theme: new ThemeData( brightness: Brightness.dark, primaryColor: Colors.lightBlue[800], @@ -53,33 +16,4 @@ class JournalAppState extends State { ), ); } - - @override - void setState(VoidCallback fn) { - super.setState(fn); - - widget.fileStorage.saveNotes(appState.notes); - } - - void addNote(Note note) { - print("Adding a note " + note.toString()); - setState(() { - note.id = new Uuid().v4(); - appState.notes.insert(0, note); - }); - } - - void removeNote(Note note) { - setState(() { - appState.notes.remove(note); - }); - } - - // FIXME: Implement this! - void updateNote(Note note) { - setState(() { - //appState.notes. - //appState.notes.remove(note); - }); - } } diff --git a/lib/file_storage.dart b/lib/file_storage.dart index 1622fb41..b0c91308 100644 --- a/lib/file_storage.dart +++ b/lib/file_storage.dart @@ -10,7 +10,7 @@ import './note.dart'; class FileStorage { final Future Function() getDirectory; - FileStorage({@required this.getDirectory}); + const FileStorage({@required this.getDirectory}); Future> loadNotes() async { final dir = await getDirectory(); diff --git a/lib/main.dart b/lib/main.dart index 9a388ec2..953de157 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,13 +1,8 @@ -import 'dart:async'; -import 'dart:io'; - import 'package:flutter/material.dart'; //import 'package:http/http.dart' as http; -import 'package:journal/app.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:path/path.dart' as p; -import 'package:journal/file_storage.dart'; +import 'package:journal/app.dart'; +import 'package:journal/state_container.dart'; /* import 'note.dart'; @@ -26,17 +21,7 @@ Future> fetchNotes() async { */ void main() { - runApp(new JournalApp( - fileStorage: FileStorage( - getDirectory: getNotesDir, - ), + runApp(new StateContainer( + child: JournalApp(), )); } - -Future getNotesDir() async { - var appDir = await getApplicationDocumentsDirectory(); - var dir = new Directory(p.join(appDir.path, "notes")); - await dir.create(); - - return dir; -} diff --git a/lib/note_editor.dart b/lib/note_editor.dart index f6faf41d..6d3bd862 100644 --- a/lib/note_editor.dart +++ b/lib/note_editor.dart @@ -1,20 +1,19 @@ import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; import 'package:journal/note.dart'; +import 'package:journal/state_container.dart'; class NoteEditor extends StatelessWidget { static final GlobalKey> noteTextKey = GlobalKey>(); - final NoteAdder noteAdder; final DateTime _createdAt; - NoteEditor({ - @required this.noteAdder, - }) : _createdAt = new DateTime.now(); + NoteEditor() : _createdAt = new DateTime.now(); @override Widget build(BuildContext context) { + final container = StateContainer.of(context); + var bodyWidget = new Container( child: new TextFormField( key: noteTextKey, @@ -44,7 +43,7 @@ class NoteEditor extends StatelessWidget { createdAt: _createdAt, body: body, ); - noteAdder(note); + container.addNote(note); Navigator.pop(context); }), diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index ee930723..000b57a0 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -1,24 +1,18 @@ import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; +import 'package:journal/state_container.dart'; import 'package:journal/widgets/journal_list.dart'; import 'package:journal/note.dart'; import 'package:journal/note_editor.dart'; import 'package:journal/note_viewer.dart'; class HomeScreen extends StatelessWidget { - final AppState appState; - final NoteAdder noteAdder; - final NoteRemover noteRemover; - - HomeScreen({ - @required this.appState, - @required this.noteAdder, - @required this.noteRemover, - }); - @override Widget build(BuildContext context) { + final container = StateContainer.of(context); + final appState = container.appState; + var createButton = new FloatingActionButton( onPressed: () => _newPost(context), child: new Icon(Icons.add), @@ -49,7 +43,6 @@ class HomeScreen extends StatelessWidget { body: new JournalList( notes: appState.notes, noteSelectedFunction: (note) => _noteSelected(note, context), - noteRemover: noteRemover, ), ); } @@ -61,10 +54,7 @@ class HomeScreen extends StatelessWidget { } void _newPost(BuildContext context) { - var route = new MaterialPageRoute( - builder: (context) => new NoteEditor( - noteAdder: noteAdder, - )); + var route = new MaterialPageRoute(builder: (context) => new NoteEditor()); Navigator.of(context).push(route); } } diff --git a/lib/state_container.dart b/lib/state_container.dart new file mode 100644 index 00000000..5558cf38 --- /dev/null +++ b/lib/state_container.dart @@ -0,0 +1,117 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:path/path.dart' as p; +import 'package:uuid/uuid.dart'; + +import 'package:journal/note.dart'; +import 'package:journal/file_storage.dart'; + +Future getNotesDir() async { + var appDir = await getApplicationDocumentsDirectory(); + var dir = new Directory(p.join(appDir.path, "notes")); + await dir.create(); + + return dir; +} + +class StateContainer extends StatefulWidget { + final FileStorage fileStorage; + final Widget child; + + StateContainer({ + @required this.child, + this.fileStorage = const FileStorage( + getDirectory: getNotesDir, + ), + }); + + static StateContainerState of(BuildContext context) { + return (context.inheritFromWidgetOfExactType(_InheritedStateContainer) + as _InheritedStateContainer) + .data; + } + + @override + State createState() { + return StateContainerState(); + } +} + +class StateContainerState extends State { + AppState appState = AppState.loading(); + + @override + void initState() { + super.initState(); + + widget.fileStorage.loadNotes().then((loadedNotes) { + setState(() { + appState = AppState(notes: loadedNotes); + }); + }).catchError((err) { + setState(() { + print("Got Error"); + print(err); + appState.isLoading = false; + }); + }); + } + + @override + void setState(VoidCallback fn) { + super.setState(fn); + + widget.fileStorage.saveNotes(appState.notes); + } + + void addNote(Note note) { + print("Adding a note " + note.toString()); + setState(() { + note.id = new Uuid().v4(); + appState.notes.insert(0, note); + }); + } + + void removeNote(Note note) { + setState(() { + appState.notes.remove(note); + }); + } + + // FIXME: Implement this! + void updateNote(Note note) { + setState(() { + //appState.notes. + //appState.notes.remove(note); + }); + } + + @override + Widget build(BuildContext context) { + return _InheritedStateContainer( + data: this, + child: widget.child, + ); + } +} + +class _InheritedStateContainer extends InheritedWidget { + final StateContainerState data; + + _InheritedStateContainer({ + Key key, + @required this.data, + @required Widget child, + }) : super(key: key, child: child); + + // Note: we could get fancy here and compare whether the old AppState is + // different than the current AppState. However, since we know this is the + // root Widget, when we make changes we also know we want to rebuild Widgets + // that depend on the StateContainer. + @override + bool updateShouldNotify(_InheritedStateContainer old) => true; +} diff --git a/lib/widgets/journal_list.dart b/lib/widgets/journal_list.dart index 714a21d5..0ffc9036 100644 --- a/lib/widgets/journal_list.dart +++ b/lib/widgets/journal_list.dart @@ -3,12 +3,12 @@ import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; import 'package:journal/note.dart'; +import 'package:journal/state_container.dart'; typedef void NoteSelectedFunction(Note note); class JournalList extends StatelessWidget { final NoteSelectedFunction noteSelectedFunction; - final NoteRemover noteRemover; final List notes; final _biggerFont = const TextStyle(fontSize: 18.0); @@ -16,11 +16,12 @@ class JournalList extends StatelessWidget { JournalList({ @required this.notes, @required this.noteSelectedFunction, - @required this.noteRemover, }); @override Widget build(BuildContext context) { + final container = StateContainer.of(context); + return new ListView.builder( padding: const EdgeInsets.all(8.0), itemBuilder: (context, i) { @@ -35,7 +36,7 @@ class JournalList extends StatelessWidget { child: _buildRow(context, note), background: new Container(color: Colors.red), onDismissed: (direction) { - noteRemover(note); + container.removeNote(note); Scaffold .of(context)