✨ Add attachment from camera
This commit is contained in:
		| @@ -256,6 +256,8 @@ | ||||
|   }, | ||||
|   "addAttachmentFromAlbum": "Add from album", | ||||
|   "addAttachmentFromClipboard": "Paste file", | ||||
|   "addAttachmentFromCameraPhoto": "Take photo", | ||||
|   "addAttachmentFromCameraVideo": "Take video", | ||||
|   "attachmentPastedImage": "Pasted Image", | ||||
|   "attachmentInsertLink": "Insert Link", | ||||
|   "attachmentSetAsPostThumbnail": "Set as post thumbnail", | ||||
|   | ||||
| @@ -256,6 +256,8 @@ | ||||
|   }, | ||||
|   "addAttachmentFromAlbum": "从相册中添加附件", | ||||
|   "addAttachmentFromClipboard": "粘贴附件", | ||||
|   "addAttachmentFromCameraPhoto": "拍摄照片", | ||||
|   "addAttachmentFromCameraVideo": "拍摄视频", | ||||
|   "attachmentPastedImage": "粘贴的图片", | ||||
|   "attachmentInsertLink": "插入连接", | ||||
|   "attachmentSetAsPostThumbnail": "设置为帖子缩略图", | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| import 'dart:io'; | ||||
|  | ||||
| import 'package:collection/collection.dart'; | ||||
| import 'package:dropdown_button2/dropdown_button2.dart'; | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/gestures.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| @@ -75,6 +78,16 @@ class _PostEditorScreenState extends State<PostEditorScreen> { | ||||
|  | ||||
|   final _imagePicker = ImagePicker(); | ||||
|  | ||||
|   void _takeMedia(bool isVideo) async { | ||||
|     final result = isVideo | ||||
|         ? await _imagePicker.pickVideo(source: ImageSource.camera) | ||||
|         : await _imagePicker.pickImage(source: ImageSource.camera); | ||||
|     if (result == null) return; | ||||
|     _writeController.addAttachments([ | ||||
|       PostWriteMedia.fromFile(result), | ||||
|     ]); | ||||
|   } | ||||
|  | ||||
|   void _selectMedia() async { | ||||
|     final result = await _imagePicker.pickMultipleMedia(); | ||||
|     if (result.isEmpty) return; | ||||
| @@ -396,6 +409,32 @@ class _PostEditorScreenState extends State<PostEditorScreen> { | ||||
|                                       color: Theme.of(context).colorScheme.primary, | ||||
|                                     ), | ||||
|                                     itemBuilder: (context) => [ | ||||
|                                       if (!kIsWeb && !Platform.isLinux && !Platform.isMacOS && !Platform.isWindows) | ||||
|                                         PopupMenuItem( | ||||
|                                           child: Row( | ||||
|                                             children: [ | ||||
|                                               const Icon(Symbols.photo_camera), | ||||
|                                               const Gap(16), | ||||
|                                               Text('addAttachmentFromCameraPhoto').tr(), | ||||
|                                             ], | ||||
|                                           ), | ||||
|                                           onTap: () { | ||||
|                                             _takeMedia(false); | ||||
|                                           }, | ||||
|                                         ), | ||||
|                                       if (!kIsWeb && !Platform.isLinux && !Platform.isMacOS && !Platform.isWindows) | ||||
|                                         PopupMenuItem( | ||||
|                                           child: Row( | ||||
|                                             children: [ | ||||
|                                               const Icon(Symbols.videocam), | ||||
|                                               const Gap(16), | ||||
|                                               Text('addAttachmentFromCameraVideo').tr(), | ||||
|                                             ], | ||||
|                                           ), | ||||
|                                           onTap: () { | ||||
|                                             _takeMedia(true); | ||||
|                                           }, | ||||
|                                         ), | ||||
|                                       PopupMenuItem( | ||||
|                                         child: Row( | ||||
|                                           children: [ | ||||
| @@ -443,7 +482,7 @@ class _PostEditorScreenState extends State<PostEditorScreen> { | ||||
|                     ).padding(horizontal: 16), | ||||
|                   ], | ||||
|                 ).padding( | ||||
|                   bottom: MediaQuery.of(context).padding.bottom, | ||||
|                   bottom: MediaQuery.of(context).padding.bottom + 8, | ||||
|                   top: 4, | ||||
|                 ), | ||||
|               ), | ||||
|   | ||||
| @@ -1,4 +1,7 @@ | ||||
| import 'dart:io'; | ||||
|  | ||||
| import 'package:easy_localization/easy_localization.dart'; | ||||
| import 'package:flutter/foundation.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:gap/gap.dart'; | ||||
| import 'package:image_picker/image_picker.dart'; | ||||
| @@ -125,6 +128,17 @@ class ChatMessageInputState extends State<ChatMessageInput> { | ||||
|   final List<PostWriteMedia> _attachments = List.empty(growable: true); | ||||
|   final _imagePicker = ImagePicker(); | ||||
|  | ||||
|   void _takeMedia(bool isVideo) async { | ||||
|     final result = isVideo | ||||
|         ? await _imagePicker.pickVideo(source: ImageSource.camera) | ||||
|         : await _imagePicker.pickImage(source: ImageSource.camera); | ||||
|     if (result == null) return; | ||||
|     _attachments.add( | ||||
|       PostWriteMedia.fromFile(result), | ||||
|     ); | ||||
|     setState(() {}); | ||||
|   } | ||||
|  | ||||
|   void _selectMedia() async { | ||||
|     final result = await _imagePicker.pickMultipleMedia(); | ||||
|     if (result.isEmpty) return; | ||||
| @@ -283,6 +297,32 @@ class ChatMessageInputState extends State<ChatMessageInput> { | ||||
|                   color: Theme.of(context).colorScheme.primary, | ||||
|                 ), | ||||
|                 itemBuilder: (context) => [ | ||||
|                   if (!kIsWeb && !Platform.isLinux && !Platform.isMacOS && !Platform.isWindows) | ||||
|                     PopupMenuItem( | ||||
|                       child: Row( | ||||
|                         children: [ | ||||
|                           const Icon(Symbols.photo_camera), | ||||
|                           const Gap(16), | ||||
|                           Text('addAttachmentFromCameraPhoto').tr(), | ||||
|                         ], | ||||
|                       ), | ||||
|                       onTap: () { | ||||
|                         _takeMedia(false); | ||||
|                       }, | ||||
|                     ), | ||||
|                   if (!kIsWeb && !Platform.isLinux && !Platform.isMacOS && !Platform.isWindows) | ||||
|                     PopupMenuItem( | ||||
|                       child: Row( | ||||
|                         children: [ | ||||
|                           const Icon(Symbols.videocam), | ||||
|                           const Gap(16), | ||||
|                           Text('addAttachmentFromCameraVideo').tr(), | ||||
|                         ], | ||||
|                       ), | ||||
|                       onTap: () { | ||||
|                         _takeMedia(true); | ||||
|                       }, | ||||
|                     ), | ||||
|                   PopupMenuItem( | ||||
|                     child: Row( | ||||
|                       children: [ | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import 'package:surface/providers/navigation.dart'; | ||||
|  | ||||
| class AppNavigationDrawer extends StatefulWidget { | ||||
|   final double? elevation; | ||||
|  | ||||
|   const AppNavigationDrawer({super.key, this.elevation}); | ||||
|  | ||||
|   @override | ||||
| @@ -19,9 +20,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> { | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     WidgetsBinding.instance.addPostFrameCallback((_) { | ||||
|       context | ||||
|           .read<NavigationProvider>() | ||||
|           .autoDetectIndex(GoRouter.maybeOf(context)); | ||||
|       context.read<NavigationProvider>().autoDetectIndex(GoRouter.maybeOf(context)); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| @@ -29,9 +28,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> { | ||||
|   Widget build(BuildContext context) { | ||||
|     final nav = context.watch<NavigationProvider>(); | ||||
|  | ||||
|     final backgroundColor = ResponsiveBreakpoints.of(context).largerThan(TABLET) | ||||
|         ? Colors.transparent | ||||
|         : null; | ||||
|     final backgroundColor = ResponsiveBreakpoints.of(context).largerThan(TABLET) ? Colors.transparent : null; | ||||
|  | ||||
|     return ListenableBuilder( | ||||
|       listenable: nav, | ||||
| @@ -51,13 +48,14 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> { | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 Text('Solar Network').bold(), | ||||
|                 Text('Canary Preview 2.0α').fontSize(12).textColor( | ||||
|                     Theme.of(context).colorScheme.onSurface.withOpacity(0.5)), | ||||
|                 Text('Canary Preview 2.0α') | ||||
|                     .fontSize(12) | ||||
|                     .textColor(Theme.of(context).colorScheme.onSurface.withOpacity(0.5)), | ||||
|               ], | ||||
|             ).padding( | ||||
|               horizontal: 32, | ||||
|               top: MediaQuery.of(context).padding.top > 32 ? 8 : 32, | ||||
|               bottom: 8, | ||||
|               top: MediaQuery.of(context).padding.top + 8, | ||||
|               bottom: 12, | ||||
|             ), | ||||
|             ...destinations.where((ele) => ele.isPinned).map((ele) { | ||||
|               return NavigationDrawerDestination( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user