didvan-app/lib/views/podcasts/widgets/slider.dart

183 lines
6.9 KiB
Dart

import 'package:carousel_slider/carousel_slider.dart';
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/enums.dart';
import 'package:didvan/models/requests/studio.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
import 'package:didvan/views/podcasts/podcasts_state.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:flutter/material.dart';
import 'package:provider/provider.dart';
class StudioSlider extends StatefulWidget {
const StudioSlider({Key? key}) : super(key: key);
@override
State<StudioSlider> createState() => _StudioSliderState();
}
class _StudioSliderState extends State<StudioSlider> {
int selectedIndex = 0;
@override
Widget build(BuildContext context) {
final state = context.watch<PodcastsState>();
return Column(
children: [
CarouselSlider(
items: [
if (state.appState == AppState.busy)
const Padding(
padding: EdgeInsets.symmetric(horizontal: 4),
child: ShimmerPlaceholder(),
),
if (state.appState == AppState.idle)
for (var i = 0; i < state.sliders.length; i++)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: GestureDetector(
onTap: () {
final firstUnreadIndex =
state.sliders.indexWhere((story) => !story.isViewed);
final startId = (firstUnreadIndex == -1)
? state.sliders.first.id
: state.sliders[firstUnreadIndex].id;
if (state.videosSelected) {
Navigator.of(context)
.pushNamed(Routes.studioDetails, arguments: {
'onMarkChanged': state.changeMark,
'id': startId,
'args':
const StudioRequestArgs(page: 0, type: 'video'),
'hasUnmarkConfirmation': false,
'isVideo': true,
});
return;
}
context.read<StudioDetailsState>().getStudioDetails(
startId,
args: const StudioRequestArgs(
page: 0,
type: 'podcast',
),
);
},
child: Stack(
alignment: Alignment.center,
children: [
SkeletonImage(
borderRadius: DesignConfig.mediumBorderRadius,
imageUrl: state.sliders[i].image,
width: double.infinity,
height: double.infinity,
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 8,
),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.focused
.withValues(alpha: 0.9),
borderRadius: const BorderRadius.vertical(
bottom: Radius.circular(10),
),
),
child: DidvanText(
state.sliders[i].title,
color: Theme.of(context).colorScheme.title,
style: Theme.of(context).textTheme.bodySmall,
),
),
),
if (state.videosSelected)
Container(
height: 52,
width: 52,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: (state.videosSelected
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.focusedBorder)
.withValues(alpha: 0.7),
),
child: Icon(
DidvanIcons.play_solid,
color: Theme.of(context).colorScheme.white,
size: 48,
),
),
],
),
),
),
],
options: CarouselOptions(
autoPlayAnimationDuration: DesignConfig.mediumAnimationDuration,
onPageChanged: (index, reason) => setState(
() => selectedIndex = index,
),
viewportFraction: 0.94,
aspectRatio: 16 / 9,
autoPlay: state.appState == AppState.idle,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (var i = 0; i < state.sliders.length; i++)
_SliderIndicator(
isCurrentIndex: selectedIndex == i,
isVideo: state.videosSelected,
),
],
),
const SizedBox(height: 16),
],
);
}
}
class _SliderIndicator extends StatelessWidget {
final bool isCurrentIndex;
final bool isVideo;
const _SliderIndicator({
Key? key,
required this.isCurrentIndex,
required this.isVideo,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: DesignConfig.lowAnimationDuration,
height: 8,
width: 8,
margin: const EdgeInsets.only(left: 4),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.focusedBorder,
),
shape: BoxShape.circle,
color:
isCurrentIndex ? Theme.of(context).colorScheme.focusedBorder : null,
),
);
}
}