diff --git a/lib/favorite_photos_repository.dart b/lib/favorite_photos_repository.dart new file mode 100644 index 000000000..2ba3bad8c --- /dev/null +++ b/lib/favorite_photos_repository.dart @@ -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 init() async { + _preferences = await SharedPreferences.getInstance(); + } + + bool isLiked(Photo photo) { + return _getLiked().contains(photo.generatedId.toString()); + } + + Future 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 _getLiked() { + final value = _preferences.getStringList(_favoritePhotoIdsKey); + if (value == null) { + return Set(); + } else { + return value.toSet(); + } + } +} diff --git a/lib/main.dart b/lib/main.dart index 721c74967..7e8eb7e14 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:photos/core/constants.dart'; import 'package:photos/core/configuration.dart'; +import 'package:photos/favorite_photos_repository.dart'; import 'package:photos/photo_sync_manager.dart'; import 'package:photos/ui/home_widget.dart'; import 'package:sentry/sentry.dart'; @@ -26,6 +27,7 @@ void _main() { WidgetsFlutterBinding.ensureInitialized(); Configuration.instance.init(); + FavoritePhotosRepository.instance.init(); PhotoSyncManager.instance.sync(); final SentryClient sentry = new SentryClient(dsn: SENTRY_DSN); diff --git a/lib/ui/album_list_widget.dart b/lib/ui/album_list_widget.dart index aa7b5ea65..8555d9fa5 100644 --- a/lib/ui/album_list_widget.dart +++ b/lib/ui/album_list_widget.dart @@ -2,6 +2,7 @@ import 'dart:collection'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; +import 'package:photos/favorite_photos_repository.dart'; import 'package:photos/models/album.dart'; import 'package:photos/models/photo.dart'; import 'package:photos/ui/album_widget.dart'; @@ -41,14 +42,22 @@ class _AlbumListWidgetState extends State { List _getAlbums(List photos) { final albumMap = new LinkedHashMap>(); + final favorites = Album("Favorites", List()); for (Photo photo in photos) { final folder = path.basename(photo.pathName); if (!albumMap.containsKey(folder)) { albumMap[folder] = new List(); } albumMap[folder].add(photo); + + if (FavoritePhotosRepository.instance.isLiked(photo)) { + favorites.photos.add(photo); + } } List albums = new List(); + if (favorites.photos.isNotEmpty) { + albums.add(favorites); + } for (String albumName in albumMap.keys) { albums.add(Album(albumName, albumMap[albumName])); } diff --git a/lib/ui/detail_page.dart b/lib/ui/detail_page.dart index 170460e4f..0b8fc6f09 100644 --- a/lib/ui/detail_page.dart +++ b/lib/ui/detail_page.dart @@ -1,6 +1,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:like_button/like_button.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/ui/extents_page_view.dart'; import 'package:photos/ui/zoomable_image.dart'; @@ -18,7 +20,7 @@ class DetailPage extends StatefulWidget { } class _DetailPageState extends State { - final logger = Logger("DetailPageState"); + final _logger = Logger("DetailPageState"); bool _shouldDisableScroll = false; List _photos; int _selectedIndex = 0; @@ -35,7 +37,7 @@ class _DetailPageState extends State { @override Widget build(BuildContext context) { - logger.info("Opening " + + _logger.info("Opening " + _photos[_selectedIndex].toString() + ". " + _selectedIndex.toString() + @@ -73,8 +75,9 @@ class _DetailPageState extends State { }, extents: 1, onPageChanged: (int index) { - logger.info("onPageChanged to " + index.toString()); - _selectedIndex = index; + setState(() { + _selectedIndex = index; + }); }, physics: _shouldDisableScroll ? NeverScrollableScrollPhysics() @@ -87,6 +90,7 @@ class _DetailPageState extends State { AppBar _buildAppBar() { return AppBar( actions: [ + _getFavoriteButton(), IconButton( icon: Icon(Icons.share), onPressed: () async { @@ -96,4 +100,14 @@ class _DetailPageState extends State { ], ); } + + Widget _getFavoriteButton() { + final photo = _photos[_selectedIndex]; + return LikeButton( + isLiked: FavoritePhotosRepository.instance.isLiked(photo), + onTap: (oldValue) { + return FavoritePhotosRepository.instance.setLiked(photo, !oldValue); + }, + ); + } } diff --git a/pubspec.lock b/pubspec.lock index d8b449ef7..cf209bfbc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,35 +21,28 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.4.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "1.0.5" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.3" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" + version: "1.1.2" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.12" + version: "1.14.11" connectivity: dependency: "direct main" description: @@ -127,13 +120,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -212,6 +198,13 @@ packages: url: "https://pub.dartlang.org" source: hosted 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: dependency: "direct main" description: @@ -253,7 +246,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.6.4" path_provider: dependency: "direct main" description: @@ -281,7 +274,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.0" + version: "1.8.0+1" petitparser: dependency: transitive description: @@ -324,6 +317,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.2.0" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" sensors: dependency: transitive description: @@ -384,7 +384,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.5.5" sqflite: dependency: "direct main" description: @@ -447,7 +447,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.15" + version: "0.2.11" toast: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index b7c6458b2..62d5b3522 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,7 @@ dependencies: shake: ^0.1.0 archive: ^2.0.11 flutter_email_sender: ^3.0.1 + like_button: ^0.2.0 dev_dependencies: flutter_test: