💄 Optimization of sharing post via image

This commit is contained in:
LittleSheep 2024-12-13 00:05:18 +08:00
parent 240ad7dc7e
commit d7c1ffe3cc
3 changed files with 109 additions and 57 deletions

View File

@ -439,5 +439,7 @@
"userUnblocked": "{} has been unblocked.", "userUnblocked": "{} has been unblocked.",
"userBlocked": "{} has been blocked.", "userBlocked": "{} has been blocked.",
"postSharingViaPicture": "Capturing post as picture, please stand by...", "postSharingViaPicture": "Capturing post as picture, please stand by...",
"postImageShareAds": "Explore posts on the Solar Network" "postImageShareAds": "Explore posts on the Solar Network",
"postShare": "Share",
"postShareImage": "Share via Image"
} }

View File

@ -437,5 +437,7 @@
"userUnblocked": "已解除屏蔽用户 {}", "userUnblocked": "已解除屏蔽用户 {}",
"userBlocked": "已屏蔽用户 {}", "userBlocked": "已屏蔽用户 {}",
"postSharingViaPicture": "正在生成帖子截图,请稍等片刻……", "postSharingViaPicture": "正在生成帖子截图,请稍等片刻……",
"postImageShareAds": "来 Solar Network 探索更多有趣帖子" "postImageShareAds": "来 Solar Network 探索更多有趣帖子",
"postShare": "分享",
"postShareImage": "分享帖图"
} }

View File

@ -57,6 +57,59 @@ class PostItem extends StatelessWidget {
if (onChanged != null) onChanged!(data); if (onChanged != null) onChanged!(data);
} }
void _doShare(BuildContext context) {
final box = context.findRenderObject() as RenderBox?;
final url = 'https://solsynth.dev/posts/${data.id}';
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
Share.shareUri(Uri.parse(url), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
} else {
Share.share(url, sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
}
}
void _doShareViaPicture(BuildContext context) async {
final box = context.findRenderObject() as RenderBox?;
context.showSnackbar('postSharingViaPicture'.tr());
final controller = ScreenshotController();
final capturedImage = await controller.captureFromLongWidget(
InheritedTheme.captureAll(
context,
MediaQuery(
data: MediaQuery.of(context),
child: Material(
child: MultiProvider(
providers: [
Provider<SnNetworkProvider>(create: (_) => context.read()),
],
child: ResponsiveBreakpoints.builder(
breakpoints: ResponsiveBreakpoints.of(context).breakpoints,
child: PostShareImage(data: data),
),
),
),
),
),
pixelRatio: 3,
context: context,
);
if (kIsWeb) return;
final directory = await getTemporaryDirectory();
final imagePath = await File(
'${directory.path}/sn-share-via-image-${DateTime.now().millisecondsSinceEpoch}.png',
).create();
await imagePath.writeAsBytes(capturedImage);
await Share.shareXFiles(
[XFile(imagePath.path)],
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
);
await imagePath.delete();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final sn = context.read<SnNetworkProvider>(); final sn = context.read<SnNetworkProvider>();
@ -74,6 +127,8 @@ class PostItem extends StatelessWidget {
_PostContentHeader( _PostContentHeader(
data: data, data: data,
isAuthor: isAuthor, isAuthor: isAuthor,
onShare: () => _doShare(context),
onShareImage: () => _doShareViaPicture(context),
onDeleted: () { onDeleted: () {
if (onDeleted != null) {} if (onDeleted != null) {}
}, },
@ -125,6 +180,8 @@ class PostItem extends StatelessWidget {
data: data, data: data,
showComments: showComments, showComments: showComments,
showReactions: showReactions, showReactions: showReactions,
onShare: () => _doShare(context),
onShareImage: () => _doShareViaPicture(context),
onChanged: _onChanged, onChanged: _onChanged,
).padding(left: 8, right: 14), ).padding(left: 8, right: 14),
], ],
@ -143,6 +200,8 @@ class PostItem extends StatelessWidget {
_PostContentHeader( _PostContentHeader(
data: data, data: data,
showMenu: showMenu, showMenu: showMenu,
onShare: () => _doShare(context),
onShareImage: () => _doShareViaPicture(context),
onDeleted: () { onDeleted: () {
if (onDeleted != null) onDeleted!(); if (onDeleted != null) onDeleted!();
}, },
@ -190,6 +249,8 @@ class PostItem extends StatelessWidget {
data: data, data: data,
showComments: showComments, showComments: showComments,
showReactions: showReactions, showReactions: showReactions,
onShare: () => _doShare(context),
onShareImage: () => _doShareViaPicture(context),
onChanged: _onChanged, onChanged: _onChanged,
).padding(left: 8, right: 14), ).padding(left: 8, right: 14),
], ],
@ -219,6 +280,8 @@ class PostShareImage extends StatelessWidget {
_PostContentHeader( _PostContentHeader(
data: data, data: data,
onDeleted: () {}, onDeleted: () {},
onShare: () {},
onShareImage: () {},
showMenu: false, showMenu: false,
isRelativeDate: false, isRelativeDate: false,
).padding(horizontal: 16, bottom: 8), ).padding(horizontal: 16, bottom: 8),
@ -241,10 +304,19 @@ class PostShareImage extends StatelessWidget {
data: data.preload!.attachments!, data: data.preload!.attachments!,
isFlatted: true, isFlatted: true,
).padding(horizontal: 16, bottom: 8), ).padding(horizontal: 16, bottom: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (data.visibility > 0) _PostVisibilityHint(data: data),
if (data.body['content_truncated'] == true) _PostTruncatedHint(data: data),
],
).padding(horizontal: 16),
_PostBottomAction( _PostBottomAction(
data: data, data: data,
showComments: true, showComments: true,
showReactions: true, showReactions: true,
onShare: () {},
onShareImage: () {},
onChanged: (SnPost data) {}, onChanged: (SnPost data) {},
).padding(left: 8, right: 14), ).padding(left: 8, right: 14),
const Divider(height: 1), const Divider(height: 1),
@ -317,67 +389,17 @@ class _PostBottomAction extends StatelessWidget {
final bool showComments; final bool showComments;
final bool showReactions; final bool showReactions;
final Function(SnPost data) onChanged; final Function(SnPost data) onChanged;
final Function() onShare, onShareImage;
const _PostBottomAction({ const _PostBottomAction({
required this.data, required this.data,
required this.showComments, required this.showComments,
required this.showReactions, required this.showReactions,
required this.onChanged, required this.onChanged,
required this.onShare,
required this.onShareImage,
}); });
void _doShare(BuildContext context) {
final box = context.findRenderObject() as RenderBox?;
final url = 'https://solsynth.dev/posts/${data.id}';
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
Share.shareUri(Uri.parse(url), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
} else {
Share.share(url, sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
}
}
void _doShareViaPicture(BuildContext context) async {
final box = context.findRenderObject() as RenderBox?;
context.showSnackbar('postSharingViaPicture'.tr());
final controller = ScreenshotController();
final capturedImage = await controller.captureFromLongWidget(
InheritedTheme.captureAll(
context,
MediaQuery(
data: MediaQuery.of(context),
child: Material(
child: MultiProvider(
providers: [
Provider<SnNetworkProvider>(create: (_) => context.read()),
],
child: ResponsiveBreakpoints.builder(
breakpoints: ResponsiveBreakpoints.of(context).breakpoints,
child: PostShareImage(data: data),
),
),
),
),
),
pixelRatio: 3,
context: context,
);
if (kIsWeb) return;
final directory = await getTemporaryDirectory();
final imagePath = await File(
'${directory.path}/sn-share-via-image-${DateTime.now().millisecondsSinceEpoch}.png',
).create();
await imagePath.writeAsBytes(capturedImage);
await Share.shareXFiles(
[XFile(imagePath.path)],
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
);
await imagePath.delete();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final iconColor = Theme.of(context).colorScheme.onSurface.withAlpha( final iconColor = Theme.of(context).colorScheme.onSurface.withAlpha(
@ -462,8 +484,8 @@ class _PostBottomAction extends StatelessWidget {
..removeLast(), ..removeLast(),
), ),
InkWell( InkWell(
onTap: () => _doShare(context), onTap: onShare,
onLongPress: () => _doShareViaPicture(context), onLongPress: onShareImage,
child: Icon( child: Icon(
Symbols.share, Symbols.share,
size: 20, size: 20,
@ -576,6 +598,7 @@ class _PostContentHeader extends StatelessWidget {
final bool isRelativeDate; final bool isRelativeDate;
final bool showMenu; final bool showMenu;
final Function onDeleted; final Function onDeleted;
final Function() onShare, onShareImage;
const _PostContentHeader({ const _PostContentHeader({
required this.data, required this.data,
@ -584,6 +607,8 @@ class _PostContentHeader extends StatelessWidget {
this.isRelativeDate = true, this.isRelativeDate = true,
this.showMenu = true, this.showMenu = true,
required this.onDeleted, required this.onDeleted,
required this.onShare,
required this.onShareImage,
}); });
Future<void> _deletePost(BuildContext context) async { Future<void> _deletePost(BuildContext context) async {
@ -744,6 +769,27 @@ class _PostContentHeader extends StatelessWidget {
}, },
), ),
const PopupMenuDivider(), const PopupMenuDivider(),
PopupMenuItem(
onTap: onShare,
child: Row(
children: [
const Icon(Symbols.share),
const Gap(16),
Text('postShare').tr(),
],
),
),
PopupMenuItem(
onTap: onShareImage,
child: Row(
children: [
const Icon(Symbols.share_reviews),
const Gap(16),
Text('postShareImage').tr(),
],
),
),
const PopupMenuDivider(),
PopupMenuItem( PopupMenuItem(
child: Row( child: Row(
children: [ children: [
@ -825,6 +871,8 @@ class _PostQuoteContent extends StatelessWidget {
isCompact: true, isCompact: true,
isRelativeDate: isRelativeDate, isRelativeDate: isRelativeDate,
showMenu: false, showMenu: false,
onShare: () {},
onShareImage: () {},
onDeleted: () {}, onDeleted: () {},
).padding(bottom: 4), ).padding(bottom: 4),
_PostContentBody(data: child), _PostContentBody(data: child),