Initial commit: Penyerahan final Source code Tugas Akhir

This commit is contained in:
ferdiakhh
2025-07-10 19:15:14 +07:00
commit e1f2206b8a
687 changed files with 80132 additions and 0 deletions

View File

@ -0,0 +1,482 @@
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:initial_folder/providers/section_lesson_course_provider.dart';
import 'package:initial_folder/screens/course/component/expansion_tile_copy.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class Aktifitas extends StatefulWidget {
const Aktifitas({
Key? key,
required this.id,
required this.totalDuration,
this.resoaktifitas,
}) : super(key: key);
final String id;
final String totalDuration;
final String? resoaktifitas;
@override
_AktifitasState createState() => _AktifitasState();
}
class _AktifitasState extends State<Aktifitas> {
final _tileKeys = [];
var _selectedIndex = -1;
final List<ValueNotifier<bool>> _isExpanded = [];
final ValueNotifier<int?> _selectedIndexNotifier = ValueNotifier<int?>(null);
@override
void initState() {
super.initState();
for (int i = 0; i < 10; i++) {
_isExpanded.add(ValueNotifier<bool>(false));
}
}
String formatDuration(String duration) {
var parts = duration.split(':');
String formattedDuration = '';
if (parts[0] != '00') {
formattedDuration += '${parts[0]} jam ';
}
formattedDuration +=
'${int.parse(parts[1])} menit ${int.parse(parts[2])} detik';
return '($formattedDuration)';
}
String formatDurations(String duration) {
if (duration == '') {
String formattedDuration = '';
print('masuk sini');
formattedDuration += '';
return formattedDuration;
}
List<String> parts = duration.split(':');
int hours = int.parse(parts[0]);
int minutes = int.parse(parts[1]);
String formattedDuration = '';
if (hours != 0) {
formattedDuration += '${hours}j';
}
if (minutes != 0) {
formattedDuration += '${int.parse(parts[1])}m';
}
formattedDuration += '${int.parse(parts[2])}d';
return formattedDuration;
}
void resetExpansionTileKeysAndSelectedIndex() {
_tileKeys.clear();
_selectedIndex = -1;
}
@override
Widget build(BuildContext context) {
String _parseHtmlString(String htmlText) {
RegExp exp = RegExp(r"<[^>]*>|&nbsp;|&amp;|&quot;",
multiLine: true, caseSensitive: true);
return htmlText.replaceAll(exp, '');
}
resetExpansionTileKeysAndSelectedIndex();
return Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(15),
right: getProportionateScreenWidth(15),
top: getProportionateScreenHeight(20),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Aktivitas',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(
height: 8,
),
Consumer<SectionLessonCourseProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: Colors.amber,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
_isExpanded.clear();
for (int i = 0; i < state.result!.data![0].length; i++) {
_isExpanded.add(ValueNotifier<bool>(false));
}
return Container(
child: Column(
children: [
Row(
children: [
Text(
'${state.result!.data![0].length} Pelajaran',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
fontWeight: light,
),
),
SizedBox(width: getProportionateScreenWidth(6)),
Text(
formatDuration(widget.totalDuration == ""
? "00:02:07"
: widget.totalDuration),
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
fontWeight: light,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Container(
height: widget.resoaktifitas == null
? getProportionateScreenHeight(195)
: getProportionateScreenHeight(195),
width: SizeConfig.screenWidth,
child: ListView.builder(
itemCount: state.result!.data![0].length,
itemBuilder: (context, index) {
var chapter = state.result!.data![0][index];
final tileKey = GlobalKey();
_tileKeys.add(tileKey);
return ValueListenableBuilder<bool>(
valueListenable: _isExpanded[index],
builder: (context, isExpanded, child) {
return Theme(
data: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: secondaryColor),
dividerColor: Colors.transparent,
),
child: Padding(
padding: EdgeInsets.only(
bottom:
getProportionateScreenHeight(15)),
child: Column(
children: [
ListTileTheme(
dense: true,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
borderRadius:
BorderRadius.circular(5),
boxShadow: [
BoxShadow(
color: baruTexthitam
.withOpacity(0.1),
blurRadius: 3,
spreadRadius: 1,
offset: Offset(0, 3),
),
],
),
child: ExpansionTileCopy(
key: tileKey,
onExpansionChanged:
(bool expanding) {
if (expanding) {
if (_selectedIndexNotifier
.value !=
null &&
_selectedIndexNotifier
.value !=
index &&
_tileKeys[_selectedIndexNotifier
.value!]
.currentState !=
null) {
_tileKeys[
_selectedIndexNotifier
.value!]
.currentState!
.closeExpansion();
}
_selectedIndexNotifier
.value = index;
} else if (_selectedIndexNotifier
.value ==
index) {
_selectedIndexNotifier
.value = null;
}
},
title: Text(
'Bab ${index + 1}',
style:
thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize:
getProportionateScreenWidth(
11),
color: Theme.of(context)
.colorScheme
.onBackground,
),
),
subtitle: Html(
shrinkWrap: true,
data: chapter.title ?? '',
style: {
"body": Style(
margin: Margins.zero,
padding:
HtmlPaddings.zero,
fontSize: FontSize(
getProportionateScreenWidth(
12)),
fontWeight: reguler,
fontFamily: 'Poppins',
color: Theme.of(context)
.colorScheme
.onBackground,
),
},
),
trailing:
ValueListenableBuilder<
int?>(
valueListenable:
_selectedIndexNotifier,
builder:
(context, value, child) {
return Icon(
value == index
? Icons.remove
: Icons.add,
color: primaryColor,
);
},
),
children: chapter.dataLesson![0]
.asMap()
.entries
.map(
(e) => ListTile(
minVerticalPadding: 15,
leading: Text(
'${e.key + 1}',
style: thirdTextStyle
.copyWith(
color: Theme.of(
context)
.colorScheme
.onBackground,
),
),
minLeadingWidth: 15,
title:
Transform.translate(
offset: Offset(0, 0),
child: Text(
_parseHtmlString(e
.value
.titleLesson ??
''),
style: TextStyle(
fontSize:
getProportionateScreenWidth(
12),
fontWeight:
semiBold,
fontFamily:
'Poppins',
color: Theme.of(
context)
.colorScheme
.onBackground,
),
),
),
subtitle:
Transform.translate(
offset: Offset(0, 0),
child: Text(
(e.value.lessonType ==
'video')
? 'Video - ${formatDuration(e.value.duration.toString())}'
: (e.value.lessonType ==
'quiz')
? 'Quiz'
: (e.value
.attachment
.toString()
.contains('.pdf'))
? 'PDFs'
: (e.value.attachment.toString().contains('.pptx'))
? 'PPT'
: (e.value.attachment.toString().contains('.rar'))
? 'RAR'
: (e.value.attachment.toString().contains('.zip'))
? 'ZIP'
: (e.value.attachment.toString().contains('.xlsx'))
? 'Excel'
: (e.value.attachment.toString().contains('.jpg') || e.value.attachment.toString().contains('.jpeg') || e.value.attachment.toString().contains('.png'))
? 'Image'
: (e.value.attachment.toString().contains('.docx'))
? 'Document'
: (e.value.attachment.toString().contains('.txt'))
? 'Text'
: 'Terjadi Kesalahan',
style:
thirdTextStyle
.copyWith(
color: Theme.of(
context)
.colorScheme
.onBackground,
fontSize:
getProportionateScreenHeight(
8),
),
),
),
trailing: (e.value
.lessonType ==
'video')
? Image.asset(
'assets/images/play_button_new.png',
color: Theme.of(
context)
.colorScheme
.onBackground,
scale: 3,
)
: (e.value.lessonType ==
'quiz')
? Image.asset(
'assets/icons/lms/ListNumbers.png',
color: Theme.of(
context)
.colorScheme
.onBackground,
scale:
getProportionateScreenWidth(
1.3),
)
: (e.value
.attachment
.toString()
.contains(
'.pdf'))
? Image
.asset(
'assets/icons/lms/FilePdf.png',
color: Theme.of(context)
.colorScheme
.onBackground,
scale: getProportionateScreenWidth(
1.3),
)
: (e.value
.attachment
.toString()
.contains(
'.rar'))
? Image
.asset(
'assets/icons/lms/FileArchive.png',
color:
Theme.of(context).colorScheme.onBackground,
scale:
getProportionateScreenWidth(1.3),
)
: (e.value.attachment.toString().contains('.zip'))
? Image.asset(
'assets/icons/lms/FileZip.png',
color: Theme.of(context).colorScheme.onBackground,
scale: getProportionateScreenWidth(1.3),
)
: (e.value.attachment.toString().contains('.pptx'))
? Image.asset(
'assets/icons/lms/FilePpt.png',
color: Theme.of(context).colorScheme.onBackground,
scale: getProportionateScreenWidth(1.3),
)
: (e.value.attachment.toString().contains('.xlsx'))
? Image.asset(
'assets/icons/lms/FileXls.png',
color: Theme.of(context).colorScheme.onBackground,
scale: getProportionateScreenWidth(1.3),
)
: (e.value.attachment.toString().contains('.jpg') || e.value.attachment.toString().contains('.jpeg') || e.value.attachment.toString().contains('.png'))
? Image.asset(
'assets/icons/lms/FileImage.png',
color: Theme.of(context).colorScheme.onBackground,
scale: getProportionateScreenWidth(1.3),
)
: (e.value.attachment.toString().contains('.txt'))
? Image.asset(
'assets/icons/lms/FileText.png',
color: Theme.of(context).colorScheme.onBackground,
scale: getProportionateScreenWidth(1.3),
)
: ((e.value.attachment.toString().contains('.docx')))
? Image.asset(
'assets/icons/lms/FileDoc.png',
color: Theme.of(context).colorScheme.onBackground,
scale: getProportionateScreenWidth(1.3),
)
: SizedBox(),
),
)
.toList(),
),
),
),
],
),
));
},
);
},
),
)
],
),
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Center(
child: Padding(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(30)),
child: Text(
'Kursus ini belum memiliki aktivitas',
style: thirdTextStyle.copyWith(),
),
),
);
} else {
return Center(child: Text(''));
}
},
),
],
),
);
}
}

View File

@ -0,0 +1,195 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/notification_provider.dart';
import 'package:initial_folder/screens/home/components/appBar/icon_btn_with_counter.dart';
import 'package:initial_folder/screens/home/components/notification.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/screens/cart/cart_page.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
class AppBarHeader extends StatelessWidget {
const AppBarHeader({
Key? key,
this.idcourse,
this.color,
}) : super(key: key);
final String? idcourse;
final Color? color;
@override
Widget build(BuildContext context) {
Future _showDialogNotLogin(String teks) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum $teks',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text(
'Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor,
),
),
),
SizedBox(width: getProportionateScreenWidth(5)),
GestureDetector(
onTap: () {
Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false);
},
child: Text(
'Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor,
),
),
),
],
),
);
}
handleNotLoginCart() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: CartPage(),
),
);
} else {
String teks = 'dapat mengakses keranjang';
return _showDialogNotLogin(teks);
}
}
handleNotLoginNotif() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: Notifikasi(),
),
);
} else {
String teks = 'dapat mengakses notifikasi';
return _showDialogNotLogin(teks);
}
}
return AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
color: color,
width: SizeConfig.screenWidth,
height: getProportionateScreenHeight(40),
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10),
left: getProportionateScreenWidth(5),
),
child: Row(
children: [
IconButton(
alignment: Alignment.centerLeft,
icon: Theme.of(context).brightness == Brightness.dark
? SvgPicture.asset('assets/icons/arrow_back_dark.svg')
: SvgPicture.asset('assets/icons/arrow_back.svg'),
onPressed: () {
Navigator.pop(context);
},
),
Spacer(),
Transform.scale(
origin: Offset(-11, 0),
scale: getProportionateScreenHeight(1),
child: Container(
padding: EdgeInsets.fromLTRB(getProportionateScreenHeight(3), 0,
getProportionateScreenHeight(4), 0),
child: Consumer<NotificationProvider>(
builder: (context, value, child) {
return IconBtnWithCounter(
icon: Theme.of(context).brightness == Brightness.dark
? SvgPicture.asset(
"assets/icons/notification_dark.svg")
: SvgPicture.asset("assets/icons/notification.svg"),
numOfitem:
(Condition.loginEmail || Condition.loginFirebase)
? value.notificationCount
: 0,
press: () {
handleNotLoginNotif();
},
);
},
),
),
),
!Condition.loginEmail && !Condition.loginFirebase
? Transform.scale(
origin: Offset(0, 0),
scale: getProportionateScreenHeight(1),
child: Container(
padding: EdgeInsets.fromLTRB(
getProportionateScreenHeight(3),
0,
getProportionateScreenHeight(3),
0),
child: IconBtnWithCounter(
numOfitem: 0,
icon: Theme.of(context).brightness == Brightness.dark
? SvgPicture.asset("assets/icons/cart_dark.svg")
: SvgPicture.asset("assets/icons/cart.svg"),
press: () => handleNotLoginCart(),
),
),
)
: Transform.scale(
origin: Offset(0, 0),
scale: getProportionateScreenHeight(1),
child: Container(
padding: EdgeInsets.fromLTRB(
getProportionateScreenHeight(3),
0,
getProportionateScreenHeight(3),
0),
child: Consumer<CartsProvider>(
builder: (context, state, _) {
return IconBtnWithCounter(
numOfitem: state.result == null ? 0 : state.lenght,
icon: Theme.of(context).brightness ==
Brightness.dark
? SvgPicture.asset("assets/icons/cart_dark.svg")
: SvgPicture.asset("assets/icons/cart.svg"),
press: () => handleNotLoginCart(),
);
},
),
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,124 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/screens/home/components/notification.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/screens/search_course/component/filter.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/screens/cart/cart_page.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
class AppBarFilter extends StatelessWidget {
const AppBarFilter({
Key? key,
this.idcourse,
}) : super(key: key);
final String? idcourse;
@override
Widget build(BuildContext context) {
Future _showDialogNotLogin(String teks) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum $teks',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
SizedBox(
width: getProportionateScreenWidth(5),
),
GestureDetector(
onTap: () {
Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false);
},
child: Text('Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
],
),
);
}
handleNotLoginCart() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
Navigator.of(context).push(
CustomNavigator(
child: CartPage(),
),
);
} else {
String teks = 'dapat mengakses keranjang';
return _showDialogNotLogin(teks);
}
}
handleNotLoginNotif() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
Navigator.push(
context,
CustomNavigator(
child: Notifikasi(),
),
);
} else {
String teks = 'dapat mengakses notifikasi';
return _showDialogNotLogin(teks);
}
}
return Container(
margin: EdgeInsets.only(left: getProportionateScreenWidth(7)),
width: SizeConfig.screenWidth,
height: getProportionateScreenHeight(40),
child: Row(
children: [
IconButton(
alignment: Alignment.centerLeft,
icon: Icon(
Icons.arrow_back,
size: getProportionateScreenHeight(18),
color: Theme.of(context).brightness == Brightness.dark
? tenthColor
: ninthColor,
),
onPressed: () {
Navigator.pop(context);
},
),
Spacer(),
// IconButton(
// padding: EdgeInsets.zero,
// onPressed: () => Navigator.of(context, rootNavigator: true).push(
// CustomNavigator(
// child: const Filter(isNotSearch: true),
// ),
// ),
// icon: Icon(Icons.tune_rounded, color: primaryColor),
// ),
],
),
);
}
}

View File

@ -0,0 +1,170 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/tab_provider.dart';
import 'package:initial_folder/screens/detail_course/components/aktifitas.dart';
import 'package:initial_folder/screens/detail_course/components/deskripsi.dart';
import 'package:initial_folder/screens/detail_course/components/tab_bar_items.dart';
import 'package:initial_folder/screens/detail_course/components/terkait.dart';
import 'package:initial_folder/screens/detail_course/components/ulasan.dart';
import 'package:initial_folder/size_config.dart';
import 'package:provider/provider.dart';
class CustomTabBar extends StatefulWidget {
const CustomTabBar({
Key? key,
required this.dataDetailCourseModel,
this.totalDuration,
this.bio,
this.instructor,
this.rating,
this.review,
this.totalLesson,
this.totalStudent,
this.fotoProfile,
this.headline,
this.resoaktifitas,
this.idCategory,
}) : super(key: key);
final DataDetailCourseModel dataDetailCourseModel;
final String? totalDuration,
bio,
instructor,
review,
totalLesson,
totalStudent,
fotoProfile,
rating,
headline,
resoaktifitas,
idCategory;
@override
State<CustomTabBar> createState() => _CustomTabBarState();
}
class _CustomTabBarState extends State<CustomTabBar> {
@override
Widget build(BuildContext context) {
TabProvider tab = Provider.of<TabProvider>(context);
void _onHorizontalDragEnd(DragEndDetails details) {
double velocity = details.primaryVelocity ?? 0.0;
if (velocity < 0) {
if (tab.currentIndex < 3) {
tab.currentIndex++;
}
} else if (velocity > 0) {
if (tab.currentIndex > 0) {
tab.currentIndex--;
}
}
}
Widget buildContent(int currentIndex) {
switch (currentIndex) {
case 0:
return Desksripsi(
dataDetailCourseModel: widget.dataDetailCourseModel,
video: true,
id: widget.dataDetailCourseModel.id,
instructor: widget.instructor,
bio: widget.bio,
rating: widget.rating,
fotoProfile: widget.fotoProfile,
review: widget.review,
totalLesson: widget.totalLesson,
totalStudent: widget.totalStudent,
headline: widget.headline,
);
case 1:
return Aktifitas(
id: widget.dataDetailCourseModel.id,
totalDuration: widget.totalDuration ?? '',
resoaktifitas: widget.resoaktifitas,
);
case 2:
return Ulasan(
id: widget.dataDetailCourseModel.id,
);
case 3:
return Terkait(
idCategory: widget.idCategory,
);
default:
return Desksripsi(
dataDetailCourseModel: widget.dataDetailCourseModel,
video: true,
id: widget.dataDetailCourseModel.id,
instructor: widget.instructor,
bio: widget.bio,
rating: widget.rating,
fotoProfile: widget.fotoProfile,
review: widget.review,
totalLesson: widget.totalLesson,
totalStudent: widget.totalStudent,
headline: widget.headline,
);
}
}
return Column(
children: [
Container(
width: SizeConfig.screenWidth,
height: getProportionateScreenHeight(29),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: -12,
blurRadius: 8,
offset: Offset(0, getProportionateScreenHeight(12)),
),
],
),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
GestureDetector(
onTap: () => tab.currentIndex = 0,
child: TabBarItems(
index: 0,
title: 'Deskripsi',
),
),
GestureDetector(
onTap: () => tab.currentIndex = 1,
child: TabBarItems(
index: 1,
title: 'Aktivitas',
),
),
GestureDetector(
onTap: () => tab.currentIndex = 2,
child: TabBarItems(
index: 2,
title: 'Ulasan',
),
),
GestureDetector(
onTap: () => tab.currentIndex = 3,
child: TabBarItems(
index: 3,
title: 'Terkait',
),
),
],
),
),
),
GestureDetector(
onHorizontalDragEnd: _onHorizontalDragEnd,
child: buildContent(tab.currentIndex),
),
],
);
}
}

View File

@ -0,0 +1,557 @@
import 'dart:convert';
import 'package:expandable/expandable.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/description_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/detail_course/components/kursus_include_item.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class Desksripsi extends StatefulWidget {
const Desksripsi({
Key? key,
required this.dataDetailCourseModel,
required this.id,
this.instructor,
this.bio,
this.rating,
this.review,
this.totalStudent,
this.totalLesson,
this.video = false,
this.fotoProfile,
this.headline,
}) : super(key: key);
final DataDetailCourseModel dataDetailCourseModel;
final String id;
final String? instructor;
final String? bio;
final String? rating;
final String? review;
final String? fotoProfile;
final String? totalLesson;
final String? totalStudent;
final String? headline;
final bool video;
@override
State<Desksripsi> createState() => _DesksripsiState();
}
class _DesksripsiState extends State<Desksripsi> {
bool isExpanded = false;
bool isExpanded2 = false;
bool isExpanded3 = false;
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
DescriptionProvider descriptionProvider =
Provider.of<DescriptionProvider>(context);
final bool hasDescription =
widget.dataDetailCourseModel.description!.isNotEmpty;
String formatDuration(String duration) {
var parts = duration.split(':');
return '${int.parse(parts[0]).toString()} jam ${int.parse(parts[1]).toString()} menit ${int.parse(parts[2]).toString()} detik';
}
List outcomes;
try {
outcomes = jsonDecode(widget.dataDetailCourseModel.outcome ?? '[]');
} catch (e) {
outcomes = [];
}
List requirement;
try {
requirement =
jsonDecode(widget.dataDetailCourseModel.requirement ?? '[]');
} catch (e) {
requirement = [];
}
Widget kemampuanDiraih(String title,
{bool showToggle = false, bool isLast = false}) {
return Container(
margin: EdgeInsets.only(bottom: 6),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.isNotEmpty
? Icon(
Icons.check,
size: getProportionateScreenHeight(13),
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
)
: SizedBox.shrink(),
SizedBox(width: getProportionateScreenWidth(9)),
Flexible(
child: RichText(
text: TextSpan(
text: title,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: light,
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih
: baruTexthitam,
),
children: showToggle || isLast
? [
TextSpan(
text:
isExpanded ? ' Lihat Sedikit' : ' Lihat Semua',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
),
recognizer: TapGestureRecognizer()
..onTap = () {
setState(() {
isExpanded = !isExpanded;
});
},
),
]
: [],
),
),
),
],
),
);
}
Widget persyaratan(String title,
{bool showToggle = false, bool isLast = false}) {
return Container(
margin: EdgeInsets.only(bottom: 6),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
title.isNotEmpty
? Icon(
Icons.brightness_1,
size: getProportionateScreenHeight(13),
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
)
: SizedBox.shrink(),
SizedBox(width: getProportionateScreenWidth(9)),
Flexible(
child: RichText(
text: TextSpan(
text: title,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: light,
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih
: baruTexthitam,
),
children: showToggle || isLast
? [
TextSpan(
text:
isExpanded3 ? ' Lihat Sedikit' : ' Lihat Semua',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
),
recognizer: TapGestureRecognizer()
..onTap = () {
setState(() {
isExpanded3 = !isExpanded3;
});
},
),
]
: [],
),
),
),
],
),
);
}
List<Widget> kemampuanDiraihList() {
List<Widget> items = outcomes
.asMap()
.entries
.map((entry) => kemampuanDiraih(entry.value,
showToggle: !isExpanded && entry.key == 2 && outcomes.length > 3,
isLast: entry.key == outcomes.length - 1 && outcomes.length > 3))
.toList();
if (!isExpanded && outcomes.length > 3) {
items = items.take(3).toList();
items.add(kemampuanDiraih("", isLast: false, showToggle: false));
}
return items;
}
List<Widget> persyaratanList() {
List<Widget> items = requirement
.asMap()
.entries
.map((entry) => persyaratan(entry.value,
showToggle:
!isExpanded3 && entry.key == 2 && requirement.length > 3,
isLast: entry.key == requirement.length - 1 &&
requirement.length > 3))
.toList();
if (!isExpanded3 && requirement.length > 3) {
items = items.take(3).toList();
items.add(persyaratan("", isLast: false, showToggle: false));
}
return items;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(9)),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
top: getProportionateScreenHeight(10),
),
child: Text(
'Kursus Ini Sudah Termasuk',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
SizedBox(height: 10),
KursusIncludeItems(
svg: 'assets/icons/clock.svg',
text:
'${formatDuration(widget.dataDetailCourseModel.totalDuration!)} video pembelajaran'),
KursusIncludeItems(
svg: 'assets/icons/lesson.svg',
text: '${widget.dataDetailCourseModel.totalLesson} pelajaran'),
KursusIncludeItems(
svg: 'assets/icons/calendar.svg',
text: 'Akses full seumur hidup'),
Padding(
padding: EdgeInsets.only(left: getProportionateScreenWidth(1)),
child: KursusIncludeItems(
svg: 'assets/icons/phone.svg',
text: ' Akses di ponsel dan TV '),
),
SizedBox(height: 10),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Column(
children: [
ExpandableNotifier(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(106),
bottom: getProportionateScreenWidth(8),
),
child: Text(
'Kemampuan Yang Akan Diraih',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(10),
bottom: widget.dataDetailCourseModel.outcome == "[]" ||
widget.dataDetailCourseModel.outcome!.isEmpty
? getProportionateScreenHeight(20)
: getProportionateScreenHeight(0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: kemampuanDiraihList(),
),
),
],
),
),
],
),
Column(
children: [
ExpandableNotifier(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(106),
bottom: getProportionateScreenWidth(8),
),
child: Text(
'Persyaratan',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(10),
bottom: widget.dataDetailCourseModel.requirement ==
"[]" ||
widget.dataDetailCourseModel.requirement!.isEmpty
? getProportionateScreenHeight(20)
: getProportionateScreenHeight(0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: persyaratanList(),
),
),
],
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Column(
children: [
isExpanded
? SizedBox(height: getProportionateScreenHeight(12))
: SizedBox.shrink(),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: Text(
'Deskripsi',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(5)),
child: Container(
height: descriptionProvider.isExpanded
? getProportionateScreenHeight(53)
: null,
child: Html(
data: widget.dataDetailCourseModel.description ?? "",
style: {
"p": Style(
fontSize: FontSize(getProportionateScreenWidth(11)),
fontWeight: light,
margin: Margins.only(top: 0, bottom: 0),
fontFamily: 'Poppins',
color: Theme.of(context).colorScheme.onBackground),
},
),
),
),
if (hasDescription &&
widget.dataDetailCourseModel.description!.length > 120)
Container(
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: RichText(
text: TextSpan(
text: descriptionProvider.isExpanded
? ' Lihat Semua'
: ' Lihat Sedikit',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih
: fourthColor,
),
recognizer: TapGestureRecognizer()
..onTap = () {
setState(() {
descriptionProvider.isExpanded =
!descriptionProvider.isExpanded;
});
},
),
),
),
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (hasDescription &&
widget.dataDetailCourseModel.description!.length > 120)
SizedBox(height: getProportionateScreenHeight(10)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: Row(
children: [
CircleAvatar(
radius: 20,
backgroundColor: primaryColor,
backgroundImage: widget.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(widget.fotoProfile!) as ImageProvider,
),
SizedBox(width: getProportionateScreenWidth(10)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.instructor ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: bold,
),
),
Row(
children: [
Text(
'Instructor, ',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
),
Text(
'${widget.totalStudent ?? '0'} Murid, ',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
),
Text(
'${widget.totalLesson ?? ''} Kursus',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
)
],
),
],
),
],
),
),
if (widget.bio == null || widget.bio!.isEmpty)
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenHeight(10),
right: getProportionateScreenHeight(10),
bottom: getProportionateScreenHeight(10),
),
child: const SizedBox(height: 5)
)
else
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(5),
right: getProportionateScreenWidth(10),
),
child: isExpanded2
? Html(
data: widget.bio,
style: {
"body": Style(
fontSize:
FontSize(getProportionateScreenWidth(11)),
fontWeight: light,
fontFamily: 'Poppins',
),
},
)
: Html(
data: widget.bio != null && widget.bio!.length > 100
? widget.bio!.substring(0, 100)
: widget.bio!,
style: {
"body": Style(
fontSize:
FontSize(getProportionateScreenWidth(11)),
fontWeight: light,
fontFamily: 'Poppins',
),
},
),
),
if (widget.bio!.isNotEmpty && widget.bio!.length > 100)
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(12),
bottom: getProportionateScreenHeight(10),
),
child: GestureDetector(
onTap: () {
setState(() {
isExpanded2 = !isExpanded2;
});
},
child: Text(
isExpanded2 ? 'Lihat Sedikit' : 'Lihat Semua',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
color:
Theme.of(context).brightness == Brightness.dark
? baruTextutih
: fourthColor,
fontSize: getProportionateScreenWidth(12),
),
),
),
),
],
),
],
),
],
);
}
}

View File

@ -0,0 +1,75 @@
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 '../../../size_config.dart';
import '../../../theme.dart';
class DetailListUlasan extends StatelessWidget {
const DetailListUlasan({
Key? key,
required this.name,
required this.starRating,
required this.review,
required this.date,
}) : super(key: key);
final String name;
final double starRating;
final String review;
final String date;
@override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(5)),
Text(
name,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
RatingBarIndicator(
itemSize: getProportionateScreenWidth(11),
rating: starRating,
direction: Axis.horizontal,
itemCount: 5,
itemPadding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(1)),
//itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
itemBuilder: (context, _) =>
FaIcon(FontAwesomeIcons.solidStar, color: thirteenColor),
),
SizedBox(width: getProportionateScreenWidth(5)),
Text(
dateFormatUlasan(date),
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
),
)
],
),
Container(
child: Text(
review,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
),
),
),
SizedBox(height: getProportionateScreenHeight(7)),
Divider(
color: Color(0xff2D2D2D),
thickness: 1,
),
],
),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,604 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/detail_course_provider.dart'
as detailCourseProv;
import 'package:initial_folder/providers/radeem_voucher_provider.dart';
import 'package:initial_folder/providers/whislist_provider.dart'
as wishlistProvider;
import 'package:initial_folder/providers/whislist_provider.dart';
import 'package:initial_folder/providers/wishlist_post_provider.dart';
import 'package:initial_folder/screens/cart/cart_page.dart';
import 'package:initial_folder/screens/checkout/components/field_kupon.dart';
import 'package:initial_folder/screens/detail_course/components/murid_and_rating.dart';
import 'package:initial_folder/screens/login/login_screen.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:initial_folder/widgets/login_regist/loading_button.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
class HeaderCoupon extends StatelessWidget {
const HeaderCoupon({
Key? key,
required this.dataDetailCourseModel,
}) : super(key: key);
final DataDetailCourseModel dataDetailCourseModel;
@override
Widget build(BuildContext context) {
WishlistPostProvider wishlistPostProvider =
Provider.of<WishlistPostProvider>(context);
// var finalRating =
// double.parse((course.specificRating![0] / 20).toStringAsFixed(2));
final kuponController = TextEditingController();
bool isLoading = false;
Future _showDialogNotLogin() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum menambahkan ke wishlist',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
SizedBox(
width: getProportionateScreenWidth(5),
),
GestureDetector(
onTap: () => Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false),
child: Text('Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
],
),
);
}
Future _showDialogNotLoginKupon() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum tukar kupon',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
SizedBox(
width: getProportionateScreenWidth(5),
),
GestureDetector(
onTap: () => Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false),
child: Text('Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
],
),
);
}
addWishlist() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 1),
backgroundColor: Colors.red[600],
content: Text(
'No Internet Connections',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
} else {
await wishlistPostProvider
.addWishlist(int.parse(dataDetailCourseModel.id));
await Provider.of<wishlistProvider.WishlistProvider>(context,
listen: false)
.getWishlist();
await Provider.of<CartProvider>(context, listen: false)
.addCart(dataDetailCourseModel.id);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
}
}
addWishlistNotExist() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 1),
backgroundColor: Colors.red[600],
content: Text(
'No Internet Connections',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
} else {
await wishlistPostProvider
.addWishlist(int.parse(dataDetailCourseModel.id));
await Provider.of<wishlistProvider.WishlistProvider>(context,
listen: false)
.getWishlist();
}
}
checkUser() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
addWishlist();
} else {
return _showDialogNotLogin();
}
}
wishlistExist() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
addWishlistNotExist();
} else {
return _showDialogNotLogin();
}
}
Future _showKupon() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(3, 1, 6, 30),
content: SingleChildScrollView(
child: Container(
width: getProportionateScreenWidth(400),
height: getProportionateScreenHeight(400),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
icon: Icon(Icons.cancel_rounded),
onPressed: () {
Navigator.pop(context);
},
),
],
),
Center(
child: Column(
children: [
SizedBox(
height: getProportionateScreenHeight(30),
),
Image.asset('assets/images/discount_coupon.png'),
SizedBox(
height: getProportionateScreenHeight(26),
),
Text(
'Tukarkan Voucher',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
SizedBox(
height: getProportionateScreenHeight(16),
),
Text(
'Masukkan kode kupon untuk klaim\npromo menarik Vocasia',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12)),
),
SizedBox(
height: getProportionateScreenHeight(30),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: FieldKupon(
controler: kuponController,
),
),
SizedBox(
height: getProportionateScreenHeight(7),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(15)),
child: isLoading
? LoadingButton(
backgroundButtonColor: primaryColor,
textButtonColor: Color(0xff050505),
)
: DefaultButton(
text: 'Tukarkan',
press: () async {
final voucher = kuponController.text;
if (await Provider.of<
RadeemVoucherProvider>(context,
listen: false)
.radeemVoucher(
int.parse(dataDetailCourseModel.id),
voucher)) {
await Provider.of<CartsProvider>(context,
listen: false)
.getCarts();
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => CartPage(
idcourse: dataDetailCourseModel.id,
isiVoucher: voucher,
),
),
);
kuponController.clear();
// _showMessage('Voucher Berhasil Digunakan');
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text(
"Kursus sudah di keranjang\natau kupon tidak valid"),
duration: Duration(seconds: 4),
));
}
},
),
),
],
),
),
],
),
),
),
),
);
}
Widget imageCourse() {
return Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
width: double.infinity,
height: getProportionateScreenWidth(178),
child: Column(
children: [
Container(
width: double.infinity,
height: getProportionateScreenWidth(178),
child: CachedNetworkImage(
imageUrl: dataDetailCourseModel.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(
top: Radius.circular(5), bottom: Radius.circular(5)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.fill,
),
),
),
placeholder: (context, url) => Shimmer(
child: Container(
color: thirdColor,
),
gradient: LinearGradient(
stops: [0.4, 0.5, 0.6],
colors: [secondaryColor, thirdColor, secondaryColor])),
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
],
),
);
}
Widget buttonKuponWishlist() {
return Row(
children: [
// Consumer<detailCourseProv.DetailCourseProvider>(
// builder: (context, state, _) {
// if (state.state == detailCourseProv.ResultState.HasData) {
// var detailCourse = state.result!.data[0][0];
// if (detailCourse.isFreeCourse == '1') {
// return SizedBox(width: 60);
// } else {
// return Container(
// margin:
// EdgeInsets.only(left: getProportionateScreenWidth(2)),
// child: ElevatedButton(
// style: ElevatedButton.styleFrom(
// primary: Color(0xFF2D2D2D),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(6))),
// onPressed: () {
// (Condition.loginEmail || Condition.loginFirebase)
// ? _showKupon()
// : _showDialogNotLoginKupon();
// },
// child: Padding(
// padding: EdgeInsets.symmetric(
// horizontal: getProportionateScreenWidth(3),
// vertical: getProportionateScreenHeight(6)),
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Image.asset(
// "assets/images/home_coupon.png",
// color: Colors.white,
// ),
// SizedBox(
// width: getProportionateScreenWidth(10),
// ),
// Text(
// 'Tukar Kupon',
// textAlign: TextAlign.start,
// style: thirdTextStyle.copyWith(
// color: Colors.white,
// fontSize: getProportionateScreenWidth(12),
// fontWeight: reguler),
// ),
// ],
// ),
// ),
// ),
// );
// }
// } else {
// return Container();
// }
// },
// ),
SizedBox(width: 60),
SizedBox(
width: getProportionateScreenWidth(16),
),
// Consumer<WishlistProvider>(builder: (context, state, _) {
// return Text(state.data.contains(dataDetailCourseModel.id)
// ? 'ada di wishlist'
// : 'ga ada');
// }),
Container(
width: getProportionateScreenWidth(173),
height: getProportionateScreenHeight(28),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(12),
vertical: getProportionateScreenHeight(6)),
// color: Color(0xFF2D2D2D),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Color(0xFF2D2D2D)),
child: GestureDetector(
onTap: Provider.of<CartsProvider>(context)
.data
.contains(dataDetailCourseModel.id)
? checkUser
: wishlistExist,
child: !Condition.loginEmail && !Condition.loginFirebase
? Row(
children: [
Icon(
Icons.favorite_border,
color: Colors.white,
size: getProportionateScreenWidth(18),
),
SizedBox(
width: getProportionateScreenWidth(6),
),
Text(
'Tambah ke Wishlist',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 0.2),
),
],
)
: Row(
children: [
Consumer<wishlistProvider.WishlistProvider>(
builder: (context, state, _) {
if (state.state ==
wishlistProvider.ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 1,
),
);
}
return Icon(
state.data.contains(dataDetailCourseModel.id)
? Icons.favorite_outlined
: Icons.favorite_border,
color:
state.data.contains(dataDetailCourseModel.id)
? Color(0xffCD2228)
: Colors.white,
size: getProportionateScreenWidth(18),
);
},
),
SizedBox(
width: getProportionateScreenWidth(6),
),
Consumer<wishlistProvider.WishlistProvider>(
builder: (contex, state, _) {
if (state.state ==
wishlistProvider.ResultState.Loading) {
return Text('');
}
return Text(
state.data.contains(dataDetailCourseModel.id)
? 'Sudah dalam wihslist'
: 'Tambah ke Wishlist',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 0.2),
);
},
),
],
),
),
),
],
);
}
return Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(15),
right: getProportionateScreenWidth(15)),
width: SizeConfig.screenWidth,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(232),
child: Text(dataDetailCourseModel.title ?? ' ',
style: primaryTextStyle.copyWith(
letterSpacing: 0.1,
fontSize: getProportionateScreenHeight(14)),
maxLines: 3,
overflow: TextOverflow.ellipsis),
),
SizedBox(
height: getProportionateScreenHeight(13),
),
// Row(
// // crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// RatingBarIndicator(
// itemSize: getProportionateScreenWidth(10),
// rating: double.parse(
// dataDetailCourseModel.rating[0].avgRating != null
// ? '${dataDetailCourseModel.rating[0].avgRating}'
// : '5.0'),
// direction: Axis.horizontal,
// itemCount: 5,
// //itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
// itemBuilder: (context, _) =>
// FaIcon(FontAwesomeIcons.solidStar, color: primaryColor)),
// SizedBox(
// width: getProportionateScreenWidth(4),
// ),
// Text(
// double.parse(dataDetailCourseModel.rating[0].avgRating != null
// ? '${dataDetailCourseModel.rating[0].avgRating}'
// : '5.0')
// .toString(),
// style: primaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(10),
// color: secondaryColor,
// fontWeight: reguler),
// ),
// SizedBox(
// width: getProportionateScreenWidth(4),
// ),
// Text(
// // '(${course.numberOfRatings.toString()})',
// '(${dataDetailCourseModel.rating[0].totalReview})',
// style: primaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(10),
// color: secondaryColor,
// fontWeight: reguler),
// ),
// ],
// ),
SizedBox(
height: getProportionateScreenHeight(9),
),
MuridAndRating(
dataDetailCourseModel: dataDetailCourseModel,
),
SizedBox(
height: getProportionateScreenHeight(16),
),
imageCourse(),
SizedBox(
height: getProportionateScreenHeight(11),
),
// Consumer<detailCourseProv.DetailCourseProvider>(
// builder: (context, state, _) {
// if (state.state == detailCourseProv.ResultState.HasData) {
// var detailCourse = state.result!.data[0][0];
// if (detailCourse.isMine == 1) {
// return Container();
// } else {
// return buttonKuponWishlist();
// }
// } else {
// return Container();
// }
// },
// ),
buttonKuponWishlist(),
SizedBox(
height: getProportionateScreenHeight(11),
),
],
),
);
}
}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import '../../../size_config.dart';
import '../../../theme.dart';
class InstructorStudentsCourses extends StatelessWidget {
const InstructorStudentsCourses(
{Key? key, required this.course, required this.murid})
: super(key: key);
final String murid;
final String course;
@override
Widget build(BuildContext context) {
return Row(
children: [
Text(
' $murid Murid',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10), letterSpacing: 0.5),
),
SizedBox(width: getProportionateScreenWidth(10)),
Text(
' $course Kursus',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10), letterSpacing: 0.5),
)
],
);
}
}

View File

@ -0,0 +1,229 @@
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class Instruktur extends StatefulWidget {
const Instruktur({
Key? key,
required this.id,
this.instructor,
this.bio,
this.rating,
this.review,
this.totalStudent,
this.totalLesson,
this.video = false,
this.fotoProfile,
this.headline,
}) : super(key: key);
final String id;
final String? instructor;
final String? bio;
final String? rating;
final String? review;
final String? fotoProfile;
final String? totalLesson;
final String? totalStudent;
final String? headline;
final bool video;
@override
State<Instruktur> createState() => _InstrukturState();
}
class _InstrukturState extends State<Instruktur> {
bool isExpanded = false;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Instruktur Kursus',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 10),
Container(
decoration: BoxDecoration(
color: const Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 16),
Container(
margin: EdgeInsets.only(left: 10),
child: CircleAvatar(
radius: 40,
backgroundColor: Colors.amber,
backgroundImage: widget.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(widget.fotoProfile!)
as ImageProvider,
),
),
const SizedBox(height: 8),
Container(
margin: EdgeInsets.only(left: 10),
child: Text(
widget.instructor ?? '',
style: TextStyle(fontSize: 15),
),
),
SizedBox(height: 2),
widget.headline != null
? Container(
margin: EdgeInsets.only(left: 10),
child: Text(
widget.headline!,
style: TextStyle(fontSize: 13),
),
)
: const SizedBox(),
SizedBox(height: 10),
Container(
margin: EdgeInsets.only(left: 10),
child: Row(
children: [
RatingBarIndicator(
itemSize: 11,
rating: double.parse(widget.rating ?? '0'),
direction: Axis.horizontal,
itemCount: 5,
itemBuilder: (context, _) => const FaIcon(
FontAwesomeIcons.solidStar,
color: Colors.amber,
),
),
SizedBox(width: 4),
Text(
double.parse(widget.rating ?? '0').toString(),
style: TextStyle(fontSize: 10),
),
SizedBox(width: 4),
Text(
'(${widget.review ?? '0'})',
style: TextStyle(fontSize: 10),
),
],
),
),
Container(
height: 40,
margin: EdgeInsets.only(left: 10, top: 1),
child: Row(
children: [
Text(
'${widget.totalStudent ?? '0'} Murid',
style: primaryTextStyle.copyWith(
color: secondaryColor,
fontSize: getProportionateScreenWidth(10),
letterSpacing: 0.5),
),
SizedBox(width: 10),
Text(
'${widget.totalLesson ?? ''} Pelajaran',
style: primaryTextStyle.copyWith(
color: secondaryColor,
fontSize: getProportionateScreenWidth(10),
letterSpacing: 0.5),
)
],
),
),
if (widget.bio == null || widget.bio!.isEmpty)
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenHeight(10),
right: getProportionateScreenHeight(10),
bottom: getProportionateScreenHeight(10)),
child: Text(
'*Instruktur belum mencantumkan profil*',
style: TextStyle(
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
fontFamily: 'Noto Sans',
color: secondaryColor,
),
),
)
else
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenHeight(5),
right: getProportionateScreenHeight(10)),
child: isExpanded
? Html(
data: widget.bio,
style: {
"body": Style(
fontSize: FontSize(12),
fontWeight: reguler,
fontFamily: 'Noto Sans',
color: secondaryColor),
},
)
: Html(
data: widget.bio != null &&
widget.bio!.length > 200
? widget.bio!.substring(0, 200)
: widget.bio!,
style: {
"body": Style(
fontSize: FontSize(12),
fontWeight: reguler,
fontFamily: 'Noto Sans',
color: secondaryColor),
},
),
),
if (widget.bio!.isNotEmpty &&
(widget.bio!.length > 70 ||
widget.bio!.length > 200))
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenHeight(7)),
child: TextButton(
onPressed: () {
setState(() {
isExpanded = !isExpanded;
});
},
child: Text(
isExpanded
? 'Tampilkan Lebih Sedikit'
: 'Tampilkan Lebih Banyak',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
color: primaryColor,
fontSize: getProportionateScreenWidth(12),
),
),
),
),
],
),
],
)
],
),
),
const SizedBox(height: 30)
],
),
);
}
}

View File

@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class KemampuainDiraihList extends StatelessWidget {
const KemampuainDiraihList({
Key? key,
required this.title,
}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 6),
child: Row(
children: [
Icon(Icons.check,
size: getProportionateScreenHeight(13), color: thirdColor),
SizedBox(
width: 10,
),
Expanded(
child: Align(
alignment: Alignment.topLeft,
// TODO : saat teks menjadi 2 baris menjadi tidak sejajar perlu dirapihkan
child: Text(
// TODO : MAX 75 Chareacters
title,
style: primaryTextStyle.copyWith(
color: secondaryColor,
fontSize: getProportionateScreenWidth(12),
letterSpacing: 0.5),
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class KursusIncludeItems extends StatelessWidget {
const KursusIncludeItems({Key? key, this.svg, required this.text})
: super(key: key);
final String? svg;
final String text;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(left: getProportionateScreenWidth(16)),
child: Column(
children: [
Row(
children: [
SvgPicture.asset(
svg!,
width: getProportionateScreenWidth(13),
height: getProportionateScreenHeight(13),
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih
: fourthColor,
),
SizedBox(width: getProportionateScreenWidth(9)),
Expanded(
child: Text(
text,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: light,
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(6)),
],
),
);
}
}

View File

@ -0,0 +1,262 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/posting_review_provider.dart';
import 'package:initial_folder/providers/whislist_provider.dart'
as wishlistProvider;
import 'package:initial_folder/providers/wishlist_post_provider.dart';
import 'package:initial_folder/screens/login/login_screen.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class MuridAndRating extends StatelessWidget {
const MuridAndRating({Key? key, required this.dataDetailCourseModel})
: super(key: key);
final DataDetailCourseModel dataDetailCourseModel;
@override
Widget build(BuildContext context) {
WishlistPostProvider wishlistPostProvider =
Provider.of<WishlistPostProvider>(context);
Future _showDialogNotLogin() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum menambahkan ke wishlist',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
SizedBox(
width: getProportionateScreenWidth(5),
),
GestureDetector(
onTap: () => Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false),
child: Text('Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
],
),
);
}
// Future _showMessage() {
// return showDialog(
// context: context,
// builder: (context) => AlertDialog(
// contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
// content: Text(
// 'Berhasil menambahkan kursus ke wishlist',
// textAlign: TextAlign.center,
// style: primaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
// ),
// ),
// );
// }
addWishlist() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 1),
backgroundColor: Colors.red[600],
content: Text(
'No Internet Connections',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
} else {
await wishlistPostProvider
.addWishlist(int.parse(dataDetailCourseModel.id));
await Provider.of<wishlistProvider.WishlistProvider>(context,
listen: false)
.getWishlist();
await Provider.of<CartProvider>(context, listen: false)
.addCart(dataDetailCourseModel.id);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
}
}
addWishlistNotExist() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 1),
backgroundColor: Colors.red[600],
content: Text(
'No Internet Connections',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
} else {
await wishlistPostProvider
.addWishlist(int.parse(dataDetailCourseModel.id));
await Provider.of<wishlistProvider.WishlistProvider>(context,
listen: false)
.getWishlist();
}
}
// deleteWishlist() async {
// var connectivityResult = await (Connectivity().checkConnectivity());
// if (connectivityResult == ConnectivityResult.none) {
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// duration: Duration(seconds: 1),
// backgroundColor: Colors.red[600],
// content: Text(
// 'No Internet Connections',
// textAlign: TextAlign.center,
// style: primaryTextStyle.copyWith(color: Colors.white),
// ),
// behavior: SnackBarBehavior.floating,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(5),
// ),
// ),
// );
// } else {
// await wishlistPostProvider
// .addWishlist(int.parse(dataDetailCourseModel.id));
// }
// }
checkUser() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
addWishlist();
} else {
return _showDialogNotLogin();
}
}
wishlistExist() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
addWishlistNotExist();
} else {
return _showDialogNotLogin();
}
}
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(15)),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset(
"assets/icons/student.svg",
width: getProportionateScreenWidth(17),
height: getProportionateScreenHeight(17),
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih
: fourthColor,
),
SizedBox(width: getProportionateScreenWidth(4)),
Text(
' ${dataDetailCourseModel.totalStudents != null ? dataDetailCourseModel.totalStudents : "0"} Murid',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: medium,
),
)
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
dataDetailCourseModel.rating[0].avgRating != null &&
dataDetailCourseModel.rating[0].avgRating != 0
? Text(
double.parse('${dataDetailCourseModel.rating[0].avgRating}')
.toString(),
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
fontWeight: medium,
),
)
: SizedBox.shrink(),
SizedBox(width: getProportionateScreenWidth(4)),
RatingBarIndicator(
itemPadding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(2)),
itemSize: getProportionateScreenWidth(13),
rating: dataDetailCourseModel.rating[0].avgRating != null &&
dataDetailCourseModel.rating[0].avgRating != 0
? double.parse('${dataDetailCourseModel.rating[0].avgRating}')
: 5.0,
direction: Axis.horizontal,
itemCount: 5,
itemBuilder: (context, _) => FaIcon(
FontAwesomeIcons.solidStar,
color: thirteenColor,
),
),
if (dataDetailCourseModel.rating[0].totalReview != null &&
int.tryParse('${dataDetailCourseModel.rating[0].totalReview}') != null &&
int.parse('${dataDetailCourseModel.rating[0].totalReview}') > 0)
...[
SizedBox(width: getProportionateScreenWidth(4)),
Text(
'(${dataDetailCourseModel.rating[0].totalReview} Reviews)',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: medium,
),
),
]
else
SizedBox.shrink(),
],
),
],
),
),
);
}
}

View File

@ -0,0 +1,283 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/posting_review_provider.dart';
import 'package:initial_folder/providers/whislist_provider.dart'
as wishlistProvider;
import 'package:initial_folder/providers/wishlist_post_provider.dart';
import 'package:initial_folder/screens/login/login_screen.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class MuridAndWhislist extends StatelessWidget {
const MuridAndWhislist({Key? key, required this.dataDetailCourseModel})
: super(key: key);
final DataDetailCourseModel dataDetailCourseModel;
@override
Widget build(BuildContext context) {
WishlistPostProvider wishlistPostProvider =
Provider.of<WishlistPostProvider>(context);
Future _showDialogNotLogin() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum menambahkan ke wishlist',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
SizedBox(
width: getProportionateScreenWidth(5),
),
GestureDetector(
onTap: () => Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false),
child: Text('Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
],
),
);
}
// Future _showMessage() {
// return showDialog(
// context: context,
// builder: (context) => AlertDialog(
// contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
// content: Text(
// 'Berhasil menambahkan kursus ke wishlist',
// textAlign: TextAlign.center,
// style: primaryTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
// ),
// ),
// );
// }
addWishlist() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 1),
backgroundColor: Colors.red[600],
content: Text(
'No Internet Connections',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
} else {
await wishlistPostProvider
.addWishlist(int.parse(dataDetailCourseModel.id));
await Provider.of<wishlistProvider.WishlistProvider>(context,
listen: false)
.getWishlist();
await Provider.of<CartProvider>(context, listen: false)
.addCart(dataDetailCourseModel.id);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
}
}
addWishlistNotExist() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 1),
backgroundColor: Colors.red[600],
content: Text(
'No Internet Connections',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
} else {
await wishlistPostProvider
.addWishlist(int.parse(dataDetailCourseModel.id));
await Provider.of<wishlistProvider.WishlistProvider>(context,
listen: false)
.getWishlist();
}
}
// deleteWishlist() async {
// var connectivityResult = await (Connectivity().checkConnectivity());
// if (connectivityResult == ConnectivityResult.none) {
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// duration: Duration(seconds: 1),
// backgroundColor: Colors.red[600],
// content: Text(
// 'No Internet Connections',
// textAlign: TextAlign.center,
// style: primaryTextStyle.copyWith(color: Colors.white),
// ),
// behavior: SnackBarBehavior.floating,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(5),
// ),
// ),
// );
// } else {
// await wishlistPostProvider
// .addWishlist(int.parse(dataDetailCourseModel.id));
// }
// }
checkUser() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
addWishlist();
} else {
return _showDialogNotLogin();
}
}
wishlistExist() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
addWishlistNotExist();
} else {
return _showDialogNotLogin();
}
}
return Container(
child: Row(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.people_outline,
color: Colors.white,
size: getProportionateScreenWidth(22),
),
SizedBox(width: getProportionateScreenWidth(4)),
Text(
' ${dataDetailCourseModel.totalStudents} Murid',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
letterSpacing: 0.5),
)
],
),
SizedBox(
width: getProportionateScreenWidth(15),
),
// Consumer<WishlistProvider>(builder: (context, state, _) {
// return Text(state.data.contains(dataDetailCourseModel.id)
// ? 'ada di wishlist'
// : 'ga ada');
// }),
GestureDetector(
onTap: Provider.of<CartsProvider>(context)
.data
.contains(dataDetailCourseModel.id)
? checkUser
: wishlistExist,
child: !Condition.loginEmail
? Row(
children: [
Icon(
Icons.favorite_border,
color: Colors.white,
size: getProportionateScreenWidth(22),
),
SizedBox(
width: getProportionateScreenWidth(4),
),
Text(
'Tambah ke wishlist',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
letterSpacing: 0.2),
),
],
)
: Row(
children: [
Consumer<wishlistProvider.WishlistProvider>(
builder: (context, state, _) {
if (state.state ==
wishlistProvider.ResultState.Loading) {
return Container(
height: 15,
width: 15,
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 1,
),
);
}
return Icon(
state.data.contains(dataDetailCourseModel.id)
? Icons.favorite_outlined
: Icons.favorite_border,
color: state.data.contains(dataDetailCourseModel.id)
? Color(0xffCD2228)
: Colors.white,
size: getProportionateScreenWidth(22),
);
},
),
SizedBox(
width: getProportionateScreenWidth(4),
),
Consumer<wishlistProvider.WishlistProvider>(
builder: (contex, state, _) {
if (state.state ==
wishlistProvider.ResultState.Loading) {
return Text('');
}
return Text(
state.data.contains(dataDetailCourseModel.id)
? 'Sudah dalam wihslist'
: 'Tambah ke wishlist',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
letterSpacing: 0.2),
);
},
),
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/tab_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class TabBarItems extends StatelessWidget {
final int index;
final String title;
const TabBarItems({
Key? key,
required this.index,
required this.title,
}) : super(key: key);
@override
Widget build(BuildContext context) {
TabProvider tab = Provider.of<TabProvider>(context, listen: false);
return GestureDetector(
onTap: () {
tab.currentIndex = index;
},
child: Container(
child: Column(
children: [
Text(
title,
style: thirdTextStyle.copyWith(
color: tab.currentIndex == index
? Theme.of(context).brightness == Brightness.light
? primaryColorligtmode
: primaryColor
: fifteenColor,
fontSize: getProportionateScreenWidth(12),
fontWeight: semiBold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Container(
width: getProportionateScreenWidth(58),
height: getProportionateScreenHeight(2),
decoration: BoxDecoration(
color: tab.currentIndex == index
? Theme.of(context).brightness == Brightness.light
? primaryColorligtmode
: primaryColor
: Colors.transparent,
borderRadius:
BorderRadius.circular(getProportionateScreenHeight(19)),
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/screens/home/components/body_comp/course_terkait.dart';
import 'package:initial_folder/size_config.dart';
class Terkait extends StatelessWidget {
const Terkait({
Key? key,
this.idCategory,
}) : super(key: key);
final String? idCategory;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(20),
left: getProportionateScreenWidth(10),
),
child: Container(
height: getProportionateScreenHeight(240),
child: Column(
children: [
Expanded(
child: CourseTerkait(
name: "",
categoryId: idCategory ?? "",
subId: "",
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,430 @@
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<Ulasan> {
int _currentPage = 1;
int _totalPages = 1;
List<DataReview> _filteredReviews = []; // Menyimpan review yang sudah difilter
// Fungsi untuk membatasi ulasan per halaman
List<DataReview> _getPaginatedReviews(List<DataReview> reviews) {
int startIndex = (_currentPage - 1) * 5;
int endIndex = startIndex + 5;
return reviews.sublist(startIndex, endIndex.clamp(0, reviews.length));
}
void _filterReviews(int rating, List<DataReview> 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>[
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<DetailRatingCourseProvider>(
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<dynamic>
? '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<dynamic>
? 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<DetailRatingCourseProvider>(
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<DetailRatingCourseProvider>(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);
}

View File

@ -0,0 +1,770 @@
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/cart_provider.dart' as cartProvider;
import 'package:initial_folder/providers/carts_provider.dart' as cartsProvider;
import 'package:initial_folder/providers/detail_course_coupon_provider.dart';
import 'package:initial_folder/providers/detail_rating_course_provider.dart'
as detailRatingCourseProvider;
import 'package:initial_folder/providers/instructor_provider.dart'
as instructorProvider;
import 'package:initial_folder/providers/lesson_course_provider.dart'
as lessonCourseProvider;
import 'package:initial_folder/providers/my_course_provider.dart'
as myCourseProvider;
import 'package:initial_folder/providers/order_provider.dart' as orderProvider;
import 'package:initial_folder/providers/payments_provider.dart'
as paymentsProvider;
import 'package:initial_folder/providers/section_lesson_course_provider.dart'
as sectionLessonCourseProvider;
import 'package:initial_folder/providers/tab_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/providers/whislist_provider.dart'
as wishlistProvider;
import 'package:initial_folder/providers/wishlist_post_provider.dart';
import 'package:initial_folder/screens/cart/cart_page.dart';
import 'package:initial_folder/screens/checkout/checkout_coupon_page.dart';
import 'package:initial_folder/screens/checkout/checkout_page.dart';
import 'package:initial_folder/screens/course/play_course_page.dart';
import 'package:initial_folder/screens/detail_course/components/header_coupon.dart';
import 'package:initial_folder/screens/login/login_screen.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/screens/my_course/success_free_course.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/screens/detail_course/components/app_bar.dart';
import 'package:initial_folder/screens/detail_course/components/custom_tab_bar.dart';
import 'package:initial_folder/screens/detail_course/components/header.dart';
import 'package:initial_folder/services/course_service.dart';
import 'package:initial_folder/services/instructor_service.dart';
import 'package:initial_folder/services/lesson_course_service.dart';
import 'package:initial_folder/services/section_lesson_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class DetailCourseCouponScreen extends StatelessWidget {
const DetailCourseCouponScreen(
{Key? key, required this.idcourse, required this.coupon})
: super(key: key);
final String idcourse;
final String coupon;
static String routeName = "/course_detail";
@override
Widget build(BuildContext context) {
final typeCoupon = Provider.of<TotalPriceProvider>(context).typeCoupon;
final selected = Provider.of<TotalPriceProvider>(context);
// Provider.of<orderProvider.OrderProvider>(context).clearOrder();
// Provider.of<orderProvider.OrderProvider>(context).clearInvoice();
paymentsProvider.PaymentsProvider pay =
Provider.of<paymentsProvider.PaymentsProvider>(context);
SizeConfig().init(context);
showNotifDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Consumer<paymentsProvider.PaymentsProvider>(
builder: (context, state, child) {
if (state.state == paymentsProvider.ResultState.gagal) {
return Container(
height: getProportionateScreenHeight(40),
width: getProportionateScreenWidth(15),
child: Center(
child: Text(
'Anda sudah memiliki kursus ini',
style: primaryTextStyle.copyWith(fontSize: 12),
textAlign: TextAlign.center,
),
),
);
} else {
return Text(
'Erorr lain',
style: thirdTextStyle,
);
}
},
),
);
},
// barrierDismissible: false,
);
}
Future _showDialogNotLogin(String teks) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 1),
content: Text(
'Mohon login terlebih dahulu sebelum $teks',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
actions: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Batal',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
SizedBox(
width: getProportionateScreenWidth(5),
),
GestureDetector(
onTap: () {
Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false);
},
child: Text('Login',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: primaryColor)),
),
],
),
);
}
Future<void> _showMessage() {
return showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Consumer<cartProvider.CartProvider>(
builder: (context, state, _) {
if (state.state == cartProvider.ResultState.loading) {
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
blurRadius: 10,
offset: Offset(0, -1),
)
],
borderRadius: BorderRadius.vertical(
top: Radius.circular(10),
),
color: Color(0xff242424),
),
height: getProportionateScreenHeight(200),
child: Center(
child: CircularProgressIndicator(
strokeWidth: 1,
color: primaryColor,
),
));
} else if (state.state == cartProvider.ResultState.succes) {
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
blurRadius: 10,
offset: Offset(0, -1),
)
],
borderRadius: BorderRadius.vertical(
top: Radius.circular(10),
),
color: Color(0xff242424),
),
height: getProportionateScreenHeight(200),
child: Column(
children: [
Row(
children: [
IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: Icon(
Icons.close,
color: secondaryColor,
size: 15,
)),
],
),
Icon(
Icons.check_rounded,
size: 40,
color: eightColor,
),
SizedBox(
height: getProportionateScreenWidth(15),
),
Text(
'Berhasil menambahkan kursus ke keranjang',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockHorizontal! * 4,
letterSpacing: 0.5),
),
SizedBox(
height: getProportionateScreenWidth(4),
),
TextButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.all(sixColor),
padding: MaterialStateProperty.all(
EdgeInsets.symmetric(vertical: 1, horizontal: 1),
),
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CartPage(
idcourse: idcourse,
)));
},
child: Text(
'Lihat keranjang',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
letterSpacing: 0.5,
color: primaryColor),
),
),
],
),
);
} else if (state.state == cartProvider.ResultState.failed) {
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
blurRadius: 10,
offset: Offset(0, -1),
)
],
borderRadius: BorderRadius.vertical(
top: Radius.circular(10),
),
color: Color(0xff242424),
),
height: getProportionateScreenHeight(200),
child: Column(
children: [
Row(
children: [
IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: Icon(
Icons.close,
color: secondaryColor,
size: 15,
)),
],
),
Icon(
Icons.check_rounded,
size: 40,
color: eightColor,
),
SizedBox(
height: getProportionateScreenWidth(15),
),
Text(
'Berhasil menghapus kursus dari keranjang',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockHorizontal! * 4,
letterSpacing: 0.5),
),
SizedBox(
height: getProportionateScreenWidth(4),
),
TextButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.all(sixColor),
padding: MaterialStateProperty.all(
EdgeInsets.symmetric(vertical: 1, horizontal: 1),
),
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CartPage(
idcourse: idcourse,
)));
},
child: Text(
'Lihat keranjang',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
letterSpacing: 0.5,
color: primaryColor),
),
),
],
),
);
} else {
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
blurRadius: 10,
offset: Offset(0, -1),
)
],
borderRadius: BorderRadius.vertical(
top: Radius.circular(10),
),
color: Color(0xff242424),
),
height: getProportionateScreenHeight(200),
child: Center(
child: Text('Terjadi Kesalahan'),
));
}
});
},
);
}
handleNotLogin() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
_showMessage();
await Provider.of<cartProvider.CartProvider>(context, listen: false)
.addCart(int.parse(idcourse));
await Provider.of<cartsProvider.CartsProvider>(context, listen: false)
.getCarts();
await Provider.of<WishlistPostProvider>(context, listen: false)
.addWishlist(int.parse(idcourse));
await Provider.of<wishlistProvider.WishlistProvider>(context,
listen: false)
.getWishlist();
// cartsDatabaseProvider.setCarts(id);
} else {
String teks = 'menambahkan ke keranjang';
return _showDialogNotLogin(teks);
}
}
handleNotLoginWishlistNotExist() async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
_showMessage();
await Provider.of<cartProvider.CartProvider>(context, listen: false)
.addCart(int.parse(idcourse));
await Provider.of<cartsProvider.CartsProvider>(context, listen: false)
.getCarts();
} else {
String teks = 'menambahkan ke keranjang';
return _showDialogNotLogin(teks);
}
}
handleNotLoginBuy(
{required String title,
required String price,
required String discountPrice,
required String instructor,
required String imageUrl}) async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
Provider.of<orderProvider.OrderProvider>(context, listen: false)
.clear();
Provider.of<orderProvider.OrderProvider>(context, listen: false)
.addOrder(
id: idcourse,
title: title,
price: price,
discountPrice: discountPrice,
imageUrl: imageUrl,
instructor: instructor,
);
Provider.of<orderProvider.OrderProvider>(context, listen: false)
.getTotalPrice(discountPrice);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CheckoutCouponPage(
discountPrice: discountPrice,
idCourse: idcourse,
instructor: instructor,
title: title,
price: price,
coupon: coupon,
)));
} else {
String teks = 'membeli kursus';
return _showDialogNotLogin(teks);
}
}
handleNotLoginFree(
String? id,
String? title,
String? thumb,
String? instr,
) async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
if (await pay.freeCourse(int.parse(idcourse))) {
await Provider.of<myCourseProvider.MyCourseProvider>(context,
listen: false)
.getMyCourse();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SuccessFreeCourse(
id: id,
thumbnail: thumb,
title: title,
instructor: instr,
)));
} else {
showNotifDialog(context);
}
} else {
String teks = 'memiliki kursus ini';
return _showDialogNotLogin(teks);
}
}
Widget freeBottomNav(String? courseId, String? instructor,
String? thumbnail, String? title) {
return Container(
width: double.infinity,
height: getProportionateScreenHeight(60),
decoration: BoxDecoration(
border:
Border.symmetric(horizontal: BorderSide(color: fourthColor)),
boxShadow: [
BoxShadow(
offset: Offset(0, -2),
blurRadius: 50,
color: fourthColor.withOpacity(0.15))
]),
child: Row(
children: [
SizedBox(
width: 13,
),
Text(
'Gratis',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenHeight(20),
letterSpacing: 0.23),
),
Spacer(),
GestureDetector(
onTap: () =>
handleNotLoginFree(courseId, title, thumbnail, instructor),
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(123),
height: getProportionateScreenHeight(33),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5)),
child: Center(
child: Consumer<paymentsProvider.PaymentsProvider>(
builder: (context, state, _) {
if (state.stateProcess ==
paymentsProvider.Process.uninitialized) {
return Text(
'Miliki sekarang',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockHorizontal! * 3.5,
letterSpacing: 0.085,
color: Color(0xff181818),
),
);
} else if (state.stateProcess ==
paymentsProvider.Process.loading) {
return Container(
width: 20,
height: 20,
child: CircularProgressIndicator(
color: eightColor,
strokeWidth: 2,
),
);
}
return Text(
'Miliki sekarang',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockHorizontal! * 3.5,
letterSpacing: 0.085,
color: Color(0xff181818),
),
);
}),
),
),
),
],
),
);
}
Widget playCourseNav(String? courseId, String? instructor,
String? thumbnail, String? title) {
return Container(
width: double.infinity,
height: getProportionateScreenHeight(60),
decoration: BoxDecoration(
border:
Border.symmetric(horizontal: BorderSide(color: fourthColor)),
boxShadow: [
BoxShadow(
offset: Offset(0, -2),
blurRadius: 50,
color: fourthColor.withOpacity(0.15))
]),
child: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size(getProportionateScreenWidth(90),
getProportionateScreenHeight(33)),
backgroundColor: primaryColor,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) =>
lessonCourseProvider.LessonCourseProvider(
lessonCourseService: LessonCourseService(),
id: int.parse(courseId ?? '0'),
),
),
ChangeNotifierProvider(
create: (context) => DetailCourseCouponProvider(
courseService: CourseService(),
id: courseId ?? '1',
coupon: coupon))
],
child: PlayCourse(
judul: title ?? '',
instruktur: instructor ?? '',
thumbnail: thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
courseeid: idcourse,
),
),
),
);
},
child: Text(
'Lanjutkan Belajar',
style: thirdTextStyle.copyWith(color: Colors.black),
),
),
));
}
Widget bottomNav(
{required String discountPrice,
required String idCourse,
required String title,
required String price,
required String instructor,
required String imageUrl}) {
return Container(
width: double.infinity,
height: getProportionateScreenHeight(60),
decoration: BoxDecoration(
border:
Border.symmetric(horizontal: BorderSide(color: fourthColor)),
boxShadow: [
BoxShadow(
offset: Offset(0, -2),
blurRadius: 50,
color: fourthColor.withOpacity(0.15))
]),
child: Row(
children: [
SizedBox(
width: 13,
),
Text(
numberFormat(discountPrice.toString().replaceAll('.', '')),
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenHeight(20),
letterSpacing: 0.23),
),
Spacer(),
Container(
width: getProportionateScreenWidth(39),
height: getProportionateScreenHeight(34),
decoration: BoxDecoration(
border: Border.all(color: primaryColor),
borderRadius: BorderRadius.circular(5),
),
child: Consumer<wishlistProvider.WishlistProvider>(
builder: (context, state, _) {
return IconButton(
padding: EdgeInsets.zero,
splashRadius: 17,
onPressed: () => state.data.contains(idcourse)
? handleNotLogin()
: handleNotLoginWishlistNotExist(),
icon: Icon(FeatherIcons.shoppingCart,
color: primaryColor, size: 20),
);
}),
),
// ),
SizedBox(
width: getProportionateScreenWidth(12),
),
GestureDetector(
onTap: () {
int total = int.parse(discountPrice);
selected.selectedTotalPrice =
total <= 50000 ? total + 5000 : total;
print("Ini total price buat ke va ${selected.totalPrice}");
handleNotLoginBuy(
title: title,
discountPrice: discountPrice,
imageUrl: imageUrl,
price: price,
instructor: instructor);
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(113),
height: getProportionateScreenHeight(33),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5)),
child: Center(
child: Text(
'Beli sekarang',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockHorizontal! * 3.5,
letterSpacing: 0.085,
color: Color(0xff181818),
),
)),
),
)
],
),
);
}
return SafeArea(
child: MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => DetailCourseCouponProvider(
courseService: CourseService(), id: idcourse, coupon: coupon),
),
ChangeNotifierProvider(
create: (context) =>
detailRatingCourseProvider.DetailRatingCourseProvider(
courseService: CourseService(), id: idcourse),
),
ChangeNotifierProvider(
create: (context) =>
sectionLessonCourseProvider.SectionLessonCourseProvider(
id: idcourse, sectionLessonService: SectionLessonService()),
),
],
child: Consumer<DetailCourseCouponProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
var detailCourse = state.result!;
return Scaffold(
body: ListView(
physics: ScrollPhysics(),
shrinkWrap: true,
children: [
AppBarHeader(
idcourse: idcourse,
),
HeaderCoupon(
dataDetailCourseModel: detailCourse,
),
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) =>
instructorProvider.InstructorProvider(
instructorService: InstructorService(),
id: int.parse(detailCourse.instructorId!)),
),
ChangeNotifierProvider(
create: (context) => TabProvider()),
],
child: CustomTabBar(
dataDetailCourseModel: detailCourse,
totalDuration: detailCourse.totalDuration,
bio: detailCourse.bio,
instructor: detailCourse.instructor,
rating: detailCourse.rating[0].avgRating.toString(),
review: detailCourse.rating[0].totalReview,
totalLesson: detailCourse.totalLesson,
totalStudent: detailCourse.totalStudents,
),
),
]
// var finalRating = double.parse(
),
bottomNavigationBar: (detailCourse.isMine == 1)
? playCourseNav(
detailCourse.id,
detailCourse.instructor,
detailCourse.thumbnail,
detailCourse.title,
)
: (detailCourse.isFreeCourse == '1' || typeCoupon == '1')
? freeBottomNav(
detailCourse.id,
detailCourse.instructor,
detailCourse.thumbnail,
detailCourse.title,
)
: bottomNav(
discountPrice: detailCourse.discountPrice ?? ' ',
idCourse: detailCourse.id,
instructor: detailCourse.instructor ?? '',
price: detailCourse.price ?? '',
title: detailCourse.title ?? '',
imageUrl: detailCourse.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'),
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('Server internal Error'),
],
),
);
} else {
return Center(child: Text(''));
}
},
),
),
);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff