create_collection_page.dart 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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("add memories"),
  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.only(
  44. top: 16, bottom: 12, left: 24, right: 24),
  45. child: OutlineButton.icon(
  46. padding: EdgeInsets.all(20),
  47. icon: Icon(Icons.create_new_folder_outlined),
  48. label: Text(
  49. "to a new album",
  50. style: Theme.of(context).textTheme.bodyText1,
  51. ),
  52. onPressed: () {
  53. _showNameAlbumDialog();
  54. },
  55. ),
  56. ),
  57. ),
  58. ],
  59. ),
  60. Padding(
  61. padding: const EdgeInsets.fromLTRB(24, 12, 8, 16),
  62. child: Align(
  63. alignment: Alignment.centerLeft,
  64. child: Text(
  65. "to an existing album",
  66. style: TextStyle(
  67. fontWeight: FontWeight.bold,
  68. color: Theme.of(context).primaryColorLight,
  69. ),
  70. ),
  71. ),
  72. ),
  73. _getExistingCollectionsWidget(),
  74. ],
  75. );
  76. }
  77. Widget _getExistingCollectionsWidget() {
  78. return FutureBuilder<List<CollectionWithThumbnail>>(
  79. future: _getCollectionsWithThumbnail(),
  80. builder: (context, snapshot) {
  81. if (snapshot.hasError) {
  82. return Text(snapshot.error.toString());
  83. } else if (snapshot.hasData) {
  84. return Flexible(
  85. child: ListView.builder(
  86. itemBuilder: (context, index) {
  87. return _buildCollectionItem(snapshot.data[index]);
  88. },
  89. itemCount: snapshot.data.length,
  90. shrinkWrap: true,
  91. ),
  92. );
  93. } else {
  94. return loadWidget;
  95. }
  96. },
  97. );
  98. }
  99. Widget _buildCollectionItem(CollectionWithThumbnail item) {
  100. return Container(
  101. padding: EdgeInsets.only(left: 24, bottom: 16),
  102. child: GestureDetector(
  103. child: Row(
  104. children: <Widget>[
  105. ClipRRect(
  106. borderRadius: BorderRadius.circular(2.0),
  107. child: Container(
  108. child: ThumbnailWidget(item.thumbnail),
  109. height: 64,
  110. width: 64,
  111. ),
  112. ),
  113. Padding(padding: EdgeInsets.all(8)),
  114. Expanded(
  115. child: Text(
  116. item.collection.name,
  117. style: TextStyle(
  118. fontSize: 16,
  119. ),
  120. ),
  121. ),
  122. ],
  123. ),
  124. onTap: () async {
  125. if (await _addToCollection(item.collection.id)) {
  126. showToast("added successfully to '" + item.collection.name);
  127. _navigateToCollection(item.collection);
  128. }
  129. },
  130. ),
  131. );
  132. }
  133. Future<List<CollectionWithThumbnail>> _getCollectionsWithThumbnail() async {
  134. final collectionsWithThumbnail = List<CollectionWithThumbnail>();
  135. final collections = CollectionsService.instance.getCollections();
  136. for (final c in collections) {
  137. if (c.owner.id != Configuration.instance.getUserID()) {
  138. continue;
  139. }
  140. var thumbnail = await FilesDB.instance.getLatestFileInCollection(c.id);
  141. if (thumbnail == null) {
  142. continue;
  143. }
  144. final lastUpdatedFile =
  145. await FilesDB.instance.getLastModifiedFileInCollection(c.id);
  146. collectionsWithThumbnail.add(CollectionWithThumbnail(
  147. c,
  148. thumbnail,
  149. lastUpdatedFile,
  150. ));
  151. }
  152. collectionsWithThumbnail.sort((first, second) {
  153. return second.lastUpdatedFile.updationTime
  154. .compareTo(first.lastUpdatedFile.updationTime);
  155. });
  156. return collectionsWithThumbnail;
  157. }
  158. void _showNameAlbumDialog() async {
  159. AlertDialog alert = AlertDialog(
  160. title: Text("album title"),
  161. content: TextFormField(
  162. decoration: InputDecoration(
  163. hintText: "Christmas 2020 / Dinner at Alice's",
  164. contentPadding: EdgeInsets.all(8),
  165. ),
  166. onChanged: (value) {
  167. setState(() {
  168. _albumName = value;
  169. });
  170. },
  171. autofocus: true,
  172. keyboardType: TextInputType.text,
  173. textCapitalization: TextCapitalization.words,
  174. ),
  175. actions: [
  176. FlatButton(
  177. child: Text("ok"),
  178. onPressed: () async {
  179. Navigator.of(context, rootNavigator: true).pop('dialog');
  180. final collection = await _createAlbum(_albumName);
  181. if (collection != null) {
  182. if (await _addToCollection(collection.id)) {
  183. showToast("album '" + _albumName + "' created.");
  184. _navigateToCollection(collection);
  185. }
  186. }
  187. },
  188. ),
  189. ],
  190. );
  191. showDialog(
  192. context: context,
  193. builder: (BuildContext context) {
  194. return alert;
  195. },
  196. );
  197. }
  198. void _navigateToCollection(Collection collection) {
  199. Navigator.pop(context);
  200. Navigator.push(
  201. context,
  202. PageTransition(
  203. type: PageTransitionType.bottomToTop,
  204. child: CollectionPage(
  205. collection,
  206. )));
  207. }
  208. Future<bool> _addToCollection(int collectionID) async {
  209. final dialog = createProgressDialog(context, "uploading files to album...");
  210. await dialog.show();
  211. try {
  212. final files = List<File>();
  213. for (final file in widget.selectedFiles.files) {
  214. final currentFile = await FilesDB.instance.getFile(file.generatedID);
  215. if (currentFile.uploadedFileID == null) {
  216. final uploadedFile = (await FileUploader.instance
  217. .forceUpload(currentFile, collectionID));
  218. files.add(uploadedFile);
  219. } else {
  220. files.add(currentFile);
  221. }
  222. }
  223. await CollectionsService.instance.addToCollection(collectionID, files);
  224. await dialog.hide();
  225. widget.selectedFiles.clearAll();
  226. return true;
  227. } catch (e, s) {
  228. _logger.severe("Could not add to album", e, s);
  229. await dialog.hide();
  230. showGenericErrorDialog(context);
  231. }
  232. return false;
  233. }
  234. Future<Collection> _createAlbum(String albumName) async {
  235. var collection;
  236. final dialog = createProgressDialog(context, "creating album...");
  237. await dialog.show();
  238. try {
  239. collection = await CollectionsService.instance.createAlbum(albumName);
  240. } catch (e, s) {
  241. _logger.severe(e, s);
  242. await dialog.hide();
  243. showGenericErrorDialog(context);
  244. } finally {
  245. await dialog.hide();
  246. }
  247. return collection;
  248. }
  249. }