diff --git a/lib/widgets/feed.dart b/lib/widgets/feed.dart index fc524f2..3fbdee0 100644 --- a/lib/widgets/feed.dart +++ b/lib/widgets/feed.dart @@ -1,19 +1,26 @@ import 'package:flutter/material.dart'; +import 'package:flutter_carousel_widget/flutter_carousel_widget.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:solaragent/models/feed.dart'; +import 'package:solaragent/widgets/image.dart'; class FeedItem extends StatelessWidget { final Feed item; const FeedItem({super.key, required this.item}); + bool hasAttachments() => + item.attachments != null && item.attachments!.isNotEmpty; + String getDescription(String desc) => desc.isEmpty ? "No description yet." : desc; + String getFileUrl(String fileId) => + 'https://co.solsynth.dev/api/attachments/o/$fileId'; + @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.symmetric(horizontal: 10), child: Column( children: [ Container( @@ -36,6 +43,45 @@ class FeedItem extends StatelessWidget { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), ), + hasAttachments() + ? Container( + decoration: const BoxDecoration( + border: Border( + top: BorderSide(width: 0.3, color: Color(0xffdedede))), + ), + child: FlutterCarousel( + options: CarouselOptions( + height: 240.0, + showIndicator: true, + slideIndicator: const CircularSlideIndicator(), + ), + items: item.attachments?.map((x) { + return Builder( + builder: (BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + margin: const EdgeInsets.symmetric(horizontal: 5.0), + child: InkWell( + child: Image.network( + getFileUrl(x.fileId), + fit: BoxFit.cover, + ), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (_) { + return ImageLightbox( + url: getFileUrl(x.fileId), + ); + })); + }, + ), + ); + }, + ); + }).toList(), + ), + ) + : Container(), ], ), ); diff --git a/lib/widgets/image.dart b/lib/widgets/image.dart new file mode 100644 index 0000000..b4dace4 --- /dev/null +++ b/lib/widgets/image.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class ImageLightbox extends StatelessWidget { + final String url; + + const ImageLightbox({super.key, required this.url}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: GestureDetector( + child: Center( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: InteractiveViewer( + boundaryMargin: const EdgeInsets.all(128), + minScale: 0.1, + maxScale: 16.0, + child: Image.network(url, fit: BoxFit.contain), + ), + ), + ), + onTap: () { + Navigator.pop(context); + }, + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 16633c1..6436066 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -126,6 +126,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_carousel_widget: + dependency: "direct main" + description: + name: flutter_carousel_widget + sha256: "37b9e55e4cafffe358152b016db24153e756152aa07c4214cfe6ee902cd69a01" + url: "https://pub.dev" + source: hosted + version: "2.2.0" flutter_launcher_icons: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index d8653d8..2e7b432 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,6 +45,7 @@ dependencies: shared_preferences: ^2.2.2 flutter_markdown: ^0.6.22 infinite_scroll_pagination: ^4.0.0 + flutter_carousel_widget: ^2.2.0 dev_dependencies: flutter_test: