mod: save panel use absolute time (#657)

This commit is contained in:
My-Responsitories
2025-04-10 12:34:40 +08:00
committed by GitHub
parent 1d4b08672b
commit 2a60a9b393
6 changed files with 168 additions and 135 deletions

View File

@@ -56,6 +56,8 @@ class SavePanel extends StatefulWidget {
class _SavePanelState extends State<SavePanel> { class _SavePanelState extends State<SavePanel> {
final boundaryKey = GlobalKey(); final boundaryKey = GlobalKey();
bool showBottom = true;
// item // item
dynamic get _item => widget.item; dynamic get _item => widget.item;
late String viewType = '查看'; late String viewType = '查看';
@@ -222,7 +224,7 @@ class _SavePanelState extends State<SavePanel> {
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png); ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List(); Uint8List pngBytes = byteData!.buffer.asUint8List();
String picName = String picName =
"plpl_reply_${DateTime.now().toString().replaceAll(RegExp(r'[- :]'), '').split('.').first}"; "plpl_reply_${DateTime.now().toString().substring(0, 19).replaceAll(RegExp(r'[- :]'), '')}";
if (isShare) { if (isShare) {
Get.back(); Get.back();
SmartDialog.dismiss(); SmartDialog.dismiss();
@@ -263,9 +265,7 @@ class _SavePanelState extends State<SavePanel> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: Get.back,
Get.back();
},
child: Stack( child: Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
alignment: Alignment.center, alignment: Alignment.center,
@@ -297,6 +297,7 @@ class _SavePanelState extends State<SavePanel> {
replyLevel: '', replyLevel: '',
needDivider: false, needDivider: false,
upMid: widget.upMid, upMid: widget.upMid,
isSave: true,
), ),
) )
else if (_item is DynamicItemModel) else if (_item is DynamicItemModel)
@@ -348,10 +349,10 @@ class _SavePanelState extends State<SavePanel> {
if (pubdate != null) ...[ if (pubdate != null) ...[
const Spacer(), const Spacer(),
Text( Text(
Utils.dateFormat( DateTime.fromMillisecondsSinceEpoch(
pubdate, pubdate! * 1000)
formatType: 'detail', .toString()
), .substring(0, 19),
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
@@ -365,96 +366,103 @@ class _SavePanelState extends State<SavePanel> {
], ],
), ),
), ),
Stack( showBottom
clipBehavior: Clip.none, ? Stack(
children: [ clipBehavior: Clip.none,
if (uri.isNotEmpty) children: [
Align( if (uri.isNotEmpty)
alignment: Alignment.centerRight, Align(
child: Row( alignment: Alignment.centerRight,
children: [ child: Row(
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.end,
children: [ children: [
if (uname?.isNotEmpty == true) ...[ Expanded(
Text( child: Column(
'@$uname', mainAxisSize: MainAxisSize.min,
maxLines: 1, crossAxisAlignment:
overflow: TextOverflow.ellipsis, CrossAxisAlignment.end,
style: TextStyle( children: [
color: Theme.of(context) if (uname?.isNotEmpty ==
.colorScheme true) ...[
.primary, Text(
), '@$uname',
), maxLines: 1,
const SizedBox(height: 4), overflow:
], TextOverflow.ellipsis,
Text( style: TextStyle(
'识别二维码,$viewType$itemType', color: Theme.of(context)
textAlign: TextAlign.end, .colorScheme
style: TextStyle( .primary,
color: Theme.of(context) ),
.colorScheme ),
.onSurfaceVariant, const SizedBox(height: 4),
],
Text(
'识别二维码,$viewType$itemType',
textAlign: TextAlign.end,
style: TextStyle(
color: Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
),
const SizedBox(height: 4),
Text(
DateTime.now()
.toString()
.split('.')
.first,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 13,
color: Theme.of(context)
.colorScheme
.outline,
),
),
],
), ),
), ),
const SizedBox(height: 4), Container(
Text( width: 100,
DateTime.now() height: 100,
.toString() padding: const EdgeInsets.all(12),
.split('.') child: Container(
.first, color: Get.isDarkMode
textAlign: TextAlign.end, ? Colors.white
style: TextStyle( : Theme.of(context)
fontSize: 13, .colorScheme
color: Theme.of(context) .surface,
.colorScheme padding:
.outline, const EdgeInsets.all(3),
child: PrettyQrView.data(
data: uri,
decoration:
const PrettyQrDecoration(
shape:
PrettyQrRoundedSymbol(
borderRadius:
BorderRadius.zero,
),
),
),
), ),
), ),
], ],
), ),
), ),
Container( Align(
alignment: Alignment.centerLeft,
child: Image.asset(
'assets/images/logo/logo_2.png',
width: 100, width: 100,
height: 100, color: Theme.of(context)
padding: const EdgeInsets.all(12), .colorScheme
child: Container( .onSurfaceVariant,
color: Get.isDarkMode
? Colors.white
: Theme.of(context)
.colorScheme
.surface,
padding: const EdgeInsets.all(3),
child: PrettyQrView.data(
data: uri,
decoration:
const PrettyQrDecoration(
shape: PrettyQrRoundedSymbol(
borderRadius: BorderRadius.zero,
),
),
),
),
), ),
], ),
), ],
), )
Align( : const SizedBox(height: 12),
alignment: Alignment.centerLeft,
child: Image.asset(
'assets/images/logo/logo_2.png',
width: 100,
color: Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
),
],
),
], ],
), ),
), ),
@@ -468,7 +476,7 @@ class _SavePanelState extends State<SavePanel> {
right: 0, right: 0,
bottom: 0, bottom: 0,
child: Container( child: Container(
decoration: BoxDecoration( decoration: const BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
@@ -494,6 +502,17 @@ class _SavePanelState extends State<SavePanel> {
iconColor: Theme.of(context).colorScheme.onSurfaceVariant, iconColor: Theme.of(context).colorScheme.onSurfaceVariant,
), ),
const SizedBox(width: 40), const SizedBox(width: 40),
iconButton(
size: 42,
tooltip: showBottom ? '隐藏' : '显示',
context: context,
icon: showBottom
? Icons.visibility_off
: Icons.visibility,
onPressed: () => setState(() {
showBottom = !showBottom;
})),
const SizedBox(width: 40),
iconButton( iconButton(
size: 42, size: 42,
tooltip: '分享', tooltip: '分享',
@@ -507,7 +526,7 @@ class _SavePanelState extends State<SavePanel> {
tooltip: '保存', tooltip: '保存',
context: context, context: context,
icon: Icons.save_alt, icon: Icons.save_alt,
onPressed: () => _onSaveOrSharePic(), onPressed: _onSaveOrSharePic,
), ),
], ],
), ),

View File

@@ -24,6 +24,7 @@ class AuthorPanel extends StatelessWidget {
final Function? addBannedList; final Function? addBannedList;
final String? source; final String? source;
final Function? onRemove; final Function? onRemove;
final bool isSave;
const AuthorPanel({ const AuthorPanel({
super.key, super.key,
@@ -31,6 +32,7 @@ class AuthorPanel extends StatelessWidget {
this.addBannedList, this.addBannedList,
this.source, this.source,
this.onRemove, this.onRemove,
this.isSave = false,
}); });
Widget _buildAvatar(double size) => NetworkImgLayer( Widget _buildAvatar(double size) => NetworkImgLayer(
@@ -43,7 +45,12 @@ class AuthorPanel extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String? pubTime = item.modules.moduleAuthor.pubTs != null String? pubTime = item.modules.moduleAuthor.pubTs != null
? Utils.dateFormat(item.modules.moduleAuthor.pubTs) ? isSave
? DateTime.fromMillisecondsSinceEpoch(
item.modules.moduleAuthor.pubTs * 1000)
.toString()
.substring(0, 19)
: Utils.dateFormat(item.modules.moduleAuthor.pubTs)
: item.modules.moduleAuthor.pubTime; : item.modules.moduleAuthor.pubTime;
return Stack( return Stack(
alignment: Alignment.center, alignment: Alignment.center,
@@ -210,30 +217,32 @@ class AuthorPanel extends StatelessWidget {
); );
} }
Widget _moreWidget(context) => SizedBox( Widget _moreWidget(BuildContext context) => isSave
width: 32, ? const SizedBox.shrink()
height: 32, : SizedBox(
child: IconButton( width: 32,
tooltip: '更多', height: 32,
style: ButtonStyle( child: IconButton(
padding: WidgetStateProperty.all(EdgeInsets.zero), tooltip: '更多',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () {
showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
constraints: BoxConstraints(
maxWidth: min(640, min(Get.width, Get.height)),
),
builder: (context) {
return morePanel(context);
},
);
},
icon: const Icon(Icons.more_vert_outlined, size: 18),
), ),
onPressed: () { );
showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
constraints: BoxConstraints(
maxWidth: min(640, min(Get.width, Get.height)),
),
builder: (context) {
return morePanel(context);
},
);
},
icon: const Icon(Icons.more_vert_outlined, size: 18),
),
);
Widget morePanel(context) { Widget morePanel(context) {
return Padding( return Padding(

View File

@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'rich_node_panel.dart'; import 'rich_node_panel.dart';
Widget content(isSave, context, item, source, callback) { Widget content(bool isSave, BuildContext context, item, source, callback) {
InlineSpan picsNodes() { InlineSpan picsNodes() {
return WidgetSpan( return WidgetSpan(
child: LayoutBuilder( child: LayoutBuilder(
@@ -55,7 +55,7 @@ Widget content(isSave, context, item, source, callback) {
child: Text.rich( child: Text.rich(
/// fix 默认20px高度 /// fix 默认20px高度
style: TextStyle( style: TextStyle(
fontSize: source == 'detail' && isSave != true ? 16 : 15, fontSize: source == 'detail' && !isSave ? 16 : 15,
), ),
richNodes, richNodes,
maxLines: source == 'detail' ? null : 6, maxLines: source == 'detail' ? null : 6,

View File

@@ -14,14 +14,14 @@ class DynamicPanel extends StatelessWidget {
final String? source; final String? source;
final Function? onRemove; final Function? onRemove;
final Function(List<String>, int)? callback; final Function(List<String>, int)? callback;
final bool? isSave; final bool isSave;
const DynamicPanel({ const DynamicPanel({
required this.item, required this.item,
this.source, this.source,
this.onRemove, this.onRemove,
this.callback, this.callback,
this.isSave, this.isSave = false,
super.key, super.key,
}); });
@@ -31,7 +31,7 @@ class DynamicPanel extends StatelessWidget {
// padding: source == 'detail' // padding: source == 'detail'
// ? const EdgeInsets.only(bottom: 12) // ? const EdgeInsets.only(bottom: 12)
// : EdgeInsets.zero, // : EdgeInsets.zero,
decoration: isSave == true || decoration: isSave ||
(source == 'detail' && (source == 'detail' &&
Get.context!.orientation == Orientation.landscape) Get.context!.orientation == Orientation.landscape)
? null ? null
@@ -133,6 +133,7 @@ class DynamicPanel extends StatelessWidget {
item: item, item: item,
source: source, source: source,
onRemove: onRemove, onRemove: onRemove,
isSave: isSave,
), ),
), ),
if (item!.modules!.moduleDynamic!.desc != null || if (item!.modules!.moduleDynamic!.desc != null ||
@@ -141,7 +142,7 @@ class DynamicPanel extends StatelessWidget {
forWard(isSave, item, context, source, callback), forWard(isSave, item, context, source, callback),
const SizedBox(height: 2), const SizedBox(height: 2),
if (source == null) ActionPanel(item: item), if (source == null) ActionPanel(item: item),
if (source == 'detail' && isSave != true) const SizedBox(height: 12), if (source == 'detail' && !isSave) const SizedBox(height: 12),
], ],
); );
} }

View File

@@ -68,7 +68,7 @@ Widget _blockedItem(BuildContext context, item, source) {
); );
} }
Widget forWard(isSave, item, BuildContext context, source, callback, Widget forWard(bool isSave, item, BuildContext context, source, callback,
{floor = 1}) { {floor = 1}) {
switch (item.type) { switch (item.type) {
// 图文 // 图文
@@ -125,12 +125,12 @@ Widget forWard(isSave, item, BuildContext context, source, callback,
Text.rich( Text.rich(
richNodes, richNodes,
// 被转发状态(floor=2) 隐藏 // 被转发状态(floor=2) 隐藏
maxLines: isSave == true maxLines: isSave
? null ? null
: source == 'detail' && floor != 2 : source == 'detail' && floor != 2
? null ? null
: 4, : 4,
overflow: isSave == true overflow: isSave
? null ? null
: source == 'detail' && floor != 2 : source == 'detail' && floor != 2
? null ? null
@@ -307,12 +307,12 @@ Widget forWard(isSave, item, BuildContext context, source, callback,
Text.rich( Text.rich(
richNodes, richNodes,
// 被转发状态(floor=2) 隐藏 // 被转发状态(floor=2) 隐藏
maxLines: isSave == true maxLines: isSave
? null ? null
: source == 'detail' && floor != 2 : source == 'detail' && floor != 2
? null ? null
: 4, : 4,
overflow: isSave == true overflow: isSave
? null ? null
: source == 'detail' && floor != 2 : source == 'detail' && floor != 2
? null ? null

View File

@@ -43,6 +43,7 @@ class ReplyItemGrpc extends StatelessWidget {
this.callback, this.callback,
this.onCheckReply, this.onCheckReply,
this.onToggleTop, this.onToggleTop,
this.isSave = false,
}); });
final ReplyInfo replyItem; final ReplyInfo replyItem;
final String replyLevel; final String replyLevel;
@@ -58,6 +59,7 @@ class ReplyItemGrpc extends StatelessWidget {
final Function(List<String>, int)? callback; final Function(List<String>, int)? callback;
final ValueChanged<ReplyInfo>? onCheckReply; final ValueChanged<ReplyInfo>? onCheckReply;
final Function(bool isUpTop, int rpid)? onToggleTop; final Function(bool isUpTop, int rpid)? onToggleTop;
final bool isSave;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -320,7 +322,12 @@ class ReplyItemGrpc extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Text( Text(
Utils.dateFormat(replyItem.ctime.toInt()), isSave
? DateTime.fromMillisecondsSinceEpoch(
replyItem.ctime.toInt() * 1000)
.toString()
.substring(0, 19)
: Utils.dateFormat(replyItem.ctime.toInt()),
style: TextStyle( style: TextStyle(
fontSize: fontSize:
Theme.of(context).textTheme.labelSmall!.fontSize, Theme.of(context).textTheme.labelSmall!.fontSize,
@@ -554,15 +561,12 @@ class ReplyItemGrpc extends StatelessWidget {
}, },
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.symmetric(
8, horizontal: 8,
i == 0 && (extraRow || replyItem.replies.length > 1) vertical:
? 8 i == 0 && (extraRow || replyItem.replies.length > 1)
: 4, ? 8
8, : 4,
i == 0 && (extraRow || replyItem.replies.length > 1)
? 4
: 6,
), ),
child: Semantics( child: Semantics(
label: label: