From 3fe62b7e2214e40c923d2d95e3fe6a4b20a09721 Mon Sep 17 00:00:00 2001 From: Brian Lu Date: Sun, 10 Oct 2021 01:03:35 -0500 Subject: [PATCH] implement SNO gallery --- lib/main.dart | 11 +- lib/models/gallery_image_model.dart | 15 +++ lib/models/ngg_image_model.dart | 11 -- lib/services/ct/ct_ngg_gallery_service.dart | 23 ++-- lib/services/ct/ct_sno_gallery_service.dart | 33 +++++ .../parser/section_parser_service.dart | 2 +- .../section/sections/gallery_section.dart | 127 ++++++++++-------- lib/ui/pages/posts_page.dart | 6 +- 8 files changed, 140 insertions(+), 88 deletions(-) create mode 100644 lib/models/gallery_image_model.dart delete mode 100644 lib/models/ngg_image_model.dart create mode 100644 lib/services/ct/ct_sno_gallery_service.dart diff --git a/lib/main.dart b/lib/main.dart index 73cc67a..7615161 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:app/models/tab_category_model.dart'; import 'package:app/services/ct/ct_ngg_gallery_service.dart'; import 'package:app/services/ct/ct_shortcode_service.dart'; +import 'package:app/services/ct/ct_sno_gallery_service.dart'; import 'package:app/services/ct/ct_tab_category_service.dart'; import 'package:app/services/saved_posts_service.dart'; import 'package:app/services/section/parser/shortcode_parser_service.dart'; @@ -16,7 +17,7 @@ import 'package:wordpress_api/wordpress_api.dart'; void main() async { Logger.root.level = Level.INFO; Logger.root.onRecord.listen((record) { - print( + debugPrint( '[${record.level.name}]-${record.loggerName}: ${record.time}: ${record.message}'); }); @@ -29,10 +30,10 @@ void main() async { WordpressMediaService.init(api); WordpressSearchService.init(api); CtNggGalleryService.init(api); + CtSnoGalleryService.init(api); CtTabCategoryService.init(api); CtShortcodeService.init(api); - ShortcodeParserService.init( - await CtShortcodeService.getShortcodeNames()); + ShortcodeParserService.init(await CtShortcodeService.getShortcodeNames()); runApp(CentralTimesApp()); } @@ -52,7 +53,9 @@ class _CentralTimesAppState extends State { Widget build(BuildContext context) { return MultiProvider( providers: [ - FutureProvider>.value(value: CtTabCategoryService.getTabCategories(), initialData: List.empty()), + FutureProvider>.value( + value: CtTabCategoryService.getTabCategories(), + initialData: List.empty()), ], child: MaterialApp( title: 'Central Times', diff --git a/lib/models/gallery_image_model.dart b/lib/models/gallery_image_model.dart new file mode 100644 index 0000000..9f8f0cd --- /dev/null +++ b/lib/models/gallery_image_model.dart @@ -0,0 +1,15 @@ +class GalleryImageModel { + final String id; + final String caption; + final String alt; + + final String url; + + GalleryImageModel(this.id, this.caption, + this.alt, this.url); + + @override + String toString() { + return 'GalleryImageModel{id: $id, caption: $caption, alt: $alt, url: $url}'; + } +} diff --git a/lib/models/ngg_image_model.dart b/lib/models/ngg_image_model.dart deleted file mode 100644 index f17a5ae..0000000 --- a/lib/models/ngg_image_model.dart +++ /dev/null @@ -1,11 +0,0 @@ -class NggImageModel { - final String pid; - final String imgSlug; - final String filename; - final String description; - final String alttext; - final String path; - - NggImageModel(this.pid, this.imgSlug, this.filename, this.description, - this.alttext, this.path); -} diff --git a/lib/services/ct/ct_ngg_gallery_service.dart b/lib/services/ct/ct_ngg_gallery_service.dart index 942dae6..6da58f5 100644 --- a/lib/services/ct/ct_ngg_gallery_service.dart +++ b/lib/services/ct/ct_ngg_gallery_service.dart @@ -1,4 +1,4 @@ -import 'package:app/models/ngg_image_model.dart'; +import 'package:app/models/gallery_image_model.dart'; import 'package:logging/logging.dart'; import 'package:wordpress_api/wordpress_api.dart'; @@ -11,30 +11,29 @@ class CtNggGalleryService { log.info("Initialized!"); } - static Future> getGalleryImageData(int id) async { - final WPResponse res = await CtNggGalleryService.api.fetch('ngg-gallery/$id', namespace: 'centraltimes/v1'); + static Future> getGalleryImageData(int id) async { + final WPResponse res = await CtNggGalleryService.api + .fetch('ngg-gallery/$id', namespace: 'centraltimes/v1'); log.config(res); - List result = []; + List result = []; for (Map nggImageMap in res.data) { - result.add(_nggImageFromMap(nggImageMap)); + result.add(_galleryImageFromMap(nggImageMap)); } return result; } - static NggImageModel _nggImageFromMap(Map nggImageMap) { - return new NggImageModel( + static GalleryImageModel _galleryImageFromMap(Map nggImageMap) { + return new GalleryImageModel( nggImageMap["pid"], - nggImageMap["image_slug"], - nggImageMap["filename"], nggImageMap["description"], nggImageMap["alttext"], - nggImageMap["path"]); + _generateImageFileUrl(nggImageMap["filename"], nggImageMap["path"])); } - static String generateImageFileUrl(NggImageModel nggImage) { + static String _generateImageFileUrl(String filename, String path) { /* TODO we just do string concatenation here, and that's fine for now as the API seems to return consistent results, but something such as a uri join @@ -42,6 +41,6 @@ class CtNggGalleryService { function isn't suited to this, as it uses the platform's separator instead of the one consistent to web URIs: "/". */ - return Uri.https(api.site, nggImage.path + nggImage.filename).toString(); + return Uri.https(api.site, path + filename).toString(); } } diff --git a/lib/services/ct/ct_sno_gallery_service.dart b/lib/services/ct/ct_sno_gallery_service.dart new file mode 100644 index 0000000..fa74413 --- /dev/null +++ b/lib/services/ct/ct_sno_gallery_service.dart @@ -0,0 +1,33 @@ +import 'package:app/models/gallery_image_model.dart'; +import 'package:logging/logging.dart'; +import 'package:wordpress_api/wordpress_api.dart'; + +class CtSnoGalleryService { + static late WordPressAPI api; + static final Logger log = new Logger("CtSnoGalleryService"); + + static void init(WordPressAPI api) { + CtSnoGalleryService.api = api; + log.info("Initialized!"); + } + + static Future> getGalleryImageData( + List ids) async { + + final WPResponse res = await CtSnoGalleryService.api + .fetch('sno-gallery/${ids.join(",")}', namespace: 'centraltimes/v1'); + + List result = []; + + for (Map mediaMap in res.data) { + result.add(_galleryImageFromMap(mediaMap)); + } + + return result; + } + + static GalleryImageModel _galleryImageFromMap(Map mediaMap) { + return new GalleryImageModel(mediaMap["ID"].toString(), mediaMap["post_excerpt"], + mediaMap["post_excerpt"], mediaMap["guid"]); + } +} diff --git a/lib/services/section/parser/section_parser_service.dart b/lib/services/section/parser/section_parser_service.dart index 01f8b2f..7076b66 100644 --- a/lib/services/section/parser/section_parser_service.dart +++ b/lib/services/section/parser/section_parser_service.dart @@ -1,4 +1,3 @@ - import 'package:app/services/section/parser/shortcode_parser_service.dart'; import 'package:app/services/section/sections/caption_section.dart'; import 'package:app/services/section/sections/gallery_section.dart'; @@ -59,6 +58,7 @@ class SectionParserService { case 'related': return RelatedSection().useShortcode(shortcode); case 'ngg': + case 'gallery': return GallerySection().useShortcode(shortcode); default: return UnsupportedSection().useShortcode(shortcode); diff --git a/lib/services/section/sections/gallery_section.dart b/lib/services/section/sections/gallery_section.dart index aea0169..e28cdd0 100644 --- a/lib/services/section/sections/gallery_section.dart +++ b/lib/services/section/sections/gallery_section.dart @@ -1,7 +1,8 @@ import 'dart:math'; -import 'package:app/models/ngg_image_model.dart'; +import 'package:app/models/gallery_image_model.dart'; import 'package:app/services/ct/ct_ngg_gallery_service.dart'; +import 'package:app/services/ct/ct_sno_gallery_service.dart'; import 'package:app/services/section/article_section.dart'; import 'package:app/services/section/parser/shortcode_parser_service.dart'; import 'package:app/ui/media_loading_indicator.dart'; @@ -12,80 +13,94 @@ import 'package:flutter/src/widgets/framework.dart'; class GallerySection implements ArticleSection { @override Widget useShortcode(Shortcode shortcode) { - assert(shortcode.name == 'ngg'); + assert(shortcode.name == 'ngg' || shortcode.name == 'gallery'); - return Gallery(galleryId: int.parse(shortcode.arguments["ids"] ?? "0")); + Future> galleryImagesFuture; + + switch (shortcode.name) { + case "ngg": // NextGEN Gallery + galleryImagesFuture = CtNggGalleryService.getGalleryImageData( + int.parse(shortcode.arguments["ids"] ?? "0")); + break; + case "gallery": // SNO Gallery + galleryImagesFuture = CtSnoGalleryService.getGalleryImageData( + (shortcode.arguments["ids"] ?? "") + .split(",") + .map((e) => int.parse(e.trim())) + .toList()); + break; + default: + throw AssertionError(); + } + + return FutureBuilder>( + future: galleryImagesFuture, + builder: (context, snapshot) { + if (snapshot.hasData) { + return Gallery(galleryImages: snapshot.data!); + } else { + return MediaLoadingIndicator(); + } + }); } } class Gallery extends StatefulWidget { - final int galleryId; + final List galleryImages; - const Gallery({Key? key, required this.galleryId}) : super(key: key); + const Gallery({Key? key, required this.galleryImages}) : super(key: key); @override - State createState() => _GalleryState(galleryId); + State createState() => _GalleryState(galleryImages); } class _GalleryState extends State { - final int galleryId; + final List galleryImages; int imageIndex = 0; - List imageData = []; List images = []; - _GalleryState(this.galleryId); + _GalleryState(this.galleryImages); @override Widget build(BuildContext context) { - return FutureBuilder>( - future: CtNggGalleryService.getGalleryImageData(galleryId), - builder: (context, snapshot) { - if (snapshot.hasData) { - imageData = snapshot.data!; - for (NggImageModel nggImage in imageData) { - images.add(CachedNetworkImage( - imageUrl: CtNggGalleryService.generateImageFileUrl(nggImage))); - } - return Column( - children: [ - Text("Gallery"), - Text("${imageIndex+1}/${imageData.length}"), - Container( - color: Colors.grey, - child: AspectRatio( - aspectRatio: 1, - child: images[imageIndex], - ), - ), - Text(imageData[imageIndex].description), - Row( - children: [ - ElevatedButton.icon( - onPressed: () { - setState(() { - imageIndex = max(imageIndex - 1, 0); - }); - }, - icon: Icon(Icons.arrow_left), - label: Text("Previous")), - ElevatedButton.icon( - onPressed: () { - setState(() { - imageIndex = min(imageIndex + 1, imageData.length - 1); - }); - }, - icon: Icon(Icons.arrow_right), - label: Text("Next")), - ], - ) - ], - ); - } else { - return MediaLoadingIndicator(); - } - }, + for (GalleryImageModel galleryImage in galleryImages) { + images.add(CachedNetworkImage(imageUrl: galleryImage.url)); + } + return Column( + children: [ + Text("Gallery"), + Text("${imageIndex + 1}/${galleryImages.length}"), + Container( + color: Colors.grey, + child: AspectRatio( + aspectRatio: 1, + child: images[imageIndex], + ), + ), + Text(galleryImages[imageIndex].caption), + Row( + children: [ + ElevatedButton.icon( + onPressed: () { + setState(() { + imageIndex = max(imageIndex - 1, 0); + }); + }, + icon: Icon(Icons.arrow_left), + label: Text("Previous")), + ElevatedButton.icon( + onPressed: () { + setState(() { + imageIndex = min(imageIndex + 1, galleryImages.length - 1); + }); + }, + icon: Icon(Icons.arrow_right), + label: Text("Next")), + ], + ) + ], ); } } diff --git a/lib/ui/pages/posts_page.dart b/lib/ui/pages/posts_page.dart index 5be8b9a..e71d642 100644 --- a/lib/ui/pages/posts_page.dart +++ b/lib/ui/pages/posts_page.dart @@ -1,5 +1,4 @@ import 'package:app/models/tab_category_model.dart'; -import 'package:app/services/ct/ct_tab_category_service.dart'; import 'package:app/ui/list/post_list/post_list_view.dart'; import 'package:app/ui/page_template.dart'; import 'package:flutter/material.dart'; @@ -25,10 +24,9 @@ class PostsPageState extends State with TickerProviderStateMixin { Tab(child: Text("All")), ...tabCategories.map((e) => Tab(child: Text(e.name))).toList() ]), - child: Flexible( - child: TabBarView(controller: tabController, children: [ + child: TabBarView(controller: tabController, children: [ PostListView(), ...tabCategories.map((e) => PostListView(category: e.id)) - ]))); + ])); } }