Optimize album generation
This commit is contained in:
parent
275c36755c
commit
f36d77da6d
4 changed files with 136 additions and 52 deletions
|
@ -60,12 +60,12 @@ class DatabaseHelper {
|
|||
}
|
||||
|
||||
Future<int> insertPhoto(Photo photo) async {
|
||||
Database db = await instance.database;
|
||||
final db = await instance.database;
|
||||
return await db.insert(table, _getRowForPhoto(photo));
|
||||
}
|
||||
|
||||
Future<List<dynamic>> insertPhotos(List<Photo> photos) async {
|
||||
Database db = await instance.database;
|
||||
final db = await instance.database;
|
||||
var batch = db.batch();
|
||||
int batchCounter = 0;
|
||||
for (Photo photo in photos) {
|
||||
|
@ -80,40 +80,56 @@ class DatabaseHelper {
|
|||
}
|
||||
|
||||
Future<List<Photo>> getAllPhotos() async {
|
||||
Database db = await instance.database;
|
||||
var results = await db.query(table,
|
||||
where: '$columnIsDeleted = 0', orderBy: '$columnCreateTimestamp DESC');
|
||||
final db = await instance.database;
|
||||
final results = await db.query(
|
||||
table,
|
||||
where: '$columnIsDeleted = 0',
|
||||
orderBy: '$columnCreateTimestamp DESC',
|
||||
);
|
||||
return _convertToPhotos(results);
|
||||
}
|
||||
|
||||
Future<List<Photo>> getAllDeletedPhotos() async {
|
||||
Database db = await instance.database;
|
||||
var results = await db.query(table,
|
||||
where: '$columnIsDeleted = 1', orderBy: '$columnCreateTimestamp DESC');
|
||||
final db = await instance.database;
|
||||
final results = await db.query(
|
||||
table,
|
||||
where: '$columnIsDeleted = 1',
|
||||
orderBy: '$columnCreateTimestamp DESC',
|
||||
);
|
||||
return _convertToPhotos(results);
|
||||
}
|
||||
|
||||
Future<List<Photo>> getPhotosToBeUploaded() async {
|
||||
Database db = await instance.database;
|
||||
var results = await db.query(table, where: '$columnUploadedFileId = -1');
|
||||
final db = await instance.database;
|
||||
final results = await db.query(
|
||||
table,
|
||||
where: '$columnUploadedFileId = -1',
|
||||
);
|
||||
return _convertToPhotos(results);
|
||||
}
|
||||
|
||||
Future<int> updatePhoto(
|
||||
int generatedId, String remotePath, int syncTimestamp) async {
|
||||
Database db = await instance.database;
|
||||
var values = new Map<String, dynamic>();
|
||||
final db = await instance.database;
|
||||
final values = new Map<String, dynamic>();
|
||||
values[columnRemotePath] = remotePath;
|
||||
values[columnSyncTimestamp] = syncTimestamp;
|
||||
return await db.update(table, values,
|
||||
where: '$columnGeneratedId = ?', whereArgs: [generatedId]);
|
||||
return await db.update(
|
||||
table,
|
||||
values,
|
||||
where: '$columnGeneratedId = ?',
|
||||
whereArgs: [generatedId],
|
||||
);
|
||||
}
|
||||
|
||||
Future<Photo> getPhotoByPath(String path) async {
|
||||
Database db = await instance.database;
|
||||
var rows =
|
||||
await db.query(table, where: '$columnRemotePath =?', whereArgs: [path]);
|
||||
if (rows.length > 0) {
|
||||
final db = await instance.database;
|
||||
final rows = await db.query(
|
||||
table,
|
||||
where: '$columnRemotePath =?',
|
||||
whereArgs: [path],
|
||||
);
|
||||
if (rows.isNotEmpty) {
|
||||
return _getPhotofromRow(rows[0]);
|
||||
} else {
|
||||
throw ("No cached photo");
|
||||
|
@ -121,17 +137,70 @@ class DatabaseHelper {
|
|||
}
|
||||
|
||||
Future<int> markPhotoForDeletion(Photo photo) async {
|
||||
Database db = await instance.database;
|
||||
final db = await instance.database;
|
||||
var values = new Map<String, dynamic>();
|
||||
values[columnIsDeleted] = 1;
|
||||
return db.update(table, values,
|
||||
where: '$columnGeneratedId =?', whereArgs: [photo.generatedId]);
|
||||
return db.update(
|
||||
table,
|
||||
values,
|
||||
where: '$columnGeneratedId =?',
|
||||
whereArgs: [photo.generatedId],
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> deletePhoto(Photo photo) async {
|
||||
Database db = await instance.database;
|
||||
return db.delete(table,
|
||||
where: '$columnGeneratedId =?', whereArgs: [photo.generatedId]);
|
||||
final db = await instance.database;
|
||||
return db.delete(
|
||||
table,
|
||||
where: '$columnGeneratedId =?',
|
||||
whereArgs: [photo.generatedId],
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<String>> getDistinctPaths() async {
|
||||
final db = await instance.database;
|
||||
final rows = await db.query(
|
||||
table,
|
||||
columns: [columnPathName],
|
||||
distinct: true,
|
||||
);
|
||||
List<String> result = List<String>();
|
||||
for (final row in rows) {
|
||||
result.add(row[columnPathName]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<Photo> getLatestPhotoInPath(String path) async {
|
||||
final db = await instance.database;
|
||||
var rows = await db.query(
|
||||
table,
|
||||
where: '$columnPathName =?',
|
||||
whereArgs: [path],
|
||||
orderBy: '$columnCreateTimestamp DESC',
|
||||
limit: 1,
|
||||
);
|
||||
if (rows.isNotEmpty) {
|
||||
return _getPhotofromRow(rows[0]);
|
||||
} else {
|
||||
throw ("No photo found in path");
|
||||
}
|
||||
}
|
||||
|
||||
Future<Photo> getLatestPhotoAmongGeneratedIds(
|
||||
List<String> generatedIds) async {
|
||||
final db = await instance.database;
|
||||
var rows = await db.query(
|
||||
table,
|
||||
where: '$columnGeneratedId IN (${generatedIds.join(",")})',
|
||||
orderBy: '$columnCreateTimestamp DESC',
|
||||
limit: 1,
|
||||
);
|
||||
if (rows.isNotEmpty) {
|
||||
return _getPhotofromRow(rows[0]);
|
||||
} else {
|
||||
throw ("No photo found with ids " + generatedIds.join(", ").toString());
|
||||
}
|
||||
}
|
||||
|
||||
List<Photo> _convertToPhotos(List<Map<String, dynamic>> results) {
|
||||
|
|
|
@ -14,11 +14,15 @@ class FavoritePhotosRepository {
|
|||
}
|
||||
|
||||
bool isLiked(Photo photo) {
|
||||
return _getLiked().contains(photo.generatedId.toString());
|
||||
return getLiked().contains(photo.generatedId.toString());
|
||||
}
|
||||
|
||||
bool hasFavorites() {
|
||||
return getLiked().isNotEmpty;
|
||||
}
|
||||
|
||||
Future<bool> setLiked(Photo photo, bool isLiked) {
|
||||
final liked = _getLiked();
|
||||
final liked = getLiked();
|
||||
if (isLiked) {
|
||||
liked.add(photo.generatedId.toString());
|
||||
} else {
|
||||
|
@ -29,7 +33,7 @@ class FavoritePhotosRepository {
|
|||
.then((_) => isLiked);
|
||||
}
|
||||
|
||||
Set<String> _getLiked() {
|
||||
Set<String> getLiked() {
|
||||
final value = _preferences.getStringList(_favoritePhotoIdsKey);
|
||||
if (value == null) {
|
||||
return Set<String>();
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:photos/models/photo.dart';
|
|||
|
||||
class Album {
|
||||
final String name;
|
||||
final List<Photo> photos;
|
||||
final Photo thumbnailPhoto;
|
||||
final GalleryItemsFilter filter;
|
||||
|
||||
Album(this.name, this.photos, this.filter);
|
||||
Album(this.name, this.thumbnailPhoto, this.filter);
|
||||
}
|
||||
|
|
|
@ -2,14 +2,16 @@ import 'dart:collection';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:photos/db/db_helper.dart';
|
||||
import 'package:photos/favorite_photos_repository.dart';
|
||||
import 'package:photos/models/album.dart';
|
||||
import 'package:photos/models/filters/favorite_items_filter.dart';
|
||||
import 'package:photos/models/filters/folder_name_filter.dart';
|
||||
import 'package:photos/models/photo.dart';
|
||||
import 'package:photos/ui/album_page.dart';
|
||||
import 'package:photos/ui/loading_widget.dart';
|
||||
import 'package:photos/ui/thumbnail_widget.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
class AlbumListWidget extends StatefulWidget {
|
||||
final List<Photo> photos;
|
||||
|
@ -23,8 +25,21 @@ class AlbumListWidget extends StatefulWidget {
|
|||
class _AlbumListWidgetState extends State<AlbumListWidget> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Album> albums = _getAlbums(widget.photos);
|
||||
return FutureBuilder(
|
||||
future: _getAlbums(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return _getAlbumListWidget(snapshot.data);
|
||||
} else if (snapshot.hasError) {
|
||||
return Text(snapshot.error.toString());
|
||||
} else {
|
||||
return loadWidget;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getAlbumListWidget(List<Album> albums) {
|
||||
return Container(
|
||||
margin: EdgeInsets.only(top: 24),
|
||||
child: GridView.builder(
|
||||
|
@ -42,27 +57,23 @@ class _AlbumListWidgetState extends State<AlbumListWidget> {
|
|||
);
|
||||
}
|
||||
|
||||
List<Album> _getAlbums(List<Photo> photos) {
|
||||
final albumMap = new LinkedHashMap<String, List<Photo>>();
|
||||
final favorites = Album("Favorites", List<Photo>(), FavoriteItemsFilter());
|
||||
for (Photo photo in photos) {
|
||||
final folder = path.basename(photo.pathName);
|
||||
if (!albumMap.containsKey(folder)) {
|
||||
albumMap[folder] = new List<Photo>();
|
||||
}
|
||||
albumMap[folder].add(photo);
|
||||
|
||||
if (FavoritePhotosRepository.instance.isLiked(photo)) {
|
||||
favorites.photos.add(photo);
|
||||
}
|
||||
Future<List<Album>> _getAlbums() async {
|
||||
final paths = await DatabaseHelper.instance.getDistinctPaths();
|
||||
final albums = List<Album>();
|
||||
for (final path in paths) {
|
||||
final photo = await DatabaseHelper.instance.getLatestPhotoInPath(path);
|
||||
final albumName = p.basename(path);
|
||||
albums.add(Album(albumName, photo, FolderNameFilter(albumName)));
|
||||
}
|
||||
List<Album> albums = new List<Album>();
|
||||
if (favorites.photos.isNotEmpty) {
|
||||
albums.add(favorites);
|
||||
}
|
||||
for (String albumName in albumMap.keys) {
|
||||
albums.add(
|
||||
Album(albumName, albumMap[albumName], FolderNameFilter(albumName)));
|
||||
albums.sort((firstAlbum, secondAlbum) {
|
||||
return secondAlbum.thumbnailPhoto.createTimestamp
|
||||
.compareTo(firstAlbum.thumbnailPhoto.createTimestamp);
|
||||
});
|
||||
if (FavoritePhotosRepository.instance.hasFavorites()) {
|
||||
final photo = await DatabaseHelper.instance
|
||||
.getLatestPhotoAmongGeneratedIds(
|
||||
FavoritePhotosRepository.instance.getLiked().toList());
|
||||
albums.insert(0, Album("Favorites", photo, FavoriteItemsFilter()));
|
||||
}
|
||||
return albums;
|
||||
}
|
||||
|
@ -72,7 +83,7 @@ class _AlbumListWidgetState extends State<AlbumListWidget> {
|
|||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
child: ThumbnailWidget(album.photos[0]),
|
||||
child: ThumbnailWidget(album.thumbnailPhoto),
|
||||
height: 150,
|
||||
width: 150,
|
||||
),
|
||||
|
|
Loading…
Add table
Reference in a new issue