Remove carousel from image viewer screen (renamed media viewer) to fix bad zoom behaviors

codemagic-setup
Hank Grabowski 2023-04-22 08:45:06 -04:00
rodzic 6a5345953a
commit 581b4bf224
7 zmienionych plików z 192 dodań i 162 usunięć

Wyświetl plik

@ -4,7 +4,7 @@ import '../../globals.dart';
import '../../models/image_entry.dart';
import '../../models/visibility.dart';
import '../../screens/existing_image_selector_screen.dart';
import '../../screens/image_viewer_screen.dart';
import '../../screens/media_viewer_screen.dart';
import '../../serializers/friendica/image_entry_friendica_extensions.dart';
import '../login_aware_cached_network_image.dart';
import '../padding.dart';
@ -66,7 +66,7 @@ class _GallerySelectorControlState extends State<GallerySelectorControl> {
onDoubleTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ImageViewerScreen(
builder: (context) => MediaViewerScreen(
attachments: widget.entries
.map((i) => i.toMediaAttachment())
.toList(),

Wyświetl plik

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import '../models/attachment_media_type_enum.dart';
import '../models/media_attachment.dart';
import '../screens/image_viewer_screen.dart';
import '../screens/media_viewer_screen.dart';
import 'audio_video/av_control.dart';
import 'image_control.dart';
@ -49,7 +49,7 @@ class _MediaAttachmentViewerControlState
altText: item.description,
onTap: () async {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return ImageViewerScreen(
return MediaViewerScreen(
attachments: widget.attachments,
initialIndex: widget.index,
);

Wyświetl plik

@ -29,7 +29,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
MediaKit.ensureInitialized();
// await dotenv.load(fileName: '.env');
const enablePreview = false;
const enablePreview = true;
Logger.root.level = Level.FINER;
Logger.root.onRecord.listen((event) {
final logName = event.loggerName.isEmpty ? 'ROOT' : event.loggerName;

Wyświetl plik

@ -8,7 +8,7 @@ import '../models/visibility.dart';
import '../serializers/friendica/image_entry_friendica_extensions.dart';
import '../services/gallery_service.dart';
import '../utils/active_profile_selector.dart';
import 'image_viewer_screen.dart';
import 'media_viewer_screen.dart';
class ExistingImageSelectorScreen extends StatefulWidget {
final Visibility? visibilityFilter;
@ -171,7 +171,7 @@ class _ExistingImageSelectorScreenState
onDoubleTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ImageViewerScreen(
builder: (context) => MediaViewerScreen(
attachments: [image.toMediaAttachment()],
),
),

Wyświetl plik

@ -11,7 +11,7 @@ import '../serializers/friendica/image_entry_friendica_extensions.dart';
import '../services/gallery_service.dart';
import '../services/network_status_service.dart';
import '../utils/active_profile_selector.dart';
import 'image_viewer_screen.dart';
import 'media_viewer_screen.dart';
class GalleryScreen extends StatelessWidget {
static const thumbnailDimension = 350.0;
@ -117,7 +117,7 @@ class GalleryScreen extends StatelessWidget {
child: GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return ImageViewerScreen(
return MediaViewerScreen(
attachments: attachments,
initialIndex: index,
);

Wyświetl plik

@ -1,153 +0,0 @@
import 'dart:io';
import 'package:carousel_slider/carousel_slider.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 '../controls/login_aware_cached_network_image.dart';
import '../friendica_client/friendica_client.dart';
import '../globals.dart';
import '../models/media_attachment.dart';
import '../services/auth_service.dart';
import '../utils/clipboard_utils.dart';
import '../utils/snackbar_builder.dart';
class ImageViewerScreen extends StatefulWidget {
final List<MediaAttachment> attachments;
final int initialIndex;
const ImageViewerScreen({
super.key,
required this.attachments,
this.initialIndex = 0,
});
@override
State<ImageViewerScreen> createState() => _ImageViewerScreenState();
}
class _ImageViewerScreenState extends State<ImageViewerScreen> {
MediaAttachment? currentAttachment;
@override
void initState() {
super.initState();
currentAttachment = widget.attachments[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 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 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) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final carouselHeight =
widget.attachments.length == 1 ? height * 0.9 : height * 0.8;
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: currentAttachment == null
? null
: () => saveImage(context, currentAttachment!),
icon: const Icon(Icons.download))
],
),
body: SafeArea(
child: Column(
children: [
CarouselSlider.builder(
disableGesture: true,
itemCount: widget.attachments.length,
itemBuilder: (context, index, realIndex) {
return SizedBox(
width: width,
height: carouselHeight,
child: InteractiveViewer(
maxScale: 10.0,
scaleFactor: 400,
child: LoginAwareCachedNetworkImage(
imageUrl: widget.attachments[index].uri.toString()),
),
);
},
options: CarouselOptions(
height: carouselHeight,
initialPage: widget.initialIndex,
enableInfiniteScroll: false,
enlargeCenterPage: true,
viewportFraction: 0.95,
onPageChanged: (index, reason) {
setState(() {
currentAttachment = widget.attachments[index];
});
}),
),
if (currentAttachment != null) buildTextArea(currentAttachment!),
],
),
),
);
}
Widget buildTextArea(MediaAttachment attachment) {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: SingleChildScrollView(
child: Text(attachment.description),
)),
IconButton(
onPressed: () async {
await copyToClipboard(
context: context,
text: attachment.description,
message: 'Image description copied to clipboard');
},
icon: Icon(Icons.copy),
),
],
),
),
);
}
}

Wyświetl plik

@ -0,0 +1,183 @@
import 'dart:io';
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 '../controls/login_aware_cached_network_image.dart';
import '../friendica_client/friendica_client.dart';
import '../globals.dart';
import '../models/media_attachment.dart';
import '../services/auth_service.dart';
import '../utils/clipboard_utils.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;
}
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 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) {
final currentAttachment = widget.attachments[currentIndex];
final height = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () => saveImage(context, currentAttachment),
icon: const Icon(Icons.download))
],
),
body: SafeArea(
child: Stack(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: InteractiveViewer(
maxScale: 10.0,
scaleFactor: 400,
child: LoginAwareCachedNetworkImage(
imageUrl:
widget.attachments[currentIndex].uri.toString()),
),
),
if (currentAttachment.description.isNotEmpty)
buildTextArea(currentAttachment),
],
),
if (widget.attachments.length > 1) ...[
Positioned(
bottom: height * 0.5,
child: Opacity(
opacity: 0.8,
child: currentIndex < 1
? null
: Container(
color: Colors.black,
child: IconButton(
color: Colors.white,
onPressed: () {
setState(() {
currentIndex--;
});
},
icon: const Icon(Icons.chevron_left),
),
),
),
),
Positioned(
bottom: height * 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: () {
setState(() {
currentIndex++;
});
},
icon: const Icon(Icons.chevron_right),
),
),
),
),
]
],
),
),
);
}
Widget buildTextArea(MediaAttachment attachment) {
final height = MediaQuery.of(context).size.height * 0.1;
return Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
height: height,
child: attachment.description.isEmpty
? null
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: SingleChildScrollView(
child: Text(attachment.description),
)),
IconButton(
onPressed: () async {
await copyToClipboard(
context: context,
text: attachment.description,
message: 'Image description copied to clipboard');
},
icon: Icon(Icons.copy),
),
],
),
),
);
}
}