photo_gallery 1.2.2 photo_gallery: ^1.2.2 copied to clipboard
A Flutter plugin that retrieves images and videos from mobile native gallery.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:photo_gallery/photo_gallery.dart';
import 'package:transparent_image/transparent_image.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Album>? _albums;
bool _loading = false;
@override
void initState() {
super.initState();
_loading = true;
initAsync();
}
Future<void> initAsync() async {
if (await _promptPermissionSetting()) {
List<Album> albums =
await PhotoGallery.listAlbums(mediumType: MediumType.image);
setState(() {
_albums = albums;
_loading = false;
});
}
setState(() {
_loading = false;
});
}
Future<bool> _promptPermissionSetting() async {
if (Platform.isIOS &&
await Permission.storage.request().isGranted &&
await Permission.photos.request().isGranted ||
Platform.isAndroid && await Permission.storage.request().isGranted) {
return true;
}
return false;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Photo gallery example'),
),
body: _loading
? Center(
child: CircularProgressIndicator(),
)
: LayoutBuilder(
builder: (context, constraints) {
double gridWidth = (constraints.maxWidth - 20) / 3;
double gridHeight = gridWidth + 33;
double ratio = gridWidth / gridHeight;
return Container(
padding: EdgeInsets.all(5),
child: GridView.count(
childAspectRatio: ratio,
crossAxisCount: 3,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
children: <Widget>[
...?_albums?.map(
(album) => GestureDetector(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => AlbumPage(album))),
child: Column(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Container(
color: Colors.grey[300],
height: gridWidth,
width: gridWidth,
child: FadeInImage(
fit: BoxFit.cover,
placeholder:
MemoryImage(kTransparentImage),
image: AlbumThumbnailProvider(
albumId: album.id,
mediumType: album.mediumType,
highQuality: true,
),
),
),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 2.0),
child: Text(
album.name ?? "Unnamed Album",
maxLines: 1,
textAlign: TextAlign.start,
style: TextStyle(
height: 1.2,
fontSize: 16,
),
),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 2.0),
child: Text(
album.count.toString(),
textAlign: TextAlign.start,
style: TextStyle(
height: 1.2,
fontSize: 12,
),
),
),
],
),
),
),
],
),
);
},
),
),
);
}
}
class AlbumPage extends StatefulWidget {
final Album album;
AlbumPage(Album album) : album = album;
@override
State<StatefulWidget> createState() => AlbumPageState();
}
class AlbumPageState extends State<AlbumPage> {
List<Medium>? _media;
@override
void initState() {
super.initState();
initAsync();
}
void initAsync() async {
MediaPage mediaPage = await widget.album.listMedia();
setState(() {
_media = mediaPage.items;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(widget.album.name ?? "Unnamed Album"),
),
body: GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0,
children: <Widget>[
...?_media?.map(
(medium) => GestureDetector(
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ViewerPage(medium))),
child: Container(
color: Colors.grey[300],
child: FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: ThumbnailProvider(
mediumId: medium.id,
mediumType: medium.mediumType,
highQuality: true,
),
),
),
),
),
],
),
),
);
}
}
class ViewerPage extends StatelessWidget {
final Medium medium;
ViewerPage(Medium medium) : medium = medium;
@override
Widget build(BuildContext context) {
DateTime? date = medium.creationDate ?? medium.modifiedDate;
return MaterialApp(
home: Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: Icon(Icons.arrow_back_ios),
),
title: date != null ? Text(date.toLocal().toString()) : null,
),
body: Container(
alignment: Alignment.center,
child: medium.mediumType == MediumType.image
? FadeInImage(
fit: BoxFit.cover,
placeholder: MemoryImage(kTransparentImage),
image: PhotoProvider(mediumId: medium.id),
)
: VideoProvider(
mediumId: medium.id,
),
),
),
);
}
}
class VideoProvider extends StatefulWidget {
final String mediumId;
const VideoProvider({
required this.mediumId,
});
@override
_VideoProviderState createState() => _VideoProviderState();
}
class _VideoProviderState extends State<VideoProvider> {
VideoPlayerController? _controller;
File? _file;
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) {
initAsync();
});
super.initState();
}
Future<void> initAsync() async {
try {
_file = await PhotoGallery.getFile(mediumId: widget.mediumId);
_controller = VideoPlayerController.file(_file!);
_controller?.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
} catch (e) {
print("Failed : $e");
}
}
@override
Widget build(BuildContext context) {
return _controller == null || !_controller!.value.isInitialized
? Container()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: VideoPlayer(_controller!),
),
TextButton(
onPressed: () {
setState(() {
_controller!.value.isPlaying
? _controller!.pause()
: _controller!.play();
});
},
child: Icon(
_controller!.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
],
);
}
}