diff --git a/lib/screens/explore.dart b/lib/screens/explore.dart index a25fedd..52f5be6 100644 --- a/lib/screens/explore.dart +++ b/lib/screens/explore.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; @@ -87,28 +88,70 @@ class _ExploreScreenState extends State final scrollProgress = (scrollOffset / colorChangeOffset).clamp(0.0, 1.0); - final backgroundColor = Color.lerp( - Theme.of(context) - .colorScheme - .surfaceContainerLow - .withOpacity(0), - Theme.of(context) - .colorScheme - .surfaceContainerLow - .withOpacity(0.9), - scrollProgress, - ); + final blurSigma = lerpDouble(0, 10, scrollProgress) ?? 0; return SliverAppBar( - backgroundColor: backgroundColor, - flexibleSpace: SizedBox( - height: 48, - child: const Row( - children: [ - RealmSwitcher(), - ], - ).paddingSymmetric(horizontal: 8), - ).paddingOnly(top: MediaQuery.of(context).padding.top), + flexibleSpace: ClipRRect( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: blurSigma, + sigmaY: blurSigma, + ), + child: ListView( + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), + children: [ + SizedBox( + height: 48, + child: const Row( + children: [ + RealmSwitcher(), + ], + ).paddingSymmetric(horizontal: 8), + ), + TabBar( + controller: _tabController, + dividerHeight: 0.3, + tabAlignment: TabAlignment.fill, + tabs: [ + Tab( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.feed, size: 20), + const Gap(8), + Text('postListNews'.tr), + ], + ), + ), + Tab( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.people, size: 20), + const Gap(8), + Text('postListFriends'.tr), + ], + ), + ), + Tab( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.shuffle_on_outlined, + size: 20), + const Gap(8), + Text('postListShuffle'.tr), + ], + ), + ), + ], + ), + ], + ).paddingOnly(top: MediaQuery.of(context).padding.top), + ), + ), + expandedHeight: 96, snap: true, floating: true, toolbarHeight: AppTheme.toolbarHeight(context), @@ -120,43 +163,6 @@ class _ExploreScreenState extends State width: AppTheme.isLargeScreen(context) ? 8 : 16, ), ], - bottom: TabBar( - controller: _tabController, - dividerHeight: 0.3, - tabAlignment: TabAlignment.fill, - tabs: [ - Tab( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.feed, size: 20), - const Gap(8), - Text('postListNews'.tr), - ], - ), - ), - Tab( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.people, size: 20), - const Gap(8), - Text('postListFriends'.tr), - ], - ), - ), - Tab( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.shuffle_on_outlined, size: 20), - const Gap(8), - Text('postListShuffle'.tr), - ], - ), - ), - ], - ), ); }, ) @@ -180,6 +186,12 @@ class _ExploreScreenState extends State onRefresh: () => _postController.reloadAllOver(), child: CustomScrollView(slivers: [ ControlledPostListWidget( + padding: AppTheme.isLargeScreen(context) + ? EdgeInsets.symmetric( + horizontal: 4, + vertical: 8, + ) + : EdgeInsets.zero, controller: _postController.pagingController, onUpdate: () => _postController.reloadAllOver(), ), @@ -191,6 +203,9 @@ class _ExploreScreenState extends State onRefresh: () => _postController.reloadAllOver(), child: CustomScrollView(slivers: [ ControlledPostListWidget( + padding: AppTheme.isLargeScreen(context) + ? EdgeInsets.symmetric(horizontal: 16) + : EdgeInsets.zero, controller: _postController.pagingController, onUpdate: () => _postController.reloadAllOver(), ), diff --git a/lib/screens/posts/post_detail.dart b/lib/screens/posts/post_detail.dart index ba7d70a..9b6fc09 100644 --- a/lib/screens/posts/post_detail.dart +++ b/lib/screens/posts/post_detail.dart @@ -4,6 +4,7 @@ import 'package:solian/exts.dart'; import 'package:solian/models/post.dart'; import 'package:solian/providers/content/posts.dart'; import 'package:solian/providers/last_read.dart'; +import 'package:solian/theme.dart'; import 'package:solian/widgets/posts/post_item.dart'; import 'package:solian/widgets/posts/post_replies.dart'; @@ -67,11 +68,18 @@ class _PostDetailScreenState extends State { isFullContent: true, isShowReply: false, isContentSelectable: true, + padding: AppTheme.isLargeScreen(context) + ? EdgeInsets.symmetric( + horizontal: 4, + vertical: 8, + ) + : EdgeInsets.zero, ), ), SliverToBoxAdapter( - child: - const Divider(thickness: 0.3, height: 1).paddingOnly(top: 4), + child: const Divider(thickness: 0.3, height: 1).paddingOnly( + top: 8, + ), ), SliverToBoxAdapter( child: Align( @@ -82,7 +90,15 @@ class _PostDetailScreenState extends State { ).paddingOnly(left: 24, right: 24, top: 16), ), ), - PostReplyList(item: item!), + PostReplyList( + item: item!, + padding: AppTheme.isLargeScreen(context) + ? EdgeInsets.symmetric( + horizontal: 4, + vertical: 8, + ) + : EdgeInsets.zero, + ), SliverToBoxAdapter( child: SizedBox(height: MediaQuery.of(context).padding.bottom), ), diff --git a/lib/widgets/account/account_profile_popup.dart b/lib/widgets/account/account_profile_popup.dart index fab114d..c69f5d2 100644 --- a/lib/widgets/account/account_profile_popup.dart +++ b/lib/widgets/account/account_profile_popup.dart @@ -89,8 +89,7 @@ class _AccountProfilePopupState extends State { return SizedBox( height: MediaQuery.of(context).size.height * 0.75, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: ListView( children: [ AccountHeadingWidget( avatar: _userinfo!.avatar, diff --git a/lib/widgets/attachments/attachment_item.dart b/lib/widgets/attachments/attachment_item.dart index 9c76d43..c4c217b 100644 --- a/lib/widgets/attachments/attachment_item.dart +++ b/lib/widgets/attachments/attachment_item.dart @@ -155,11 +155,18 @@ class _AttachmentItemImage extends StatelessWidget { ), if (showBadge && badge != null) Positioned( - right: 12, - bottom: 8, + right: 8, + bottom: 4, child: Material( color: Colors.transparent, - child: Chip(label: Text(badge!)), + child: Chip( + label: Text(badge!), + labelStyle: GoogleFonts.robotoMono(), + visualDensity: const VisualDensity( + horizontal: -4, + vertical: -2, + ), + ), ), ), if (showHideButton && item.isMature) diff --git a/lib/widgets/attachments/attachment_list.dart b/lib/widgets/attachments/attachment_list.dart index 37bb01c..40c1d79 100644 --- a/lib/widgets/attachments/attachment_list.dart +++ b/lib/widgets/attachments/attachment_list.dart @@ -1,7 +1,6 @@ import 'dart:math' as math; import 'dart:ui'; -import 'package:carousel_slider/carousel_slider.dart'; import 'package:dismissible_page/dismissible_page.dart'; import 'package:flutter/material.dart' hide CarouselController; import 'package:flutter_animate/flutter_animate.dart'; @@ -23,6 +22,7 @@ class AttachmentList extends StatefulWidget { final bool autoload; final double columnMaxWidth; + final EdgeInsets? padding; final double? width; final double? viewport; @@ -36,6 +36,7 @@ class AttachmentList extends StatefulWidget { this.isFullWidth = false, this.autoload = false, this.columnMaxWidth = 480, + this.padding, this.width, this.viewport, }); @@ -161,9 +162,7 @@ class _AttachmentListState extends State { color: _unFocusColor, ).paddingOnly(right: 5), Text( - 'attachmentHint'.trParams( - {'count': _attachments.toString()}, - ), + 'attachmentHint'.trParams({'count': _attachments.toString()}), style: TextStyle(color: _unFocusColor, fontSize: 12), ) ], @@ -179,8 +178,8 @@ class _AttachmentListState extends State { final element = _attachments.first; double ratio = element!.metadata?['ratio']?.toDouble() ?? 16 / 9; return Container( + width: MediaQuery.of(context).size.width, constraints: BoxConstraints( - maxWidth: widget.columnMaxWidth, maxHeight: 640, ), child: AspectRatio( @@ -271,26 +270,26 @@ class _AttachmentListState extends State { ); } - return SizedBox( - width: math.min(MediaQuery.of(context).size.width, widget.columnMaxWidth), - child: CarouselSlider.builder( - options: CarouselOptions( - disableCenter: true, - animateToClosest: true, - aspectRatio: _aspectRatio, - enlargeCenterPage: true, - viewportFraction: widget.viewport ?? 0.95, - enableInfiniteScroll: false, - ), + return Container( + constraints: BoxConstraints( + maxHeight: 320, + ), + child: ListView.separated( + padding: widget.padding, + scrollDirection: Axis.horizontal, + shrinkWrap: true, itemCount: _attachments.length, - itemBuilder: (context, idx, _) { + itemBuilder: (context, idx) { final element = _attachments[idx]; if (element == null) const SizedBox.shrink(); - double ratio = element!.metadata?['ratio']?.toDouble() ?? 16 / 9; + final ratio = element!.metadata?['ratio']?.toDouble() ?? 16 / 9; return Container( constraints: BoxConstraints( - maxWidth: widget.columnMaxWidth, - maxHeight: 640, + maxWidth: math.min( + widget.columnMaxWidth, + MediaQuery.of(context).size.width - + (widget.padding?.horizontal ?? 0), + ), ), child: AspectRatio( aspectRatio: ratio, @@ -310,6 +309,7 @@ class _AttachmentListState extends State { ), ); }, + separatorBuilder: (context, _) => const Gap(8), ), ); } diff --git a/lib/widgets/link_expansion.dart b/lib/widgets/link_expansion.dart index ec4ab21..6203161 100644 --- a/lib/widgets/link_expansion.dart +++ b/lib/widgets/link_expansion.dart @@ -2,15 +2,21 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_svg/svg.dart'; import 'package:get/get.dart'; +import 'package:solian/models/link.dart'; import 'package:solian/providers/link_expander.dart'; import 'package:solian/widgets/auto_cache_image.dart'; import 'package:url_launcher/url_launcher_string.dart'; -class LinkExpansion extends StatelessWidget { +class LinkExpansion extends StatefulWidget { final String content; const LinkExpansion({super.key, required this.content}); + @override + State createState() => _LinkExpansionState(); +} + +class _LinkExpansionState extends State { Widget _buildImage(String url, {double? width, double? height}) { if (url.endsWith('svg')) { return SvgPicture.network(url, width: width, height: height); @@ -22,61 +28,74 @@ class LinkExpansion extends StatelessWidget { ); } - @override - Widget build(BuildContext context) { + List? _meta; + + Future _doExpand() async { final linkRegex = RegExp( r'(? out = List.empty(growable: true); + for (final x in matches) { + final result = await expandController.expandLink(x.group(0)!); + if (result != null) out.add(result); + } + + setState(() => _meta = out); + } + + @override + void initState() { + super.initState(); + _doExpand(); + } + + @override + Widget build(BuildContext context) { + if (_meta?.isEmpty ?? true) return const SizedBox.shrink(); + return Wrap( - children: matches.map((x) { + children: _meta!.map((x) { return Container( constraints: BoxConstraints( - maxWidth: matches.length == 1 ? 480 : 340, + maxWidth: _meta!.length == 1 ? 480 : 340, ), - child: FutureBuilder( - future: expandController.expandLink(x.group(0)!), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const SizedBox.shrink(); - } - + child: Builder( + builder: (context) { final isRichDescription = [ 'solsynth.dev', - ].contains(Uri.parse(snapshot.data!.url).host); + ].contains(Uri.parse(x.url).host); return GestureDetector( child: Card( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if ([ - (snapshot.data!.icon?.isNotEmpty ?? false), - snapshot.data!.siteName != null - ].any((x) => x)) + if ([(x.icon?.isNotEmpty ?? false), x.siteName != null] + .any((x) => x)) Row( children: [ - if (snapshot.data!.icon?.isNotEmpty ?? false) + if (x.icon?.isNotEmpty ?? false) ClipRRect( borderRadius: const BorderRadius.all( Radius.circular(8), ), child: _buildImage( - snapshot.data!.icon!, + x.icon!, width: 32, height: 32, ), ).paddingOnly(right: 8), - if (snapshot.data!.siteName != null) + if (x.siteName != null) Expanded( child: Text( - snapshot.data!.siteName!, + x.siteName!, style: Theme.of(context).textTheme.labelLarge, maxLines: 1, overflow: TextOverflow.ellipsis, @@ -84,32 +103,27 @@ class LinkExpansion extends StatelessWidget { ), ], ).paddingOnly( - bottom: (snapshot.data!.icon?.isNotEmpty ?? false) - ? 8 - : 4, + bottom: (x.icon?.isNotEmpty ?? false) ? 8 : 4, ), - if (snapshot.data!.image != null && - (snapshot.data!.image?.startsWith('http') ?? false)) + if (x.image != null && + (x.image?.startsWith('http') ?? false)) ClipRRect( borderRadius: const BorderRadius.all( Radius.circular(8), ), - child: _buildImage( - snapshot.data!.image!, - ), + child: _buildImage(x.image!), ).paddingOnly(bottom: 8), Text( - snapshot.data!.title ?? 'No Title', + x.title ?? 'No Title', maxLines: 1, overflow: TextOverflow.fade, style: Theme.of(context).textTheme.bodyLarge, ), - if (snapshot.data!.description != null && - isRichDescription) - MarkdownBody(data: snapshot.data!.description!) - else if (snapshot.data!.description != null) + if (x.description != null && isRichDescription) + MarkdownBody(data: x.description!) + else if (x.description != null) Text( - snapshot.data!.description!, + x.description!, maxLines: 3, overflow: TextOverflow.ellipsis, ), @@ -117,7 +131,7 @@ class LinkExpansion extends StatelessWidget { ).paddingAll(12), ), onTap: () { - launchUrlString(x.group(0)!); + launchUrlString(x.url); }, ); }, diff --git a/lib/widgets/posts/post_item.dart b/lib/widgets/posts/post_item.dart index 4bc231c..8267864 100644 --- a/lib/widgets/posts/post_item.dart +++ b/lib/widgets/posts/post_item.dart @@ -8,6 +8,7 @@ import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:solian/models/post.dart'; import 'package:solian/providers/content/posts.dart'; +import 'package:solian/router.dart'; import 'package:solian/screens/posts/post_detail.dart'; import 'package:solian/shells/title_shell.dart'; import 'package:solian/theme.dart'; @@ -34,7 +35,10 @@ class PostItem extends StatefulWidget { final bool isContentSelectable; final bool showFeaturedReply; final String? attachmentParent; + + final EdgeInsets? padding; final Color? backgroundColor; + final Function? onComment; const PostItem({ @@ -51,6 +55,7 @@ class PostItem extends StatefulWidget { this.isContentSelectable = false, this.showFeaturedReply = false, this.attachmentParent, + this.padding, this.backgroundColor, this.onComment, }); @@ -126,9 +131,7 @@ class _PostItemState extends State { LinkExpansion(content: item.body['content']).paddingOnly( left: 8, right: 8, - top: 4, ), - _PostFooterWidget(item: item).paddingOnly(left: 12), if (attachments.isNotEmpty) Row( children: [ @@ -149,9 +152,8 @@ class _PostItemState extends State { ); } - return OpenContainer( - tappable: widget.isClickable, - closedBuilder: (_, openContainer) => Column( + return GestureDetector( + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _PostThumbnail( @@ -220,18 +222,20 @@ class _PostItemState extends State { ), ), _PostFooterWidget(item: item), - LinkExpansion(content: item.body['content']).paddingOnly(top: 4), + LinkExpansion(content: item.body['content']), ], - ).paddingOnly( - right: 16, - left: 16, + ).paddingSymmetric( + horizontal: (widget.padding?.horizontal ?? 0) + 16, + ), + if (hasAttachment) const Gap(8), + _PostAttachmentWidget( + item: item, + padding: widget.padding, ), - _PostAttachmentWidget(item: item), if (widget.showFeaturedReply) _PostFeaturedReplyWidget(item: item).paddingSymmetric( - horizontal: 12, + horizontal: (widget.padding?.horizontal ?? 0) + 12, ), - if (widget.showFeaturedReply) const Gap(8), if (widget.isShowReply || widget.isReactable) PostQuickAction( isShowReply: widget.isShowReply, @@ -249,22 +253,23 @@ class _PostItemState extends State { } }, ).paddingOnly( - left: 14, - right: 14, + top: 8, + left: (widget.padding?.left ?? 0) + 14, + right: (widget.padding?.right ?? 0) + 14, ) ], + ).paddingOnly( + top: widget.padding?.top ?? 0, + bottom: widget.padding?.bottom ?? 0, ), - openBuilder: (_, __) => TitleShell( - title: 'postDetail'.tr, - child: PostDetailScreen( - id: item.id.toString(), - post: item, - ), - ), - closedElevation: 0, - openElevation: 0, - closedColor: Colors.transparent, - openColor: Theme.of(context).colorScheme.surface, + onTap: () { + if (widget.isClickable) { + AppRouter.instance.pushNamed( + 'postDetail', + pathParameters: {'id': item.id.toString()}, + ); + } + }, ); } } @@ -293,6 +298,7 @@ class _PostFeaturedReplyWidget extends StatelessWidget { } return Container( + padding: EdgeInsets.only(top: 8), constraints: const BoxConstraints(maxWidth: 480), child: Card( margin: EdgeInsets.zero, @@ -389,8 +395,9 @@ class _PostFeaturedReplyWidget extends StatelessWidget { class _PostAttachmentWidget extends StatelessWidget { final Post item; + final EdgeInsets? padding; - const _PostAttachmentWidget({required this.item}); + const _PostAttachmentWidget({required this.item, required this.padding}); @override Widget build(BuildContext context) { @@ -402,14 +409,22 @@ class _PostAttachmentWidget extends StatelessWidget { if (attachments.isEmpty) return const SizedBox.shrink(); - if (attachments.length == 1) { + if (attachments.length == 1 && !isLargeScreen) { return AttachmentList( parentId: item.id.toString(), attachmentIds: item.preload == null ? attachments : null, attachments: item.preload?.attachments, autoload: false, isFullWidth: true, - ).paddingOnly(top: 4); + ); + } else if (attachments.length == 1) { + return AttachmentList( + parentId: item.id.toString(), + attachmentIds: item.preload == null ? attachments : null, + attachments: item.preload?.attachments, + autoload: false, + isColumn: true, + ).paddingSymmetric(horizontal: (padding?.horizontal ?? 0) + 14); } else if (attachments.length > 1 && attachments.length % 3 == 0 && !isLargeScreen) { @@ -419,14 +434,17 @@ class _PostAttachmentWidget extends StatelessWidget { attachments: item.preload?.attachments, autoload: false, isGrid: true, - ).paddingSymmetric(horizontal: 14, vertical: 8); + ).paddingSymmetric(horizontal: (padding?.horizontal ?? 0) + 14); } else { return AttachmentList( parentId: item.id.toString(), attachmentIds: item.preload == null ? attachments : null, attachments: item.preload?.attachments, + padding: EdgeInsets.symmetric( + horizontal: (padding?.horizontal ?? 0) + 14, + ), autoload: false, - ).paddingOnly(bottom: 8, top: 4); + ); } } } @@ -568,7 +586,7 @@ class _PostFooterWidget extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: widgets, - ).paddingOnly(top: 4); + ).paddingSymmetric(vertical: 4); } } } diff --git a/lib/widgets/posts/post_list.dart b/lib/widgets/posts/post_list.dart index 70d8159..d9fe325 100644 --- a/lib/widgets/posts/post_list.dart +++ b/lib/widgets/posts/post_list.dart @@ -60,8 +60,9 @@ class PostListEntryWidget extends StatelessWidget { final bool isClickable; final bool showFeaturedReply; final Post item; - final Function onUpdate; final Color? backgroundColor; + final EdgeInsets? padding; + final Function onUpdate; const PostListEntryWidget({ super.key, @@ -70,8 +71,9 @@ class PostListEntryWidget extends StatelessWidget { required this.isClickable, required this.showFeaturedReply, required this.item, - required this.onUpdate, this.backgroundColor, + this.padding, + required this.onUpdate, }); @override @@ -83,6 +85,7 @@ class PostListEntryWidget extends StatelessWidget { isShowEmbed: isShowEmbed, isClickable: isNestedClickable, showFeaturedReply: showFeaturedReply, + padding: padding, backgroundColor: backgroundColor, onComment: () { AppRouter.instance @@ -129,6 +132,7 @@ class ControlledPostListWidget extends StatelessWidget { final bool isNestedClickable; final bool isPinned; final PagingController controller; + final EdgeInsets? padding; final Function? onUpdate; const ControlledPostListWidget({ @@ -138,6 +142,7 @@ class ControlledPostListWidget extends StatelessWidget { this.isClickable = true, this.isNestedClickable = true, this.isPinned = true, + this.padding, this.onUpdate, }); @@ -156,6 +161,7 @@ class ControlledPostListWidget extends StatelessWidget { isNestedClickable: isNestedClickable, isClickable: isClickable, showFeaturedReply: true, + padding: padding, item: item, onUpdate: onUpdate ?? () {}, ); diff --git a/lib/widgets/posts/post_replies.dart b/lib/widgets/posts/post_replies.dart index fdca4f5..024278a 100644 --- a/lib/widgets/posts/post_replies.dart +++ b/lib/widgets/posts/post_replies.dart @@ -8,11 +8,13 @@ import 'package:solian/widgets/posts/post_list.dart'; class PostReplyList extends StatefulWidget { final Post item; + final EdgeInsets? padding; final Color? backgroundColor; const PostReplyList({ super.key, required this.item, + this.padding, this.backgroundColor, }); @@ -53,7 +55,7 @@ class _PostReplyListState extends State { @override Widget build(BuildContext context) { return PostListWidget( - padding: EdgeInsets.symmetric(horizontal: 10), + padding: widget.padding, isShowEmbed: false, controller: _pagingController, backgroundColor: widget.backgroundColor, @@ -93,6 +95,7 @@ class PostReplyListPopup extends StatelessWidget { slivers: [ PostReplyList( item: item, + padding: EdgeInsets.symmetric(horizontal: 10), backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, ), diff --git a/pubspec.lock b/pubspec.lock index 487e503..6153eea 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -198,14 +198,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" - carousel_slider: - dependency: "direct main" - description: - name: carousel_slider - sha256: "7b006ec356205054af5beaef62e2221160ea36b90fb70a35e4deacd49d0349ae" - url: "https://pub.dev" - source: hosted - version: "5.0.0" characters: dependency: transitive description: @@ -2278,10 +2270,10 @@ packages: dependency: transitive description: name: win32 - sha256: "4d45dc9069dba4619dc0ebd93c7cec5e66d8482cb625a370ac806dcc8165f2ec" + sha256: e5c39a90447e7c81cfec14b041cdbd0d0916bd9ebbc7fe02ab69568be703b9bd url: "https://pub.dev" source: hosted - version: "5.5.5" + version: "5.6.0" win32_registry: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e1dc24e..7bd0352 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,7 +18,6 @@ dependencies: flutter_markdown: ^0.7.1 flutter_animate: ^4.5.0 flutter_secure_storage: ^9.2.1 - carousel_slider: ^5.0.0 url_launcher: ^6.2.6 infinite_scroll_pagination: ^4.0.0 image_picker: ^1.1.1