Sync photos on resume

This commit is contained in:
Vishnu Mohandas 2020-04-27 18:32:29 +05:30
parent 0d63576118
commit 46f0e7905f
6 changed files with 59 additions and 175 deletions

View file

@ -6,19 +6,20 @@ import 'package:myapp/photo_sync_manager.dart';
import 'package:myapp/ui/home_widget.dart';
import 'package:provider/provider.dart';
final provider = PhotoProvider();
final logger = Logger();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
provider.refreshGalleryList().then((_) => PhotoSyncManager(provider.list));
PhotoProvider.instance
.refreshGalleryList()
.then((_) => PhotoSyncManager.instance.load(PhotoProvider.instance.list));
}
class MyApp extends StatelessWidget {
class MyApp extends StatelessWidget with WidgetsBindingObserver {
final _title = 'Orma';
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addObserver(this);
return MaterialApp(
title: _title,
theme: ThemeData.dark(),
@ -28,4 +29,13 @@ class MyApp extends StatelessWidget {
),
);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
PhotoProvider.instance.refreshGalleryList().then((_) {
return PhotoSyncManager.instance.load(PhotoProvider.instance.list);
});
}
}
}

View file

@ -1,89 +1,13 @@
import 'package:flutter/foundation.dart';
import 'package:photo_manager/photo_manager.dart';
import 'main.dart';
class PhotoProvider extends ChangeNotifier {
PhotoProvider._privateConstructor();
static final PhotoProvider instance = PhotoProvider._privateConstructor();
List<AssetPathEntity> list = [];
RequestType type = RequestType.all;
DateTime dt = DateTime.now();
var hasAll = true;
var onlyAll = false;
Map<AssetPathEntity, PathProvider> pathProviderMap = {};
bool _notifying = false;
bool _needTitle = false;
bool get needTitle => _needTitle;
set needTitle(bool needTitle) {
_needTitle = needTitle;
notifyListeners();
}
bool get notifying => _notifying;
Duration _minDuration = Duration(seconds: 10);
Duration get minDuration => _minDuration;
set minDuration(Duration minDuration) {
_minDuration = minDuration;
notifyListeners();
}
Duration _maxDuration = Duration(hours: 1);
Duration get maxDuration => _maxDuration;
set maxDuration(Duration maxDuration) {
_maxDuration = maxDuration;
notifyListeners();
}
set notifying(bool notifying) {
_notifying = notifying;
notifyListeners();
}
void changeType(RequestType type) {
this.type = type;
notifyListeners();
}
void changeHasAll(bool value) {
this.hasAll = value;
notifyListeners();
}
void changeOnlyAll(bool value) {
this.onlyAll = value;
notifyListeners();
}
void changeDateToNow() {
this.dt = DateTime.now();
notifyListeners();
}
void changeDate(DateTime pickDt) {
this.dt = pickDt;
notifyListeners();
}
void reset() {
this.list.clear();
pathProviderMap.clear();
}
Future<void> refreshGalleryList() async {
reset();
var result = await PhotoManager.requestPermission();
if (!result) {
print("Did not get permission");
@ -100,76 +24,4 @@ class PhotoProvider extends ChangeNotifier {
this.list.clear();
this.list.addAll(galleryList);
}
Future<void> refreshAllGalleryProperties() async {
for (var gallery in list) {
await gallery.refreshPathProperties();
}
notifyListeners();
}
PathProvider getOrCreatePathProvider(AssetPathEntity pathEntity) {
pathProviderMap[pathEntity] ??= PathProvider(pathEntity);
return pathProviderMap[pathEntity];
}
}
class PathProvider extends ChangeNotifier {
static const loadCount = 50;
bool isInit = false;
final AssetPathEntity path;
PathProvider(this.path);
List<AssetEntity> list = [];
var page = 0;
int get showItemCount {
if (list.length == path.assetCount) {
return path.assetCount;
} else {
return path.assetCount;
}
}
Future onRefresh() async {
final list = await path.getAssetListPaged(0, loadCount);
page = 0;
this.list.clear();
this.list.addAll(list);
isInit = true;
notifyListeners();
printListLength("onRefresh");
}
Future<void> onLoadMore() async {
if (showItemCount > path.assetCount) {
print("already max");
return;
}
final list = await path.getAssetListPaged(page + 1, loadCount);
page = page + 1;
this.list.addAll(list);
notifyListeners();
printListLength("loadmore");
}
void delete(AssetEntity entity) async {
final result = await PhotoManager.editor.deleteWithIds([entity.id]);
if (result.isNotEmpty) {
await Future.delayed(Duration(seconds: 3));
await provider.refreshAllGalleryProperties();
final list =
await path.getAssetListRange(start: 0, end: this.list.length);
printListLength("deleted");
this.list.clear();
this.list.addAll(list);
}
}
void printListLength(String tag) {
print("$tag length : ${list.length}");
}
}

View file

@ -15,14 +15,22 @@ import 'package:myapp/core/constants.dart' as Constants;
class PhotoSyncManager {
final _logger = Logger();
final _dio = Dio();
bool _isLoadInProgress = false;
static final _lastSyncTimestampKey = "last_sync_timestamp_0";
static final _lastDBUpdateTimestampKey = "last_db_update_timestamp";
PhotoSyncManager(List<AssetPathEntity> pathEntities) {
init(pathEntities);
}
PhotoSyncManager._privateConstructor();
static final PhotoSyncManager instance =
PhotoSyncManager._privateConstructor();
Future<void> init(List<AssetPathEntity> pathEntities) async {
Future<void> load(List<AssetPathEntity> pathEntities) async {
if (_isLoadInProgress) {
_logger.w("Load already in progress, skipping.");
return;
}
_isLoadInProgress = true;
_logger.i("Loading...");
final prefs = await SharedPreferences.getInstance();
var lastDBUpdateTimestamp = prefs.getInt(_lastDBUpdateTimestampKey);
if (lastDBUpdateTimestamp == null) {
@ -47,14 +55,19 @@ class PhotoSyncManager {
}
}
}
photos.sort((first, second) =>
first.createTimestamp.compareTo(second.createTimestamp));
_updateDatabase(photos, prefs, lastDBUpdateTimestamp).then((_) {
_syncPhotos().then((_) {
_deletePhotos();
if (photos.isEmpty) {
_isLoadInProgress = false;
return;
} else {
photos.sort((first, second) =>
first.createTimestamp.compareTo(second.createTimestamp));
_updateDatabase(photos, prefs, lastDBUpdateTimestamp).then((_) {
_isLoadInProgress = false;
_syncPhotos().then((_) {
_deletePhotos();
});
});
});
}
}
Future<bool> _updateDatabase(final List<Photo> photos,

View file

@ -26,7 +26,6 @@ class _DetailPageState extends State<DetailPage> {
@override
void initState() {
Logger().i("initState");
_photos = widget.photos;
_selectedIndex = widget.selectedIndex;
_cachedImages = LRUMap<int, ZoomableImage>(5);
@ -36,10 +35,12 @@ class _DetailPageState extends State<DetailPage> {
@override
Widget build(BuildContext context) {
Logger().i("Opening " +
_photos[_selectedIndex].title +
", " +
_selectedIndex.toString() +
" / " +
_photos.length.toString() +
"photos .");
" photos .");
return Scaffold(
appBar: _buildAppBar(),
body: Center(

View file

@ -34,14 +34,10 @@ class _GalleryState extends State<Gallery> {
bool _shouldSelectOnTap = false;
List<Photo> _photos;
@override
void initState() {
_photos = widget.photos;
super.initState();
}
@override
Widget build(BuildContext context) {
_photos = widget.photos;
Logger().i("Building with " + _photos.length.toString());
_collatePhotos();
return ListView.builder(

View file

@ -60,4 +60,16 @@ class _ThumbnailWidgetState extends State<ThumbnailWidget> {
return loadingWidget;
}
}
@override
void didUpdateWidget(ThumbnailWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.photo.generatedId != oldWidget.photo.generatedId) {
setState(() {
_loadedSmallThumbnail = false;
_loadedLargeThumbnail = false;
_imageProvider = null;
});
}
}
}