photo_manager 3.5.2 photo_manager: ^3.5.2 copied to clipboard
A Flutter plugin that provides album assets abstraction management APIs on Android, iOS, macOS, and OpenHarmony.
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:oktoast/oktoast.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:provider/provider.dart';
import 'model/photo_provider.dart';
import 'page/index_page.dart';
import 'widget/image_item_widget.dart';
final PhotoProvider provider = PhotoProvider();
void main() {
runZonedGuarded(
() => runApp(const _SimpleExampleApp()),
(Object e, StackTrace s) {
if (kDebugMode) {
FlutterError.reportError(FlutterErrorDetails(exception: e, stack: s));
}
showToast('$e\n$s', textAlign: TextAlign.start);
},
);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.transparent,
),
);
}
class _SimpleExampleApp extends StatelessWidget {
const _SimpleExampleApp();
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<PhotoProvider>.value(
value: provider, // This is for the advanced usages.
child: MaterialApp(
title: 'Photo Manager Example',
theme: ThemeData(
colorSchemeSeed: Colors.blue,
),
builder: (context, child) {
if (child == null) {
return const SizedBox.shrink();
}
return Banner(
message: 'Debug',
location: BannerLocation.bottomStart,
child: OKToast(child: child),
);
},
home: const _SimpleExamplePage(),
debugShowCheckedModeBanner: false,
),
);
}
}
class _SimpleExamplePage extends StatefulWidget {
const _SimpleExamplePage();
@override
_SimpleExamplePageState createState() => _SimpleExamplePageState();
}
class _SimpleExamplePageState extends State<_SimpleExamplePage> {
final int _sizePerPage = 50;
AssetPathEntity? _path;
List<AssetEntity>? _entities;
int _totalEntitiesCount = 0;
int _page = 0;
bool _isLoading = false;
bool _isLoadingMore = false;
bool _hasMoreToLoad = true;
Future<void> _requestAssets() async {
setState(() {
_isLoading = true;
});
// Request permissions.
final PermissionState ps = await PhotoManager.requestPermissionExtend();
if (!mounted) {
return;
}
// Further requests can be only proceed with authorized or limited.
if (!ps.hasAccess) {
setState(() {
_isLoading = false;
});
showToast('Permission is not accessible.');
return;
}
// Customize your own filter options.
final PMFilter filter = FilterOptionGroup(
imageOption: const FilterOption(
sizeConstraint: SizeConstraint(ignoreSize: true),
),
);
// Obtain assets using the path entity.
final List<AssetPathEntity> paths = await PhotoManager.getAssetPathList(
onlyAll: true,
filterOption: filter,
);
if (!mounted) {
return;
}
// Return if not paths found.
if (paths.isEmpty) {
setState(() {
_isLoading = false;
});
showToast('No paths found.');
return;
}
setState(() {
_path = paths.first;
});
_totalEntitiesCount = await _path!.assetCountAsync;
final List<AssetEntity> entities = await _path!.getAssetListPaged(
page: 0,
size: _sizePerPage,
);
if (!mounted) {
return;
}
setState(() {
_entities = entities;
_isLoading = false;
_hasMoreToLoad = _entities!.length < _totalEntitiesCount;
});
}
Future<void> _loadMoreAsset() async {
final List<AssetEntity> entities = await _path!.getAssetListPaged(
page: _page + 1,
size: _sizePerPage,
);
if (!mounted) {
return;
}
setState(() {
_entities!.addAll(entities);
_page++;
_hasMoreToLoad = _entities!.length < _totalEntitiesCount;
_isLoadingMore = false;
});
}
Widget _buildBody(BuildContext context) {
if (_isLoading) {
return const Center(child: CircularProgressIndicator.adaptive());
}
if (_path == null) {
return const Center(child: Text('Request paths first.'));
}
if (_entities?.isNotEmpty != true) {
return const Center(child: Text('No assets found on this device.'));
}
return GridView.custom(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
),
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index == _entities!.length - 8 &&
!_isLoadingMore &&
_hasMoreToLoad) {
_loadMoreAsset();
}
final AssetEntity entity = _entities![index];
return ImageItemWidget(
key: ValueKey<int>(index),
entity: entity,
option: const ThumbnailOption(size: ThumbnailSize.square(200)),
);
},
childCount: _entities!.length,
findChildIndexCallback: (Key key) {
// Re-use elements.
if (key is ValueKey<int>) {
return key.value;
}
return null;
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('photo_manager')),
body: Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'This page will only obtain the first page of assets '
'under the primary album (a.k.a. Recent). '
'If you want more filtering assets, '
'head over to "Advanced usages".',
),
),
Expanded(child: _buildBody(context)),
],
),
persistentFooterButtons: <TextButton>[
TextButton(
onPressed: () {
Navigator.of(context).push<void>(
MaterialPageRoute<void>(builder: (_) => const IndexPage()),
);
},
child: const Text('Advanced usages'),
),
],
floatingActionButton: FloatingActionButton(
onPressed: _requestAssets,
child: const Icon(Icons.developer_board),
),
);
}
}