Split the Standard Folder View

This way its code can more easily be shared
This commit is contained in:
Vishesh Handa
2020-03-05 18:23:33 +01:00
parent db901e51ea
commit 846dda252e
2 changed files with 159 additions and 123 deletions

View File

@ -0,0 +1,151 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/core/note.dart';
import 'package:gitjournal/core/notes_folder.dart';
import 'package:gitjournal/state_container.dart';
import 'package:gitjournal/utils.dart';
import 'package:gitjournal/widgets/icon_dismissable.dart';
typedef void NoteSelectedFunction(Note note);
typedef Widget NoteTileBuilder(BuildContext context, Note note);
class FolderListView extends StatefulWidget {
final NoteTileBuilder noteTileBuilder;
final NoteSelectedFunction noteSelectedFunction;
final NotesFolderReadOnly folder;
final String emptyText;
FolderListView({
@required this.folder,
@required this.noteTileBuilder,
@required this.noteSelectedFunction,
@required this.emptyText,
});
@override
_FolderListViewState createState() => _FolderListViewState();
}
class _FolderListViewState extends State<FolderListView> {
var _listKey = GlobalKey<AnimatedListState>();
var deletedViaDismissed = <String>[];
@override
void initState() {
super.initState();
widget.folder.addNoteAddedListener(_noteAdded);
widget.folder.addNoteRemovedListener(_noteRemoved);
widget.folder.addListener(_folderChanged);
}
@override
void dispose() {
widget.folder.removeNoteAddedListener(_noteAdded);
widget.folder.removeNoteRemovedListener(_noteRemoved);
widget.folder.removeListener(_folderChanged);
super.dispose();
}
void _noteAdded(int index, Note _) {
if (_listKey.currentState == null) {
return;
}
_listKey.currentState.insertItem(index);
}
void _noteRemoved(int index, Note note) {
if (_listKey.currentState == null) {
return;
}
_listKey.currentState.removeItem(index, (context, animation) {
var i = deletedViaDismissed.indexWhere((path) => path == note.filePath);
if (i == -1) {
return _buildNote(context, note, animation);
} else {
deletedViaDismissed.removeAt(i);
return Container();
}
});
}
void _folderChanged() {
setState(() {});
}
@override
Widget build(BuildContext context) {
if (widget.folder.notes.isEmpty) {
return Center(
child: Text(
widget.emptyText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 28.0,
fontWeight: FontWeight.w300,
color: Colors.grey[350],
),
),
);
}
return AnimatedList(
key: _listKey,
itemBuilder: _buildItem,
initialItemCount: widget.folder.notes.length,
);
}
Widget _buildItem(BuildContext context, int i, Animation<double> animation) {
// vHanda FIXME: Why does this method get called with i >= length ?
if (i >= widget.folder.notes.length) {
return Container();
}
var note = widget.folder.notes[i];
return _buildNote(context, note, animation);
}
Widget _buildNote(
BuildContext context,
Note note,
Animation<double> animation,
) {
var viewItem = IconDismissable(
key: ValueKey("FolderListView_" + note.filePath),
child: Hero(
tag: note.filePath,
child: widget.noteTileBuilder(context, note),
flightShuttleBuilder: (BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext) =>
Material(child: toHeroContext.widget),
),
backgroundColor: Colors.red[800],
iconData: Icons.delete,
onDismissed: (direction) {
deletedViaDismissed.add(note.filePath);
var stateContainer =
Provider.of<StateContainer>(context, listen: false);
stateContainer.removeNote(note);
var snackBar = buildUndoDeleteSnackbar(context, note);
Scaffold.of(context).showSnackBar(snackBar);
},
);
return SizeTransition(
key: ValueKey("FolderListView_tr_" + note.filePath),
axis: Axis.vertical,
sizeFactor: animation,
child: viewItem,
);
}
}

View File

@ -1,20 +1,15 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gitjournal/folder_views/list_view.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/core/sorting_mode.dart';
import 'package:gitjournal/settings.dart';
import 'package:gitjournal/core/note.dart';
import 'package:gitjournal/core/notes_folder.dart';
import 'package:gitjournal/state_container.dart';
import 'package:gitjournal/utils.dart';
import 'package:gitjournal/widgets/icon_dismissable.dart';
typedef void NoteSelectedFunction(Note note);
class StandardView extends StatefulWidget {
class StandardView extends StatelessWidget {
final NoteSelectedFunction noteSelectedFunction;
final NotesFolderReadOnly folder;
final String emptyText;
@ -26,123 +21,13 @@ class StandardView extends StatefulWidget {
});
@override
_StandardViewState createState() => _StandardViewState();
}
class _StandardViewState extends State<StandardView> {
var _listKey = GlobalKey<AnimatedListState>();
var deletedViaDismissed = <String>[];
@override
void initState() {
super.initState();
widget.folder.addNoteAddedListener(_noteAdded);
widget.folder.addNoteRemovedListener(_noteRemoved);
widget.folder.addListener(_folderChanged);
}
@override
void dispose() {
widget.folder.removeNoteAddedListener(_noteAdded);
widget.folder.removeNoteRemovedListener(_noteRemoved);
widget.folder.removeListener(_folderChanged);
super.dispose();
}
void _noteAdded(int index, Note _) {
if (_listKey.currentState == null) {
return;
}
_listKey.currentState.insertItem(index);
}
void _noteRemoved(int index, Note note) {
if (_listKey.currentState == null) {
return;
}
_listKey.currentState.removeItem(index, (context, animation) {
var i = deletedViaDismissed.indexWhere((path) => path == note.filePath);
if (i == -1) {
return _buildNote(context, note, animation);
} else {
deletedViaDismissed.removeAt(i);
return Container();
}
});
}
void _folderChanged() {
setState(() {});
}
@override
Widget build(BuildContext context) {
if (widget.folder.notes.isEmpty) {
return Center(
child: Text(
widget.emptyText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 28.0,
fontWeight: FontWeight.w300,
color: Colors.grey[350],
),
),
);
}
return AnimatedList(
key: _listKey,
itemBuilder: _buildItem,
initialItemCount: widget.folder.notes.length,
);
}
Widget _buildItem(BuildContext context, int i, Animation<double> animation) {
// vHanda FIXME: Why does this method get called with i >= length ?
if (i >= widget.folder.notes.length) {
return Container();
}
var note = widget.folder.notes[i];
return _buildNote(context, note, animation);
}
Widget _buildNote(
BuildContext context, Note note, Animation<double> animation) {
var viewItem = IconDismissable(
key: ValueKey("StandardView_" + note.filePath),
child: Hero(
tag: note.filePath,
child: _buildRow(context, note),
flightShuttleBuilder: (BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext) =>
Material(child: toHeroContext.widget),
),
backgroundColor: Colors.red[800],
iconData: Icons.delete,
onDismissed: (direction) {
deletedViaDismissed.add(note.filePath);
var stateContainer =
Provider.of<StateContainer>(context, listen: false);
stateContainer.removeNote(note);
var snackBar = buildUndoDeleteSnackbar(context, note);
Scaffold.of(context).showSnackBar(snackBar);
},
);
return SizeTransition(
key: ValueKey("StandardView_tr_" + note.filePath),
axis: Axis.vertical,
sizeFactor: animation,
child: viewItem,
return FolderListView(
folder: folder,
noteSelectedFunction: noteSelectedFunction,
emptyText: emptyText,
noteTileBuilder: _buildRow,
);
}
@ -196,7 +81,7 @@ class _StandardViewState extends State<StandardView> {
children: children,
crossAxisAlignment: CrossAxisAlignment.start,
),
onTap: () => widget.noteSelectedFunction(note),
onTap: () => noteSelectedFunction(note),
);
var dc = Theme.of(context).dividerColor;