diff --git a/lib/main.dart b/lib/main.dart index 54364dc9d..5ba01c077 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,15 +2,10 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; -import 'package:myapp/models/photo.dart'; -import 'package:myapp/photo_loader.dart'; import 'package:myapp/photo_provider.dart'; import 'package:myapp/photo_sync_manager.dart'; -import 'package:myapp/ui/gallery.dart'; -import 'package:myapp/ui/loading_widget.dart'; -import 'package:myapp/ui/search_page.dart'; +import 'package:myapp/ui/home_widget.dart'; import 'package:photo_manager/photo_manager.dart'; -import 'package:provider/provider.dart'; final provider = PhotoProvider(); final logger = Logger(); @@ -35,73 +30,13 @@ Future init(List assets) async { } class MyApp extends StatelessWidget { - final PhotoLoader photoLoader = PhotoLoader.instance; - + final _title = 'Orma'; @override Widget build(BuildContext context) { - final title = 'Orma'; - return FutureBuilder( - future: photoLoader.loadPhotos(), - builder: (context, snapshot) { - Widget body; - if (snapshot.hasData) { - body = HomeWidget(); - } else if (snapshot.hasError) { - logger.e(snapshot.error); - body = Text("Error!"); - } else { - body = loadWidget; - } - return ChangeNotifierProvider.value( - value: photoLoader, - child: MaterialApp( - title: title, - theme: ThemeData.dark(), - home: Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: body), - ), - ); - }); - } -} - -class HomeWidget extends StatelessWidget { - const HomeWidget({ - Key key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - child: Column( - children: [ - Hero( - child: TextField( - readOnly: true, - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return SearchPage(); - }, - ), - ); - }, - decoration: InputDecoration( - border: InputBorder.none, - hintText: 'Search "Paris"', - contentPadding: const EdgeInsets.all(12.0), - ), - ), - tag: "search"), - Flexible( - child: Gallery(), - ) - ], - ), + return MaterialApp( + title: _title, + theme: ThemeData.dark(), + home: HomeWidget(_title), ); } } diff --git a/lib/ui/detail_page.dart b/lib/ui/detail_page.dart index 0de4d205a..0b8efe09c 100644 --- a/lib/ui/detail_page.dart +++ b/lib/ui/detail_page.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:logger/logger.dart'; import 'package:myapp/core/lru_map.dart'; import 'package:myapp/models/photo.dart'; import 'package:share_extend/share_extend.dart'; @@ -12,6 +13,7 @@ class DetailPage extends StatelessWidget { @override Widget build(BuildContext context) { + Logger().i(photo.localPath); return Scaffold( appBar: AppBar( actions: [ diff --git a/lib/ui/gallery.dart b/lib/ui/gallery.dart index 6b25cbea9..34b97200f 100644 --- a/lib/ui/gallery.dart +++ b/lib/ui/gallery.dart @@ -10,10 +10,13 @@ import 'package:myapp/utils/date_time_util.dart'; import 'package:provider/provider.dart'; import 'package:share_extend/share_extend.dart'; -import 'change_notifier_builder.dart'; import 'detail_page.dart'; class Gallery extends StatefulWidget { + final List> collatedPhotos; + + const Gallery(this.collatedPhotos, {Key key}) : super(key: key); + @override _GalleryState createState() { return _GalleryState(); @@ -26,19 +29,15 @@ class _GalleryState extends State { @override Widget build(BuildContext context) { - return ChangeNotifierBuilder( - value: photoLoader, - builder: (_, __) { - return ListView.builder( - itemCount: photoLoader.collatedPhotos.length, - itemBuilder: _buildListItem, - controller: _scrollController, - ); - }); + return ListView.builder( + itemCount: widget.collatedPhotos.length, + itemBuilder: _buildListItem, + controller: _scrollController, + ); } Widget _buildListItem(BuildContext context, int index) { - var photos = photoLoader.collatedPhotos[index]; + var photos = widget.collatedPhotos[index]; return Column( children: [ _getDay(photos[0].createTimestamp), diff --git a/lib/ui/gallery_container_widget.dart b/lib/ui/gallery_container_widget.dart new file mode 100644 index 000000000..c15fde214 --- /dev/null +++ b/lib/ui/gallery_container_widget.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:myapp/models/photo.dart'; +import 'package:myapp/ui/change_notifier_builder.dart'; +import 'package:myapp/ui/search_page.dart'; +import 'package:myapp/utils/camera_items_filter.dart'; +import 'package:myapp/utils/gallery_items_filter.dart'; +import 'package:provider/provider.dart'; + +import '../photo_loader.dart'; +import 'gallery.dart'; +import 'loading_widget.dart'; + +class GalleryContainer extends StatelessWidget { + final GalleryType type; + + static final importantItemsFilter = CameraItemsFilter(); + static final galleryItemsFilter = GalleryItemsFilter(); + + const GalleryContainer( + this.type, { + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final photoLoader = PhotoLoader.instance; + return Column( + children: [ + Hero( + child: TextField( + readOnly: true, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) { + return SearchPage(); + }, + ), + ); + }, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'Search "Paris"', + contentPadding: const EdgeInsets.all(12.0), + ), + ), + tag: "search"), + FutureBuilder( + future: photoLoader.loadPhotos(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return ChangeNotifierProvider.value( + value: photoLoader, + child: ChangeNotifierBuilder( + value: photoLoader, + builder: (_, __) { + var collatedPhotos = photoLoader.collatedPhotos; + return Flexible(child: _getGallery(collatedPhotos)); + }), + ); + } else if (snapshot.hasError) { + return Text("Error!"); + } else { + return loadWidget; + } + }, + ) + ], + ); + } + + Gallery _getGallery(List> collatedPhotos) { + return type == GalleryType.important_photos + ? Gallery(getCollatedPhotos(collatedPhotos, importantItemsFilter)) + : Gallery(getCollatedPhotos(collatedPhotos, galleryItemsFilter)); + } + + List> getCollatedPhotos( + List> source, GalleryItemsFilter filter) { + final List> collatedList = List>(); + for (List unfilteredPhotos in source) { + final List filteredPhotos = List(); + for (Photo photo in unfilteredPhotos) { + if (filter.shouldInclude(photo)) { + filteredPhotos.add(photo); + } + } + if (filteredPhotos.isNotEmpty) { + collatedList.add(filteredPhotos); + } + } + return collatedList; + } +} + +enum GalleryType { + important_photos, + all_photos, +} diff --git a/lib/ui/home_widget.dart b/lib/ui/home_widget.dart new file mode 100644 index 000000000..e448fc33b --- /dev/null +++ b/lib/ui/home_widget.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'gallery_container_widget.dart'; + +class HomeWidget extends StatefulWidget { + final String title; + + const HomeWidget(this.title, {Key key}) : super(key: key); + + @override + State createState() => _HomeWidgetState(); +} + +class _HomeWidgetState extends State { + int _selectedIndex = 0; + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: widget.title, + theme: ThemeData.dark(), + home: Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + bottomNavigationBar: BottomNavigationBar( + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.photo_filter), + title: Text('Photos'), + ), + BottomNavigationBarItem( + icon: Icon(Icons.photo_library), + title: Text('Gallery'), + ), + ], + currentIndex: _selectedIndex, + selectedItemColor: Colors.yellow[800], + onTap: _onItemTapped, + ), + body: GalleryContainer(_selectedIndex == 0 + ? GalleryType.important_photos + : GalleryType.all_photos), + ), + ); + } + + void _onItemTapped(int index) { + setState(() { + _selectedIndex = index; + }); + } +} diff --git a/lib/utils/camera_items_filter.dart b/lib/utils/camera_items_filter.dart new file mode 100644 index 000000000..cfb4e4bfc --- /dev/null +++ b/lib/utils/camera_items_filter.dart @@ -0,0 +1,10 @@ +import 'package:myapp/models/photo.dart'; +import 'package:myapp/utils/gallery_items_filter.dart'; + +class CameraItemsFilter implements GalleryItemsFilter { + @override + bool shouldInclude(Photo photo) { + // TODO: Improve logic + return photo.localPath.contains("Camera"); + } +} diff --git a/lib/utils/gallery_items_filter.dart b/lib/utils/gallery_items_filter.dart new file mode 100644 index 000000000..d1e8c3c92 --- /dev/null +++ b/lib/utils/gallery_items_filter.dart @@ -0,0 +1,7 @@ +import 'package:myapp/models/photo.dart'; + +class GalleryItemsFilter { + bool shouldInclude(Photo photo) { + return true; + } +} diff --git a/pubspec.lock b/pubspec.lock index d37e2b299..330735481 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -191,6 +191,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.8" + photo_view: + dependency: "direct main" + description: + name: photo_view + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.2" platform: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ec9b0f682..11f995549 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: image: ^2.1.4 share_extend: "^1.1.2" draggable_scrollbar: ^0.0.4 + photo_view: ^0.9.2 dev_dependencies: flutter_test: