Optimize album generation

This commit is contained in:
Vishnu Mohandas 2020-05-06 23:43:24 +05:30
parent 275c36755c
commit f36d77da6d
4 changed files with 136 additions and 52 deletions

View file

@ -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) {

View file

@ -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>();

View file

@ -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);
}

View file

@ -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,
),