♿ Share post as image on web
This commit is contained in:
		@@ -484,5 +484,6 @@
 | 
			
		||||
  "authMaximumAuthStepsDesc": "The maximum number of authentication steps when logging in, higher value is more secure, lower value is more convenient; default is 2",
 | 
			
		||||
  "auditLog": "Audit log",
 | 
			
		||||
  "shareImage": "Share as image",
 | 
			
		||||
  "shareImageFooter": "Only on the Solar Network"
 | 
			
		||||
  "shareImageFooter": "Only on the Solar Network",
 | 
			
		||||
  "fileSavedAt": "File saved at @path"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -480,5 +480,6 @@
 | 
			
		||||
  "authMaximumAuthStepsDesc": "登陆时最多的验证步数,值越高则越安全,反之则会相对方便;默认设置为 2",
 | 
			
		||||
  "auditLog": "活动日志",
 | 
			
		||||
  "shareImage": "分享图片",
 | 
			
		||||
  "shareImageFooter": "上 Solar Network 看更多有趣帖子"
 | 
			
		||||
  "shareImageFooter": "上 Solar Network 看更多有趣帖子",
 | 
			
		||||
  "fileSavedAt": "文件保存于 @path"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ class _AttachmentListState extends State<AttachmentList> {
 | 
			
		||||
  bool _isLoading = true;
 | 
			
		||||
  bool _showMature = false;
 | 
			
		||||
 | 
			
		||||
  // ignore: unused_field
 | 
			
		||||
  double _aspectRatio = 1;
 | 
			
		||||
 | 
			
		||||
  List<Attachment?> _attachments = List.empty();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import 'dart:io';
 | 
			
		||||
import 'dart:math';
 | 
			
		||||
 | 
			
		||||
import 'package:file_saver/file_saver.dart';
 | 
			
		||||
@@ -7,9 +6,6 @@ import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_animate/flutter_animate.dart';
 | 
			
		||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
 | 
			
		||||
import 'package:get/get.dart';
 | 
			
		||||
import 'package:intl/intl.dart';
 | 
			
		||||
import 'package:path/path.dart' as path;
 | 
			
		||||
import 'package:path_provider/path_provider.dart';
 | 
			
		||||
import 'package:screenshot/screenshot.dart';
 | 
			
		||||
import 'package:share_plus/share_plus.dart';
 | 
			
		||||
import 'package:solian/exts.dart';
 | 
			
		||||
@@ -113,16 +109,17 @@ class _PostActionState extends State<PostAction> {
 | 
			
		||||
        maxHeight: double.infinity,
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
    final directory = await getApplicationDocumentsDirectory();
 | 
			
		||||
    final imageFile = await File(
 | 
			
		||||
      '${directory.path}/share_image_${DateFormat('yyyy-MM-dd-HH-mm-ss').format(DateTime.now())}.png',
 | 
			
		||||
    ).create();
 | 
			
		||||
    await imageFile.writeAsBytes(image);
 | 
			
		||||
 | 
			
		||||
    final filename = 'share_post#${widget.item.id}';
 | 
			
		||||
 | 
			
		||||
    if (PlatformInfo.isAndroid || PlatformInfo.isIOS) {
 | 
			
		||||
      final box = context.findRenderObject() as RenderBox?;
 | 
			
		||||
 | 
			
		||||
      final file = XFile(imageFile.path);
 | 
			
		||||
      final file = XFile.fromData(
 | 
			
		||||
        image,
 | 
			
		||||
        mimeType: 'image/png',
 | 
			
		||||
        name: filename,
 | 
			
		||||
      );
 | 
			
		||||
      await Share.shareXFiles(
 | 
			
		||||
        [file],
 | 
			
		||||
        subject: 'postShareSubject'.trParams({
 | 
			
		||||
@@ -132,15 +129,14 @@ class _PostActionState extends State<PostAction> {
 | 
			
		||||
        sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      await FileSaver.instance.saveAs(
 | 
			
		||||
        name: path.basename(imageFile.path),
 | 
			
		||||
        ext: path.extension(imageFile.path),
 | 
			
		||||
      final filepath = await FileSaver.instance.saveFile(
 | 
			
		||||
        name: filename,
 | 
			
		||||
        ext: 'png',
 | 
			
		||||
        mimeType: MimeType.png,
 | 
			
		||||
        file: imageFile,
 | 
			
		||||
        bytes: image,
 | 
			
		||||
      );
 | 
			
		||||
      context.showSnackbar('fileSavedAt'.trParams({'path': filepath}));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await imageFile.delete();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import 'package:flutter/gestures.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:get/get.dart';
 | 
			
		||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
 | 
			
		||||
@@ -73,50 +74,59 @@ class PostListEntryWidget extends StatelessWidget {
 | 
			
		||||
    required this.onUpdate,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  void _openActions(BuildContext context) {
 | 
			
		||||
    final AuthProvider auth = Get.find();
 | 
			
		||||
    if (auth.isAuthorized.isFalse) return;
 | 
			
		||||
 | 
			
		||||
    showModalBottomSheet(
 | 
			
		||||
      useRootNavigator: true,
 | 
			
		||||
      context: context,
 | 
			
		||||
      builder: (context) => PostAction(item: item),
 | 
			
		||||
    ).then((value) {
 | 
			
		||||
      if (value is Future) {
 | 
			
		||||
        value.then((_) {
 | 
			
		||||
          onUpdate();
 | 
			
		||||
        });
 | 
			
		||||
      } else if (value != null) {
 | 
			
		||||
        onUpdate();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return GestureDetector(
 | 
			
		||||
      child: PostItem(
 | 
			
		||||
        key: Key('p${item.id}'),
 | 
			
		||||
        item: item,
 | 
			
		||||
        isShowEmbed: isShowEmbed,
 | 
			
		||||
        isClickable: isNestedClickable,
 | 
			
		||||
        showFeaturedReply: showFeaturedReply,
 | 
			
		||||
        padding: padding,
 | 
			
		||||
        onComment: () {
 | 
			
		||||
          AppRouter.instance
 | 
			
		||||
              .pushNamed(
 | 
			
		||||
            'postEditor',
 | 
			
		||||
            extra: PostPublishArguments(reply: item),
 | 
			
		||||
          )
 | 
			
		||||
              .then((value) {
 | 
			
		||||
            if (value is Future) {
 | 
			
		||||
              value.then((_) {
 | 
			
		||||
    return TapRegion(
 | 
			
		||||
      child: GestureDetector(
 | 
			
		||||
        onLongPress: () => _openActions(context),
 | 
			
		||||
        child: PostItem(
 | 
			
		||||
          key: Key('p${item.id}'),
 | 
			
		||||
          item: item,
 | 
			
		||||
          isShowEmbed: isShowEmbed,
 | 
			
		||||
          isClickable: isNestedClickable,
 | 
			
		||||
          showFeaturedReply: showFeaturedReply,
 | 
			
		||||
          padding: padding,
 | 
			
		||||
          onComment: () {
 | 
			
		||||
            AppRouter.instance
 | 
			
		||||
                .pushNamed(
 | 
			
		||||
              'postEditor',
 | 
			
		||||
              extra: PostPublishArguments(reply: item),
 | 
			
		||||
            )
 | 
			
		||||
                .then((value) {
 | 
			
		||||
              if (value is Future) {
 | 
			
		||||
                value.then((_) {
 | 
			
		||||
                  onUpdate();
 | 
			
		||||
                });
 | 
			
		||||
              } else if (value != null) {
 | 
			
		||||
                onUpdate();
 | 
			
		||||
              });
 | 
			
		||||
            } else if (value != null) {
 | 
			
		||||
              onUpdate();
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        },
 | 
			
		||||
      ).paddingSymmetric(vertical: 8),
 | 
			
		||||
      onLongPress: () {
 | 
			
		||||
        final AuthProvider auth = Get.find();
 | 
			
		||||
        if (auth.isAuthorized.isFalse) return;
 | 
			
		||||
 | 
			
		||||
        showModalBottomSheet(
 | 
			
		||||
          useRootNavigator: true,
 | 
			
		||||
          context: context,
 | 
			
		||||
          builder: (context) => PostAction(item: item),
 | 
			
		||||
        ).then((value) {
 | 
			
		||||
          if (value is Future) {
 | 
			
		||||
            value.then((_) {
 | 
			
		||||
              onUpdate();
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
          } else if (value != null) {
 | 
			
		||||
            onUpdate();
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
          },
 | 
			
		||||
        ).paddingSymmetric(vertical: 8),
 | 
			
		||||
      ),
 | 
			
		||||
      onTapInside: (event) {
 | 
			
		||||
        if (event.buttons == kSecondaryMouseButton) {
 | 
			
		||||
          _openActions(context);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,8 @@ PODS:
 | 
			
		||||
    - FlutterMacOS
 | 
			
		||||
  - device_info_plus (0.0.1):
 | 
			
		||||
    - FlutterMacOS
 | 
			
		||||
  - file_saver (0.0.1):
 | 
			
		||||
    - FlutterMacOS
 | 
			
		||||
  - file_selector_macos (0.0.1):
 | 
			
		||||
    - FlutterMacOS
 | 
			
		||||
  - Firebase/Analytics (11.2.0):
 | 
			
		||||
@@ -230,6 +232,7 @@ DEPENDENCIES:
 | 
			
		||||
  - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin`)
 | 
			
		||||
  - desktop_drop (from `Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos`)
 | 
			
		||||
  - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
 | 
			
		||||
  - file_saver (from `Flutter/ephemeral/.symlinks/plugins/file_saver/macos`)
 | 
			
		||||
  - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
 | 
			
		||||
  - firebase_analytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos`)
 | 
			
		||||
  - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
 | 
			
		||||
@@ -288,6 +291,8 @@ EXTERNAL SOURCES:
 | 
			
		||||
    :path: Flutter/ephemeral/.symlinks/plugins/desktop_drop/macos
 | 
			
		||||
  device_info_plus:
 | 
			
		||||
    :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
 | 
			
		||||
  file_saver:
 | 
			
		||||
    :path: Flutter/ephemeral/.symlinks/plugins/file_saver/macos
 | 
			
		||||
  file_selector_macos:
 | 
			
		||||
    :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
 | 
			
		||||
  firebase_analytics:
 | 
			
		||||
@@ -349,6 +354,7 @@ SPEC CHECKSUMS:
 | 
			
		||||
  connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
 | 
			
		||||
  desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
 | 
			
		||||
  device_info_plus: f1aae8670672f75c4c8850ecbe0b2ddef62b0a22
 | 
			
		||||
  file_saver: 44e6fbf666677faf097302460e214e977fdd977b
 | 
			
		||||
  file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
 | 
			
		||||
  Firebase: 98e6bf5278170668a7983e12971a66b2cd57fc8c
 | 
			
		||||
  firebase_analytics: 30ff72f6d4847ff0b479d8edd92fc8582e719072
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ name: solian
 | 
			
		||||
description: "The Solar Network App"
 | 
			
		||||
publish_to: "none"
 | 
			
		||||
 | 
			
		||||
version: 1.3.7+12
 | 
			
		||||
version: 1.3.8+12
 | 
			
		||||
 | 
			
		||||
environment:
 | 
			
		||||
  sdk: ">=3.3.4 <4.0.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -111,15 +111,14 @@
 | 
			
		||||
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
  <body oncontextmenu="return false;">
 | 
			
		||||
  <picture id="splash">
 | 
			
		||||
      <source srcset="splash/img/light-1x.png 1x, splash/img/light-2x.png 2x, splash/img/light-3x.png 3x, splash/img/light-4x.png 4x" media="(prefers-color-scheme: light)">
 | 
			
		||||
      <source srcset="splash/img/dark-1x.png 1x, splash/img/dark-2x.png 2x, splash/img/dark-3x.png 3x, splash/img/dark-4x.png 4x" media="(prefers-color-scheme: dark)">
 | 
			
		||||
      <img class="center" aria-hidden="true" src="splash/img/light-1x.png" alt="">
 | 
			
		||||
  </picture>
 | 
			
		||||
  
 | 
			
		||||
  
 | 
			
		||||
    <script src="flutter_bootstrap.js" async=""></script>
 | 
			
		||||
  <script src="flutter_bootstrap.js" async=""></script>
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
</body></html>
 | 
			
		||||
		Reference in New Issue
	
	Block a user