Introduce favorites

This commit is contained in:
Vishnu Mohandas 2020-05-06 22:13:03 +05:30
parent 9abe5335b2
commit 3fafd47fdd
6 changed files with 92 additions and 26 deletions

View file

@ -0,0 +1,40 @@
import 'package:photos/models/photo.dart';
import 'package:shared_preferences/shared_preferences.dart';
class FavoritePhotosRepository {
static final _favoritePhotoIdsKey = "favorite_photo_ids";
FavoritePhotosRepository._privateConstructor();
static FavoritePhotosRepository instance =
FavoritePhotosRepository._privateConstructor();
SharedPreferences _preferences;
Future<void> init() async {
_preferences = await SharedPreferences.getInstance();
}
bool isLiked(Photo photo) {
return _getLiked().contains(photo.generatedId.toString());
}
Future<bool> setLiked(Photo photo, bool isLiked) {
final liked = _getLiked();
if (isLiked) {
liked.add(photo.generatedId.toString());
} else {
liked.remove(photo.generatedId.toString());
}
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();
}
}
}

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:photos/core/constants.dart'; import 'package:photos/core/constants.dart';
import 'package:photos/core/configuration.dart'; import 'package:photos/core/configuration.dart';
import 'package:photos/favorite_photos_repository.dart';
import 'package:photos/photo_sync_manager.dart'; import 'package:photos/photo_sync_manager.dart';
import 'package:photos/ui/home_widget.dart'; import 'package:photos/ui/home_widget.dart';
import 'package:sentry/sentry.dart'; import 'package:sentry/sentry.dart';
@ -26,6 +27,7 @@ void _main() {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
Configuration.instance.init(); Configuration.instance.init();
FavoritePhotosRepository.instance.init();
PhotoSyncManager.instance.sync(); PhotoSyncManager.instance.sync();
final SentryClient sentry = new SentryClient(dsn: SENTRY_DSN); final SentryClient sentry = new SentryClient(dsn: SENTRY_DSN);

View file

@ -2,6 +2,7 @@ import 'dart:collection';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:photos/favorite_photos_repository.dart';
import 'package:photos/models/album.dart'; import 'package:photos/models/album.dart';
import 'package:photos/models/photo.dart'; import 'package:photos/models/photo.dart';
import 'package:photos/ui/album_widget.dart'; import 'package:photos/ui/album_widget.dart';
@ -41,14 +42,22 @@ class _AlbumListWidgetState extends State<AlbumListWidget> {
List<Album> _getAlbums(List<Photo> photos) { List<Album> _getAlbums(List<Photo> photos) {
final albumMap = new LinkedHashMap<String, List<Photo>>(); final albumMap = new LinkedHashMap<String, List<Photo>>();
final favorites = Album("Favorites", List<Photo>());
for (Photo photo in photos) { for (Photo photo in photos) {
final folder = path.basename(photo.pathName); final folder = path.basename(photo.pathName);
if (!albumMap.containsKey(folder)) { if (!albumMap.containsKey(folder)) {
albumMap[folder] = new List<Photo>(); albumMap[folder] = new List<Photo>();
} }
albumMap[folder].add(photo); albumMap[folder].add(photo);
if (FavoritePhotosRepository.instance.isLiked(photo)) {
favorites.photos.add(photo);
}
} }
List<Album> albums = new List<Album>(); List<Album> albums = new List<Album>();
if (favorites.photos.isNotEmpty) {
albums.add(favorites);
}
for (String albumName in albumMap.keys) { for (String albumName in albumMap.keys) {
albums.add(Album(albumName, albumMap[albumName])); albums.add(Album(albumName, albumMap[albumName]));
} }

View file

@ -1,6 +1,8 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:like_button/like_button.dart';
import 'package:photos/core/cache/lru_map.dart'; import 'package:photos/core/cache/lru_map.dart';
import 'package:photos/favorite_photos_repository.dart';
import 'package:photos/models/photo.dart'; import 'package:photos/models/photo.dart';
import 'package:photos/ui/extents_page_view.dart'; import 'package:photos/ui/extents_page_view.dart';
import 'package:photos/ui/zoomable_image.dart'; import 'package:photos/ui/zoomable_image.dart';
@ -18,7 +20,7 @@ class DetailPage extends StatefulWidget {
} }
class _DetailPageState extends State<DetailPage> { class _DetailPageState extends State<DetailPage> {
final logger = Logger("DetailPageState"); final _logger = Logger("DetailPageState");
bool _shouldDisableScroll = false; bool _shouldDisableScroll = false;
List<Photo> _photos; List<Photo> _photos;
int _selectedIndex = 0; int _selectedIndex = 0;
@ -35,7 +37,7 @@ class _DetailPageState extends State<DetailPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
logger.info("Opening " + _logger.info("Opening " +
_photos[_selectedIndex].toString() + _photos[_selectedIndex].toString() +
". " + ". " +
_selectedIndex.toString() + _selectedIndex.toString() +
@ -73,8 +75,9 @@ class _DetailPageState extends State<DetailPage> {
}, },
extents: 1, extents: 1,
onPageChanged: (int index) { onPageChanged: (int index) {
logger.info("onPageChanged to " + index.toString()); setState(() {
_selectedIndex = index; _selectedIndex = index;
});
}, },
physics: _shouldDisableScroll physics: _shouldDisableScroll
? NeverScrollableScrollPhysics() ? NeverScrollableScrollPhysics()
@ -87,6 +90,7 @@ class _DetailPageState extends State<DetailPage> {
AppBar _buildAppBar() { AppBar _buildAppBar() {
return AppBar( return AppBar(
actions: <Widget>[ actions: <Widget>[
_getFavoriteButton(),
IconButton( IconButton(
icon: Icon(Icons.share), icon: Icon(Icons.share),
onPressed: () async { onPressed: () async {
@ -96,4 +100,14 @@ class _DetailPageState extends State<DetailPage> {
], ],
); );
} }
Widget _getFavoriteButton() {
final photo = _photos[_selectedIndex];
return LikeButton(
isLiked: FavoritePhotosRepository.instance.isLiked(photo),
onTap: (oldValue) {
return FavoritePhotosRepository.instance.setLiked(photo, !oldValue);
},
);
}
} }

View file

@ -21,35 +21,28 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.1" version: "2.4.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "1.0.5"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
name: charcode name: charcode
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.3" version: "1.1.2"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.12" version: "1.14.11"
connectivity: connectivity:
dependency: "direct main" dependency: "direct main"
description: description:
@ -127,13 +120,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -212,6 +198,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.1" version: "3.0.1"
like_button:
dependency: "direct main"
description:
name: like_button
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
local_image_provider: local_image_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -253,7 +246,7 @@ packages:
name: path name: path
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.7.0" version: "1.6.4"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
@ -281,7 +274,7 @@ packages:
name: pedantic name: pedantic
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.0" version: "1.8.0+1"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@ -324,6 +317,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.2.0" version: "3.2.0"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
sensors: sensors:
dependency: transitive dependency: transitive
description: description:
@ -384,7 +384,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.7.0" version: "1.5.5"
sqflite: sqflite:
dependency: "direct main" dependency: "direct main"
description: description:
@ -447,7 +447,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.15" version: "0.2.11"
toast: toast:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -45,6 +45,7 @@ dependencies:
shake: ^0.1.0 shake: ^0.1.0
archive: ^2.0.11 archive: ^2.0.11
flutter_email_sender: ^3.0.1 flutter_email_sender: ^3.0.1
like_button: ^0.2.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: