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.
This commit is contained in:
Vishesh Handa
2018-05-24 12:33:46 +02:00
parent 98ece86579
commit b6c38dde3c
7 changed files with 139 additions and 113 deletions

View File

@ -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<JournalApp> {
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<JournalApp> {
),
);
}
@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);
});
}
}

View File

@ -10,7 +10,7 @@ import './note.dart';
class FileStorage {
final Future<Directory> Function() getDirectory;
FileStorage({@required this.getDirectory});
const FileStorage({@required this.getDirectory});
Future<List<Note>> loadNotes() async {
final dir = await getDirectory();

View File

@ -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<List<Note>> fetchNotes() async {
*/
void main() {
runApp(new JournalApp(
fileStorage: FileStorage(
getDirectory: getNotesDir,
),
runApp(new StateContainer(
child: JournalApp(),
));
}
Future<Directory> getNotesDir() async {
var appDir = await getApplicationDocumentsDirectory();
var dir = new Directory(p.join(appDir.path, "notes"));
await dir.create();
return dir;
}

View File

@ -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<FormFieldState<String>> noteTextKey =
GlobalKey<FormFieldState<String>>();
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);
}),

View File

@ -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);
}
}

117
lib/state_container.dart Normal file
View File

@ -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<Directory> 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<StatefulWidget> createState() {
return StateContainerState();
}
}
class StateContainerState extends State<StateContainer> {
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;
}

View File

@ -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<Note> 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)