💄 Optimized post editor
This commit is contained in:
parent
af93a8386a
commit
cf767a1d94
@ -115,7 +115,7 @@ PODS:
|
|||||||
- TOCropViewController (~> 2.7.4)
|
- TOCropViewController (~> 2.7.4)
|
||||||
- image_picker_ios (0.0.1):
|
- image_picker_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- livekit_client (2.2.3):
|
- livekit_client (2.2.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- WebRTC-SDK (= 125.6422.04)
|
- WebRTC-SDK (= 125.6422.04)
|
||||||
- media_kit_libs_ios_video (1.0.4):
|
- media_kit_libs_ios_video (1.0.4):
|
||||||
@ -306,7 +306,7 @@ SPEC CHECKSUMS:
|
|||||||
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
|
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
|
||||||
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
|
image_cropper: 37d40f62177c101ff4c164906d259ea2c3aa70cf
|
||||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
livekit_client: bad83a7776a41abc42e1f26d903eeac9164c8a9f
|
livekit_client: d079c5f040d4bf2b80440ff0ae997725a183e4bc
|
||||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||||
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
||||||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||||
|
@ -260,37 +260,104 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (_isBusy)
|
Expanded(
|
||||||
const LinearProgressIndicator().animate().scaleX(),
|
child: ListView(
|
||||||
Container(
|
children: [
|
||||||
padding: const EdgeInsets.symmetric(
|
if (_isBusy)
|
||||||
horizontal: 16,
|
const LinearProgressIndicator()
|
||||||
vertical: 8,
|
.animate()
|
||||||
),
|
.scaleX(),
|
||||||
child: TextField(
|
Container(
|
||||||
maxLines: null,
|
padding: const EdgeInsets.symmetric(
|
||||||
autofocus: true,
|
horizontal: 16,
|
||||||
autocorrect: true,
|
vertical: 8,
|
||||||
keyboardType: TextInputType.multiline,
|
),
|
||||||
controller: _editorController.contentController,
|
child: TextField(
|
||||||
focusNode: _contentFocusNode,
|
maxLines: null,
|
||||||
decoration: InputDecoration.collapsed(
|
autofocus: true,
|
||||||
hintText: 'postContentPlaceholder'.tr,
|
autocorrect: true,
|
||||||
),
|
keyboardType: TextInputType.multiline,
|
||||||
onTapOutside: (_) =>
|
controller:
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
_editorController.contentController,
|
||||||
|
focusNode: _contentFocusNode,
|
||||||
|
decoration: InputDecoration.collapsed(
|
||||||
|
hintText: 'postContentPlaceholder'.tr,
|
||||||
|
),
|
||||||
|
onTapOutside: (_) => FocusManager
|
||||||
|
.instance.primaryFocus
|
||||||
|
?.unfocus(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 120)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 120)
|
Obx(() {
|
||||||
|
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: [
|
||||||
|
if (showFactors[0])
|
||||||
|
Text('postRestoreFromLocal'.tr,
|
||||||
|
style: textStyle)
|
||||||
|
.paddingOnly(right: 4),
|
||||||
|
if (showFactors[0])
|
||||||
|
InkWell(
|
||||||
|
child: Text('clear'.tr, style: textStyle),
|
||||||
|
onTap: () {
|
||||||
|
_editorController.localClear();
|
||||||
|
_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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.animate(
|
||||||
|
key: const Key('post-editor-hint-animation'),
|
||||||
|
target: doShow ? 1 : 0,
|
||||||
|
)
|
||||||
|
.fade(curve: Curves.easeInOut, duration: 300.ms);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (SolianTheme.isLargeScreen(context))
|
if (SolianTheme.isLargeScreen(context))
|
||||||
const VerticalDivider(width: 0.3, thickness: 0.3)
|
const VerticalDivider(width: 0.3, thickness: 0.3)
|
||||||
.paddingSymmetric(
|
.paddingSymmetric(
|
||||||
horizontal: 8,
|
horizontal: 16,
|
||||||
),
|
),
|
||||||
if (SolianTheme.isLargeScreen(context))
|
if (SolianTheme.isLargeScreen(context))
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -298,7 +365,7 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
|||||||
child: MarkdownTextContent(
|
child: MarkdownTextContent(
|
||||||
content: _editorController.contentController.text,
|
content: _editorController.contentController.text,
|
||||||
parentId: 'post-editor-preview',
|
parentId: 'post-editor-preview',
|
||||||
).paddingOnly(top: 8),
|
).paddingOnly(top: 12, right: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -309,85 +376,39 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Obx(() {
|
const Divider(thickness: 0.3, height: 0.3),
|
||||||
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: [
|
|
||||||
if (showFactors[0])
|
|
||||||
Text('postRestoreFromLocal'.tr, style: textStyle)
|
|
||||||
.paddingOnly(right: 4),
|
|
||||||
if (showFactors[0])
|
|
||||||
InkWell(
|
|
||||||
child: Text('clear'.tr, style: textStyle),
|
|
||||||
onTap: () {
|
|
||||||
_editorController.localClear();
|
|
||||||
_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,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.animate(
|
|
||||||
key: const Key('post-editor-hint-animation'),
|
|
||||||
target: doShow ? 1 : 0,
|
|
||||||
)
|
|
||||||
.fade(curve: Curves.easeInOut, duration: 300.ms);
|
|
||||||
}),
|
|
||||||
if (_editorController.mode.value == 0)
|
|
||||||
Obx(
|
|
||||||
() => TweenAnimationBuilder<double>(
|
|
||||||
tween: Tween(
|
|
||||||
begin: 0,
|
|
||||||
end: _editorController.contentLength.value / 4096,
|
|
||||||
),
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
builder: (context, value, _) => LinearProgressIndicator(
|
|
||||||
minHeight: 2,
|
|
||||||
color: _editorController.contentLength.value > 4096
|
|
||||||
? Colors.red[900]
|
|
||||||
: Theme.of(context).colorScheme.primary,
|
|
||||||
value: value,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 56,
|
height: 56,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
children: [
|
children: [
|
||||||
|
if (_editorController.mode.value == 0)
|
||||||
|
Obx(
|
||||||
|
() => TweenAnimationBuilder<double>(
|
||||||
|
tween: Tween(
|
||||||
|
begin: 0,
|
||||||
|
end: _editorController.contentLength.value /
|
||||||
|
4096,
|
||||||
|
),
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
builder: (context, value, _) => SizedBox(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 3,
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.secondaryContainer,
|
||||||
|
color: _editorController.contentLength.value >
|
||||||
|
4096
|
||||||
|
? Colors.red[900]
|
||||||
|
: Theme.of(context).colorScheme.primary,
|
||||||
|
value: value,
|
||||||
|
),
|
||||||
|
).paddingAll(10),
|
||||||
|
),
|
||||||
|
).paddingSymmetric(horizontal: 4),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final isDraft = _editorController.isDraft.value;
|
final isDraft = _editorController.isDraft.value;
|
||||||
return IconButton(
|
return IconButton(
|
||||||
|
@ -15,6 +15,7 @@ class AttachmentItem extends StatefulWidget {
|
|||||||
final Attachment item;
|
final Attachment item;
|
||||||
final bool showBadge;
|
final bool showBadge;
|
||||||
final bool showHideButton;
|
final bool showHideButton;
|
||||||
|
final bool autoload;
|
||||||
final BoxFit fit;
|
final BoxFit fit;
|
||||||
final String? badge;
|
final String? badge;
|
||||||
final Function? onHide;
|
final Function? onHide;
|
||||||
@ -27,6 +28,7 @@ class AttachmentItem extends StatefulWidget {
|
|||||||
this.fit = BoxFit.cover,
|
this.fit = BoxFit.cover,
|
||||||
this.showBadge = true,
|
this.showBadge = true,
|
||||||
this.showHideButton = true,
|
this.showHideButton = true,
|
||||||
|
this.autoload = false,
|
||||||
this.onHide,
|
this.onHide,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -49,7 +51,10 @@ class _AttachmentItemState extends State<AttachmentItem> {
|
|||||||
onHide: widget.onHide,
|
onHide: widget.onHide,
|
||||||
);
|
);
|
||||||
case 'video':
|
case 'video':
|
||||||
return _AttachmentItemVideo(item: widget.item);
|
return _AttachmentItemVideo(
|
||||||
|
item: widget.item,
|
||||||
|
autoload: widget.autoload,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return Center(
|
return Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
@ -17,6 +17,7 @@ class AttachmentList extends StatefulWidget {
|
|||||||
final List<int> attachmentsId;
|
final List<int> attachmentsId;
|
||||||
final bool isGrid;
|
final bool isGrid;
|
||||||
final bool isForceGrid;
|
final bool isForceGrid;
|
||||||
|
final bool autoload;
|
||||||
final double flatMaxHeight;
|
final double flatMaxHeight;
|
||||||
|
|
||||||
final double? width;
|
final double? width;
|
||||||
@ -28,6 +29,7 @@ class AttachmentList extends StatefulWidget {
|
|||||||
required this.attachmentsId,
|
required this.attachmentsId,
|
||||||
this.isGrid = false,
|
this.isGrid = false,
|
||||||
this.isForceGrid = false,
|
this.isForceGrid = false,
|
||||||
|
this.autoload = false,
|
||||||
this.flatMaxHeight = 720,
|
this.flatMaxHeight = 720,
|
||||||
this.width,
|
this.width,
|
||||||
this.viewport,
|
this.viewport,
|
||||||
@ -208,6 +210,7 @@ class AttachmentListEntry extends StatelessWidget {
|
|||||||
final bool showBadge;
|
final bool showBadge;
|
||||||
final bool showMature;
|
final bool showMature;
|
||||||
final bool isDense;
|
final bool isDense;
|
||||||
|
final bool autoload;
|
||||||
final Function(bool) onReveal;
|
final Function(bool) onReveal;
|
||||||
|
|
||||||
const AttachmentListEntry({
|
const AttachmentListEntry({
|
||||||
@ -221,6 +224,7 @@ class AttachmentListEntry extends StatelessWidget {
|
|||||||
this.showBadge = false,
|
this.showBadge = false,
|
||||||
this.showMature = false,
|
this.showMature = false,
|
||||||
this.isDense = false,
|
this.isDense = false,
|
||||||
|
this.autoload = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -259,6 +263,7 @@ class AttachmentListEntry extends StatelessWidget {
|
|||||||
item: item!,
|
item: item!,
|
||||||
badge: showBadge ? badgeContent : null,
|
badge: showBadge ? badgeContent : null,
|
||||||
showHideButton: !item!.isMature || showMature,
|
showHideButton: !item!.isMature || showMature,
|
||||||
|
autoload: autoload,
|
||||||
onHide: () {
|
onHide: () {
|
||||||
onReveal(false);
|
onReveal(false);
|
||||||
},
|
},
|
||||||
|
@ -465,6 +465,7 @@ class _PostItemState extends State<PostItem> {
|
|||||||
flatMaxHeight: MediaQuery.of(context).size.width,
|
flatMaxHeight: MediaQuery.of(context).size.width,
|
||||||
parentId: widget.item.id.toString(),
|
parentId: widget.item.id.toString(),
|
||||||
attachmentsId: attachments,
|
attachmentsId: attachments,
|
||||||
|
autoload: true,
|
||||||
isGrid: attachments.length > 1,
|
isGrid: attachments.length > 1,
|
||||||
),
|
),
|
||||||
if (widget.isShowReply || widget.isReactable)
|
if (widget.isShowReply || widget.isReactable)
|
||||||
|
Loading…
Reference in New Issue
Block a user