diff --git a/lib/assets/icons/archive-tick.svg b/lib/assets/icons/archive-tick.svg
new file mode 100644
index 0000000..d1c6c07
--- /dev/null
+++ b/lib/assets/icons/archive-tick.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/assets/icons/arrow-right.svg b/lib/assets/icons/arrow-right.svg
new file mode 100644
index 0000000..1aec4ea
--- /dev/null
+++ b/lib/assets/icons/arrow-right.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/assets/icons/bookmark_fill.svg b/lib/assets/icons/bookmark_fill.svg
new file mode 100644
index 0000000..6a55ac7
--- /dev/null
+++ b/lib/assets/icons/bookmark_fill.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/assets/icons/element-plus.svg b/lib/assets/icons/element-plus.svg
new file mode 100644
index 0000000..db4b982
--- /dev/null
+++ b/lib/assets/icons/element-plus.svg
@@ -0,0 +1,7 @@
+
diff --git a/lib/assets/icons/heart.svg b/lib/assets/icons/heart.svg
new file mode 100644
index 0000000..2dd9197
--- /dev/null
+++ b/lib/assets/icons/heart.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/assets/icons/heart_fill.svg b/lib/assets/icons/heart_fill.svg
new file mode 100644
index 0000000..f2eb26f
--- /dev/null
+++ b/lib/assets/icons/heart_fill.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/assets/icons/more_loading.svg b/lib/assets/icons/more_loading.svg
new file mode 100644
index 0000000..bbeba8a
--- /dev/null
+++ b/lib/assets/icons/more_loading.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/assets/icons/send-2.svg b/lib/assets/icons/send-2.svg
new file mode 100644
index 0000000..45b3808
--- /dev/null
+++ b/lib/assets/icons/send-2.svg
@@ -0,0 +1,4 @@
+
diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart
index 604a8ee..48d8780 100644
--- a/lib/services/network/request_helper.dart
+++ b/lib/services/network/request_helper.dart
@@ -205,8 +205,8 @@ class RequestHelper {
static String deleteComment(int id) => '$baseUrl/comment/$id';
static String reportComment(int id) => '$baseUrl/comment/$id/report';
static String widgetNews() => '$baseUrl/user/widget';
- static String aiChats() => '$baseUrl/ai/chat/v2';
- static String aiArchived() => '$baseUrl/ai/chat/v2${_urlConcatGenerator([
+ static String aiChats() => '$baseUrl/ai/aichat';
+ static String aiArchived() => '$baseUrl/ai/aichat${_urlConcatGenerator([
const MapEntry('archived', true),
])}';
static String aiBots() => '$baseUrl/ai/bot/v2';
diff --git a/lib/views/home/main/widgets/infography_item.dart b/lib/views/home/main/widgets/infography_item.dart
index 027e757..bb6ef96 100644
--- a/lib/views/home/main/widgets/infography_item.dart
+++ b/lib/views/home/main/widgets/infography_item.dart
@@ -8,14 +8,13 @@ import 'package:didvan/routes/routes.dart';
import 'package:didvan/views/widgets/animated_visibility.dart';
import 'package:didvan/views/widgets/bookmark_button.dart';
import 'package:didvan/views/widgets/didvan/card.dart';
-import 'package:didvan/views/widgets/didvan/divider.dart';
-import 'package:didvan/views/widgets/didvan/icon_button.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/infography_tag.dart';
import 'package:didvan/views/widgets/ink_wrapper.dart';
import 'package:didvan/views/widgets/liked_button.dart';
import 'package:didvan/views/widgets/skeleton_image.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
class _BackButton extends StatefulWidget {
const _BackButton({Key? key}) : super(key: key);
@@ -117,77 +116,106 @@ class InfographyItem extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
),
+ const SizedBox(
+ height: 10,
+ ),
Padding(
- padding: const EdgeInsets.symmetric(vertical: 8.0),
+ padding: const EdgeInsets.symmetric(vertical: 0.0),
child: GestureDetector(
onTap: () => _openInteractiveViewer(context, image),
child: SkeletonImage(
- imageUrl: image,
- aspectRatio: 16 / 9,
- ),
+ imageUrl: image,
+ aspectRatio: 16 / 9,
+ borderRadius: const BorderRadius.only(
+ bottomLeft: Radius.circular(0.0),
+ bottomRight: Radius.circular(0.0),
+ topLeft: Radius.circular(13.0),
+ topRight: Radius.circular(13.0),
+ )),
),
),
+ Container(
+ decoration: const BoxDecoration(
+ color: Color.fromARGB(255, 0, 69, 92),
+ borderRadius: BorderRadius.only(
+ bottomRight: Radius.circular(13.0),
+ bottomLeft: Radius.circular(13.0)),
+ ),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ InfoCat(
+ category: category,
+ createdAt: createdAt,
+ ),
+ Row(
+ children: [
+ GestureDetector(
+ onTap: () => Navigator.of(context).pushNamed(
+ Routes.mentions,
+ arguments: {
+ 'id': id,
+ 'type': 'banner',
+ 'title': title,
+ },
+ ),
+ child: SvgPicture.asset(
+ 'lib/assets/icons/send-2.svg',
+ width: 25,
+ height: 25,
+ colorFilter: const ColorFilter.mode(
+ Colors.white,
+ BlendMode.srcIn,
+ ),
+ ),
+ ),
+ BookmarkButton(
+ itemId: id,
+ type: 'infography',
+ gestureSize: 22,
+ value: marked,
+ onMarkChanged: (value) => onMarkChanged(id, value, true),
+ svgIconOn: 'lib/assets/icons/bookmark_fill.svg',
+ svgIconOff: 'lib/assets/icons/archive-tick.svg',
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 8),
+ child: LikedButton(
+ itemId: id,
+ type: 'infography',
+ gestureSize: 32,
+ value: liked,
+ onMarkChanged: (value) => onLikedChanged(id, value, true),
+ likes: likes,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(
+ height: 10,
+ ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- Wrap(
- spacing: 4,
- runSpacing: 4,
- children: [
- for (var i = 0; i < tag.length; i++)
- InfographyTag(
- tag: tag[i],
- onMarkChanged: onMarkChanged,
- ),
- ],
+ Expanded(
+ child: Wrap(
+ spacing: 4,
+ runSpacing: 4,
+ children: [
+ for (var i = 0; i < tag.length; i++)
+ InfographyTag(
+ tag: tag[i],
+ onMarkChanged: onMarkChanged,
+ ),
+ ],
+ ),
),
],
),
- const DidvanDivider(),
- Row(
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- InfoCat(
- category: category,
- createdAt: createdAt,
- ),
- Row(
- children: [
- LikedButton(
- itemId: id,
- type: 'infography',
- gestureSize: 32,
- value: liked,
- onMarkChanged: (value) => onLikedChanged(id, value, true),
- likes: likes,
- ),
- const SizedBox(
- width: 4.0,
- ),
- DidvanIconButton(
- gestureSize: 32,
- onPressed: () => Navigator.of(context).pushNamed(
- Routes.mentions,
- arguments: {
- 'id': id,
- 'type': 'banner',
- 'title': title,
- },
- ),
- icon: DidvanIcons.mention_icon,
- ),
- BookmarkButton(
- itemId: id,
- type: 'infography',
- gestureSize: 32,
- value: marked,
- onMarkChanged: (value) => onMarkChanged(id, value, true),
- ),
- ],
- ),
- ],
- )
],
),
);
diff --git a/lib/views/home/media/media_page.dart b/lib/views/home/media/media_page.dart
index 4aff354..eaa5879 100644
--- a/lib/views/home/media/media_page.dart
+++ b/lib/views/home/media/media_page.dart
@@ -1,12 +1,13 @@
import 'package:didvan/views/home/media/podcast_tab_page.dart';
import 'package:didvan/views/home/media/videocast_tab_page.dart';
-import 'package:didvan/views/widgets/didvan/text.dart';
-import 'package:didvan/views/home/main/widgets/banner.dart';
+import 'package:didvan/views/home/media/widgets/media_banner_with_thumbnails.dart';
+import 'package:didvan/views/home/media/widgets/banner_grid_view.dart';
import 'package:didvan/views/widgets/home_app_bar.dart';
import 'package:didvan/views/widgets/custom_media_tab_bar.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:didvan/views/podcasts/podcasts_state.dart';
+import 'package:didvan/views/home/infography/infography_screen_state.dart';
class MediaPage extends StatefulWidget {
const MediaPage({super.key});
@@ -101,25 +102,18 @@ class _MediaPageState extends State {
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 16.0, vertical: 16.0),
- child: MainPageBanner(isFirst: true),
+ child: MediaBannerWithThumbnails(isFirst: true),
),
),
- Center(
- key: const ValueKey('InfographyPage'),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(
- Icons.photo_library,
- size: 48,
- color: Theme.of(context).colorScheme.primary,
- ),
- const SizedBox(height: 8),
- DidvanText(
- 'صفحه اینفوگرافی',
- style: Theme.of(context).textTheme.titleSmall,
- ),
- ],
+ ChangeNotifierProvider(
+ create: (_) => InfographyScreenState(),
+ child: const SingleChildScrollView(
+ key: ValueKey('InfographyPage'),
+ child: Padding(
+ padding: EdgeInsets.symmetric(
+ horizontal: 8.0, vertical: 16.0),
+ child: BannerGridView(),
+ ),
),
),
],
diff --git a/lib/views/home/media/widgets/banner_grid_view.dart b/lib/views/home/media/widgets/banner_grid_view.dart
new file mode 100644
index 0000000..4ca1a2a
--- /dev/null
+++ b/lib/views/home/media/widgets/banner_grid_view.dart
@@ -0,0 +1,264 @@
+import 'package:didvan/views/home/infography/infography_screen_state.dart';
+import 'package:didvan/views/home/main/widgets/infography_item.dart';
+import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
+import 'package:didvan/views/widgets/shimmer_placeholder.dart';
+import 'package:didvan/views/widgets/didvan/card.dart';
+import 'package:didvan/views/widgets/didvan/divider.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:provider/provider.dart';
+
+class BannerGridView extends StatefulWidget {
+ const BannerGridView({super.key});
+
+ @override
+ State createState() => _BannerGridViewState();
+}
+
+class _BannerGridViewState extends State {
+ int _visibleItemCount = 4;
+ final ScrollController _scrollController = ScrollController();
+ int pageNumber = 1;
+
+ @override
+ void initState() {
+ super.initState();
+ Future.microtask(() {
+ context.read().init();
+ });
+ }
+
+ @override
+ void dispose() {
+ _scrollController.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Consumer(
+ builder: (context, state, child) {
+ return StateHandler(
+ placeholder: Column(
+ children: [
+ _buildPlaceholder(),
+ const SizedBox(height: 8.0),
+ _buildPlaceholder(),
+ ],
+ ),
+ topPadding: 0,
+ onRetry: () => state.init(),
+ state: state,
+ builder: (context, state) {
+ final contents = state.contents;
+
+ final itemsToShow = _visibleItemCount > contents.length
+ ? contents.length
+ : _visibleItemCount;
+
+ final hasMoreItems = itemsToShow < contents.length;
+
+ return Column(
+ children: [
+ _buildCategoryFilters(state),
+
+ const SizedBox(height: 16),
+
+ ListView.separated(
+ shrinkWrap: true,
+ physics: const NeverScrollableScrollPhysics(),
+ padding: const EdgeInsets.all(8.0),
+ itemCount: itemsToShow,
+ separatorBuilder: (context, index) =>
+ const SizedBox(height: 8.0),
+ itemBuilder: (context, index) {
+ final item = contents[index];
+ return InfographyItem(
+ id: item.id,
+ onMarkChanged: (id, value, _) =>
+ state.changeMark(id, value),
+ image: item.image,
+ category: item.category,
+ createdAt: item.createdAt,
+ title: item.title,
+ tag: item.tags,
+ marked: item.marked,
+ liked: item.liked,
+ onLikedChanged: (id, value, _) =>
+ state.changeLiked(id, value),
+ likes: item.likes,
+ );
+ },
+ ),
+
+ if (hasMoreItems)
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 16.0),
+ child: GestureDetector(
+ onTap: () {
+ setState(() {
+ _visibleItemCount += 4;
+ });
+ },
+ child: Container(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 50.0,
+ vertical: 12.0,
+ ),
+ decoration: BoxDecoration(
+ color: const Color.fromARGB(255, 0, 126, 167),
+ borderRadius: BorderRadius.circular(15),
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SvgPicture.asset(
+ 'lib/assets/icons/element-plus.svg',
+ ),
+ const SizedBox(width: 8),
+ const Text(
+ 'بارگذاری بیشتر',
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 14,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ );
+ },
+ );
+ }
+
+ Widget _buildCategoryFilters(InfographyScreenState state) {
+ return SingleChildScrollView(
+ scrollDirection: Axis.horizontal,
+ padding: const EdgeInsets.symmetric(horizontal: 8.0),
+ child: Row(
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(left: 8.0),
+ child: FilterChip(
+ label: const Padding(
+ padding: EdgeInsets.all(1.0),
+ child: Text('همه'),
+ ),
+ selected: state.selectedCats.isEmpty,
+ onSelected: (selected) {
+ if (selected) {
+ state.selectedCats.clear();
+ state.getInfographyContent(page: 1);
+ setState(() {
+ _visibleItemCount = 4;
+ });
+ }
+ },
+ selectedColor: const Color.fromARGB(255, 200, 224, 244),
+ backgroundColor: state.selectedCats.isEmpty
+ ? const Color.fromARGB(255, 200, 224, 244)
+ : const Color.fromARGB(255, 224, 224, 224),
+ labelStyle: TextStyle(
+ color: state.selectedCats.isEmpty
+ ? const Color.fromARGB(255, 0, 115, 153)
+ : const Color.fromARGB(255, 102, 102, 102),
+ fontWeight: state.selectedCats.isEmpty
+ ? FontWeight.bold
+ : FontWeight.normal,
+ ),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(24),
+ ),
+ showCheckmark: false,
+ ),
+ ),
+
+ ...state.categories.map((category) {
+ final isSelected = state.selectedCats.contains(category);
+
+ return Padding(
+ padding: const EdgeInsets.only(left: 8.0),
+ child: FilterChip(
+ label: Padding(
+ padding: const EdgeInsets.all(1.0),
+ child: Text(category.label),
+ ),
+ selected: isSelected,
+ onSelected: (selected) {
+ if (selected) {
+ state.selectedCats.add(category);
+ } else {
+ state.selectedCats.remove(category);
+ }
+ state.getInfographyContent(page: 1);
+ setState(() {
+ _visibleItemCount = 4;
+ });
+ },
+ selectedColor: const Color.fromARGB(255, 200, 224, 244),
+ backgroundColor: isSelected
+ ? const Color.fromARGB(255, 200, 224, 244)
+ : const Color.fromARGB(255, 224, 224, 224),
+ labelStyle: TextStyle(
+ color: isSelected
+ ? const Color.fromARGB(255, 0, 115, 153)
+ : const Color.fromARGB(255, 102, 102, 102),
+ fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
+ ),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(24),
+ ),
+ showCheckmark: false,
+ ),
+ );
+ }).toList(),
+ ],
+ ),
+ );
+ }
+
+ Widget _buildPlaceholder() {
+ return const DidvanCard(
+ padding: EdgeInsets.all(8),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ShimmerPlaceholder(
+ height: 16,
+ width: 240,
+ ),
+ ],
+ ),
+ SizedBox(height: 12),
+ ShimmerPlaceholder(height: 200, width: 400),
+ SizedBox(height: 12),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ShimmerPlaceholder(
+ height: 32,
+ width: 100,
+ ),
+ ],
+ ),
+ DidvanDivider(
+ verticalPadding: 12,
+ ),
+ ShimmerPlaceholder(
+ height: 16,
+ width: double.infinity,
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/views/home/media/widgets/media_banner_with_thumbnails.dart b/lib/views/home/media/widgets/media_banner_with_thumbnails.dart
new file mode 100644
index 0000000..60ce9f5
--- /dev/null
+++ b/lib/views/home/media/widgets/media_banner_with_thumbnails.dart
@@ -0,0 +1,235 @@
+import 'package:didvan/utils/action_sheet.dart';
+import 'package:didvan/views/home/main/main_page_state.dart';
+import 'package:didvan/views/widgets/skeleton_image.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:provider/provider.dart';
+import 'package:url_launcher/url_launcher_string.dart';
+import 'package:carousel_slider/carousel_slider.dart';
+
+class MediaBannerWithThumbnails extends StatefulWidget {
+ final bool isFirst;
+ const MediaBannerWithThumbnails({super.key, required this.isFirst});
+
+ @override
+ State createState() => _MediaBannerWithThumbnailsState();
+}
+
+class _MediaBannerWithThumbnailsState extends State {
+ int _currentIndex = 0;
+ int _thumbnailStartIndex = 0;
+ final CarouselSliderController _carouselController = CarouselSliderController();
+
+ @override
+ Widget build(BuildContext context) {
+ final state = context.read();
+ final banners = state.content!.banners[widget.isFirst ? 0 : 1];
+
+ return Column(
+ children: [
+ CarouselSlider.builder(
+ carouselController: _carouselController,
+ itemCount: banners.length,
+ itemBuilder: (context, index, realIndex) {
+ final item = banners[index];
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 5),
+ child: GestureDetector(
+ onTap: () => item.link == null || item.link!.isEmpty
+ ? ActionSheetUtils(context)
+ .openInteractiveViewer(context, item.image, false)
+ : launchUrlString(item.link!, mode: LaunchMode.inAppWebView),
+ child: ClipRRect(
+ borderRadius: BorderRadius.circular(16),
+ child: SkeletonImage(
+ imageUrl: item.image,
+ borderRadius: BorderRadius.circular(16),
+ ),
+ ),
+ ),
+ );
+ },
+ options: CarouselOptions(
+ height: (MediaQuery.of(context).size.width - 8) * 9.0 / 16.0,
+ viewportFraction: 1.0,
+ enableInfiniteScroll: true,
+ autoPlay: true,
+ autoPlayInterval: const Duration(seconds: 5),
+ onPageChanged: (index, reason) {
+ setState(() {
+ _currentIndex = index;
+ if (index >= _thumbnailStartIndex + 3) {
+ _thumbnailStartIndex = index - 2;
+ } else if (index < _thumbnailStartIndex) {
+ _thumbnailStartIndex = index;
+ }
+ });
+ },
+ ),
+ ),
+
+ const SizedBox(height: 8),
+
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: banners.asMap().entries.map((entry) {
+ return AnimatedContainer(
+ duration: const Duration(milliseconds: 300),
+ width: _currentIndex == entry.key ? 10 : 5,
+ height: _currentIndex == entry.key ? 10 : 5,
+ margin: const EdgeInsets.symmetric(horizontal: 4),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(300),
+ boxShadow: [
+ BoxShadow(
+ color: _currentIndex == entry.key
+ ? const Color.fromARGB(100, 0, 126, 167)
+ : const Color.fromARGB(0, 0, 0, 0),
+ spreadRadius: 2.5,
+ offset: const Offset(0, 0),
+ ),
+ ],
+ color: _currentIndex == entry.key
+ ? const Color.fromARGB(255, 0, 126, 167)
+ : const Color.fromARGB(255, 200, 200, 200),
+ ),
+ );
+ }).toList(),
+ ),
+
+ const SizedBox(height: 16),
+
+ Row(
+ children: [
+ IconButton(
+ icon: SvgPicture.asset(
+ 'lib/assets/icons/arrow-right.svg',
+ width: 24,
+ height: 24,
+ colorFilter: ColorFilter.mode(
+ _thumbnailStartIndex > 0
+ ? const Color.fromARGB(255, 0, 126, 167)
+ : const Color.fromARGB(255, 200, 200, 200),
+ BlendMode.srcIn,
+ ),
+ ),
+ onPressed: _thumbnailStartIndex > 0
+ ? () {
+ setState(() {
+ _thumbnailStartIndex = (_thumbnailStartIndex - 1).clamp(0, banners.length - 3);
+ });
+ }
+ : null,
+ ),
+
+ Expanded(
+ child: SizedBox(
+ height: 60,
+ width: double.infinity,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: List.generate(3, (index) {
+ if (_thumbnailStartIndex + index >= banners.length) {
+ return const SizedBox(width: 0);
+ }
+
+ final actualIndex = _thumbnailStartIndex + index;
+ final item = banners[actualIndex];
+ final isSelected = actualIndex == _currentIndex;
+
+ return Expanded(
+ child: GestureDetector(
+ onTap: () {
+ if (actualIndex == _currentIndex) return;
+
+ _carouselController.animateToPage(
+ actualIndex,
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.easeInOut,
+ );
+
+ setState(() {
+ _currentIndex = actualIndex;
+
+ if (actualIndex < _thumbnailStartIndex) {
+ _thumbnailStartIndex = actualIndex;
+ } else if (actualIndex >= _thumbnailStartIndex + 3) {
+ _thumbnailStartIndex = (actualIndex - 2).clamp(0, banners.length - 3);
+ }
+ });
+ },
+ child: AnimatedContainer(
+ duration: const Duration(milliseconds: 200),
+ margin: const EdgeInsets.symmetric(horizontal: 4),
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ border: Border.all(
+ color: isSelected
+ ? const Color.fromARGB(255, 0, 126, 167)
+ : Colors.transparent,
+ width: 2,
+ ),
+
+ ),
+ child: ClipRRect(
+ borderRadius: BorderRadius.circular(8),
+ child: AnimatedOpacity(
+ duration: const Duration(milliseconds: 200),
+ opacity: isSelected ? 1.0 : 0.6,
+ child: ColorFiltered(
+ colorFilter: isSelected
+ ? const ColorFilter.mode(
+ Colors.transparent,
+ BlendMode.multiply,
+ )
+ : const ColorFilter.matrix([
+ 0.2126, 0.7152, 0.0722, 0, 0,
+ 0.2126, 0.7152, 0.0722, 0, 0,
+ 0.2126, 0.7152, 0.0722, 0, 0,
+ 0, 0, 0, 1, 0,
+ ]),
+ child: AspectRatio(
+ aspectRatio: 19 / 13,
+ child: SkeletonImage(
+ imageUrl: item.image,
+ borderRadius: BorderRadius.circular(8),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }),
+ ),
+ ),
+ ),
+
+ // فلش چپ (برای رفتن به جلو)
+ IconButton(
+ icon: SvgPicture.asset(
+ 'lib/assets/icons/arrow-left.svg',
+ width: 24,
+ height: 24,
+ colorFilter: ColorFilter.mode(
+ _thumbnailStartIndex < banners.length - 3
+ ? const Color.fromARGB(255, 0, 126, 167)
+ : const Color.fromARGB(255, 200, 200, 200),
+ BlendMode.srcIn,
+ ),
+ ),
+ onPressed: _thumbnailStartIndex < banners.length - 3
+ ? () {
+ setState(() {
+ _thumbnailStartIndex = (_thumbnailStartIndex + 1).clamp(0, banners.length - 3);
+ });
+ }
+ : null,
+ ),
+ ],
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/views/widgets/bookmark_button.dart b/lib/views/widgets/bookmark_button.dart
index 0578174..f671bac 100644
--- a/lib/views/widgets/bookmark_button.dart
+++ b/lib/views/widgets/bookmark_button.dart
@@ -1,4 +1,3 @@
-import 'package:didvan/config/design_config.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/providers/user.dart';
@@ -78,6 +77,9 @@ class _BookmarkButtonState extends State {
Widget build(BuildContext context) {
print("BookmarkButton build - value: $_value");
+ final iconOn = widget.svgIconOn ?? 'lib/assets/icons/bookmark_on.svg';
+ final iconOff = widget.svgIconOff ?? 'lib/assets/icons/bookmark_off.svg';
+
return IconButton(
iconSize: widget.gestureSize,
onPressed: _handleTap,
@@ -87,7 +89,7 @@ class _BookmarkButtonState extends State {
return ScaleTransition(scale: animation, child: child);
},
child: SvgPicture.asset(
- _value ? 'lib/assets/icons/bookmark_on.svg' : 'lib/assets/icons/bookmark_off.svg',
+ _value ? iconOn : iconOff,
key: ValueKey('bookmark_$_value'),
width: widget.gestureSize,
height: widget.gestureSize,
diff --git a/lib/views/widgets/didvan/bnb.dart b/lib/views/widgets/didvan/bnb.dart
index a78c486..d74d584 100644
--- a/lib/views/widgets/didvan/bnb.dart
+++ b/lib/views/widgets/didvan/bnb.dart
@@ -5,8 +5,6 @@ import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
-import '../audio/player_navbar.dart';
-
class DidvanBNB extends StatelessWidget {
final int currentTabIndex;
final void Function(int index) onTabChanged;
@@ -17,28 +15,19 @@ class DidvanBNB extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Stack(
- children: [
- const PlayerNavBar(
- inHome: true,
+ return Container(
+ height: 72,
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.surface,
+ borderRadius:
+ const BorderRadius.vertical(top: Radius.circular(0)),
+ border: const Border(
+ top: BorderSide(
+ color: Color.fromARGB(255, 224, 224, 224),
+ width: 1.5,
+ ),
),
- Positioned(
- bottom: 0,
- left: 0,
- right: 0,
- child: Container(
- height: 72,
- decoration: BoxDecoration(
- color: Theme.of(context).colorScheme.surface,
- borderRadius:
- const BorderRadius.vertical(top: Radius.circular(0)),
- border: const Border(
- top: BorderSide(
- color: Color.fromARGB(255, 224, 224, 224),
- width: 1.5,
- ),
- ),
- ),
+ ),
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
@@ -87,10 +76,7 @@ class DidvanBNB extends StatelessWidget {
),
],
),
- ),
- ),
- ],
- );
+ );
}
}
@@ -229,7 +215,6 @@ class _NavBarItemState extends State<_NavBarItem>
child: Stack(
alignment: Alignment.center,
children: [
- // Ripple effect background
AnimatedBuilder(
animation: _rippleAnimation,
builder: (context, child) {
@@ -245,7 +230,6 @@ class _NavBarItemState extends State<_NavBarItem>
);
},
),
- // Main content
Column(
children: [
const SizedBox(height: 4),
@@ -261,7 +245,6 @@ class _NavBarItemState extends State<_NavBarItem>
padding: EdgeInsets.all(widget.isHomeButton ? 8 : 4),
duration: DesignConfig.lowAnimationDuration,
- //shadow
decoration:
BoxDecoration(
shape: BoxShape.circle,
@@ -302,7 +285,6 @@ class _NavBarItemState extends State<_NavBarItem>
);
},
),
- // Animated text with fade and slide
AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: (!widget.isHomeButton && !widget.isSelected)
diff --git a/lib/views/widgets/didvan/scaffold.dart b/lib/views/widgets/didvan/scaffold.dart
index ca06b25..7e9067a 100644
--- a/lib/views/widgets/didvan/scaffold.dart
+++ b/lib/views/widgets/didvan/scaffold.dart
@@ -2,8 +2,6 @@ import 'package:didvan/models/view/app_bar_data.dart';
import 'package:didvan/views/widgets/didvan/app_bar.dart';
import 'package:flutter/material.dart';
-import '../audio/player_navbar.dart';
-
class DidvanScaffold extends StatefulWidget {
final List? slivers;
final List? children;
@@ -137,19 +135,6 @@ class _DidvanScaffoldState extends State {
appBarData: widget.appBarData!,
scrollController: _scrollController,
),
- if (!widget.hidePlayer)
- const Positioned(
- bottom: 16,
- left: 16,
- right: 16,
- child: SizedBox(
- child: Center(
- child: PlayerNavBar(
- inHome: false,
- ),
- ),
- ),
- ),
],
),
),
diff --git a/lib/views/widgets/didvan/slider.dart b/lib/views/widgets/didvan/slider.dart
index 93fa533..39d8681 100644
--- a/lib/views/widgets/didvan/slider.dart
+++ b/lib/views/widgets/didvan/slider.dart
@@ -72,18 +72,22 @@ class _CarouselIndicator extends StatelessWidget {
children: [
for (int i = 0; i < count; i++)
Container(
- width: 8,
- height: 8,
+ width: 7,
+ height: 7,
margin: const EdgeInsets.symmetric(horizontal: 2),
decoration: BoxDecoration(
shape: BoxShape.circle,
- border: Border.all(
- width: 1,
- color: Theme.of(context).colorScheme.primary,
- ),
+ boxShadow: [
+ BoxShadow(
+ color: currentIndex == i ? const Color.fromARGB(255, 176, 215, 228) : Colors.transparent,
+ blurRadius: 0,
+ spreadRadius: 2.5,
+ offset: const Offset(0, 0),
+ ),
+ ],
color: currentIndex == i
- ? Theme.of(context).colorScheme.primary
- : Colors.transparent,
+ ? const Color.fromARGB(255, 0, 126, 167)
+ : const Color.fromARGB(255, 173, 173, 173),
),
)
],
diff --git a/lib/views/widgets/infography_tag.dart b/lib/views/widgets/infography_tag.dart
index f61c80f..afefa91 100644
--- a/lib/views/widgets/infography_tag.dart
+++ b/lib/views/widgets/infography_tag.dart
@@ -1,11 +1,11 @@
import 'package:didvan/config/design_config.dart';
-import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/tag.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/ink_wrapper.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
import 'package:persian_number_utility/persian_number_utility.dart';
class InfographyTag extends StatelessWidget {
@@ -34,23 +34,26 @@ class InfographyTag extends StatelessWidget {
horizontal: 4,
),
decoration: BoxDecoration(
- borderRadius: DesignConfig.lowBorderRadius,
+ borderRadius: DesignConfig.mediumBorderRadius,
border: Border.all(
- color: Theme.of(context).colorScheme.focusedBorder,
+ color: const Color.fromARGB(255, 184, 184, 184),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
- Icon(
+ const Icon(
DidvanIcons.hashtag_regular,
- color: Theme.of(context).colorScheme.focusedBorder,
+ color: Color.fromARGB(255, 102, 102, 102),
size: 16,
),
- DidvanText(
- tag.label,
- color: Theme.of(context).colorScheme.focusedBorder,
- style: Theme.of(context).textTheme.labelLarge,
+ Padding(
+ padding: const EdgeInsets.all(2.0),
+ child: DidvanText(
+ tag.label,
+ color: const Color.fromARGB(255, 102, 102, 102),
+ style: Theme.of(context).textTheme.labelMedium,
+ ),
),
],
),
@@ -73,13 +76,16 @@ class InfoCat extends StatelessWidget {
Widget build(BuildContext context) {
return Row(
children: [
+ const SizedBox(width: 15,),
+ SvgPicture.asset('lib/assets/icons/calendar.svg',color: Colors.white,height: 22,),
+ const SizedBox(width: 5,),
+ // DidvanText(
+ // category,
+ // style: Theme.of(context).textTheme.bodySmall,
+ // ),
DidvanText(
- category,
- style: Theme.of(context).textTheme.bodySmall,
- ),
- DidvanText(
- ' / ${DateTime.parse(createdAt).toPersianDateStr()}',
- style: Theme.of(context).textTheme.bodySmall,
+ DateTime.parse(createdAt).toPersianDateStr(),
+ style: const TextStyle(color: Colors.white),
),
],
);
diff --git a/lib/views/widgets/liked_button.dart b/lib/views/widgets/liked_button.dart
index 6bcf942..b42b3ed 100644
--- a/lib/views/widgets/liked_button.dart
+++ b/lib/views/widgets/liked_button.dart
@@ -3,8 +3,8 @@ import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/providers/user.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
-import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
class LikedButton extends StatefulWidget {
final bool value;
@@ -59,6 +59,7 @@ class _LikedButtonState extends State {
child: DidvanText(
likes.toString(),
fontSize: 14,
+ color: Colors.white,
),
),
InkWell(
@@ -90,11 +91,11 @@ class _LikedButtonState extends State {
UserProvider.changeItemLiked(widget.type, widget.itemId, _value);
}
},
- child: Icon(
- _value ? CupertinoIcons.heart_fill : CupertinoIcons.heart,
- size: 24,
+ child: SvgPicture.asset(
+ _value ? 'lib/assets/icons/heart_fill.svg':'lib/assets/icons/heart.svg',
+ height: 24,
color: widget.color ??
- (!_value ? null : Theme.of(context).colorScheme.error),
+ (!_value ? Colors.white : Theme.of(context).colorScheme.error),
),
),
],