💄 Optimize post editor

This commit is contained in:
LittleSheep 2024-10-08 00:06:08 +08:00
parent 606a0d708a
commit 442ef06147
2 changed files with 177 additions and 116 deletions

View File

@ -273,116 +273,69 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
), ),
if (_isBusy) const LinearProgressIndicator().animate().scaleX(), if (_isBusy) const LinearProgressIndicator().animate().scaleX(),
Expanded( Expanded(
child: Row( child: DefaultTabController(
crossAxisAlignment: CrossAxisAlignment.start, length: 2,
children: [ child: AppTheme.isLargeScreen(context)
Expanded( ? Row(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: ListView( child: _PostEditorTextField(
children: [ focusNode: _contentFocusNode,
Container( controller: _editorController,
padding: const EdgeInsets.symmetric( onUpdate: () => setState(() {}),
horizontal: 16, ),
vertical: 8, ),
), const VerticalDivider(width: 0.3, thickness: 0.3)
child: TextField( .paddingSymmetric(horizontal: 16),
maxLines: null, Expanded(
autofocus: true, child: SingleChildScrollView(
autocorrect: true, padding:
keyboardType: TextInputType.multiline, const EdgeInsets.only(top: 12, bottom: 64),
controller: child: MarkdownTextContent(
_editorController.contentController, isAutoWarp: _editorController.mode.value == 0,
focusNode: _contentFocusNode, content:
decoration: InputDecoration.collapsed( _editorController.contentController.text,
hintText: 'postContentPlaceholder'.tr, parentId: 'post-editor-preview',
), ).paddingOnly(right: 16),
onTapOutside: (_) => FocusManager ),
.instance.primaryFocus ),
?.unfocus(), ],
), )
), : Column(
const Gap(120) children: [
TabBar(
tabs: [
const Tab(icon: Icon(Icons.edit)),
const Tab(icon: Icon(Icons.preview)),
], ],
), ),
), Expanded(
Obx(() { child: TabBarView(
final textStyle = TextStyle(
fontSize: 12,
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.75),
);
final showFactors = [
_editorController.isRestoreFromLocal.value,
_editorController.lastSaveTime.value != null,
];
final doShow = showFactors.any((x) => x);
return Container(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 16,
),
child: Row(
children: [ children: [
if (showFactors[0]) _PostEditorTextField(
Text('postRestoreFromLocal'.tr, focusNode: _contentFocusNode,
style: textStyle) controller: _editorController,
.paddingOnly(right: 4), onUpdate: () => setState(() {}),
if (showFactors[0]) ),
InkWell( SingleChildScrollView(
child: Text('clear'.tr, style: textStyle), padding: const EdgeInsets.only(
onTap: () { top: 12,
_editorController.localClear(); bottom: 64,
_editorController.currentClear();
setState(() {});
},
),
if (showFactors.where((x) => x).length > 1)
Text(
'·',
style: textStyle,
).paddingSymmetric(horizontal: 8),
if (showFactors[1])
Text(
'postAutoSaveAt'.trParams({
'date': DateFormat('HH:mm:ss').format(
_editorController.lastSaveTime.value ??
DateTime.now(),
)
}),
style: textStyle,
), ),
child: MarkdownTextContent(
isAutoWarp:
_editorController.mode.value == 0,
content: _editorController
.contentController.text,
parentId: 'post-editor-preview',
).paddingOnly(left: 16, right: 16),
)
], ],
), ),
) ),
.animate( ],
key: const Key('post-editor-hint-animation'),
target: doShow ? 1 : 0,
)
.fade(curve: Curves.easeInOut, duration: 300.ms);
}),
],
),
),
if (AppTheme.isLargeScreen(context))
const VerticalDivider(width: 0.3, thickness: 0.3)
.paddingSymmetric(
horizontal: 16,
),
if (AppTheme.isLargeScreen(context))
Expanded(
child: SingleChildScrollView(
child: MarkdownTextContent(
isAutoWarp: _editorController.mode.value == 0,
content: _editorController.contentController.text,
parentId: 'post-editor-preview',
).paddingOnly(top: 12, right: 16),
), ),
),
],
), ),
), ),
Material( Material(
@ -391,6 +344,26 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Divider(thickness: 0.3, height: 0.3), const Divider(thickness: 0.3, height: 0.3),
SizedBox(
height: 40,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: MarkdownToolbar(
width: 38,
height: 38,
iconSize: 20,
spacing: 8,
hideImage: true,
useIncludedTextField: false,
backgroundColor: Theme.of(context).colorScheme.surface,
iconColor: Theme.of(context).colorScheme.onSurface,
controller: _editorController.contentController,
focusNode: _contentFocusNode,
borderRadius:
const BorderRadius.all(Radius.circular(20)),
).paddingSymmetric(horizontal: 12),
),
).paddingOnly(top: 12),
SizedBox( SizedBox(
height: 56, height: 56,
child: ListView( child: ListView(
@ -520,7 +493,7 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
top: -4, top: -4,
end: -6, end: -6,
), ),
child: const Icon(Icons.preview), child: const Icon(Icons.wallpaper),
); );
}), }),
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
@ -547,18 +520,6 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
_editorController.editPublishDate(context); _editorController.editPublishDate(context);
}, },
), ),
MarkdownToolbar(
hideImage: true,
useIncludedTextField: false,
backgroundColor:
Theme.of(context).colorScheme.surface,
iconColor: Theme.of(context).colorScheme.onSurface,
controller: _editorController.contentController,
focusNode: _contentFocusNode,
borderRadius:
const BorderRadius.all(Radius.circular(20)),
width: 40,
).paddingSymmetric(horizontal: 2),
], ],
).paddingSymmetric(horizontal: 6, vertical: 8), ).paddingSymmetric(horizontal: 6, vertical: 8),
), ),
@ -578,3 +539,102 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
super.dispose(); super.dispose();
} }
} }
class _PostEditorTextField extends StatelessWidget {
final FocusNode focusNode;
final PostEditorController controller;
final Function onUpdate;
const _PostEditorTextField({
super.key,
required this.focusNode,
required this.controller,
required this.onUpdate,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: ListView(
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: TextField(
maxLines: null,
autofocus: true,
autocorrect: true,
keyboardType: TextInputType.multiline,
controller: controller.contentController,
focusNode: focusNode,
decoration: InputDecoration.collapsed(
hintText: 'postContentPlaceholder'.tr,
),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
),
const Gap(120)
],
),
),
Obx(() {
final textStyle = TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.75),
);
final showFactors = [
controller.isRestoreFromLocal.value,
controller.lastSaveTime.value != null,
];
final doShow = showFactors.any((x) => x);
return Container(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 16,
),
child: Row(
children: [
if (showFactors[0])
Text('postRestoreFromLocal'.tr, style: textStyle)
.paddingOnly(right: 4),
if (showFactors[0])
InkWell(
child: Text('clear'.tr, style: textStyle),
onTap: () {
controller.localClear();
controller.currentClear();
onUpdate();
},
),
if (showFactors.where((x) => x).length > 1)
Text(
'·',
style: textStyle,
).paddingSymmetric(horizontal: 8),
if (showFactors[1])
Text(
'postAutoSaveAt'.trParams({
'date': DateFormat('HH:mm:ss').format(
controller.lastSaveTime.value ?? DateTime.now(),
)
}),
style: textStyle,
),
],
),
)
.animate(
key: const Key('post-editor-hint-animation'),
target: doShow ? 1 : 0,
)
.fade(curve: Curves.easeInOut, duration: 300.ms);
}),
],
);
}
}

View File

@ -49,6 +49,7 @@ class RootShell extends StatelessWidget {
return Scaffold( return Scaffold(
key: rootScaffoldKey, key: rootScaffoldKey,
backgroundColor: Theme.of(context).colorScheme.surface,
bottomNavigationBar: showBottomNavigation bottomNavigationBar: showBottomNavigation
? AppNavigationBottom( ? AppNavigationBottom(
initialIndex: destNames.indexOf(routeName ?? 'page'), initialIndex: destNames.indexOf(routeName ?? 'page'),