import 'dart:math'; import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/studio_details_data.dart'; import 'package:didvan/views/comments/comments.dart'; import 'package:didvan/views/comments/comments_state.dart'; import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart'; import 'package:didvan/views/podcasts/studio_details/widgets/details_tab_bar.dart'; import 'package:didvan/views/widgets/overview/multitype.dart'; import 'package:didvan/views/widgets/tag_item.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/shimmer_placeholder.dart'; import 'package:didvan/views/widgets/skeleton_image.dart'; import 'package:didvan/views/widgets/state_handlers/state_handler.dart'; import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_svg/svg.dart'; import 'package:persian_number_utility/persian_number_utility.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; class StudioDetailsWidget extends StatelessWidget { final void Function(int id, bool value) onMarkChanged; const StudioDetailsWidget({ Key? key, required this.onMarkChanged, }) : super(key: key); @override Widget build(BuildContext context) { final ds = MediaQuery.of(context).size; return SafeArea( bottom: true, child: Consumer( builder: (context, state, child) { bool isVideo = state.studio.iframe != null; double topOffset = isVideo ? ds.width * 9 / 16 : 400; return Container( height: max( ds.height - topOffset - 72 - MediaQuery.of(context).padding.top, 0), color: Theme.of(context).colorScheme.surface, child: Stack( children: [ Positioned( top: 72, left: 0, right: 0, bottom: 0, child: StateHandler( onRetry: () {}, state: state, builder: (context, state) { if (state.selectedDetailsIndex == 0) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Html( key: ValueKey(state.studio.id), data: state.studio.description, onAnchorTap: (href, _, __) => launchUrlString(href!), style: { '*': Style( direction: TextDirection.rtl, textAlign: TextAlign.right, lineHeight: LineHeight.percent(135), margin: const Margins(), padding: HtmlPaddings.zero, ), }, ), if (state.studio.tags.isNotEmpty) const SizedBox(height: 20), Wrap( spacing: 8, runSpacing: 8, children: [ for (var i = 0; i < state.studio.tags.length; i++) TagItem( tag: state.studio.tags[i], onMarkChanged: (id, value) => _onMarkChanged(id, value, state), type: isVideo ? 'video' : 'podcast', ), ], ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const SizedBox(), if (state.nextStudio != null && state.alongSideState == AppState.idle) StudioPreview( isNext: true, studio: state.nextStudio!, ), if (state.alongSideState == AppState.busy) StudioPreview.placeHolder, if (state.prevStudio != null && state.alongSideState == AppState.idle) StudioPreview( isNext: false, studio: state.prevStudio!, ), if (state.alongSideState == AppState.busy) StudioPreview.placeHolder, const SizedBox(), ], ), ], ), ); } if (state.selectedDetailsIndex == 1) { return ChangeNotifierProvider( create: (context) => CommentsState(), child: SizedBox( height: ds.height - ds.width * 9 / 16 - 172 - MediaQuery.of(context).padding.top, child: Comments( pageData: { 'id': state.studio.id, 'type': 'studio', 'title': state.studio.title, 'onCommentsChanged': state.onCommentsChanged, 'isPage': false, }, ), ), ); } return Padding( padding: const EdgeInsets.only(top: 24.0), child: Column( children: [ if (state.studio.relatedContents.isEmpty && !state.studio.relatedContentsIsEmpty) for (var i = 0; i < 3; i++) Padding( padding: const EdgeInsets.only( bottom: 8, left: 16, right: 16, ), child: MultitypeOverview.placeholder, ), for (var i = 0; i < state.studio.relatedContents.length; i++) Padding( padding: const EdgeInsets.only( bottom: 8, left: 16, right: 16, ), child: MultitypeOverview( item: state.studio.relatedContents[i], onMarkChanged: (id, value) {}, ), ), ], ), ); }, ), ), DetailsTabBar( isVideo: isVideo, ), ], ), ); }, ), ); } void _onMarkChanged(id, value, state) { onMarkChanged(id, value); if (state.studio.id == id) { state.studio.marked = value; } else if (state.nextStudio?.id == id) { state.nextStudio!.marked = value; } else if (state.prevStudio?.id == id) { state.prevStudio!.marked = value; } } } class StudioPreview extends StatelessWidget { final bool isNext; final StudioDetailsData studio; const StudioPreview({ Key? key, required this.isNext, required this.studio, }) : super(key: key); String get _previewTitle { if (studio.type == 'video') { return 'ویدیوکست ${isNext ? 'بعدی' : 'قبلی'} '; } return 'پادکست ${isNext ? 'بعدی' : 'قبلی'} '; } String _formatDuration(int? duration) { if (duration == null) return ''; final minutes = duration ~/ 60; final seconds = duration % 60; return '”${seconds.toString().padLeft(2, '0')}:’${minutes.toString().padLeft(2, '0')}'; } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { final state = context.read(); state.getStudioDetails( isNext ? state.nextStudio!.id : state.prevStudio!.id, args: state.args, isForward: isNext, ); }, child: Padding( padding: const EdgeInsets.all(8.0), child: Container( width: 170, height: 235, decoration: BoxDecoration( color: DesignConfig.isDark? const Color.fromARGB(255, 83, 83, 83): const Color.fromRGBO(235, 235, 235, 1), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(6.0), child: AspectRatio( aspectRatio: 17 / 14, child: ClipRRect( borderRadius: BorderRadius.circular(20), child: SkeletonImage( imageUrl: studio.image, width: double.infinity, height: double.infinity, borderRadius: BorderRadius.circular(20), ), ), ), ), Expanded( child: Padding( padding: const EdgeInsets.fromLTRB(12, 4, 8, 3), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ DidvanText( _previewTitle, style: Theme.of(context).textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.normal, color: Theme.of(context).colorScheme.caption, fontSize: 12 ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), DidvanText( studio.title, style: Theme.of(context).textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.normal, color: DesignConfig.isDark? Colors.white70 : Colors.black87, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Row( children: [ SvgPicture.asset( 'lib/assets/icons/clock.svg', color: Theme.of(context).colorScheme.caption, ), const SizedBox(width: 4), DidvanText( _formatDuration(studio.duration).toPersianDigit(), style: Theme.of(context) .textTheme .bodySmall ?.copyWith( color: Theme.of(context).colorScheme.caption, ), ), ], ), ], ), ), ), ], ), ), ), ); } static Widget get placeHolder => const SizedBox( width: 88, height: 216, child: Column( children: [ ShimmerPlaceholder(width: 88, height: 88), SizedBox(height: 8), ShimmerPlaceholder(height: 20, width: 20), SizedBox(height: 16), ShimmerPlaceholder(height: 14, width: 60), SizedBox(height: 16), ShimmerPlaceholder(height: 12, width: double.infinity), SizedBox(height: 8), ShimmerPlaceholder(height: 12, width: 40), ], ), ); }