relatica/lib/screens/existing_image_selector_scr...

205 wiersze
7.1 KiB
Dart

import 'package:flutter/material.dart' hide Visibility;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../controls/async_value_widget.dart';
import '../controls/error_message_widget.dart';
import '../controls/login_aware_cached_network_image.dart';
import '../models/auth/profile.dart';
import '../models/gallery_data.dart';
import '../models/image_entry.dart';
import '../models/visibility.dart';
import '../riverpod_controllers/account_services.dart';
import '../riverpod_controllers/gallery_services.dart';
import '../serializers/friendica/image_entry_friendica_extensions.dart';
import 'media_viewer_screen.dart';
class ExistingImageSelectorScreen extends ConsumerStatefulWidget {
final Visibility? visibilityFilter;
const ExistingImageSelectorScreen({
super.key,
this.visibilityFilter,
});
@override
ConsumerState<ExistingImageSelectorScreen> createState() =>
_ExistingImageSelectorScreenState();
}
class _ExistingImageSelectorScreenState
extends ConsumerState<ExistingImageSelectorScreen> {
GalleryData? selectedGallery;
final selectedImages = <ImageEntry>[];
@override
Widget build(BuildContext context) {
final profile = ref.watch(activeProfileProvider);
final galleryListAsyncValue = ref.watch(galleryListProvider(profile));
final title = switch (galleryListAsyncValue) {
AsyncData() => selectedImages.isEmpty
? 'Select Image(s)'
: '${selectedImages.length} selected',
AsyncLoading() => 'Loading...',
_ => 'Error loading',
};
final List<Widget> actions = switch (galleryListAsyncValue) {
AsyncData() => [
IconButton(
onPressed: selectedImages.isEmpty
? null
: () {
Navigator.of(context).pop(selectedImages);
},
tooltip: 'Attach selected files',
icon: const Icon(Icons.attach_file),
),
IconButton(
onPressed: selectedImages.isEmpty
? null
: () {
setState(() {
selectedImages.clear();
});
},
tooltip: 'Clear Selection',
icon: const Icon(Icons.remove_circle_outline),
),
],
_ => [],
};
final body = AsyncValueWidget(galleryListAsyncValue,
valueBuilder: (context, ref, galleriesResult) {
return galleriesResult.fold(
onSuccess: (galleries) {
return Center(
child: Column(
children: [
DropdownButton<GalleryData>(
value: selectedGallery,
items: galleries
.map((g) =>
DropdownMenuItem(value: g, child: Text(g.name)))
.toList(),
onChanged: (value) {
setState(() {
selectedGallery = value;
});
}),
const VerticalDivider(),
selectedGallery == null
? buildInfoBody()
: Expanded(child: buildGrid(context, profile)),
],
));
},
onError: (error) =>
ErrorMessageWidget(message: 'Error getting galleries: $error'));
});
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(title),
actions: actions,
),
body: body,
),
);
}
Widget buildInfoBody() {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [Text('Select a gallery')],
),
);
}
Widget buildGrid(
BuildContext context,
Profile profile,
) {
const thumbnailDimension = 350.0;
final galleryName = selectedGallery!.name;
final expectedPhotoCount = selectedGallery!.count;
return AsyncValueWidget(
ref.watch(galleryImagesProvider(profile, galleryName)),
valueBuilder: (context, ref, imagesResult) {
return imagesResult.fold(
onSuccess: (images) {
return GridView.builder(
itemCount: images.length,
padding: const EdgeInsets.all(5.0),
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: thumbnailDimension),
itemBuilder: (context, index) {
final image = images[index];
// TODO May need to take out since there is a count discrepency for OAuth users
if (images.length < expectedPhotoCount &&
index == images.length - 1) {
ref
.read(galleryImagesProvider(profile, galleryName)
.notifier)
.updateGalleryImages(
withNextPage: true,
nextPageOnly: true,
);
}
final selected = selectedImages.contains(image);
final tileWidget = Card(
child: Stack(
children: [
LoginAwareCachedNetworkImage(
imageUrl: image.thumbnailUrl,
),
if (selected)
const Positioned(
child: Icon(
Icons.check_circle,
color: Colors.green,
)),
Positioned(
bottom: 5.0,
right: 5.0,
child: Icon(
image.visibility.type == VisibilityType.public
? Icons.public
: Icons.lock),
),
],
),
);
return Padding(
padding: const EdgeInsets.all(2.0),
child: GestureDetector(
onTap: () {
setState(() {
if (selected) {
selectedImages.remove(image);
} else {
selectedImages.add(image);
}
});
},
onDoubleTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MediaViewerScreen(
attachments: [image.toMediaAttachment()],
),
),
);
},
child: tileWidget,
),
);
});
},
onError: (error) =>
ErrorMessageWidget(message: 'Error getting image list: $error'));
});
}
}