relatica/lib/screens/image_viewer_screen.dart

182 wiersze
5.0 KiB
Dart

import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../globals.dart';
import '../models/media_attachment.dart';
import '../services/auth_service.dart';
import '../utils/snackbar_builder.dart';
class ImageViewerScreen extends StatefulWidget {
final List<MediaAttachment> attachments;
final int initialIndex;
const ImageViewerScreen({
super.key,
required this.attachments,
int this.initialIndex = 0,
});
@override
State<ImageViewerScreen> createState() => _ImageViewerScreenState();
}
class _ImageViewerScreenState extends State<ImageViewerScreen> {
var index = 0;
@override
void initState() {
index = widget.initialIndex;
}
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 getIt<AuthService>()
.currentClient
.value
.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 params = SaveFileDialogParams(
data: bytesResult.value,
fileName: filename,
);
await FlutterFileDialog.saveFile(params: params);
} 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) {
print('Index: $index');
final attachment = widget.attachments[index];
final height = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () => saveImage(context, attachment),
icon: const Icon(Icons.download))
],
),
body: SafeArea(
child: Stack(
children: [
GestureDetector(
onHorizontalDragEnd: (details) {
final velocity = details.primaryVelocity ?? 0.0;
print('Velocity: $velocity');
if (velocity > 0 && index > 0) {
setState(() {
index--;
});
}
if (velocity < 0 && index < widget.attachments.length - 1) {
setState(() {
index++;
});
}
},
child: buildCoreViewer(attachment),
),
if (index > 0)
Positioned(
top: height / 2,
left: 0.0,
child: buildButton(
Icon(Icons.keyboard_arrow_left),
onPressed: () {
setState(() {
index--;
});
},
),
),
if (index < widget.attachments.length - 1)
Positioned(
top: height / 2,
right: 0.0,
child: buildButton(
Icon(Icons.keyboard_arrow_right),
onPressed: () {
setState(() {
index++;
});
},
),
),
],
),
),
);
}
Widget buildCoreViewer(MediaAttachment attachment) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: width,
height: 0.8 * height,
child: InteractiveViewer(
maxScale: 10.0,
scaleFactor: 400,
child: CachedNetworkImage(imageUrl: attachment.uri.toString()),
),
),
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(attachment.description),
),
),
),
],
);
}
Widget buildButton(Icon icon, {required Function() onPressed}) {
return Center(
child: Ink(
decoration: ShapeDecoration(
color: Theme.of(context).focusColor,
shape: CircleBorder(),
),
child: IconButton(
icon: icon,
color: Colors.white,
onPressed: onPressed,
),
),
);
}
}