import 'package:flutter/material.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:initial_folder/helper/validator.dart'; import 'package:initial_folder/models/detail_rating_course_model.dart'; import 'package:initial_folder/providers/detail_rating_course_provider.dart'; import 'package:initial_folder/screens/detail_course/components/detail_list_ulasan.dart'; import 'package:initial_folder/size_config.dart'; import 'package:initial_folder/theme.dart'; import 'package:provider/provider.dart'; class Ulasan extends StatefulWidget { const Ulasan({ Key? key, required this.id, }) : super(key: key); final String id; @override _UlasanState createState() => _UlasanState(); } class _UlasanState extends State { int _currentPage = 1; int _totalPages = 1; List _filteredReviews = []; // Menyimpan review yang sudah difilter // Fungsi untuk membatasi ulasan per halaman List _getPaginatedReviews(List reviews) { int startIndex = (_currentPage - 1) * 5; int endIndex = startIndex + 5; return reviews.sublist(startIndex, endIndex.clamp(0, reviews.length)); } void _filterReviews(int rating, List allReviews) { setState(() { _filteredReviews = allReviews.where((review) => double.parse(review.rating ?? '0') == rating).toList(); _totalPages = (_filteredReviews.length / 5).ceil(); _currentPage = 1; // Reset ke halaman pertama saat filter diubah }); } @override Widget build(BuildContext context) { final listChoices = [ ItemChoice(0, 0, 'Semua '), ItemChoice(5, 1, '5'), ItemChoice(4, 1, '4'), ItemChoice(3, 1, '3'), ItemChoice(2, 1, '2'), ItemChoice(1, 1, '1'), ]; return SingleChildScrollView( child: Column( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.only( left: getProportionateScreenWidth(10), right: getProportionateScreenWidth(10), ), child: Consumer( builder: (context, state, _) { if (state.state == ResultState.Loading) { return Padding( padding: const EdgeInsets.all(8.0), child: Center( child: CircularProgressIndicator( color: primaryColor, strokeWidth: 2, ), ), ); } else if (state.state == ResultState.HasData) { var ulasan = state.result; // Hitung total halaman berdasarkan jumlah ulasan jika semua ulasan ditampilkan if (state.currentIndex == 0) { _filteredReviews = ulasan!.dataReview; _totalPages = (_filteredReviews.length / 5).ceil(); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: getProportionateScreenHeight(20)), Text( 'Ulasan Kursus', style: thirdTextStyle.copyWith( fontWeight: semiBold, fontSize: getProportionateScreenWidth(15), ), ), Row( children: [ Text( ulasan!.data.avgRating is List ? '0' : double.parse(ulasan.data.avgRating) .toStringAsFixed(1) .replaceAll('.', ','), style: thirdTextStyle.copyWith( fontSize: getProportionateScreenWidth(29), ), ), SizedBox(width: getProportionateScreenWidth(8)), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: getProportionateScreenHeight(2)), RatingBarIndicator( itemSize: getProportionateScreenWidth(10), rating: ulasan.data.avgRating is List ? 5.0 : double.parse(ulasan.data.avgRating), direction: Axis.horizontal, itemCount: 5, itemBuilder: (context, _) => FaIcon( FontAwesomeIcons.solidStar, color: thirteenColor, ), ), SizedBox( height: getProportionateScreenHeight(2)), Text( '(${ulasan.dataReview.length} Ulasan)', style: thirdTextStyle.copyWith( fontSize: getProportionateScreenWidth(12), ), ), ], ), ], ), SizedBox(height: getProportionateScreenHeight(11)), VerticalRatingBar( lebar: ulasan.data.precentageRating.rating5.toString(), text: '5.0', total: (ulasan.data.precentageRating.rating5.runtimeType == String) ? '${persentaseUlasan(ulasan.data.precentageRating.rating5)}' : '${ulasan.data.precentageRating.rating5}'), VerticalRatingBar( lebar: ulasan.data.precentageRating.rating4.toString(), text: '4.0', total: (ulasan.data.precentageRating.rating4.runtimeType == String) ? '${persentaseUlasan(ulasan.data.precentageRating.rating4)}' : '${ulasan.data.precentageRating.rating4}'), VerticalRatingBar( lebar: ulasan.data.precentageRating.rating3.toString(), text: '3.0', total: (ulasan.data.precentageRating.rating3.runtimeType == String) ? '${persentaseUlasan(ulasan.data.precentageRating.rating3)}' : '${ulasan.data.precentageRating.rating3}'), VerticalRatingBar( lebar: ulasan.data.precentageRating.rating2.toString(), text: '2.0', total: (ulasan.data.precentageRating.rating2.runtimeType == String) ? '${persentaseUlasan(ulasan.data.precentageRating.rating2)}' : '${ulasan.data.precentageRating.rating2}'), VerticalRatingBar( lebar: ulasan.data.precentageRating.rating1.toString(), text: '1.0', total: (ulasan.data.precentageRating.rating1.runtimeType == String) ? '${persentaseUlasan(ulasan.data.precentageRating.rating1)}' : '${ulasan.data.precentageRating.rating1}'), ], ); } return Text( 'Terjadi Kesalan ', style: primaryTextStyle, ); }), ), ], ), SizedBox(height: getProportionateScreenHeight(11)), Consumer( builder: (context, state, _) { if (state.state == ResultState.HasData) { var ulasan = state.result; return Column( children: [ SizedBox(height: getProportionateScreenHeight(8)), Wrap( spacing: 6, runSpacing: 3, children: listChoices .map( (e) => InkWell( onTap: () { state.currentIndex = e.id; if (state.currentIndex == 0) { // Reset ke semua review jika memilih filter "Semua" Provider.of(context, listen: false) .getDetailCourse(); _filteredReviews = ulasan!.dataReview; _totalPages = (_filteredReviews.length / 5).ceil(); _currentPage = 1; } else { // Filter sesuai dengan rating yang dipilih _filterReviews(e.id, ulasan!.dataReview); } }, child: Container( padding: EdgeInsets.symmetric(horizontal: 5), decoration: BoxDecoration( color: state.currentIndex == e.id ? Theme.of(context) .colorScheme .onBackground : Theme.of(context) .colorScheme .primaryContainer, border: Border.all( color: Theme.of(context) .colorScheme .brightness == Brightness.dark ? seventeenColor : secondaryColor, ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: baruTexthitam.withOpacity(0.2), blurRadius: 2, spreadRadius: 1, offset: Offset(0, 2), ) ], ), child: Padding( padding: EdgeInsets.symmetric( horizontal: getProportionateScreenWidth(5), vertical: getProportionateScreenHeight(5), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ (e.icon == 0) ? Text('') : FaIcon( FontAwesomeIcons.solidStar, color: thirteenColor, size: getProportionateScreenWidth(11), ), SizedBox(width: getProportionateScreenWidth(3)), Text( e.label, style: thirdTextStyle.copyWith( color: state.currentIndex == e.id ? Theme.of(context) .colorScheme .background : e.label == "Semua " ? primaryColor : Theme.of(context) .colorScheme .onBackground, fontSize: getProportionateScreenWidth(12), fontWeight: reguler, ), ), ], ), ), ), ), ) .toList(), ), SizedBox(height: getProportionateScreenHeight(17)), Container( margin: EdgeInsets.only( left: getProportionateScreenWidth(15), right: getProportionateScreenWidth(10), ), child: (_filteredReviews.isEmpty) ? SizedBox(height: getProportionateScreenHeight(15)) : Column( children: _getPaginatedReviews(_filteredReviews) .map( (e) => DetailListUlasan( review: e.review ?? '', date: e.date ?? '-', name: e.name ?? '', starRating: double.parse(e.rating ?? '5'), ), ) .toList()), ), // Navigasi Pagination Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (_filteredReviews.isEmpty) Text( 'Belum ada rating untuk kategori bintang ini', style: thirdTextStyle.copyWith( fontSize: getProportionateScreenWidth(12), ), ) else ...[ if (_currentPage > 1) IconButton( onPressed: () { setState(() { _currentPage--; }); }, icon: Icon(Icons.arrow_back), ), Text('$_currentPage of $_totalPages'), if (_currentPage < _totalPages) IconButton( onPressed: () { setState(() { _currentPage++; }); }, icon: Icon(Icons.arrow_forward), ), ] ], ), ], ); } return Text(''); }, ), SizedBox( height: 30, ) ], ), ); } } class VerticalRatingBar extends StatelessWidget { const VerticalRatingBar({ Key? key, required this.text, this.lebar = '0', required this.total, }) : super(key: key); final String text; final String total; final String lebar; @override Widget build(BuildContext context) { return Container( margin: EdgeInsets.only(bottom: getProportionateScreenWidth(8)), child: Column( children: [ Row( children: [ FaIcon( FontAwesomeIcons.solidStar, color: thirteenColor, size: getProportionateScreenWidth(11), ), SizedBox(width: getProportionateScreenWidth(4)), Text( text, style: thirdTextStyle.copyWith( fontSize: getProportionateScreenWidth(10), ), ), SizedBox(width: getProportionateScreenWidth(6)), Expanded( child: Column( children: [ Stack( children: [ Container( height: getProportionateScreenWidth(4), decoration: BoxDecoration( color: fourthColor, borderRadius: BorderRadius.circular(10)), ), Container( width: (SizeConfig.screenWidth - getProportionateScreenWidth(110)) * double.parse(persentaseUlasan(lebar) .replaceAll(',', '.')) / 100, height: getProportionateScreenWidth(4), decoration: BoxDecoration( color: thirteenColor, borderRadius: BorderRadius.circular(10)), ) ], ), ], ), ), SizedBox(width: getProportionateScreenWidth(8)), Container( width: getProportionateScreenWidth(30), child: Text( total, style: thirdTextStyle.copyWith( fontSize: getProportionateScreenWidth(10), ), textAlign: TextAlign.start, ), ) ], ), ], ), ); } } class ItemChoice { final int id; final int icon; final String label; ItemChoice(this.id, this.icon, this.label); }