123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- import 'dart:async';
- import 'dart:typed_data';
-
- import 'package:flutter/material.dart';
- import 'package:photo/src/delegate/badge_delegate.dart';
- import 'package:photo/src/delegate/loading_delegate.dart';
- import 'package:photo/src/engine/lru_cache.dart';
- import 'package:photo/src/engine/throttle.dart';
- import 'package:photo/src/entity/options.dart';
- import 'package:photo/src/provider/config_provider.dart';
- import 'package:photo/src/provider/gallery_list_provider.dart';
- import 'package:photo/src/provider/i18n_provider.dart';
- import 'package:photo/src/provider/selected_provider.dart';
- import 'package:photo/src/ui/dialog/change_gallery_dialog.dart';
- import 'package:photo/src/ui/page/photo_preview_page.dart';
- import 'package:photo_manager/photo_manager.dart';
-
- part './main/bottom_widget.dart';
- part './main/image_item.dart';
-
- class PhotoMainPage extends StatefulWidget {
- final ValueChanged<List<AssetEntity>> onClose;
- final Options options;
- final List<AssetPathEntity> photoList;
-
- const PhotoMainPage({
- Key key,
- this.onClose,
- this.options,
- this.photoList,
- }) : super(key: key);
-
- @override
- _PhotoMainPageState createState() => _PhotoMainPageState();
- }
-
- class _PhotoMainPageState extends State<PhotoMainPage>
- with SelectedProvider, GalleryListProvider {
- Options get options => widget.options;
-
- I18nProvider get i18nProvider => ConfigProvider.of(context).provider;
-
- List<AssetEntity> list = [];
-
- Color get themeColor => options.themeColor;
-
- AssetPathEntity _currentPath = AssetPathEntity.all;
-
- bool _isInit = false;
-
- AssetPathEntity get currentPath {
- if (_currentPath == null) {
- return null;
- }
- return _currentPath;
- }
-
- set currentPath(AssetPathEntity value) {
- _currentPath = value;
- }
-
- String get currentGalleryName {
- if (currentPath.isAll) {
- return i18nProvider.getAllGalleryText(options);
- }
- return currentPath.name;
- }
-
- GlobalKey scaffoldKey;
- ScrollController scrollController;
-
- bool isPushed = false;
-
- bool get useAlbum => widget.photoList == null || widget.photoList.isEmpty;
-
- Throttle _changeThrottle;
-
- @override
- void initState() {
- super.initState();
- _refreshList();
- scaffoldKey = GlobalKey();
- scrollController = ScrollController();
- _changeThrottle = Throttle(onCall: _onAssetChange);
- PhotoManager.addChangeCallback(_changeThrottle.call);
- PhotoManager.startChangeNotify();
- }
-
- @override
- void dispose() {
- PhotoManager.removeChangeCallback(_changeThrottle.call);
- PhotoManager.stopChangeNotify();
- _changeThrottle.dispose();
- scaffoldKey = null;
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- var textStyle = TextStyle(
- color: options.textColor,
- fontSize: 14.0,
- );
- return Theme(
- data: Theme.of(context).copyWith(primaryColor: options.themeColor),
- child: DefaultTextStyle(
- style: textStyle,
- child: Scaffold(
- appBar: AppBar(
- leading: IconButton(
- icon: Icon(Icons.close),
- onPressed: _cancel,
- ),
- title: Text(
- i18nProvider.getTitleText(options),
- ),
- actions: <Widget>[
- FlatButton(
- splashColor: Colors.transparent,
- child: Text(
- i18nProvider.getSureText(options, selectedCount),
- style: selectedCount == 0
- ? textStyle.copyWith(color: options.disableColor)
- : textStyle,
- ),
- onPressed: selectedCount == 0 ? null : sure,
- ),
- ],
- ),
- body: _buildBody(),
- bottomNavigationBar: _BottomWidget(
- key: scaffoldKey,
- provider: i18nProvider,
- options: options,
- galleryName: currentGalleryName,
- onGalleryChange: _onGalleryChange,
- onTapPreview: selectedList.isEmpty ? null : _onTapPreview,
- selectedProvider: this,
- galleryListProvider: this,
- ),
- ),
- ),
- );
- }
-
- void _cancel() {
- selectedList.clear();
- widget.onClose(selectedList);
- }
-
- @override
- bool isUpperLimit() {
- var result = selectedCount == options.maxSelected;
- if (result) _showTip(i18nProvider.getMaxTipText(options));
- return result;
- }
-
- void sure() {
- widget.onClose?.call(selectedList);
- }
-
- void _showTip(String msg) {
- if (isPushed) {
- return;
- }
- Scaffold.of(scaffoldKey.currentContext).showSnackBar(
- SnackBar(
- content: Text(
- msg,
- style: TextStyle(
- color: options.textColor,
- fontSize: 14.0,
- ),
- ),
- duration: Duration(milliseconds: 1500),
- backgroundColor: themeColor.withOpacity(0.7),
- ),
- );
- }
-
- void _refreshList() {
- if (!useAlbum) {
- _refreshListFromWidget();
- return;
- }
-
- _refreshListFromGallery();
- }
-
- Future<void> _refreshListFromWidget() async {
- galleryPathList.clear();
- galleryPathList.addAll(widget.photoList);
- this.list.clear();
- var assetList = await galleryPathList[0].assetList;
- _sortAssetList(assetList);
- this.list.addAll(assetList);
- setState(() {
- _isInit = true;
- });
- }
-
- Future<void> _refreshListFromGallery() async {
- List<AssetPathEntity> pathList;
- switch (options.pickType) {
- case PickType.onlyImage:
- pathList = await PhotoManager.getImageAsset();
- break;
- case PickType.onlyVideo:
- pathList = await PhotoManager.getVideoAsset();
- break;
- default:
- pathList = await PhotoManager.getAssetPathList();
- }
-
- if (pathList == null) {
- return;
- }
-
- options.sortDelegate.sort(pathList);
-
- galleryPathList.clear();
- galleryPathList.addAll(pathList);
-
- List<AssetEntity> imageList;
-
- if (pathList.isNotEmpty) {
- imageList = await pathList[0].assetList;
- _sortAssetList(imageList);
- _currentPath = pathList[0];
- }
-
- for (var path in pathList) {
- if (path.isAll) {
- path.name = i18nProvider.getAllGalleryText(options);
- }
- }
-
- this.list.clear();
- if (imageList != null) {
- this.list.addAll(imageList);
- }
- setState(() {
- _isInit = true;
- });
- }
-
- void _sortAssetList(List<AssetEntity> assetList) {
- options?.sortDelegate?.assetDelegate?.sort(assetList);
- }
-
- Widget _buildBody() {
- if (!_isInit) {
- return _buildLoading();
- }
-
- return Container(
- color: options.dividerColor,
- child: GridView.builder(
- controller: scrollController,
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: options.rowCount,
- childAspectRatio: options.itemRadio,
- crossAxisSpacing: options.padding,
- mainAxisSpacing: options.padding,
- ),
- itemBuilder: _buildItem,
- itemCount: list.length,
- ),
- );
- }
-
- Widget _buildItem(BuildContext context, int index) {
- var data = list[index];
- return RepaintBoundary(
- child: GestureDetector(
- onTap: () => _onItemClick(data, index),
- child: Stack(
- children: <Widget>[
- ImageItem(
- entity: data,
- themeColor: themeColor,
- size: options.thumbSize,
- loadingDelegate: options.loadingDelegate,
- badgeDelegate: options.badgeDelegate,
- ),
- _buildMask(containsEntity(data)),
- _buildSelected(data),
- ],
- ),
- ),
- );
- }
-
- _buildMask(bool showMask) {
- return IgnorePointer(
- child: AnimatedContainer(
- color: showMask ? Colors.black.withOpacity(0.5) : Colors.transparent,
- duration: Duration(milliseconds: 300),
- ),
- );
- }
-
- Widget _buildSelected(AssetEntity entity) {
- var currentSelected = containsEntity(entity);
- return Positioned(
- right: 0.0,
- width: 36.0,
- height: 36.0,
- child: GestureDetector(
- onTap: () {
- changeCheck(!currentSelected, entity);
- },
- behavior: HitTestBehavior.translucent,
- child: _buildText(entity),
- ),
- );
- }
-
- Widget _buildText(AssetEntity entity) {
- var isSelected = containsEntity(entity);
- Widget child;
- BoxDecoration decoration;
- if (isSelected) {
- child = Text(
- (indexOfSelected(entity) + 1).toString(),
- textAlign: TextAlign.center,
- style: TextStyle(
- fontSize: 12.0,
- color: options.textColor,
- ),
- );
- decoration = BoxDecoration(color: themeColor);
- } else {
- decoration = BoxDecoration(
- borderRadius: BorderRadius.circular(1.0),
- border: Border.all(
- color: themeColor,
- ),
- );
- }
- return Padding(
- padding: const EdgeInsets.all(8.0),
- child: AnimatedContainer(
- duration: Duration(milliseconds: 300),
- decoration: decoration,
- alignment: Alignment.center,
- child: child,
- ),
- );
- }
-
- void changeCheck(bool value, AssetEntity entity) {
- if (value) {
- addSelectEntity(entity);
- } else {
- removeSelectEntity(entity);
- }
- setState(() {});
- }
-
- void _onGalleryChange(AssetPathEntity assetPathEntity) {
- _currentPath = assetPathEntity;
-
- _currentPath.assetList.then((v) {
- _sortAssetList(v);
- list.clear();
- list.addAll(v);
- scrollController.jumpTo(0.0);
- setState(() {});
- });
- }
-
- void _onItemClick(AssetEntity data, int index) {
- var result = new PhotoPreviewResult();
- isPushed = true;
- Navigator.of(context).push(
- MaterialPageRoute(
- builder: (ctx) {
- return ConfigProvider(
- provider: ConfigProvider.of(context).provider,
- options: options,
- child: PhotoPreviewPage(
- selectedProvider: this,
- list: List.of(list),
- initIndex: index,
- changeProviderOnCheckChange: true,
- result: result,
- ),
- );
- },
- ),
- ).then((v) {
- if (handlePreviewResult(v)) {
- Navigator.pop(context, v);
- return;
- }
- isPushed = false;
- setState(() {});
- });
- }
-
- void _onTapPreview() async {
- var result = new PhotoPreviewResult();
- isPushed = true;
- var v = await Navigator.of(context).push(
- MaterialPageRoute(
- builder: (ctx) => ConfigProvider(
- provider: ConfigProvider.of(context).provider,
- options: options,
- child: PhotoPreviewPage(
- selectedProvider: this,
- list: List.of(selectedList),
- changeProviderOnCheckChange: false,
- result: result,
- ),
- ),
- ),
- );
- if (handlePreviewResult(v)) {
- // print(v);
- Navigator.pop(context, v);
- return;
- }
- isPushed = false;
- compareAndRemoveEntities(result.previewSelectedList);
- }
-
- bool handlePreviewResult(List<AssetEntity> v) {
- if (v == null) {
- return false;
- }
- if (v is List<AssetEntity>) {
- return true;
- }
- return false;
- }
-
- Widget _buildLoading() {
- return Center(
- child: Column(
- children: <Widget>[
- Container(
- width: 40.0,
- height: 40.0,
- padding: const EdgeInsets.all(5.0),
- child: CircularProgressIndicator(
- valueColor: AlwaysStoppedAnimation(themeColor),
- ),
- ),
- Padding(
- padding: const EdgeInsets.all(8.0),
- child: Text(
- i18nProvider.loadingText(),
- style: const TextStyle(
- fontSize: 12.0,
- ),
- ),
- ),
- ],
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisAlignment: MainAxisAlignment.center,
- ),
- );
- }
-
- void _onAssetChange() {
- if (useAlbum) {
- _onPhotoRefresh();
- }
- }
-
- void _onPhotoRefresh() async {
- List<AssetPathEntity> pathList;
- switch (options.pickType) {
- case PickType.onlyImage:
- pathList = await PhotoManager.getImageAsset();
- break;
- case PickType.onlyVideo:
- pathList = await PhotoManager.getVideoAsset();
- break;
- default:
- pathList = await PhotoManager.getAssetPathList();
- }
-
- if (pathList == null) {
- return;
- }
-
- this.galleryPathList.clear();
- this.galleryPathList.addAll(pathList);
-
- if (!this.galleryPathList.contains(this.currentPath)) {
- // current path is deleted , 当前的相册被删除, 应该提示刷新
- if (this.galleryPathList.length > 0) {
- _onGalleryChange(this.galleryPathList[0]);
- }
- return;
- }
- // Not deleted
- _onGalleryChange(this.currentPath);
- }
- }
|