diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 60383e94..cea4dfc5 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:app/pages/read_only_page.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_quill/models/documents/document.dart'; @@ -55,6 +56,10 @@ class _HomePageState extends State { ), actions: [], ), + drawer: Material( + color: Colors.grey.shade800, + child: _buildMenuBar(context), + ), body: _buildWelcomeEditor(context), ); } @@ -84,4 +89,29 @@ class _HomePageState extends State { ], ); } + + Widget _buildMenuBar(BuildContext context) { + final headerStyle = TextStyle( + fontSize: 11, color: Colors.grey.shade500, fontWeight: FontWeight.bold); + final itemStyle = TextStyle(color: Colors.white); + return ListView( + children: [ + ListTile( + title: Text('Read only demo', style: itemStyle), + dense: true, + visualDensity: VisualDensity.compact, + onTap: _readOnly, + ) + ], + ); + } + + void _readOnly() { + Navigator.push( + context, + MaterialPageRoute( + builder: (BuildContext context) => ReadOnlyPage(), + ), + ); + } } diff --git a/app/lib/pages/read_only_page.dart b/app/lib/pages/read_only_page.dart new file mode 100644 index 00000000..30857bc1 --- /dev/null +++ b/app/lib/pages/read_only_page.dart @@ -0,0 +1,57 @@ +import 'package:app/widgets/demo_scaffold.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_quill/widgets/controller.dart'; +import 'package:flutter_quill/widgets/editor.dart'; + +class ReadOnlyPage extends StatefulWidget { + @override + _ReadOnlyPageState createState() => _ReadOnlyPageState(); +} + +class _ReadOnlyPageState extends State { + final FocusNode _focusNode = FocusNode(); + + bool _edit = false; + + @override + Widget build(BuildContext context) { + return DemoScaffold( + documentFilename: 'sample_data.json', + builder: _buildContent, + showToolbar: _edit == true, + floatingActionButton: FloatingActionButton.extended( + label: Text(_edit == true ? 'Done' : 'Edit'), + onPressed: _toggleEdit, + icon: Icon(_edit == true ? Icons.check : Icons.edit)), + ); + } + + Widget _buildContent(BuildContext context, QuillController controller) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.grey.shade200), + ), + child: QuillEditor( + controller: controller, + scrollController: ScrollController(), + scrollable: true, + focusNode: _focusNode, + autoFocus: true, + readOnly: !_edit, + enableInteractiveSelection: true, + expands: false, + padding: EdgeInsets.zero, + ), + ), + ); + } + + void _toggleEdit() { + setState(() { + _edit = !_edit; + }); + } +} diff --git a/app/lib/widgets/demo_scaffold.dart b/app/lib/widgets/demo_scaffold.dart new file mode 100644 index 00000000..a2ae3918 --- /dev/null +++ b/app/lib/widgets/demo_scaffold.dart @@ -0,0 +1,107 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_quill/models/documents/document.dart'; +import 'package:flutter_quill/widgets/controller.dart'; +import 'package:flutter_quill/widgets/toolbar.dart'; + + +typedef DemoContentBuilder = Widget Function( + BuildContext context, QuillController controller); + +// Common scaffold for all examples. +class DemoScaffold extends StatefulWidget { + /// Filename of the document to load into the editor. + final String documentFilename; + final DemoContentBuilder builder; + final List actions; + final Widget floatingActionButton; + final bool showToolbar; + + const DemoScaffold({ + Key key, + @required this.documentFilename, + @required this.builder, + this.actions, + this.showToolbar = true, + this.floatingActionButton, + }) : super(key: key); + + @override + _DemoScaffoldState createState() => _DemoScaffoldState(); +} + +class _DemoScaffoldState extends State { + final _scaffoldKey = GlobalKey(); + QuillController _controller; + + bool _loading = false; + bool _canSave = false; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (_controller == null && !_loading) { + _loading = true; + _loadFromAssets(); + } + } + + @override + void dispose() { + _controller?.dispose(); + super.dispose(); + } + + Future _loadFromAssets() async { + try { + final result = + await rootBundle.loadString('assets/${widget.documentFilename}'); + final doc = Document.fromJson(jsonDecode(result)); + setState(() { + _controller = QuillController( + document: doc, selection: TextSelection.collapsed(offset: 0)); + _loading = false; + }); + } catch (error) { + final doc = Document()..insert(0, 'Empty asset'); + setState(() { + _controller = QuillController( + document: doc, selection: TextSelection.collapsed(offset: 0)); + _loading = false; + }); + } + } + + + @override + Widget build(BuildContext context) { + final actions = widget.actions ?? []; + return Scaffold( + key: _scaffoldKey, + appBar: AppBar( + elevation: 0, + backgroundColor: Theme.of(context).canvasColor, + centerTitle: false, + titleSpacing: 0, + leading: IconButton( + icon: Icon( + Icons.chevron_left, + color: Colors.grey.shade800, + size: 18, + ), + onPressed: () => Navigator.pop(context), + ), + title: _loading || widget.showToolbar == false + ? null + : QuillToolbar.basic(controller: _controller), + actions: actions, + ), + floatingActionButton: widget.floatingActionButton, + body: _loading + ? Center(child: Text('Loading...')) + : widget.builder(context, _controller), + ); + } +}