Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement SNO gallery #28

Merged
merged 1 commit into from
Oct 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debugPrint will not attempt to print on production builds, as opposed to print

'[${record.level.name}]-${record.loggerName}: ${record.time}: ${record.message}');
});

Expand All @@ -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());
}
Expand All @@ -52,7 +53,9 @@ class _CentralTimesAppState extends State<CentralTimesApp> {
Widget build(BuildContext context) {
return MultiProvider(
providers: [
FutureProvider<List<TabCategoryModel>>.value(value: CtTabCategoryService.getTabCategories(), initialData: List.empty()),
FutureProvider<List<TabCategoryModel>>.value(
value: CtTabCategoryService.getTabCategories(),
initialData: List.empty()),
],
child: MaterialApp(
title: 'Central Times',
Expand Down
15 changes: 15 additions & 0 deletions lib/models/gallery_image_model.dart
Original file line number Diff line number Diff line change
@@ -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}';
}
}
11 changes: 0 additions & 11 deletions lib/models/ngg_image_model.dart

This file was deleted.

23 changes: 11 additions & 12 deletions lib/services/ct/ct_ngg_gallery_service.dart
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -11,37 +11,36 @@ class CtNggGalleryService {
log.info("Initialized!");
}

static Future<List<NggImageModel>> getGalleryImageData(int id) async {
final WPResponse res = await CtNggGalleryService.api.fetch('ngg-gallery/$id', namespace: 'centraltimes/v1');
static Future<List<GalleryImageModel>> getGalleryImageData(int id) async {
final WPResponse res = await CtNggGalleryService.api
.fetch('ngg-gallery/$id', namespace: 'centraltimes/v1');

log.config(res);

List<NggImageModel> result = [];
List<GalleryImageModel> result = [];
for (Map<String, dynamic> nggImageMap in res.data) {
result.add(_nggImageFromMap(nggImageMap));
result.add(_galleryImageFromMap(nggImageMap));
}

return result;
}

static NggImageModel _nggImageFromMap(Map<String, dynamic> nggImageMap) {
return new NggImageModel(
static GalleryImageModel _galleryImageFromMap(Map<String, dynamic> 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
function would be more robust. Unfortunately the path library's join
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();
}
}
33 changes: 33 additions & 0 deletions lib/services/ct/ct_sno_gallery_service.dart
Original file line number Diff line number Diff line change
@@ -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<List<GalleryImageModel>> getGalleryImageData(
List<int> ids) async {

final WPResponse res = await CtSnoGalleryService.api
.fetch('sno-gallery/${ids.join(",")}', namespace: 'centraltimes/v1');

List<GalleryImageModel> result = [];

for (Map<String, dynamic> mediaMap in res.data) {
result.add(_galleryImageFromMap(mediaMap));
}

return result;
}

static GalleryImageModel _galleryImageFromMap(Map<String, dynamic> mediaMap) {
return new GalleryImageModel(mediaMap["ID"].toString(), mediaMap["post_excerpt"],
mediaMap["post_excerpt"], mediaMap["guid"]);
}
}
2 changes: 1 addition & 1 deletion lib/services/section/parser/section_parser_service.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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);
Expand Down
127 changes: 71 additions & 56 deletions lib/services/section/sections/gallery_section.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<List<GalleryImageModel>> 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<List<GalleryImageModel>>(
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<GalleryImageModel> galleryImages;

const Gallery({Key? key, required this.galleryId}) : super(key: key);
const Gallery({Key? key, required this.galleryImages}) : super(key: key);

@override
State<StatefulWidget> createState() => _GalleryState(galleryId);
State<StatefulWidget> createState() => _GalleryState(galleryImages);
}

class _GalleryState extends State<Gallery> {
final int galleryId;
final List<GalleryImageModel> galleryImages;

int imageIndex = 0;

List<NggImageModel> imageData = [];
List<CachedNetworkImage> images = [];

_GalleryState(this.galleryId);
_GalleryState(this.galleryImages);

@override
Widget build(BuildContext context) {
return FutureBuilder<List<NggImageModel>>(
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")),
],
)
],
);
}
}
6 changes: 2 additions & 4 deletions lib/ui/pages/posts_page.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -25,10 +24,9 @@ class PostsPageState extends State<PostsPage> 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: [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small fix to prevent exception from occurring related to Flexible

PostListView(),
...tabCategories.map((e) => PostListView(category: e.id))
])));
]));
}
}