🐛 Optimize content render
This commit is contained in:
parent
5853de32a2
commit
ac1b3fe15c
@ -348,7 +348,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
|||||||
detail: _userinfo,
|
detail: _userinfo,
|
||||||
profile: _userinfo!.profile,
|
profile: _userinfo!.profile,
|
||||||
extraWidgets: [
|
extraWidgets: [
|
||||||
if (_dailySignRecords.isNotEmpty)
|
if (_dailySignRecords.length > 1)
|
||||||
Card(
|
Card(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 180,
|
height: 180,
|
||||||
|
@ -198,7 +198,7 @@ class _CallScreenState extends State<CallScreen> with TickerProviderStateMixin {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ChatCallProvider ctrl = Get.find();
|
final ChatCallProvider ctrl = Get.find();
|
||||||
|
|
||||||
return RootContainer(
|
return ResponsiveRootContainer(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: widget.hideAppBar
|
appBar: widget.hideAppBar
|
||||||
? null
|
? null
|
||||||
|
@ -229,7 +229,10 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
|||||||
.listMetadata(widget.initialAttachments ?? List.empty())
|
.listMetadata(widget.initialAttachments ?? List.empty())
|
||||||
.then((result) {
|
.then((result) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_attachments = List.from(result, growable: true);
|
_attachments = List.from(
|
||||||
|
result.where((x) => x != null),
|
||||||
|
growable: true,
|
||||||
|
);
|
||||||
_isBusy = false;
|
_isBusy = false;
|
||||||
_isFirstTimeBusy = false;
|
_isFirstTimeBusy = false;
|
||||||
});
|
});
|
||||||
|
@ -265,8 +265,15 @@ class _AttachmentFullScreenState extends State<AttachmentFullScreen> {
|
|||||||
'ISO${widget.item.metadata?['exif']?['ISO']}',
|
'ISO${widget.item.metadata?['exif']?['ISO']}',
|
||||||
style: metaTextStyle,
|
style: metaTextStyle,
|
||||||
).paddingOnly(right: 2),
|
).paddingOnly(right: 2),
|
||||||
if (widget.item.metadata?['exif']?['Megapixels'] !=
|
if (widget.item.metadata?['exif']?['Aperture'] !=
|
||||||
null)
|
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(
|
Text(
|
||||||
'${widget.item.metadata?['exif']?['Megapixels']}MP',
|
'${widget.item.metadata?['exif']?['Megapixels']}MP',
|
||||||
style: metaTextStyle,
|
style: metaTextStyle,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import 'dart:developer';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:markdown/markdown.dart' as markdown;
|
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';
|
import 'account/account_profile_popup.dart';
|
||||||
|
|
||||||
class MarkdownTextContent extends StatelessWidget {
|
class MarkdownTextContent extends StatefulWidget {
|
||||||
final String content;
|
final String content;
|
||||||
final String parentId;
|
final String parentId;
|
||||||
final bool isSelectable;
|
final bool isSelectable;
|
||||||
@ -31,190 +31,191 @@ class MarkdownTextContent extends StatelessWidget {
|
|||||||
this.isAutoWarp = false,
|
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]+):');
|
final stickerRegex = RegExp(r':([-\w]+):');
|
||||||
|
|
||||||
// Split the content into paragraphs
|
// 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
|
// Iterate over each paragraph to process stickers individually
|
||||||
List<Widget> contentWidgets = [];
|
|
||||||
for (var idx = 0; idx < paragraphs.length; idx++) {
|
for (var idx = 0; idx < paragraphs.length; idx++) {
|
||||||
// Getting paragraph
|
// Getting paragraph
|
||||||
var paragraph = paragraphs[idx];
|
var paragraph = paragraphs[idx];
|
||||||
|
|
||||||
// Matching stickers
|
// Matching stickers
|
||||||
final stickerMatch = stickerRegex.allMatches(paragraph);
|
final stickerMatch = stickerRegex.allMatches(paragraph);
|
||||||
final isOnlySticker =
|
if (stickerMatch.length > 3) {
|
||||||
paragraph.replaceAll(stickerRegex, '').trim().isEmpty;
|
_stickerSizes.addAll(List.filled(stickerMatch.length, 16));
|
||||||
|
} else if (stickerMatch.length > 1) {
|
||||||
contentWidgets.add(
|
_stickerSizes.addAll(List.filled(stickerMatch.length, 32));
|
||||||
Markdown(
|
} else {
|
||||||
shrinkWrap: true,
|
_stickerSizes.addAll(List.filled(stickerMatch.length, 128));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return the list of widgets for the paragraphs
|
Widget _buildContent(BuildContext context) {
|
||||||
return Column(
|
var stickerIdx = 0;
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
return Markdown(
|
||||||
children: contentWidgets,
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (isSelectable) {
|
if (widget.isSelectable) {
|
||||||
return SelectionArea(child: _buildContent(context));
|
return SelectionArea(child: _buildContent(context));
|
||||||
}
|
}
|
||||||
return _buildContent(context);
|
return _buildContent(context);
|
||||||
|
@ -526,7 +526,7 @@ class _PostHeaderDividerWidget extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (item.body['description'] != null || item.body['title'] != null) {
|
if (item.body['description'] != null || item.body['title'] != null) {
|
||||||
return const Gap(8);
|
return const SizedBox(height: 8);
|
||||||
}
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
@ -2214,10 +2214,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_windows
|
name: url_launcher_windows
|
||||||
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
|
sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.3"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -2350,10 +2350,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: e5c39a90447e7c81cfec14b041cdbd0d0916bd9ebbc7fe02ab69568be703b9bd
|
sha256: "2294c64768987ea280b43a3d8357d42d5679f3e2b5b69b602be45b2abbd165b0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.6.0"
|
version: "5.6.1"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -2,7 +2,7 @@ name: solian
|
|||||||
description: "The Solar Network App"
|
description: "The Solar Network App"
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
|
|
||||||
version: 1.4.0+16
|
version: 1.4.0+17
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.4 <4.0.0"
|
sdk: ">=3.3.4 <4.0.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user