Sync photos on resume
This commit is contained in:
parent
0d63576118
commit
46f0e7905f
6 changed files with 59 additions and 175 deletions
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue