Update like-unlike interactions

This commit is contained in:
Vishnu Mohandas 2020-10-24 15:55:02 +05:30
parent 28061ed69a
commit be2522d85f
10 changed files with 87 additions and 105 deletions

View file

@ -149,7 +149,7 @@ class FilesDB {
return _convertToFiles(results);
}
Future<List<File>> getAllInCollection(
Future<List<File>> getAllInCollectionBeforeCreationTime(
int collectionID, int beforeCreationTime, int limit) async {
final db = await instance.database;
final results = await db.query(
@ -163,6 +163,18 @@ class FilesDB {
return _convertToFiles(results);
}
Future<List<File>> getAllInCollection(int collectionID) async {
final db = await instance.database;
final results = await db.query(
table,
where:
'$columnCollectionID = ?',
whereArgs: [collectionID],
orderBy: '$columnCreationTime DESC',
);
return _convertToFiles(results);
}
Future<List<File>> getFilesCreatedWithinDuration(
int startCreationTime, int endCreationTime) async {
final db = await instance.database;

View file

@ -4,13 +4,15 @@ import 'package:photos/models/file.dart';
class DeviceFolder {
final String name;
final String path;
final List<File> Function() loader;
final File thumbnail;
final GalleryItemsFilter filter;
DeviceFolder(
this.name,
this.path,
this.thumbnail,
this.loader,
this.thumbnail, {
this.filter,
);
});
}

View file

@ -1,17 +0,0 @@
import 'package:photos/core/configuration.dart';
import 'package:photos/models/filters/gallery_items_filter.dart';
import 'package:photos/models/file.dart';
import 'package:path/path.dart' as path;
class DeviceFolderNameFilter implements GalleryItemsFilter {
final String folderName;
DeviceFolderNameFilter(this.folderName);
@override
bool shouldInclude(File file) {
return (file.ownerID == null ||
file.ownerID == Configuration.instance.getUserID()) &&
path.basename(file.deviceFolder) == folderName;
}
}

View file

@ -1,10 +0,0 @@
import 'package:photos/services/favorites_service.dart';
import 'package:photos/models/filters/gallery_items_filter.dart';
import 'package:photos/models/file.dart';
class FavoriteItemsFilter implements GalleryItemsFilter {
@override
bool shouldInclude(File file) {
return FavoritesService.instance.isLiked(file);
}
}

View file

@ -1,10 +0,0 @@
import 'package:photos/models/file.dart';
import 'package:photos/models/file_type.dart';
import 'package:photos/models/filters/gallery_items_filter.dart';
class VideoFileFilter implements GalleryItemsFilter {
@override
bool shouldInclude(File file) {
return file.fileType == FileType.video;
}
}

View file

@ -1,6 +1,7 @@
import 'package:flutter_sodium/flutter_sodium.dart';
import 'package:photos/core/configuration.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/models/collection.dart';
import 'package:photos/models/file.dart';
@ -10,17 +11,19 @@ import 'package:photos/utils/file_uploader.dart';
import 'package:shared_preferences/shared_preferences.dart';
class FavoritesService {
static final _favoritePhotoIdsKey = "favorite_photo_ids";
static final _favoritesCollectionIDKey = "favorites_collection_id";
final _cachedFavoriteFiles = Set<File>();
Configuration _config;
CollectionsService _collectionsService;
FileUploader _fileUploader;
FilesDB _filesDB;
FavoritesService._privateConstructor() {
_config = Configuration.instance;
_collectionsService = CollectionsService.instance;
_fileUploader = FileUploader.instance;
_filesDB = FilesDB.instance;
}
static FavoritesService instance = FavoritesService._privateConstructor();
@ -28,36 +31,19 @@ class FavoritesService {
Future<void> init() async {
_preferences = await SharedPreferences.getInstance();
}
bool isLiked(File photo) {
return getLiked().contains(photo.generatedID.toString());
}
bool hasFavorites() {
return getLiked().isNotEmpty;
}
Future<bool> setLiked(File photo, bool isLiked) {
final liked = getLiked();
if (isLiked) {
liked.add(photo.generatedID.toString());
} else {
liked.remove(photo.generatedID.toString());
if (_preferences.containsKey(_favoritesCollectionIDKey)) {
final collectionID = _preferences.getInt(_favoritesCollectionIDKey);
_cachedFavoriteFiles
.addAll((await _filesDB.getAllInCollection(collectionID)).toSet());
}
Bus.instance.fire(LocalPhotosUpdatedEvent());
return _preferences
.setStringList(_favoritePhotoIdsKey, liked.toList())
.then((_) => isLiked);
}
Set<String> getLiked() {
final value = _preferences.getStringList(_favoritePhotoIdsKey);
if (value == null) {
return Set<String>();
} else {
return value.toSet();
}
Set<File> getFavoriteFiles() {
return _cachedFavoriteFiles;
}
bool isLiked(File file) {
return _cachedFavoriteFiles.contains(file);
}
Future<void> addToFavorites(File file) async {
@ -66,8 +52,22 @@ class FavoritesService {
if (fileID == null) {
file.collectionID = collectionID;
fileID = (await _fileUploader.encryptAndUploadFile(file)).uploadedFileID;
await _filesDB.update(
file.generatedID,
file.uploadedFileID,
file.ownerID,
file.collectionID,
file.updationTime,
file.encryptedKey,
file.keyDecryptionNonce,
file.fileDecryptionHeader,
file.thumbnailDecryptionHeader,
file.metadataDecryptionHeader,
);
} else {
return _collectionsService.addToCollection(collectionID, [file]);
await _collectionsService.addToCollection(collectionID, [file]);
_cachedFavoriteFiles.add(file);
Bus.instance.fire(LocalPhotosUpdatedEvent());
}
}
@ -77,7 +77,9 @@ class FavoritesService {
if (fileID == null) {
// Do nothing, ignore
} else {
return _collectionsService.removeFromCollection(collectionID, [file]);
await _collectionsService.removeFromCollection(collectionID, [file]);
_cachedFavoriteFiles.remove(file);
Bus.instance.fire(LocalPhotosUpdatedEvent());
}
}

View file

@ -182,6 +182,7 @@ class _DetailPageState extends State<DetailPage> {
isLiked: FavoritesService.instance.isLiked(file),
onTap: (oldValue) async {
final isLiked = !oldValue;
bool hasError = false;
if (isLiked) {
final dialog =
createProgressDialog(context, "Adding to favorites...");
@ -192,6 +193,7 @@ class _DetailPageState extends State<DetailPage> {
} catch (e, s) {
_logger.severe(e, s);
await dialog.hide();
hasError = true;
showGenericErrorDialog(context);
} finally {
await dialog.hide();
@ -206,12 +208,13 @@ class _DetailPageState extends State<DetailPage> {
} catch (e, s) {
_logger.severe(e, s);
await dialog.hide();
hasError = true;
showGenericErrorDialog(context);
} finally {
await dialog.hide();
}
}
return isLiked;
return hasError ? oldValue : isLiked;
},
likeBuilder: (isLiked) {
return Icon(

View file

@ -2,8 +2,6 @@ import 'package:flutter/material.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/models/device_folder.dart';
import 'package:photos/models/file.dart';
import 'package:photos/repositories/file_repository.dart';
import 'package:photos/models/selected_files.dart';
import 'package:photos/ui/gallery.dart';
import 'package:photos/ui/gallery_app_bar_widget.dart';
@ -23,7 +21,7 @@ class _DeviceFolderPageState extends State<DeviceFolderPage> {
@override
Widget build(Object context) {
var gallery = Gallery(
syncLoader: () => _getFilteredFiles(FileRepository.instance.files),
syncLoader: widget.folder.loader,
reloadEvent: Bus.instance.on<LocalPhotosUpdatedEvent>(),
tagPrefix: "device_folder:" + widget.folder.path,
selectedFiles: _selectedFiles,
@ -38,17 +36,4 @@ class _DeviceFolderPageState extends State<DeviceFolderPage> {
body: gallery,
);
}
List<File> _getFilteredFiles(List<File> unfilteredFiles) {
if (widget.folder.filter == null) {
return unfilteredFiles;
}
final List<File> filteredFiles = List<File>();
for (File file in unfilteredFiles) {
if (widget.folder.filter.shouldInclude(file)) {
filteredFiles.add(file);
}
}
return filteredFiles;
}
}

View file

@ -5,11 +5,10 @@ import 'package:flutter/widgets.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/files_db.dart';
import 'package:photos/events/local_photos_updated_event.dart';
import 'package:photos/models/file.dart';
import 'package:photos/repositories/file_repository.dart';
import 'package:photos/services/favorites_service.dart';
import 'package:photos/models/device_folder.dart';
import 'package:photos/models/filters/favorite_items_filter.dart';
import 'package:photos/models/filters/device_folder_name_filter.dart';
import 'package:photos/models/filters/video_file_filter.dart';
import 'package:photos/ui/common_elements.dart';
import 'package:photos/ui/device_folder_page.dart';
import 'package:photos/ui/loading_widget.dart';
@ -76,25 +75,40 @@ class _DeviceFolderGalleryWidgetState extends State<DeviceFolderGalleryWidget> {
final paths = await FilesDB.instance.getLocalPaths();
final folders = List<DeviceFolder>();
for (final path in paths) {
final file = await FilesDB.instance.getLatestFileInPath(path);
final thumbnail = await FilesDB.instance.getLatestFileInPath(path);
final files = List<File>();
for (File file in FileRepository.instance.files) {
if (file.deviceFolder == path) {
files.add(file);
}
}
final folderName = p.basename(path);
folders.add(
DeviceFolder(folderName, path, file, DeviceFolderNameFilter(folderName)));
folders.add(DeviceFolder(folderName, path, () => files, thumbnail));
}
folders.sort((first, second) {
return second.thumbnail.creationTime
.compareTo(first.thumbnail.creationTime);
});
if (FavoritesService.instance.hasFavorites()) {
final file = await FilesDB.instance.getLatestFileAmongGeneratedIDs(
FavoritesService.instance.getLiked().toList());
folders.insert(0,
DeviceFolder("Favorites", "/Favorites", file, FavoriteItemsFilter()));
final favorites = FavoritesService.instance.getFavoriteFiles().toList();
favorites.sort((first, second) {
return second.creationTime.compareTo(first.creationTime);
});
if (favorites.length > 0) {
folders.insert(
0,
DeviceFolder("Favorites", "/Favorites", () {
final favorites =
FavoritesService.instance.getFavoriteFiles().toList();
favorites.sort((first, second) {
return second.creationTime.compareTo(first.creationTime);
});
return favorites;
}, favorites[0]));
}
final videos = await FilesDB.instance.getAllVideos();
if (videos.length > 0) {
folders.insert(
0, DeviceFolder("Videos", "/Videos", videos[0], VideoFileFilter()));
0, DeviceFolder("Videos", "/Videos", () => videos, videos[0]));
}
return folders;
}

View file

@ -20,12 +20,13 @@ class _SharedCollectionPageState extends State<SharedCollectionPage> {
@override
Widget build(Object context) {
var gallery = Gallery(
asyncLoader: (lastFile, limit) => FilesDB.instance.getAllInCollection(
widget.collection.id,
lastFile == null
? DateTime.now().microsecondsSinceEpoch
: lastFile.creationTime,
limit),
asyncLoader: (lastFile, limit) => FilesDB.instance
.getAllInCollectionBeforeCreationTime(
widget.collection.id,
lastFile == null
? DateTime.now().microsecondsSinceEpoch
: lastFile.creationTime,
limit),
// onRefresh: () => FolderSharingService.instance.syncDiff(widget.folder),
tagPrefix: "shared_collection",
selectedFiles: _selectedFiles,