More attachment source

This commit is contained in:
LittleSheep 2024-04-16 23:19:53 +08:00
parent 718c715cae
commit da5f3a24e7
3 changed files with 100 additions and 26 deletions

View File

@ -23,6 +23,9 @@
"attachment": "Attachment", "attachment": "Attachment",
"attachmentAdd": "Add new attachment", "attachmentAdd": "Add new attachment",
"pickPhoto": "Gallery photo", "pickPhoto": "Gallery photo",
"takePhoto": "Capture photo",
"pickVideo": "Gallery video",
"takeVideo": "Record video",
"newMoment": "Record a moment", "newMoment": "Record a moment",
"newComment": "Leave a comment", "newComment": "Leave a comment",
"postIdentityNotify": "You will create this post as", "postIdentityNotify": "You will create this post as",

View File

@ -23,6 +23,9 @@
"attachment": "附件", "attachment": "附件",
"attachmentAdd": "附加新附件", "attachmentAdd": "附加新附件",
"pickPhoto": "相册照片", "pickPhoto": "相册照片",
"takePhoto": "拍摄照片",
"pickVideo": "相册视频",
"takeVideo": "拍摄视频",
"newMoment": "记录时刻", "newMoment": "记录时刻",
"newComment": "留下评论", "newComment": "留下评论",
"postIdentityNotify": "你将会以该身份发表本帖子", "postIdentityNotify": "你将会以该身份发表本帖子",

View File

@ -16,8 +16,7 @@ class AttachmentEditor extends StatefulWidget {
final List<Attachment> current; final List<Attachment> current;
final void Function(List<Attachment> data) onUpdate; final void Function(List<Attachment> data) onUpdate;
const AttachmentEditor( const AttachmentEditor({super.key, required this.current, required this.onUpdate});
{super.key, required this.current, required this.onUpdate});
@override @override
State<AttachmentEditor> createState() => _AttachmentEditorState(); State<AttachmentEditor> createState() => _AttachmentEditorState();
@ -34,16 +33,46 @@ class _AttachmentEditorState extends State<AttachmentEditor> {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
builder: (context) => AttachmentEditorMethodPopup( builder: (context) => AttachmentEditorMethodPopup(
pickImage: () => pickImageToUpload(context), pickImage: () => pickImageToUpload(context, ImageSource.gallery),
takeImage: () => pickImageToUpload(context, ImageSource.camera),
pickVideo: () => pickVideoToUpload(context, ImageSource.gallery),
takeVideo: () => pickVideoToUpload(context, ImageSource.camera),
), ),
); );
} }
Future<void> pickImageToUpload(BuildContext context) async { Future<void> pickImageToUpload(BuildContext context, ImageSource source) async {
final auth = context.read<AuthProvider>(); final auth = context.read<AuthProvider>();
if (!await auth.isAuthorized()) return; if (!await auth.isAuthorized()) return;
final image = await _imagePicker.pickImage(source: ImageSource.gallery); final image = await _imagePicker.pickImage(source: source);
if (image == null) return;
setState(() => _isSubmitting = true);
final file = File(image.path);
final hashcode = await calculateSha256(file);
if (Navigator.canPop(context)) {
Navigator.pop(context);
}
try {
await uploadAttachment(file, hashcode);
} catch (err) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Something went wrong... $err")),
);
} finally {
setState(() => _isSubmitting = false);
}
}
Future<void> pickVideoToUpload(BuildContext context, ImageSource source) async {
final auth = context.read<AuthProvider>();
if (!await auth.isAuthorized()) return;
final image = await _imagePicker.pickVideo(source: source);
if (image == null) return; if (image == null) return;
setState(() => _isSubmitting = true); setState(() => _isSubmitting = true);
@ -87,8 +116,7 @@ class _AttachmentEditorState extends State<AttachmentEditor> {
} }
} }
Future<void> disposeAttachment( Future<void> disposeAttachment(BuildContext context, Attachment item, int index) async {
BuildContext context, Attachment item, int index) async {
final auth = context.read<AuthProvider>(); final auth = context.read<AuthProvider>();
final req = MultipartRequest( final req = MultipartRequest(
@ -137,17 +165,7 @@ class _AttachmentEditorState extends State<AttachmentEditor> {
if (bytes == 0) return '0 Bytes'; if (bytes == 0) return '0 Bytes';
const k = 1024; const k = 1024;
final dm = decimals < 0 ? 0 : decimals; final dm = decimals < 0 ? 0 : decimals;
final sizes = [ final sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
'Bytes',
'KiB',
'MiB',
'GiB',
'TiB',
'PiB',
'EiB',
'ZiB',
'YiB'
];
final i = (math.log(bytes) / math.log(k)).floor().toInt(); final i = (math.log(bytes) / math.log(k)).floor().toInt();
return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}'; return '${(bytes / math.pow(k, i)).toStringAsFixed(dm)} ${sizes[i]}';
} }
@ -184,9 +202,7 @@ class _AttachmentEditorState extends State<AttachmentEditor> {
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data == true) { if (snapshot.hasData && snapshot.data == true) {
return TextButton( return TextButton(
onPressed: _isSubmitting onPressed: _isSubmitting ? null : () => viewAttachMethods(context),
? null
: () => viewAttachMethods(context),
style: TextButton.styleFrom(shape: const CircleBorder()), style: TextButton.styleFrom(shape: const CircleBorder()),
child: const Icon(Icons.add_circle), child: const Icon(Icons.add_circle),
); );
@ -230,8 +246,7 @@ class _AttachmentEditorState extends State<AttachmentEditor> {
foregroundColor: Colors.red, foregroundColor: Colors.red,
), ),
child: const Icon(Icons.delete), child: const Icon(Icons.delete),
onPressed: () => onPressed: () => disposeAttachment(context, element, index),
disposeAttachment(context, element, index),
), ),
], ],
), ),
@ -247,8 +262,17 @@ class _AttachmentEditorState extends State<AttachmentEditor> {
class AttachmentEditorMethodPopup extends StatelessWidget { class AttachmentEditorMethodPopup extends StatelessWidget {
final Function pickImage; final Function pickImage;
final Function takeImage;
final Function pickVideo;
final Function takeVideo;
const AttachmentEditorMethodPopup({super.key, required this.pickImage}); const AttachmentEditorMethodPopup({
super.key,
required this.pickImage,
required this.takeImage,
required this.pickVideo,
required this.takeVideo,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -280,14 +304,58 @@ class AttachmentEditorMethodPopup extends StatelessWidget {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon(Icons.add_photo_alternate, const Icon(Icons.add_photo_alternate, color: Colors.indigo),
color: Colors.indigo),
const SizedBox(height: 8), const SizedBox(height: 8),
Text(AppLocalizations.of(context)!.pickPhoto), Text(AppLocalizations.of(context)!.pickPhoto),
], ],
), ),
), ),
), ),
InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () => takeImage(),
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.camera_alt, color: Colors.indigo),
const SizedBox(height: 8),
Text(AppLocalizations.of(context)!.takePhoto),
],
),
),
),
InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () => pickVideo(),
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.camera, color: Colors.indigo),
const SizedBox(height: 8),
Text(AppLocalizations.of(context)!.pickVideo),
],
),
),
),
InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () => takeVideo(),
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.video_call, color: Colors.indigo),
const SizedBox(height: 8),
Text(AppLocalizations.of(context)!.takeVideo),
],
),
),
),
], ],
), ),
), ),