🐛 Optimize content render

This commit is contained in:
LittleSheep 2024-10-19 00:32:16 +08:00
parent 5853de32a2
commit ac1b3fe15c
8 changed files with 188 additions and 177 deletions

View File

@ -348,7 +348,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
detail: _userinfo,
profile: _userinfo!.profile,
extraWidgets: [
if (_dailySignRecords.isNotEmpty)
if (_dailySignRecords.length > 1)
Card(
child: SizedBox(
height: 180,

View File

@ -198,7 +198,7 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
Widget build(BuildContext context) {
final ChatCallProvider ctrl = Get.find();
return RootContainer(
return ResponsiveRootContainer(
child: Scaffold(
appBar: widget.hideAppBar
? null

View File

@ -229,7 +229,10 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
.listMetadata(widget.initialAttachments ?? List.empty())
.then((result) {
setState(() {
_attachments = List.from(result, growable: true);
_attachments = List.from(
result.where((x) => x != null),
growable: true,
);
_isBusy = false;
_isFirstTimeBusy = false;
});

View File

@ -265,8 +265,15 @@ class _AttachmentFullScreenState extends State<AttachmentFullScreen> {
'ISO${widget.item.metadata?['exif']?['ISO']}',
style: metaTextStyle,
).paddingOnly(right: 2),
if (widget.item.metadata?['exif']?['Megapixels'] !=
if (widget.item.metadata?['exif']?['Aperture'] !=
null)
Text(
'f/${widget.item.metadata?['exif']?['Aperture']}',
style: metaTextStyle,
).paddingOnly(right: 2),
if (widget.item.metadata?['exif']?['Megapixels'] !=
null &&
widget.item.metadata?['exif']?['Model'] != null)
Text(
'${widget.item.metadata?['exif']?['Megapixels']}MP',
style: metaTextStyle,

View File

@ -1,8 +1,8 @@
import 'dart:developer';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:markdown/markdown.dart' as markdown;
@ -15,7 +15,7 @@ import 'package:url_launcher/url_launcher_string.dart';
import 'account/account_profile_popup.dart';
class MarkdownTextContent extends StatelessWidget {
class MarkdownTextContent extends StatefulWidget {
final String content;
final String parentId;
final bool isSelectable;
@ -31,190 +31,191 @@ class MarkdownTextContent extends StatelessWidget {
this.isAutoWarp = false,
});
Widget _buildContent(BuildContext context) {
@override
State<MarkdownTextContent> createState() => _MarkdownTextContentState();
}
class _MarkdownTextContentState extends State<MarkdownTextContent> {
final List<int> _stickerSizes = [];
@override
initState() {
super.initState();
final stickerRegex = RegExp(r':([-\w]+):');
// Split the content into paragraphs
final paragraphs = content.split(RegExp(r'\n\s*\n'));
final paragraphs = widget.content.split(RegExp(r'\n\s*\n'));
// Iterate over each paragraph to process stickers individually
List<Widget> contentWidgets = [];
for (var idx = 0; idx < paragraphs.length; idx++) {
// Getting paragraph
var paragraph = paragraphs[idx];
// Matching stickers
final stickerMatch = stickerRegex.allMatches(paragraph);
final isOnlySticker =
paragraph.replaceAll(stickerRegex, '').trim().isEmpty;
contentWidgets.add(
Markdown(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
data: paragraph,
padding: EdgeInsets.zero,
styleSheet: MarkdownStyleSheet.fromTheme(
Theme.of(context),
).copyWith(
textScaler: TextScaler.linear(isLargeText ? 1.1 : 1),
blockquote: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
blockquoteDecoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: const BorderRadius.all(Radius.circular(4)),
),
horizontalRuleDecoration: BoxDecoration(
border: Border(
top: BorderSide(
width: 1.0,
color: Theme.of(context).dividerColor,
),
),
),
codeblockDecoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).dividerColor,
width: 0.3,
),
borderRadius: const BorderRadius.all(Radius.circular(4)),
color: Theme.of(context).colorScheme.surface.withOpacity(0.5),
)),
builders: {
'code': _MarkdownTextCodeElement(),
},
softLineBreak: true,
extensionSet: markdown.ExtensionSet(
<markdown.BlockSyntax>[
markdown.CodeBlockSyntax(),
...markdown.ExtensionSet.commonMark.blockSyntaxes,
...markdown.ExtensionSet.gitHubFlavored.blockSyntaxes,
],
<markdown.InlineSyntax>[
if (isAutoWarp) markdown.LineBreakSyntax(),
_UserNameCardInlineSyntax(),
_CustomEmoteInlineSyntax(),
markdown.AutolinkSyntax(),
markdown.AutolinkExtensionSyntax(),
markdown.CodeSyntax(),
...markdown.ExtensionSet.commonMark.inlineSyntaxes,
...markdown.ExtensionSet.gitHubFlavored.inlineSyntaxes
],
),
onTapLink: (text, href, title) async {
if (href == null) return;
if (href.startsWith('solink://')) {
final segments = href.replaceFirst('solink://', '').split('/');
switch (segments[0]) {
case 'users':
showModalBottomSheet(
useRootNavigator: true,
isScrollControlled: true,
backgroundColor: Theme.of(context).colorScheme.surface,
context: context,
builder: (context) => AccountProfilePopup(
name: segments[1],
),
);
}
return;
}
await launchUrlString(
href,
mode: LaunchMode.externalApplication,
);
},
imageBuilder: (uri, title, alt) {
var url = uri.toString();
double? width, height;
BoxFit? fit;
if (url.startsWith('solink://')) {
final segments = url.replaceFirst('solink://', '').split('/');
switch (segments[0]) {
case 'stickers':
double radius = 8;
final StickerProvider sticker = Get.find();
// Adjust sticker size based on the sticker count in this paragraph
if (stickerMatch.length <= 1 && isOnlySticker) {
width = 128;
height = 128;
} else if (stickerMatch.length <= 3 && isOnlySticker) {
width = 32;
height = 32;
} else {
radius = 4;
width = 16;
height = 16;
}
fit = BoxFit.contain;
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(radius)),
child: Container(
width: width,
height: height,
color: Theme.of(context).colorScheme.surfaceContainer,
child: FutureBuilder(
future: sticker.getStickerByAlias(segments[1]),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator());
}
return AutoCacheImage(
snapshot.data!.imageUrl,
width: width,
height: height,
fit: fit,
noErrorWidget: true,
);
},
),
),
).paddingSymmetric(vertical: 4);
case 'attachments':
const radius = BorderRadius.all(Radius.circular(8));
return LimitedBox(
maxHeight: MediaQuery.of(context).size.width,
child: ClipRRect(
borderRadius: radius,
child: AttachmentSelfContainedEntry(
isDense: true,
parentId: parentId,
rid: segments[1],
),
),
).paddingSymmetric(vertical: 4);
}
}
return AutoCacheImage(
url,
width: width,
height: height,
fit: fit,
);
},
),
);
if (idx < paragraphs.length - 1) {
contentWidgets.add(isAutoWarp ? const Gap(4) : const Gap(8));
if (stickerMatch.length > 3) {
_stickerSizes.addAll(List.filled(stickerMatch.length, 16));
} else if (stickerMatch.length > 1) {
_stickerSizes.addAll(List.filled(stickerMatch.length, 32));
} else {
_stickerSizes.addAll(List.filled(stickerMatch.length, 128));
}
}
}
// Return the list of widgets for the paragraphs
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: contentWidgets,
Widget _buildContent(BuildContext context) {
var stickerIdx = 0;
return Markdown(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
data: widget.content,
padding: EdgeInsets.zero,
styleSheet: MarkdownStyleSheet.fromTheme(
Theme.of(context),
).copyWith(
textScaler: TextScaler.linear(widget.isLargeText ? 1.1 : 1),
blockquote: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
blockquoteDecoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: const BorderRadius.all(Radius.circular(4)),
),
horizontalRuleDecoration: BoxDecoration(
border: Border(
top: BorderSide(
width: 1.0,
color: Theme.of(context).dividerColor,
),
),
),
codeblockDecoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).dividerColor,
width: 0.3,
),
borderRadius: const BorderRadius.all(Radius.circular(4)),
color: Theme.of(context).colorScheme.surface.withOpacity(0.5),
)),
builders: {
'code': _MarkdownTextCodeElement(),
},
softLineBreak: true,
extensionSet: markdown.ExtensionSet(
<markdown.BlockSyntax>[
markdown.CodeBlockSyntax(),
...markdown.ExtensionSet.commonMark.blockSyntaxes,
...markdown.ExtensionSet.gitHubFlavored.blockSyntaxes,
],
<markdown.InlineSyntax>[
if (widget.isAutoWarp) markdown.LineBreakSyntax(),
_UserNameCardInlineSyntax(),
_CustomEmoteInlineSyntax(),
markdown.AutolinkSyntax(),
markdown.AutolinkExtensionSyntax(),
markdown.CodeSyntax(),
...markdown.ExtensionSet.commonMark.inlineSyntaxes,
...markdown.ExtensionSet.gitHubFlavored.inlineSyntaxes
],
),
onTapLink: (text, href, title) async {
if (href == null) return;
if (href.startsWith('solink://')) {
final segments = href.replaceFirst('solink://', '').split('/');
switch (segments[0]) {
case 'users':
showModalBottomSheet(
useRootNavigator: true,
isScrollControlled: true,
backgroundColor: Theme.of(context).colorScheme.surface,
context: context,
builder: (context) => AccountProfilePopup(
name: segments[1],
),
);
}
return;
}
await launchUrlString(
href,
mode: LaunchMode.externalApplication,
);
},
imageBuilder: (uri, title, alt) {
var url = uri.toString();
double? width, height;
BoxFit? fit;
if (url.startsWith('solink://')) {
final segments = url.replaceFirst('solink://', '').split('/');
switch (segments[0]) {
case 'stickers':
double radius = 4;
final StickerProvider sticker = Get.find();
// Adjust sticker size based on the sticker count in this paragraph
width =
_stickerSizes.elementAtOrNull(stickerIdx)?.toDouble() ?? 16;
height =
_stickerSizes.elementAtOrNull(stickerIdx)?.toDouble() ?? 16;
if (width > 16) {
radius = 8;
}
stickerIdx++;
fit = BoxFit.contain;
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(radius)),
child: Container(
width: width,
height: height,
color: Theme.of(context).colorScheme.surfaceContainer,
child: FutureBuilder(
future: sticker.getStickerByAlias(segments[1]),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
return AutoCacheImage(
snapshot.data!.imageUrl,
width: width,
height: height,
fit: fit,
noErrorWidget: true,
);
},
),
),
).paddingSymmetric(vertical: 4);
case 'attachments':
const radius = BorderRadius.all(Radius.circular(8));
return LimitedBox(
maxHeight: MediaQuery.of(context).size.width,
child: ClipRRect(
borderRadius: radius,
child: AttachmentSelfContainedEntry(
isDense: true,
parentId: widget.parentId,
rid: segments[1],
),
),
).paddingSymmetric(vertical: 4);
}
}
return AutoCacheImage(
url,
width: width,
height: height,
fit: fit,
);
},
);
}
@override
Widget build(BuildContext context) {
if (isSelectable) {
if (widget.isSelectable) {
return SelectionArea(child: _buildContent(context));
}
return _buildContent(context);

View File

@ -526,7 +526,7 @@ class _PostHeaderDividerWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (item.body['description'] != null || item.body['title'] != null) {
return const Gap(8);
return const SizedBox(height: 8);
}
return const SizedBox.shrink();
}

View File

@ -2214,10 +2214,10 @@ packages:
dependency: transitive
description:
name: url_launcher_windows
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
uuid:
dependency: "direct main"
description:
@ -2350,10 +2350,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: e5c39a90447e7c81cfec14b041cdbd0d0916bd9ebbc7fe02ab69568be703b9bd
sha256: "2294c64768987ea280b43a3d8357d42d5679f3e2b5b69b602be45b2abbd165b0"
url: "https://pub.dev"
source: hosted
version: "5.6.0"
version: "5.6.1"
win32_registry:
dependency: transitive
description:

View File

@ -2,7 +2,7 @@ name: solian
description: "The Solar Network App"
publish_to: "none"
version: 1.4.0+16
version: 1.4.0+17
environment:
sdk: ">=3.3.4 <4.0.0"