relatica/lib/screens/media_viewer_screen.dart

207 wiersze
6.2 KiB
Dart

import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../controls/audio_video/av_control.dart';
import '../controls/login_aware_cached_network_image.dart';
import '../friendica_client/friendica_client.dart';
import '../globals.dart';
import '../models/attachment_media_type_enum.dart';
import '../models/media_attachment.dart';
import '../services/auth_service.dart';
import '../utils/snackbar_builder.dart';
class MediaViewerScreen extends StatefulWidget {
final List<MediaAttachment> attachments;
final int initialIndex;
const MediaViewerScreen({
super.key,
required this.attachments,
this.initialIndex = 0,
});
@override
State<MediaViewerScreen> createState() => _MediaViewerScreenState();
}
class _MediaViewerScreenState extends State<MediaViewerScreen> {
var currentIndex = 0;
@override
void initState() {
super.initState();
currentIndex = widget.initialIndex;
}
void nextAttachment() {
if (currentIndex >= widget.attachments.length - 1) {
return;
}
setState(() {
currentIndex++;
});
}
void previousAttachment() {
if (currentIndex < 1) {
return;
}
setState(() {
currentIndex--;
});
}
Future<void> saveImage(
BuildContext context,
MediaAttachment attachment,
) async {
buildSnackbar(context, 'Downloading full image to save locally');
final appsDir = await getApplicationDocumentsDirectory();
final filename = p.basename(attachment.fullFileUri.path);
final bytesResult =
await RemoteFileClient(getIt<AccountsService>().currentProfile)
.getFileBytes(attachment.uri);
if (bytesResult.isFailure && mounted) {
buildSnackbar(context,
'Error getting full size version of file: ${bytesResult.error}');
return;
}
if (Platform.isAndroid || Platform.isIOS) {
final saveResult = await ImageGallerySaver.saveImage(bytesResult.value);
if (saveResult['isSuccess']) {
buildSnackbar(context, 'Image saved to gallery');
} else {
buildSnackbar(context, 'Unable to save to gallery, check permissions');
}
} else {
final location = await FilePicker.platform.saveFile(
dialogTitle: 'Save Image',
fileName: filename,
initialDirectory: appsDir.path,
);
if (location != null) {
await File(location).writeAsBytes(bytesResult.value);
}
}
}
@override
Widget build(BuildContext context) {
final currentAttachment = widget.attachments[currentIndex];
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height * 1.0;
final mediaHeight = height;
late final bool canSave;
late final Widget mediaViewer;
switch (currentAttachment.explicitType) {
case AttachmentMediaType.image:
canSave = true;
mediaViewer = InteractiveViewer(
maxScale: 10.0,
scaleFactor: 400,
child: LoginAwareCachedNetworkImage(
imageUrl: currentAttachment.mainUri.toString()),
);
break;
case AttachmentMediaType.unknown:
case AttachmentMediaType.video:
canSave = false;
if (Platform.isLinux) {
mediaViewer = Text(
'No media viewer for ${currentAttachment.explicitType.name} type for link ${currentAttachment.fullFileUri}');
} else {
mediaViewer = SizedBox(
width: width,
height: mediaHeight,
child: AVControl(
videoUrl: currentAttachment.fullFileUri.toString(),
description: currentAttachment.description,
),
);
}
break;
}
return Scaffold(
appBar: AppBar(
actions: [
if (canSave)
IconButton(
onPressed: () => saveImage(context, currentAttachment),
icon: const Icon(Icons.download))
],
),
body: SafeArea(
child: Stack(
children: [
SizedBox(
height: height,
width: width,
child: mediaViewer,
),
if (widget.attachments.length > 1) ...[
Positioned(
bottom: mediaHeight * 0.5,
child: Opacity(
opacity: 0.8,
child: currentIndex < 1
? null
: Container(
color: Colors.black,
child: IconButton(
color: Colors.white,
onPressed: previousAttachment,
icon: const Icon(Icons.chevron_left),
),
),
),
),
Positioned(
bottom: mediaHeight * 0.5,
right: 0.0,
child: Opacity(
opacity: 0.8,
child: currentIndex >= widget.attachments.length - 1
? null
: Container(
color: Colors.black,
child: IconButton(
color: Colors.white,
onPressed: nextAttachment,
icon: const Icon(Icons.chevron_right),
),
),
),
),
if (currentAttachment.description.isNotEmpty)
Positioned(
bottom: 5.0,
left: 5.0,
child: ElevatedButton(
onPressed: () async => await showConfirmDialog(
context,
currentAttachment.description,
),
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context)
.scaffoldBackgroundColor
.withOpacity(0.7)),
child: const Text('ALT'),
),
),
]
],
),
),
);
}
}