Skip to content

Commit 626b50a

Browse files
committed
Make editor toolbar float to improve appearance on iOS 26
This isn't immediately required thanks to deb48d5 but will be eventually See #194
1 parent 52d59f8 commit 626b50a

1 file changed

Lines changed: 191 additions & 160 deletions

File tree

lib/src/pages/editor/editor.dart

Lines changed: 191 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -152,25 +152,26 @@ class _EditorPageState extends State<EditorPage> with RestorationMixin {
152152
),
153153
],
154154
),
155-
body: Column(
155+
body: Stack(
156156
// mainAxisSize: MainAxisSize.min,
157157
children: [
158-
Expanded(
159-
child: TextField(
160-
controller: _controller.value,
161-
undoController: _undoController,
162-
scrollController: PrimaryScrollController.of(context),
163-
focusNode: _focusNode,
164-
maxLines: null,
165-
expands: true,
166-
decoration: const InputDecoration(
167-
border: InputBorder.none,
168-
contentPadding: EdgeInsets.symmetric(horizontal: 8),
169-
),
170-
style: _textStyle,
158+
TextField(
159+
controller: _controller.value,
160+
undoController: _undoController,
161+
scrollController: PrimaryScrollController.of(context),
162+
focusNode: _focusNode,
163+
maxLines: null,
164+
expands: true,
165+
decoration: const InputDecoration(
166+
border: InputBorder.none,
167+
contentPadding: EdgeInsets.symmetric(horizontal: 8),
171168
),
169+
style: _textStyle,
170+
),
171+
Align(
172+
alignment: Alignment.bottomCenter,
173+
child: _EditorToolbar(undoController: _undoController),
172174
),
173-
_EditorToolbar(undoController: _undoController),
174175
],
175176
),
176177
),
@@ -205,153 +206,183 @@ class _EditorToolbar extends StatelessWidget {
205206

206207
@override
207208
Widget build(BuildContext context) {
208-
return Container(
209-
decoration: BoxDecoration(
210-
color: Theme.of(context).highlightColor,
211-
border: Border(
212-
top: BorderSide(color: Theme.of(context).dividerColor, width: 1),
213-
),
214-
),
215-
width: double.infinity,
216-
child: SafeArea(
217-
child: SingleChildScrollView(
218-
scrollDirection: Axis.horizontal,
219-
padding: const EdgeInsets.symmetric(horizontal: 8),
220-
child: Row(
221-
children: [
222-
ValueListenableBuilder(
223-
valueListenable: undoController,
224-
builder: (context, value, _) => IconButton(
225-
tooltip: AppLocalizations.of(context)!.tooltipUndo,
226-
icon: const Icon(Icons.undo),
227-
onPressed: value.canUndo ? undoController.undo : null,
228-
),
229-
),
230-
ValueListenableBuilder(
231-
valueListenable: undoController,
232-
builder: (context, value, _) => IconButton(
233-
tooltip: AppLocalizations.of(context)!.tooltipRedo,
234-
icon: const Icon(Icons.redo),
235-
onPressed: value.canRedo ? undoController.redo : null,
236-
),
237-
),
238-
IconButton(
239-
tooltip: AppLocalizations.of(context)!.tooltipInsertHeadline,
240-
icon: const Icon(Icons.emergency),
241-
onPressed: Actions.handler(
242-
context,
243-
const InsertHeadlineIntent(),
244-
),
245-
),
246-
IconButton(
247-
tooltip: AppLocalizations.of(
248-
context,
249-
)!.tooltipToggleUnorderedList,
250-
icon: const Icon(Icons.format_list_bulleted),
251-
onPressed: Actions.handler(
252-
context,
253-
const ToggleListItemIntent(ordered: false),
254-
),
255-
),
256-
IconButton(
257-
tooltip: AppLocalizations.of(context)!.tooltipToggleOrderedList,
258-
icon: const Icon(Icons.format_list_numbered),
259-
onPressed: Actions.handler(
260-
context,
261-
const ToggleListItemIntent(ordered: true),
262-
),
263-
),
264-
IconButton(
265-
tooltip: AppLocalizations.of(context)!.tooltipDecreaseIndent,
266-
icon: const Icon(Icons.format_indent_decrease),
267-
onPressed: Actions.handler(
268-
context,
269-
const ChangeIndentIntent(increase: false),
270-
),
271-
),
272-
IconButton(
273-
tooltip: AppLocalizations.of(context)!.tooltipIncreaseIndent,
274-
icon: const Icon(Icons.format_indent_increase),
275-
onPressed: Actions.handler(
276-
context,
277-
const ChangeIndentIntent(increase: true),
278-
),
279-
),
280-
IconButton(
281-
tooltip: AppLocalizations.of(context)!.tooltipBold,
282-
icon: const Icon(Icons.format_bold),
283-
onPressed: Actions.handler(context, const MakeBoldIntent()),
284-
),
285-
IconButton(
286-
tooltip: AppLocalizations.of(context)!.tooltipItalic,
287-
icon: const Icon(Icons.format_italic),
288-
onPressed: Actions.handler(context, const MakeItalicIntent()),
289-
),
290-
IconButton(
291-
tooltip: AppLocalizations.of(context)!.tooltipUnderline,
292-
icon: const Icon(Icons.format_underline),
293-
onPressed: Actions.handler(
294-
context,
295-
const MakeUnderlineIntent(),
296-
),
297-
),
298-
IconButton(
299-
tooltip: AppLocalizations.of(context)!.tooltipStrikethrough,
300-
icon: const Icon(Icons.format_strikethrough),
301-
onPressed: Actions.handler(
302-
context,
303-
const MakeStrikethroughIntent(),
304-
),
305-
),
306-
IconButton(
307-
tooltip: AppLocalizations.of(context)!.tooltipCode,
308-
icon: const Icon(Icons.code),
309-
onPressed: Actions.handler(context, const MakeCodeIntent()),
310-
),
311-
IconButton(
312-
tooltip: AppLocalizations.of(context)!.tooltipInsertLink,
313-
icon: const Icon(Icons.link),
314-
onPressed: Actions.handler(context, const InsertLinkIntent()),
315-
),
316-
IconButton(
317-
tooltip: AppLocalizations.of(context)!.tooltipInsertDate,
318-
icon: const Icon(Icons.calendar_today),
319-
onPressed: Actions.handler(
320-
context,
321-
const InsertDateIntent(active: false),
322-
),
323-
onLongPress: Actions.handler(
324-
context,
325-
const InsertDateIntent(active: true),
326-
),
327-
),
328-
IconButton(
329-
tooltip: AppLocalizations.of(context)!.tooltipSubscript,
330-
icon: const Icon(Icons.subscript),
331-
onPressed: Actions.handler(
332-
context,
333-
const MakeSubscriptIntent(),
334-
),
335-
),
336-
IconButton(
337-
tooltip: AppLocalizations.of(context)!.tooltipSuperscript,
338-
icon: const Icon(Icons.superscript),
339-
onPressed: Actions.handler(
340-
context,
341-
const MakeSuperscriptIntent(),
342-
),
343-
),
344-
IconButton(
345-
tooltip: AppLocalizations.of(context)!.tooltipEncryptSection,
346-
icon: const Icon(Icons.lock_outline),
347-
onPressed: Actions.handler(
348-
context,
349-
const EncryptSectionIntent(),
209+
return SafeArea(
210+
child: Padding(
211+
padding: const EdgeInsets.all(8),
212+
child: Material(
213+
child: Container(
214+
decoration: BoxDecoration(
215+
color: Theme.of(context).highlightColor,
216+
borderRadius: const BorderRadius.all(Radius.circular(12)),
217+
),
218+
width: double.infinity,
219+
child: SingleChildScrollView(
220+
scrollDirection: Axis.horizontal,
221+
padding: const EdgeInsets.symmetric(horizontal: 8),
222+
child: TooltipTheme(
223+
data: TooltipTheme.of(context).copyWith(preferBelow: false),
224+
child: Row(
225+
children: [
226+
ValueListenableBuilder(
227+
valueListenable: undoController,
228+
builder: (context, value, _) => IconButton(
229+
tooltip: AppLocalizations.of(context)!.tooltipUndo,
230+
icon: const Icon(Icons.undo),
231+
onPressed: value.canUndo ? undoController.undo : null,
232+
),
233+
),
234+
ValueListenableBuilder(
235+
valueListenable: undoController,
236+
builder: (context, value, _) => IconButton(
237+
tooltip: AppLocalizations.of(context)!.tooltipRedo,
238+
icon: const Icon(Icons.redo),
239+
onPressed: value.canRedo ? undoController.redo : null,
240+
),
241+
),
242+
IconButton(
243+
tooltip: AppLocalizations.of(
244+
context,
245+
)!.tooltipInsertHeadline,
246+
icon: const Icon(Icons.emergency),
247+
onPressed: Actions.handler(
248+
context,
249+
const InsertHeadlineIntent(),
250+
),
251+
),
252+
IconButton(
253+
tooltip: AppLocalizations.of(
254+
context,
255+
)!.tooltipToggleUnorderedList,
256+
icon: const Icon(Icons.format_list_bulleted),
257+
onPressed: Actions.handler(
258+
context,
259+
const ToggleListItemIntent(ordered: false),
260+
),
261+
),
262+
IconButton(
263+
tooltip: AppLocalizations.of(
264+
context,
265+
)!.tooltipToggleOrderedList,
266+
icon: const Icon(Icons.format_list_numbered),
267+
onPressed: Actions.handler(
268+
context,
269+
const ToggleListItemIntent(ordered: true),
270+
),
271+
),
272+
IconButton(
273+
tooltip: AppLocalizations.of(
274+
context,
275+
)!.tooltipDecreaseIndent,
276+
icon: const Icon(Icons.format_indent_decrease),
277+
onPressed: Actions.handler(
278+
context,
279+
const ChangeIndentIntent(increase: false),
280+
),
281+
),
282+
IconButton(
283+
tooltip: AppLocalizations.of(
284+
context,
285+
)!.tooltipIncreaseIndent,
286+
icon: const Icon(Icons.format_indent_increase),
287+
onPressed: Actions.handler(
288+
context,
289+
const ChangeIndentIntent(increase: true),
290+
),
291+
),
292+
IconButton(
293+
tooltip: AppLocalizations.of(context)!.tooltipBold,
294+
icon: const Icon(Icons.format_bold),
295+
onPressed: Actions.handler(
296+
context,
297+
const MakeBoldIntent(),
298+
),
299+
),
300+
IconButton(
301+
tooltip: AppLocalizations.of(context)!.tooltipItalic,
302+
icon: const Icon(Icons.format_italic),
303+
onPressed: Actions.handler(
304+
context,
305+
const MakeItalicIntent(),
306+
),
307+
),
308+
IconButton(
309+
tooltip: AppLocalizations.of(context)!.tooltipUnderline,
310+
icon: const Icon(Icons.format_underline),
311+
onPressed: Actions.handler(
312+
context,
313+
const MakeUnderlineIntent(),
314+
),
315+
),
316+
IconButton(
317+
tooltip: AppLocalizations.of(
318+
context,
319+
)!.tooltipStrikethrough,
320+
icon: const Icon(Icons.format_strikethrough),
321+
onPressed: Actions.handler(
322+
context,
323+
const MakeStrikethroughIntent(),
324+
),
325+
),
326+
IconButton(
327+
tooltip: AppLocalizations.of(context)!.tooltipCode,
328+
icon: const Icon(Icons.code),
329+
onPressed: Actions.handler(
330+
context,
331+
const MakeCodeIntent(),
332+
),
333+
),
334+
IconButton(
335+
tooltip: AppLocalizations.of(context)!.tooltipInsertLink,
336+
icon: const Icon(Icons.link),
337+
onPressed: Actions.handler(
338+
context,
339+
const InsertLinkIntent(),
340+
),
341+
),
342+
IconButton(
343+
tooltip: AppLocalizations.of(context)!.tooltipInsertDate,
344+
icon: const Icon(Icons.calendar_today),
345+
onPressed: Actions.handler(
346+
context,
347+
const InsertDateIntent(active: false),
348+
),
349+
onLongPress: Actions.handler(
350+
context,
351+
const InsertDateIntent(active: true),
352+
),
353+
),
354+
IconButton(
355+
tooltip: AppLocalizations.of(context)!.tooltipSubscript,
356+
icon: const Icon(Icons.subscript),
357+
onPressed: Actions.handler(
358+
context,
359+
const MakeSubscriptIntent(),
360+
),
361+
),
362+
IconButton(
363+
tooltip: AppLocalizations.of(context)!.tooltipSuperscript,
364+
icon: const Icon(Icons.superscript),
365+
onPressed: Actions.handler(
366+
context,
367+
const MakeSuperscriptIntent(),
368+
),
369+
),
370+
IconButton(
371+
tooltip: AppLocalizations.of(
372+
context,
373+
)!.tooltipEncryptSection,
374+
icon: const Icon(Icons.lock_outline),
375+
onPressed: Actions.handler(
376+
context,
377+
const EncryptSectionIntent(),
378+
),
379+
),
380+
// TODO(aaron): Offer more quick-insert actions?
381+
// - Code blocks
382+
],
350383
),
351384
),
352-
// TODO(aaron): Offer more quick-insert actions?
353-
// - Code blocks
354-
],
385+
),
355386
),
356387
),
357388
),

0 commit comments

Comments
 (0)