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()); } /// The main widget of example app class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { List? _albums; bool _loading = false; @override void initState() { super.initState(); _loading = true; initAsync(); } Future initAsync() async { if (await _promptPermissionSetting()) { List albums = await PhotoGallery.listAlbums(); setState(() { _albums = albums; _loading = false; }); } setState(() { _loading = false; }); } Future _promptPermissionSetting() async { if (Platform.isIOS) { if (await Permission.photos.request().isGranted || await Permission.storage.request().isGranted) { return true; } } if (Platform.isAndroid) { if (await Permission.storage.request().isGranted || await Permission.photos.request().isGranted && await Permission.videos.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: [ ...?_albums?.map( (album) => GestureDetector( onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (context) => AlbumPage(album)), ), child: Column( children: [ 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( album: album, 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, ), ), ), ], ), ), ), ], ), ); }, ), ), ); } } /// The album page widget class AlbumPage extends StatefulWidget { /// Album object to show in the page final Album album; /// The constructor of AlbumPage AlbumPage(Album album) : album = album; @override State createState() => _AlbumPageState(); } class _AlbumPageState extends State { List? _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: [ ...?_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, ), ), ), ), ), ], ), ), ); } } /// The viewer page widget class ViewerPage extends StatelessWidget { /// The medium object to show in the page final Medium medium; /// The constructor of ViewerPage 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 ? GestureDetector( onTap: () async { PhotoGallery.deleteMedium(mediumId: medium.id); }, child: FadeInImage( fit: BoxFit.cover, placeholder: MemoryImage(kTransparentImage), image: PhotoProvider(mediumId: medium.id), ), ) : VideoProvider( mediumId: medium.id, ), ), ), ); } } /// The video provider widget class VideoProvider extends StatefulWidget { /// The identifier of medium final String mediumId; /// The constructor of VideoProvider const VideoProvider({ required this.mediumId, }); @override _VideoProviderState createState() => _VideoProviderState(); } class _VideoProviderState extends State { VideoPlayerController? _controller; File? _file; @override void initState() { WidgetsBinding.instance.addPostFrameCallback((_) { initAsync(); }); super.initState(); } Future 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: [ 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, ), ), ], ); } }