Skip to content

Instantly share code, notes, and snippets.

View xinthink's full-sized avatar

Yingxin Wu xinthink

View GitHub Profile
extension NoteStateX on NoteState {
/// Checks if a note in this state can be edited.
bool get canEdit => this < NoteState.deleted;
/// Returns true if this state is preceding to the other one.
bool operator <(NoteState other) => (this?.index ?? 0) < (other?.index ?? 0);
/// Message describes the state transition.
String get message {
switch (this) {
/// Save the note before the editor is dismissed
Future<dynamic> _onPop(String uid) => _isDirty
? _note.saveToFireStore(uid)
: Future.value();
extension NoteStore on Note {
/// Save this note to FireStore.
Future<dynamic> saveToFireStore(String uid) async {
final col = notesCollection(uid);
return id == null
? col.add(toJson())
: col.document(id).updateData(toJson());
}
...
}
class _HomeScreenState extends State<HomeScreen> with CommandHandler {
Widget _fab(BuildContext context) => FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () async {
final command = await Navigator.pushNamed(context, '/note');
processNoteCommand(_scaffoldKey.currentState, command);
},
);
...
}
mixin CommandHandler<T extends StatefulWidget> on State<T> {
/// Processes the given [command].
Future<void> processNoteCommand(ScaffoldState scaffoldState, NoteCommand command) async {
if (command == null) {
return;
}
await command.execute();
final msg = command.message;
if (mounted && msg?.isNotEmpty == true) {
scaffoldState?.showSnackBar(SnackBar(
@override
Widget build(BuildContext context) {
final uid = Provider.of<CurrentUser>(context).data.uid;
return ChangeNotifierProvider.value(
value: _note,
child: Consumer<Note>(
builder: (_, __, ___) => Hero(
tag: 'NoteItem${_note.id}',
child: DefaultTextStyle(
style: ...
// in the note list
@override
Widget build(BuildContext context) => Hero(
tag: 'NoteItem${note.id}',
child: DefaultTextStyle(
style: kNoteTextLight,
child: Container(
...
),
),
// when pressed, dissmiss the bottom sheet and return a command
IconButton(
icon: const Icon(Icons.archive),
tooltip: 'Archive',
onPressed: () => Navigator.pop(context, NoteStateUpdateCommand(
id: _note.id,
uid: uid,
from: _note.state, // the current state
to: NoteState.archived, // the transition target
)),
class NoteStateUpdateCommand extends NoteCommand {
final NoteState from;
final NoteState to;
/// Create a [NoteCommand] to update state of a note [from] the current state [to] another.
NoteStateUpdateCommand({
@required String id,
@required String uid,
@required this.from,
@required this.to,
abstract class NoteCommand {
final String id;
final String uid;
/// Defines an reversible action to a note, provides the note [id], and the current user's [uid].
const NoteCommand({
@required this.id,
@required this.uid,
});