✨ Post reactions
This commit is contained in:
parent
1c7077225e
commit
a011278fae
@ -1,33 +1,92 @@
|
|||||||
PODS:
|
PODS:
|
||||||
|
- DKImagePickerController/Core (4.3.9):
|
||||||
|
- DKImagePickerController/ImageDataManager
|
||||||
|
- DKImagePickerController/Resource
|
||||||
|
- DKImagePickerController/ImageDataManager (4.3.9)
|
||||||
|
- DKImagePickerController/PhotoGallery (4.3.9):
|
||||||
|
- DKImagePickerController/Core
|
||||||
|
- DKPhotoGallery
|
||||||
|
- DKImagePickerController/Resource (4.3.9)
|
||||||
|
- DKPhotoGallery (0.0.19):
|
||||||
|
- DKPhotoGallery/Core (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Model (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Preview (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Resource (= 0.0.19)
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Core (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Preview
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Model (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Preview (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Resource
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Resource (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- file_picker (0.0.1):
|
||||||
|
- DKImagePickerController/PhotoGallery
|
||||||
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_secure_storage (6.0.0):
|
- flutter_secure_storage (6.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- image_picker_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- SDWebImage (5.19.2):
|
||||||
|
- SDWebImage/Core (= 5.19.2)
|
||||||
|
- SDWebImage/Core (5.19.2)
|
||||||
|
- SwiftyGif (5.4.5)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
|
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||||
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
|
||||||
|
SPEC REPOS:
|
||||||
|
trunk:
|
||||||
|
- DKImagePickerController
|
||||||
|
- DKPhotoGallery
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
|
file_picker:
|
||||||
|
:path: ".symlinks/plugins/file_picker/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||||
|
image_picker_ios:
|
||||||
|
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
|
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||||
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
|
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||||
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
|
SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a
|
||||||
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
|
|
||||||
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
|
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
|
||||||
|
@ -28,6 +28,12 @@
|
|||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
<string>Main</string>
|
<string>Main</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>Allow you add photo to your message or post</string>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>Allow you take photo/video for your message or post</string>
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>Allow you record audio for your message or post</string>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
35
lib/exts.dart
Normal file
35
lib/exts.dart
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
extension SolianExtenions on BuildContext {
|
||||||
|
void showSnackbar(String content) {
|
||||||
|
ScaffoldMessenger.of(this).showSnackBar(SnackBar(
|
||||||
|
content: Text(content),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> showErrorDialog(dynamic exception) {
|
||||||
|
String formatMessage(dynamic exception) {
|
||||||
|
final message = exception.toString();
|
||||||
|
if (message.trim().isEmpty) return '';
|
||||||
|
return message
|
||||||
|
.split(' ')
|
||||||
|
.map((element) => '${element[0].toUpperCase()}${element.substring(1).toLowerCase()}')
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return showDialog<void>(
|
||||||
|
context: this,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
title: Text('errorHappened'.tr),
|
||||||
|
content: Text(formatMessage(exception)),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(ctx),
|
||||||
|
child: Text('okay'.tr),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
@ -29,7 +30,7 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
if (messages.last.contains('risk')) {
|
if (messages.last.contains('risk')) {
|
||||||
final ticketId = RegExp(r'ticketId=(\d+)').firstMatch(messages.last);
|
final ticketId = RegExp(r'ticketId=(\d+)').firstMatch(messages.last);
|
||||||
if (ticketId == null) {
|
if (ticketId == null) {
|
||||||
Get.snackbar('errorHappened'.tr, 'Requested to multi-factor authenticate, but the ticket id was not found');
|
context.showErrorDialog('Requested to multi-factor authenticate, but the ticket id was not found');
|
||||||
}
|
}
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
AppRouter.instance.replaceNamed('auth.sign-in');
|
AppRouter.instance.replaceNamed('auth.sign-in');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('errorHappened'.tr, resp.bodyString!);
|
context.showErrorDialog(resp.bodyString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
import 'package:solian/widgets/account/account_avatar.dart';
|
import 'package:solian/widgets/account/account_avatar.dart';
|
||||||
import 'package:solian/shells/nav_shell.dart' as shell;
|
import 'package:solian/shells/nav_shell.dart' as shell;
|
||||||
|
import 'package:solian/widgets/attachments/attachment_publish.dart';
|
||||||
|
|
||||||
class PostPublishingScreen extends StatefulWidget {
|
class PostPublishingScreen extends StatefulWidget {
|
||||||
const PostPublishingScreen({super.key});
|
const PostPublishingScreen({super.key});
|
||||||
@ -19,6 +21,19 @@ class _PostPublishingScreenState extends State<PostPublishingScreen> {
|
|||||||
|
|
||||||
bool _isSubmitting = false;
|
bool _isSubmitting = false;
|
||||||
|
|
||||||
|
List<String> _attachments = List.empty();
|
||||||
|
|
||||||
|
void showAttachments(BuildContext context) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AttachmentPublishingPopup(
|
||||||
|
usage: 'i.attachment',
|
||||||
|
current: _attachments,
|
||||||
|
onUpdate: (value) => _attachments = value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void applyPost() async {
|
void applyPost() async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
if (!await auth.isAuthorized) return;
|
if (!await auth.isAuthorized) return;
|
||||||
@ -32,9 +47,10 @@ class _PostPublishingScreenState extends State<PostPublishingScreen> {
|
|||||||
|
|
||||||
final resp = await client.post('/api/posts', {
|
final resp = await client.post('/api/posts', {
|
||||||
'content': _contentController.value.text,
|
'content': _contentController.value.text,
|
||||||
|
'attachments': _attachments,
|
||||||
});
|
});
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
Get.snackbar('errorHappened'.tr, resp.bodyString!);
|
context.showErrorDialog(resp.bodyString);
|
||||||
} else {
|
} else {
|
||||||
AppRouter.instance.pop(resp.body);
|
AppRouter.instance.pop(resp.body);
|
||||||
}
|
}
|
||||||
@ -107,7 +123,7 @@ class _PostPublishingScreenState extends State<PostPublishingScreen> {
|
|||||||
TextButton(
|
TextButton(
|
||||||
style: TextButton.styleFrom(shape: const CircleBorder()),
|
style: TextButton.styleFrom(shape: const CircleBorder()),
|
||||||
child: const Icon(Icons.camera_alt),
|
child: const Icon(Icons.camera_alt),
|
||||||
onPressed: () {},
|
onPressed: () => showAttachments(context),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -4,6 +4,7 @@ class SolianMessages extends Translations {
|
|||||||
@override
|
@override
|
||||||
Map<String, Map<String, String>> get keys => {
|
Map<String, Map<String, String>> get keys => {
|
||||||
'en_US': {
|
'en_US': {
|
||||||
|
'okay': 'Okay',
|
||||||
'next': 'Next',
|
'next': 'Next',
|
||||||
'page': 'Page',
|
'page': 'Page',
|
||||||
'home': 'Home',
|
'home': 'Home',
|
||||||
@ -32,9 +33,16 @@ class SolianMessages extends Translations {
|
|||||||
'postReaction': 'Reactions of the Post',
|
'postReaction': 'Reactions of the Post',
|
||||||
'reactAdd': 'React',
|
'reactAdd': 'React',
|
||||||
'reactCompleted': 'Your reaction has been added',
|
'reactCompleted': 'Your reaction has been added',
|
||||||
'reactUncompleted': 'Your reaction has been removed'
|
'reactUncompleted': 'Your reaction has been removed',
|
||||||
|
'attachmentAdd': 'Attach attachments',
|
||||||
|
'attachmentAddGalleryPhoto': 'Gallery photo',
|
||||||
|
'attachmentAddGalleryVideo': 'Gallery video',
|
||||||
|
'attachmentAddCameraPhoto': 'Capture photo',
|
||||||
|
'attachmentAddCameraVideo': 'Capture video',
|
||||||
|
'attachmentAddFile': 'Attach file',
|
||||||
},
|
},
|
||||||
'zh_CN': {
|
'zh_CN': {
|
||||||
|
'okay': '确认',
|
||||||
'next': '下一步',
|
'next': '下一步',
|
||||||
'page': '页面',
|
'page': '页面',
|
||||||
'home': '首页',
|
'home': '首页',
|
||||||
@ -62,7 +70,13 @@ class SolianMessages extends Translations {
|
|||||||
'postReaction': '帖子的反应',
|
'postReaction': '帖子的反应',
|
||||||
'reactAdd': '作出反应',
|
'reactAdd': '作出反应',
|
||||||
'reactCompleted': '你的反应已被添加',
|
'reactCompleted': '你的反应已被添加',
|
||||||
'reactUncompleted': '你的反应已被移除'
|
'reactUncompleted': '你的反应已被移除',
|
||||||
|
'attachmentAdd': '附加附件',
|
||||||
|
'attachmentAddGalleryPhoto': '相册照片',
|
||||||
|
'attachmentAddGalleryVideo': '相册视频',
|
||||||
|
'attachmentAddCameraPhoto': '拍摄图片',
|
||||||
|
'attachmentAddCameraVideo': '拍摄视频',
|
||||||
|
'attachmentAddFile': '附加文件',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
315
lib/widgets/attachments/attachment_publish.dart
Normal file
315
lib/widgets/attachments/attachment_publish.dart
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
import 'package:solian/exts.dart';
|
||||||
|
import 'package:solian/models/attachment.dart';
|
||||||
|
import 'package:solian/providers/auth.dart';
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:solian/services.dart';
|
||||||
|
|
||||||
|
Future<String> calculateFileSha256(File file) async {
|
||||||
|
final bytes = await file.readAsBytes();
|
||||||
|
final digest = sha256.convert(bytes);
|
||||||
|
return digest.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AttachmentPublishingPopup extends StatefulWidget {
|
||||||
|
final String usage;
|
||||||
|
final List<String> current;
|
||||||
|
final void Function(List<String> data) onUpdate;
|
||||||
|
|
||||||
|
const AttachmentPublishingPopup({
|
||||||
|
super.key,
|
||||||
|
required this.usage,
|
||||||
|
required this.current,
|
||||||
|
required this.onUpdate,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AttachmentPublishingPopup> createState() => _AttachmentPublishingPopupState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AttachmentPublishingPopupState extends State<AttachmentPublishingPopup> {
|
||||||
|
final _imagePicker = ImagePicker();
|
||||||
|
|
||||||
|
bool _isSubmitting = false;
|
||||||
|
|
||||||
|
final List<Attachment> _attachments = List.empty(growable: true);
|
||||||
|
|
||||||
|
Future<void> pickPhotoToUpload() async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
if (!await auth.isAuthorized) return;
|
||||||
|
|
||||||
|
final medias = await _imagePicker.pickMultiImage();
|
||||||
|
if (medias.isEmpty) return;
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = true);
|
||||||
|
|
||||||
|
for (final media in medias) {
|
||||||
|
final file = File(media.path);
|
||||||
|
final hash = await calculateFileSha256(file);
|
||||||
|
final image = await decodeImageFromList(await file.readAsBytes());
|
||||||
|
final ratio = image.width / image.height;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await uploadAttachment(file, hash, ratio: ratio);
|
||||||
|
} catch (err) {
|
||||||
|
this.context.showErrorDialog(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pickVideoToUpload() async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
if (!await auth.isAuthorized) return;
|
||||||
|
|
||||||
|
final media = await _imagePicker.pickVideo(source: ImageSource.gallery);
|
||||||
|
if (media == null) return;
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = true);
|
||||||
|
|
||||||
|
final file = File(media.path);
|
||||||
|
final hash = await calculateFileSha256(file);
|
||||||
|
const ratio = 16 / 9; // TODO Calculate ratio of video
|
||||||
|
|
||||||
|
try {
|
||||||
|
await uploadAttachment(file, hash, ratio: ratio);
|
||||||
|
} catch (err) {
|
||||||
|
this.context.showErrorDialog(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pickFileToUpload() async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
if (!await auth.isAuthorized) return;
|
||||||
|
|
||||||
|
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true);
|
||||||
|
if (result == null) return;
|
||||||
|
|
||||||
|
List<File> files = result.paths.map((path) => File(path!)).toList();
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = true);
|
||||||
|
|
||||||
|
for (final file in files) {
|
||||||
|
final hash = await calculateFileSha256(file);
|
||||||
|
try {
|
||||||
|
await uploadAttachment(file, hash);
|
||||||
|
} catch (err) {
|
||||||
|
this.context.showErrorDialog(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> takeMediaToUpload(bool isVideo) async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
if (!await auth.isAuthorized) return;
|
||||||
|
|
||||||
|
XFile? media;
|
||||||
|
if (isVideo) {
|
||||||
|
media = await _imagePicker.pickVideo(source: ImageSource.camera);
|
||||||
|
} else {
|
||||||
|
media = await _imagePicker.pickImage(source: ImageSource.camera);
|
||||||
|
}
|
||||||
|
if (media == null) return;
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = true);
|
||||||
|
|
||||||
|
double? ratio;
|
||||||
|
final file = File(media.path);
|
||||||
|
final hash = await calculateFileSha256(file);
|
||||||
|
|
||||||
|
if (isVideo) {
|
||||||
|
// TODO Calculate ratio of video
|
||||||
|
ratio = 16 / 9;
|
||||||
|
} else {
|
||||||
|
final image = await decodeImageFromList(await file.readAsBytes());
|
||||||
|
ratio = image.width / image.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await uploadAttachment(file, hash, ratio: ratio);
|
||||||
|
} catch (err) {
|
||||||
|
this.context.showErrorDialog(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> uploadAttachment(File file, String hash, {double? ratio}) async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
|
||||||
|
final client = GetConnect();
|
||||||
|
client.httpClient.baseUrl = ServiceFinder.services['paperclip'];
|
||||||
|
client.httpClient.addAuthenticator(auth.reqAuthenticator);
|
||||||
|
|
||||||
|
final filePayload = MultipartFile(await file.readAsBytes(), filename: basename(file.path));
|
||||||
|
final fileAlt = basename(file.path).contains('.')
|
||||||
|
? basename(file.path).substring(0, basename(file.path).lastIndexOf('.'))
|
||||||
|
: basename(file.path);
|
||||||
|
|
||||||
|
final resp = await client.post(
|
||||||
|
'/api/attachments',
|
||||||
|
FormData({
|
||||||
|
'alt': fileAlt,
|
||||||
|
'file': filePayload,
|
||||||
|
'hash': hash,
|
||||||
|
'usage': widget.usage,
|
||||||
|
'metadata': {
|
||||||
|
if (ratio != null) 'ratio': ratio,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (resp.statusCode == 200) {
|
||||||
|
var result = Attachment.fromJson(resp.body);
|
||||||
|
setState(() => _attachments.add(result));
|
||||||
|
widget.onUpdate(_attachments.map((e) => e.uuid).toList());
|
||||||
|
} else {
|
||||||
|
throw Exception(resp.bodyString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> disposeAttachment(Attachment item, int index) async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
|
||||||
|
final client = GetConnect();
|
||||||
|
client.httpClient.baseUrl = ServiceFinder.services['paperclip'];
|
||||||
|
client.httpClient.addAuthenticator(auth.reqAuthenticator);
|
||||||
|
|
||||||
|
setState(() => _isSubmitting = true);
|
||||||
|
var resp = await client.delete('/api/attachments/${item.id}');
|
||||||
|
if (resp.statusCode == 200) {
|
||||||
|
setState(() => _attachments.removeAt(index));
|
||||||
|
widget.onUpdate(_attachments.map((e) => e.uuid).toList());
|
||||||
|
} else {
|
||||||
|
this.context.showErrorDialog(resp.bodyString);
|
||||||
|
}
|
||||||
|
setState(() => _isSubmitting = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatBytes(int bytes, {int decimals = 2}) {
|
||||||
|
if (bytes == 0) return '0 Bytes';
|
||||||
|
const k = 1024;
|
||||||
|
final dm = decimals < 0 ? 0 : decimals;
|
||||||
|
final sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||||
|
final i = (math.log(bytes) / math.log(k)).floor().toInt();
|
||||||
|
return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
const density = VisualDensity(horizontal: 0, vertical: 0);
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
child: SizedBox(
|
||||||
|
height: MediaQuery.of(context).size.height * 0.85,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'attachmentAdd'.tr,
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
).paddingOnly(left: 24, right: 24, top: 32, bottom: 16),
|
||||||
|
_isSubmitting ? const LinearProgressIndicator().animate().scaleX() : Container(),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: _attachments.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final element = _attachments[index];
|
||||||
|
final fileType = element.mimetype.split('/').first;
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.only(left: 16, right: 8, bottom: 16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
element.alt,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${fileType[0].toUpperCase()}${fileType.substring(1)} · ${formatBytes(element.size)}',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
foregroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.delete),
|
||||||
|
onPressed: () => disposeAttachment(element, index),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(thickness: 0.3, height: 0.3),
|
||||||
|
SizedBox(
|
||||||
|
height: 64,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 0,
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
runAlignment: WrapAlignment.center,
|
||||||
|
children: [
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.add_photo_alternate),
|
||||||
|
label: Text('attachmentAddGalleryPhoto'.tr),
|
||||||
|
style: const ButtonStyle(visualDensity: density),
|
||||||
|
onPressed: () => pickPhotoToUpload(),
|
||||||
|
),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.add_road),
|
||||||
|
label: Text('attachmentAddGalleryVideo'.tr),
|
||||||
|
style: const ButtonStyle(visualDensity: density),
|
||||||
|
onPressed: () => pickVideoToUpload(),
|
||||||
|
),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.photo_camera_back),
|
||||||
|
label: Text('attachmentAddCameraPhoto'.tr),
|
||||||
|
style: const ButtonStyle(visualDensity: density),
|
||||||
|
onPressed: () => takeMediaToUpload(false),
|
||||||
|
),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.video_camera_back_outlined),
|
||||||
|
label: Text('attachmentAddCameraVideo'.tr),
|
||||||
|
style: const ButtonStyle(visualDensity: density),
|
||||||
|
onPressed: () => takeMediaToUpload(true),
|
||||||
|
),
|
||||||
|
ElevatedButton.icon(
|
||||||
|
icon: const Icon(Icons.file_present_rounded),
|
||||||
|
label: Text('attachmentAddFile'.tr),
|
||||||
|
style: const ButtonStyle(visualDensity: density),
|
||||||
|
onPressed: () => pickFileToUpload(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).paddingSymmetric(horizontal: 12),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/models/post.dart';
|
import 'package:solian/models/post.dart';
|
||||||
import 'package:solian/models/reaction.dart';
|
import 'package:solian/models/reaction.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
@ -52,12 +53,12 @@ class _PostQuickActionState extends State<PostQuickAction> {
|
|||||||
});
|
});
|
||||||
if (resp.statusCode == 201) {
|
if (resp.statusCode == 201) {
|
||||||
widget.onReact(symbol, 1);
|
widget.onReact(symbol, 1);
|
||||||
Get.snackbar('', 'reactCompleted'.tr);
|
context.showSnackbar('reactCompleted'.tr);
|
||||||
} else if (resp.statusCode == 204) {
|
} else if (resp.statusCode == 204) {
|
||||||
widget.onReact(symbol, -1);
|
widget.onReact(symbol, -1);
|
||||||
Get.snackbar('', 'reactUncompleted'.tr);
|
context.showSnackbar('reactUncompleted'.tr);
|
||||||
} else {
|
} else {
|
||||||
Get.snackbar('errorHappened'.tr, resp.bodyString!);
|
context.showErrorDialog(resp.bodyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() => _isSubmitting = false);
|
setState(() => _isSubmitting = false);
|
||||||
|
@ -6,10 +6,14 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
file_selector_linux
|
||||||
flutter_secure_storage_linux
|
flutter_secure_storage_linux
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
@ -5,11 +5,13 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import file_selector_macos
|
||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_macos
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
|
132
pubspec.lock
132
pubspec.lock
@ -57,8 +57,16 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.18.0"
|
version: "1.18.0"
|
||||||
crypto:
|
cross_file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4+1"
|
||||||
|
crypto:
|
||||||
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
||||||
@ -89,6 +97,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.2"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "29c90806ac5f5fb896547720b73b17ee9aed9bba540dc5d91fe29f8c5745b10a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.3"
|
||||||
|
file_selector_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_linux
|
||||||
|
sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.2+1"
|
||||||
|
file_selector_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_macos
|
||||||
|
sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.4"
|
||||||
|
file_selector_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_platform_interface
|
||||||
|
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.2"
|
||||||
|
file_selector_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_windows
|
||||||
|
sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.3+1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -118,6 +166,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "0.7.1"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.19"
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -224,6 +280,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
image_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: image_picker
|
||||||
|
sha256: "33974eca2e87e8b4e3727f1b94fa3abcb25afe80b6bc2c4d449a0e150aedf720"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
image_picker_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_android
|
||||||
|
sha256: "0f57fee1e8bfadf8cc41818bbcd7f72e53bb768a54d9496355d5e8a5681a19f1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.12+1"
|
||||||
|
image_picker_for_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_for_web
|
||||||
|
sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.4"
|
||||||
|
image_picker_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_ios
|
||||||
|
sha256: "4824d8c7f6f89121ef0122ff79bb00b009607faecc8545b86bca9ab5ce1e95bf"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.11+2"
|
||||||
|
image_picker_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_linux
|
||||||
|
sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1+1"
|
||||||
|
image_picker_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_macos
|
||||||
|
sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1+1"
|
||||||
|
image_picker_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_platform_interface
|
||||||
|
sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.10.0"
|
||||||
|
image_picker_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_windows
|
||||||
|
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1+1"
|
||||||
infinite_scroll_pagination:
|
infinite_scroll_pagination:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -320,6 +440,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.14.0"
|
version: "1.14.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.5"
|
||||||
oauth2:
|
oauth2:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -329,7 +457,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.2"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
|
@ -45,6 +45,10 @@ dependencies:
|
|||||||
carousel_slider: ^4.2.1
|
carousel_slider: ^4.2.1
|
||||||
url_launcher: ^6.2.6
|
url_launcher: ^6.2.6
|
||||||
infinite_scroll_pagination: ^4.0.0
|
infinite_scroll_pagination: ^4.0.0
|
||||||
|
image_picker: ^1.1.1
|
||||||
|
file_picker: ^8.0.3
|
||||||
|
crypto: ^3.0.3
|
||||||
|
path: ^1.9.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -6,10 +6,13 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
file_selector_windows
|
||||||
flutter_secure_storage_windows
|
flutter_secure_storage_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user