💄 Optimize post editor
This commit is contained in:
parent
606a0d708a
commit
442ef06147
@ -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);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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'),
|
||||||
|
Loading…
Reference in New Issue
Block a user