create_collection_page.dart 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/widgets.dart';
  3. import 'package:logging/logging.dart';
  4. import 'package:page_transition/page_transition.dart';
  5. import 'package:photos/core/configuration.dart';
  6. import 'package:photos/db/files_db.dart';
  7. import 'package:photos/models/collection.dart';
  8. import 'package:photos/models/collection_items.dart';
  9. import 'package:photos/models/file.dart';
  10. import 'package:photos/models/selected_files.dart';
  11. import 'package:photos/services/collections_service.dart';
  12. import 'package:photos/ui/collection_page.dart';
  13. import 'package:photos/ui/loading_widget.dart';
  14. import 'package:photos/ui/thumbnail_widget.dart';
  15. import 'package:photos/utils/dialog_util.dart';
  16. import 'package:photos/utils/file_uploader.dart';
  17. import 'package:photos/utils/toast_util.dart';
  18. class CreateCollectionPage extends StatefulWidget {
  19. final SelectedFiles selectedFiles;
  20. const CreateCollectionPage(this.selectedFiles, {Key key}) : super(key: key);
  21. @override
  22. _CreateCollectionPageState createState() => _CreateCollectionPageState();
  23. }
  24. class _CreateCollectionPageState extends State<CreateCollectionPage> {
  25. final _logger = Logger("CreateCollectionPage");
  26. String _albumName;
  27. @override
  28. Widget build(BuildContext context) {
  29. return Scaffold(
  30. appBar: AppBar(
  31. title: Text("Create album"),
  32. ),
  33. body: _getBody(context),
  34. );
  35. }
  36. Widget _getBody(BuildContext context) {
  37. return Column(
  38. children: [
  39. Row(
  40. children: [
  41. Expanded(
  42. child: Padding(
  43. padding: const EdgeInsets.all(8.0),
  44. child: OutlineButton(
  45. child: Text(
  46. "Create a new album",
  47. style: Theme.of(context).textTheme.bodyText1,
  48. ),
  49. onPressed: () {
  50. _showNameAlbumDialog();
  51. },
  52. ),
  53. ),
  54. ),
  55. ],
  56. ),
  57. Padding(
  58. padding: const EdgeInsets.fromLTRB(8, 12, 8, 8),
  59. child: Align(
  60. alignment: Alignment.centerLeft,
  61. child: Text(
  62. "Add to an existing collection",
  63. style: TextStyle(
  64. fontWeight: FontWeight.bold,
  65. color: Theme.of(context).primaryColorLight,
  66. ),
  67. ),
  68. ),
  69. ),
  70. _getExistingCollectionsWidget(),
  71. ],
  72. );
  73. }
  74. Widget _getExistingCollectionsWidget() {
  75. return FutureBuilder<List<CollectionWithThumbnail>>(
  76. future: _getCollectionsWithThumbnail(),
  77. builder: (context, snapshot) {
  78. if (snapshot.hasError) {
  79. return Text(snapshot.error.toString());
  80. } else if (snapshot.hasData) {
  81. return Flexible(
  82. child: ListView.builder(
  83. itemBuilder: (context, index) {
  84. return _buildCollectionItem(snapshot.data[index]);
  85. },
  86. itemCount: snapshot.data.length,
  87. shrinkWrap: true,
  88. ),
  89. );
  90. } else {
  91. return loadWidget;
  92. }
  93. },
  94. );
  95. }
  96. Widget _buildCollectionItem(CollectionWithThumbnail item) {
  97. return Container(
  98. padding: EdgeInsets.all(8),
  99. child: GestureDetector(
  100. child: Row(
  101. children: <Widget>[
  102. ClipRRect(
  103. borderRadius: BorderRadius.circular(2.0),
  104. child: Container(
  105. child: ThumbnailWidget(item.thumbnail),
  106. height: 64,
  107. width: 64,
  108. ),
  109. ),
  110. Padding(padding: EdgeInsets.all(8)),
  111. Expanded(
  112. child: Text(
  113. item.collection.name,
  114. style: TextStyle(
  115. fontSize: 16,
  116. ),
  117. ),
  118. ),
  119. ],
  120. ),
  121. onTap: () async {
  122. if (await _addToCollection(item.collection.id)) {
  123. showToast("Added successfully to '" + item.collection.name);
  124. Navigator.pop(context);
  125. Navigator.push(
  126. context,
  127. PageTransition(
  128. type: PageTransitionType.bottomToTop,
  129. child: CollectionPage(
  130. item.collection,
  131. )));
  132. }
  133. },
  134. ),
  135. );
  136. }
  137. Future<List<CollectionWithThumbnail>> _getCollectionsWithThumbnail() async {
  138. final collectionsWithThumbnail = List<CollectionWithThumbnail>();
  139. final collections = CollectionsService.instance.getCollections();
  140. for (final c in collections) {
  141. if (c.owner.id != Configuration.instance.getUserID()) {
  142. continue;
  143. }
  144. var thumbnail = await FilesDB.instance.getLatestFileInCollection(c.id);
  145. if (thumbnail == null) {
  146. continue;
  147. }
  148. final lastUpdatedFile =
  149. await FilesDB.instance.getLastModifiedFileInCollection(c.id);
  150. collectionsWithThumbnail.add(CollectionWithThumbnail(
  151. c,
  152. thumbnail,
  153. lastUpdatedFile,
  154. ));
  155. }
  156. collectionsWithThumbnail.sort((first, second) {
  157. return second.lastUpdatedFile.updationTime
  158. .compareTo(first.lastUpdatedFile.updationTime);
  159. });
  160. return collectionsWithThumbnail;
  161. }
  162. void _showNameAlbumDialog() async {
  163. AlertDialog alert = AlertDialog(
  164. title: Text("Album title"),
  165. content: TextFormField(
  166. decoration: InputDecoration(
  167. hintText: "Christmas 21 / Dinner at Bob's",
  168. contentPadding: EdgeInsets.all(8),
  169. ),
  170. onChanged: (value) {
  171. setState(() {
  172. _albumName = value;
  173. });
  174. },
  175. autofocus: true,
  176. keyboardType: TextInputType.text,
  177. ),
  178. actions: [
  179. FlatButton(
  180. child: Text("OK"),
  181. onPressed: () async {
  182. Navigator.pop(context);
  183. final collection = await _createAlbum(_albumName);
  184. if (collection != null) {
  185. if (await _addToCollection(collection.id)) {
  186. showToast("Album '" + _albumName + "' created.");
  187. Navigator.pop(context);
  188. Navigator.push(
  189. context,
  190. PageTransition(
  191. type: PageTransitionType.bottomToTop,
  192. child: CollectionPage(
  193. collection,
  194. )));
  195. }
  196. }
  197. },
  198. ),
  199. ],
  200. );
  201. showDialog(
  202. context: context,
  203. builder: (BuildContext context) {
  204. return alert;
  205. },
  206. );
  207. }
  208. Future<bool> _addToCollection(int collectionID) async {
  209. final dialog = createProgressDialog(context, "Uploading files to album...");
  210. await dialog.show();
  211. final files = List<File>();
  212. for (final file in widget.selectedFiles.files) {
  213. if (file.uploadedFileID == null) {
  214. final uploadedFile =
  215. (await FileUploader.instance.forceUpload(file, collectionID));
  216. files.add(uploadedFile);
  217. } else {
  218. files.add(file);
  219. }
  220. }
  221. try {
  222. await CollectionsService.instance.addToCollection(collectionID, files);
  223. await dialog.hide();
  224. widget.selectedFiles.clearAll();
  225. return true;
  226. } catch (e, s) {
  227. _logger.severe(e, s);
  228. await dialog.hide();
  229. showGenericErrorDialog(context);
  230. }
  231. return false;
  232. }
  233. Future<Collection> _createAlbum(String albumName) async {
  234. var collection;
  235. final dialog = createProgressDialog(context, "Creating album...");
  236. await dialog.show();
  237. try {
  238. collection = await CollectionsService.instance.createAlbum(albumName);
  239. } catch (e, s) {
  240. _logger.severe(e, s);
  241. await dialog.hide();
  242. showGenericErrorDialog(context);
  243. } finally {
  244. await dialog.hide();
  245. }
  246. return collection;
  247. }
  248. }