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

0
lib/screens/.gitkeep Normal file
View File

View File

@ -0,0 +1,874 @@
import 'dart:async';
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/models/carts_model.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/cart/components/cart_list.dart';
import 'package:initial_folder/screens/checkout/checkout_cart_page.dart';
import 'package:initial_folder/screens/checkout/components/field_kupon.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:provider/provider.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:initial_folder/providers/order_provider.dart' as orderProv;
import 'package:initial_folder/providers/radeem_voucher_provider.dart'
as radeemVoucher;
class CartPage extends StatefulWidget {
const CartPage({
Key? key,
this.idcourse,
this.cartsModel,
this.isiVoucher,
}) : super(key: key);
final String? idcourse;
final DataCartsModel? cartsModel;
final String? isiVoucher;
@override
State<CartPage> createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<CartsProvider>(context, listen: false).getCarts();
});
}
bool isChecked = true;
Set<int> selectedItems = {};
bool isMultiSelectionMode = false;
bool isToastShowing = false;
void _onItemLongPressed(int index) {
setState(() {
isMultiSelectionMode = true;
selectedItems.add(index);
});
}
void _onItemTapped(int index) {
// setState(() {
// if (selectedItems.contains(index)) {
// selectedItems.remove(index);
// if (selectedItems.isEmpty) {
// isMultiSelectionMode = false;
// }
// } else {
// selectedItems.add(index);
// }
// });
}
void _selectAllItems(bool selectAll, int itemCount) {
setState(() {
if (selectAll) {
for (int i = 0; i < itemCount; i++) {
selectedItems.add(i);
}
} else {
selectedItems.clear();
}
isChecked = selectAll;
});
}
void _showToast(String message) {
isToastShowing = true;
CherryToast.error(
title: Text(message),
animationDuration: Durations.medium1,
animationType: AnimationType.fromTop,
autoDismiss: true,
).show(context);
Timer(Duration(seconds: 2), () {
isToastShowing = false;
});
}
@override
Widget build(BuildContext context) {
List<String> idCarts = [];
Provider.of<orderProv.OrderProvider>(context, listen: false).clear();
TextEditingController kuponController = TextEditingController();
var kuponIsApplied = TextEditingController();
final selectedTotalPrice = Provider.of<TotalPriceProvider>(context);
Widget _validasiKupon() {
return Dialog(
elevation: 5.0,
child: Padding(
padding: const EdgeInsets.all(29),
child: Text(
'Kupon tidak valid atau sudah habis',
textAlign: TextAlign.center,
),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
);
}
Widget kupon(List<String> idKursus) {
Provider.of<orderProv.OrderProvider>(context).clear();
return Consumer<CartsProvider>(
builder: (context, state, _) {
var resultData = state.result!.data.length;
for (var i = 0; i <= resultData - 1; i++) {
if (state.result?.data[i].coupon != null) {
kuponIsApplied = TextEditingController(
text: state.result?.data[i].coupon?.codeCoupon ?? '');
return Column(
children: [
Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(4),
top: getProportionateScreenHeight(14)),
child: FieldKupon(
prefix: IconButton(
onPressed: () async {
await Provider.of<
radeemVoucher
.RadeemVoucherProvider>(context,
listen: false)
.deleteCoupon(kuponIsApplied.text);
kuponIsApplied.text = '';
kuponIsApplied.clear();
Provider.of<orderProv.OrderProvider>(context,
listen: false)
.clear();
await Provider.of<CartsProvider>(context,
listen: false)
.getCarts();
},
icon: Icon(Icons.close),
iconSize: 15,
color: secondaryColor,
),
controler: kuponIsApplied,
),
),
),
SizedBox(width: getProportionateScreenWidth(13)),
Container(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(12),
vertical: getProportionateScreenHeight(8),
),
),
onPressed: () async {
final voucher = kuponIsApplied.text;
if (await Provider.of<
radeemVoucher.RadeemVoucherProvider>(
context,
listen: false)
.redeemVoucherCart(
idKursus,
voucher,
)) {
kuponIsApplied = TextEditingController(
text: state
.result?.data.last.coupon?.codeCoupon);
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => CartPage(),
),
);
} else {
showDialog(
barrierColor: Color.fromARGB(70, 24, 24, 24),
context: context,
builder: (context) {
return _validasiKupon();
},
);
}
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Gunakan',
textAlign: TextAlign.start,
style: thirdTextStyle.copyWith(
color: baruTextutih,
fontSize: getProportionateScreenWidth(13),
fontWeight: reguler,
),
),
SizedBox(width: getProportionateScreenWidth(8)),
Image.asset(
"assets/icons/cart_gunakan.png",
color: baruTextutih,
width: getProportionateScreenWidth(16),
),
],
),
),
),
],
),
],
);
}
}
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(4),
top: getProportionateScreenHeight(14)),
child: FieldKupon(
controler: kuponController,
),
),
),
SizedBox(width: 14),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(12),
vertical: getProportionateScreenHeight(8),
),
),
onPressed: () async {
final voucher = kuponController.text;
if (await Provider.of<
radeemVoucher.RadeemVoucherProvider>(context,
listen: false)
.redeemVoucherCart(idKursus, voucher)) {
Provider.of<CartsProvider>(context, listen: false)
.getCarts();
kuponController.clear();
} else {
showDialog(
barrierColor: Color.fromARGB(70, 24, 24, 24),
context: context,
builder: (context) {
return _validasiKupon();
},
);
}
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Gunakan',
textAlign: TextAlign.start,
style: thirdTextStyle.copyWith(
color: baruTextutih,
fontSize: getProportionateScreenWidth(13),
fontWeight: reguler,
),
),
SizedBox(width: getProportionateScreenWidth(8)),
Image.asset(
"assets/icons/cart_gunakan.png",
width: getProportionateScreenWidth(16),
color: baruTextutih,
),
],
),
),
],
)
],
);
},
);
}
Widget custombottomCart(
String price, String total, List<String> coursesId) {
return SingleChildScrollView(
child: Container(
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor.withOpacity(0.9)
: baruTextutih.withOpacity(0.3),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
top: getProportionateScreenHeight(12),
),
child: Row(
children: [
Text(
'Subtotal Harga Kursus',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
Spacer(),
SizedBox(width: getProportionateScreenWidth(8)),
if (int.parse(price) < 50000)
RichText(
text: TextSpan(
children: [
TextSpan(
text: numberFormat(total),
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.8,
),
),
WidgetSpan(
child: SizedBox(
width: getProportionateScreenWidth(8))),
TextSpan(
text: numberFormat(int.parse(price) < 50000
? (int.parse(price) - 5000).toString()
: price),
style: thirdTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.8,
color: Theme.of(context).colorScheme.onPrimary,
),
),
],
),
)
else
RichText(
text: TextSpan(
children: [
TextSpan(
text: "",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.8,
),
),
WidgetSpan(
child: SizedBox(
width: getProportionateScreenWidth(8))),
TextSpan(
text: numberFormat(price),
style: thirdTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.8,
color: Theme.of(context).colorScheme.onPrimary,
),
)
],
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(3)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Biaya Layanan',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
Text(
numberFormat(int.parse(price) < 50000 ? "5000" : "0"),
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(3)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Potongan Kupon',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
Text(
numberFormat("0"),
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(16)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Bayar',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 3.2,
),
),
Text(
numberFormat(price),
style: thirdTextStyle.copyWith(
fontWeight: bold,
fontSize: SizeConfig.blockHorizontal! * 3.2,
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(12)),
Consumer<CartsProvider>(
builder: (context, state, _) {
int _hasil = 0;
var priceDiscount = state.result!.data
.map((e) => int.parse(e.discountPrice ?? '0'))
.toList();
var diskonHarga = 0;
for (var i = 0; i < state.data.length; i++) {
diskonHarga += priceDiscount[i];
}
var potonganKupon = state.result!.potonganKupon;
return Container(
color: Theme.of(context).colorScheme.primaryContainer,
height: getProportionateScreenHeight(52),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Row(
children: [
// GestureDetector(
// onTap: () {
// _selectAllItems(
// !isChecked, state.result!.data.length);
// },
// child: Container(
// decoration: BoxDecoration(
// color: isChecked
// ? (Theme.of(context).brightness ==
// Brightness.light
// ? baruTexthitam
// : baruTextutih)
// : Theme.of(context).brightness ==
// Brightness.light
// ? baruTextutih
// : seventeenColor,
// shape: BoxShape.rectangle,
// border: Border.all(
// color: isChecked
// ? Theme.of(context).brightness ==
// Brightness.light
// ? baruTexthitam
// : baruTextutih
// : (Theme.of(context).brightness ==
// Brightness.light
// ? baruTexthitam.withOpacity(0.7)
// : Colors.grey),
// width: getProportionateScreenWidth(3),
// ),
// borderRadius: BorderRadius.circular(6),
// ),
// width: getProportionateScreenWidth(18),
// height: getProportionateScreenHeight(16),
// child: isChecked
// ? Icon(
// Icons.check,
// size: getProportionateScreenWidth(13),
// color: Theme.of(context)
// .colorScheme
// .background,
// )
// : null,
// ),
// ),
SizedBox(width: getProportionateScreenWidth(5)),
// Text(
// 'Semua',
// style: thirdTextStyle.copyWith(
// fontWeight: reguler,
// fontSize: SizeConfig.blockHorizontal! * 3,
// ),
// ),
SizedBox(width: getProportionateScreenWidth(13)),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Total',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 3.4,
),
),
Text(
numberFormat(price),
style: thirdTextStyle.copyWith(
fontWeight: bold,
fontSize: SizeConfig.blockHorizontal! * 3.8,
),
),
],
),
Spacer(),
Container(
child: DefaultButton(
isCart: true,
text: 'Checkout (${selectedItems.length})',
press: () {
if (!isToastShowing) {
if (selectedItems.isEmpty) {
_showToast("Anda belum memilih kursus!");
} else {
selectedTotalPrice.selectedTotalPrice =
int.parse(price);
setState(() {
if (potonganKupon != null) {
_hasil = potonganKupon;
}
});
Navigator.of(context).push(
CustomNavigator(
child: CheckoutCartPage(
idCart: idCarts,
potonganKupon: _hasil,
discountHarga: diskonHarga,
isCart: true,
),
),
);
}
}
},
),
),
],
),
),
);
},
),
],
),
),
);
}
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Keranjang',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Consumer<CartsProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
List<String> coursesId = [];
var carts = state.result!.data;
for (int i = 0; i < carts.length; i++) {
idCarts.add(carts[i].cartId!);
}
for (int i = 0; i < carts.length; i++) {
coursesId.add(carts[i].courseId!);
}
WidgetsBinding.instance.addPostFrameCallback((_) {
if (state.result != null && selectedItems.isEmpty) {
_selectAllItems(true, state.result!.data.length);
}
});
return Stack(
children: [
SingleChildScrollView(
child: Container(
margin:
EdgeInsets.only(left: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${state.result?.data.length} Kursus di Keranjang ',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(13)),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: state.result!.data.length,
itemBuilder: (context, index) {
var carts = state.result!.data[index];
Provider.of<orderProv.OrderProvider>(context)
.addOrder(
id: carts.courseId,
title: carts.title,
price: carts.price,
imageUrl: carts.thumbnail ??
'https://vocasia.id/uploads/thumbnails/course_thumbnails/course_thumbnail_default_63.jpg',
discountPrice: carts.finalPrice,
instructor: carts.instructor!,
);
bool isSelected = selectedItems.contains(index);
return GestureDetector(
onTap: () => _onItemTapped(index),
child: CartList(
idCourse: carts.courseId ?? '0',
id: carts.cartId ?? '',
image: carts.thumbnail ??
'https://vocasia.id/uploads/thumbnails/course_thumbnails/course_thumbnail_default_63.jpg',
title: carts.title ?? '',
instruktur: carts.instructor ?? '',
price: carts.price ?? '',
discountPrice: carts.finalPrice ?? '',
isSelected: isSelected,
),
);
},
),
SizedBox(height: 90),
],
),
),
),
],
);
} else if (state.state == ResultState.NoData) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: 48),
Container(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Center(
child: Column(
children: [
Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(100),
child: ColorFiltered(
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onPrimary,
BlendMode.srcATop,
),
child: Image.asset('assets/images/search.png'),
),
),
SizedBox(height: 16),
Text(
"Keranjang Kosong",
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: Theme.of(context).colorScheme.onPrimary,
),
),
SizedBox(height: 4),
Text(
"Keranjang kamu kosong, tetap berbelanja dan cari kursus",
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).colorScheme.onPrimary,
),
),
SizedBox(height: 16),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(78),
vertical: getProportionateScreenHeight(10)),
child: DefaultButton(
weight: reguler,
text: 'Belanja Kursus',
press: () {
Navigator.of(context).pop();
},
),
),
],
),
),
),
],
),
);
} else if (state.state == ResultState.Error) {
return AlertDialog(
title: const Text('Koneksi Internet'),
content: const Text('Terjadi Kesalahan'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
],
);
} else {
return Center(child: Text(''));
}
},
),
bottomNavigationBar: Consumer<CartsProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Container(
width: double.infinity,
height: getProportionateScreenHeight(121),
child: Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
),
);
} else if (state.state == ResultState.HasData) {
var total = state.result!.data.map((e) {
if (e.price != null && e.discountPrice != null) {
return int.parse(e.discountPrice!) == 0
? 0
: int.parse(e.price!);
} else {
return 0;
}
}).toList();
var result = 0;
for (var i = 0; i < total.length; i++) {
result += total[i];
}
Provider.of<orderProv.OrderProvider>(context)
.getTotalPrice((state.result?.totalPayment.toString() ?? '0'));
var carts = state.result!.data;
List<String> coursesId = [];
for (int i = 0; i < carts.length; i++) {
coursesId.add(carts[i].courseId!);
}
selectedTotalPrice.selectedSubTotal = result.toString();
return custombottomCart(
state.result?.totalPayment.toString() ?? '0',
result.toString(),
coursesId,
);
} else if (state.state == ResultState.NoData) {
return Text(
"",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
);
} else if (state.state == ResultState.Error) {
return Text('');
} else {
return Center(child: Text(''));
}
},
),
);
}
}
// Align(
// alignment: Alignment.bottomCenter,
// child: SingleChildScrollView(
// child: Container(
// padding: EdgeInsets.symmetric(
// horizontal: getProportionateScreenWidth(16)),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Promotions",
// style: thirdTextStyle.copyWith(
// fontWeight: semiBold,
// letterSpacing: 1,
// fontSize: SizeConfig.blockHorizontal! * 3.4,
// ),
// ),
// kupon(coursesId),
// ],
// ),
// ),
// ),
// ),

View File

@ -0,0 +1,325 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_svg/svg.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/providers/whislist_provider.dart';
import 'package:initial_folder/providers/wishlist_post_provider.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/carts_provider.dart' as cartsProv;
class CartList extends StatefulWidget {
const CartList({
Key? key,
required this.image,
required this.title,
required this.instruktur,
required this.price,
required this.id,
required this.idCourse,
this.discountPrice,
this.isSelected = false,
}) : super(key: key);
final String image, instruktur, title, price, id, idCourse;
final String? discountPrice;
final bool isSelected;
@override
State<CartList> createState() => _CartListState();
}
class _CartListState extends State<CartList> {
@override
Widget build(BuildContext context) {
final pageProvider = Provider.of<PageProvider>(context);
Future<void> getCartsLength() async {}
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Padding(
padding: EdgeInsets.only(bottom: getProportionateScreenHeight(20)),
child: Container(
width: getProportionateScreenWidth(330 + 108),
child: Stack(
children: [
Container(
height: getProportionateScreenHeight(98),
width: getProportionateScreenWidth(330),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: sixteenColor,
),
),
Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(9),
right: getProportionateScreenWidth(15),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 11,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(156),
height: getProportionateScreenWidth(88),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(widget.image),
),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
],
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: getProportionateScreenHeight(2)),
Text(
'oleh ${widget.instruktur}',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: light,
),
),
Visibility(
visible: widget.discountPrice != "0",
child: Text(
numberFormat(widget.discountPrice),
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
),
),
Visibility(
visible: widget.discountPrice == widget.price,
child: SizedBox(
height: getProportionateScreenHeight(2)),
),
Visibility(
visible: widget.discountPrice != widget.price,
child: Text(
numberFormat(widget.price),
style: thirdTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
color: secondaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
),
),
],
),
),
],
),
),
// widget.isSelected
// ? Padding(
// padding: EdgeInsets.only(
// top: getProportionateScreenHeight(13),
// left: getProportionateScreenWidth(6),
// ),
// child:
// SvgPicture.asset("assets/icons/cart_checklist.svg"),
// )
// : Padding(
// padding: EdgeInsets.only(
// top: getProportionateScreenHeight(13),
// left: getProportionateScreenWidth(6),
// ),
// child:
// SvgPicture.asset("assets/icons/cart_unchecklist.svg"),
// ),
widget.isSelected
? Container(
height: getProportionateScreenHeight(98),
width: getProportionateScreenWidth(330),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Theme.of(context).brightness == Brightness.light
? baruTexthitam.withOpacity(0.1)
: baruTexthitam.withOpacity(0.3),
),
)
: Container(),
Consumer<cartsProv.CartsProvider>(
builder: (context, state, _) {
if (state.state == cartsProv.ResultState.Loading) {
return CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () async {
await Provider.of<WishlistPostProvider>(context,
listen: false)
.addWishlist(int.parse(widget.idCourse));
await Provider.of<WishlistProvider>(context,
listen: false)
.getWishlist();
showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor:
Theme.of(context).colorScheme.background,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding:
EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(14)),
child: Text(
textAlign: TextAlign.left,
'Berhasil memindahkan kursus ke wishlist',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
),
),
),
actions: [
SizedBox(
width: getProportionateScreenWidth(10)),
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text(
'Kembali',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(12),
color: primaryColor,
),
),
),
SizedBox(
width: getProportionateScreenWidth(3)),
GestureDetector(
onTap: () {
pageProvider.currentIndex = 3;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
(route) => false);
},
child: Text(
'Lihat Wishlist',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(12),
color: primaryColor,
),
),
),
],
),
);
},
child: SvgPicture.asset(
"assets/icons/cart_wishlist.svg",
height: getProportionateScreenHeight(96),
width: getProportionateScreenWidth(45),
),
),
GestureDetector(
onTap: () async {
await Provider.of<CartProvider>(context,
listen: false)
.deleteCart(widget.id);
Provider.of<OrderProvider>(context, listen: false)
.removeOrder(
id: widget.idCourse,
title: widget.title,
price: widget.price,
imageUrl: widget.image,
discountPrice: widget.discountPrice,
instructor: widget.instruktur,
);
showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor:
Theme.of(context).colorScheme.background,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding:
EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(14)),
child: Text(
textAlign: TextAlign.center,
'Berhasil menghapus kursus',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
),
),
),
),
);
await Provider.of<cartsProv.CartsProvider>(context,
listen: false)
.getCarts();
},
child: SvgPicture.asset(
"assets/icons/cart_remove.svg",
height: getProportionateScreenHeight(96),
width: getProportionateScreenWidth(45),
),
),
],
);
}
},
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/certificate_provider.dart';
import 'package:initial_folder/screens/certificate/component/all_certificate_header.dart';
import 'package:initial_folder/screens/certificate/component/all_certificate_item.dart';
import 'package:provider/provider.dart';
import '../../size_config.dart';
import '../../theme.dart';
class AllCertificate extends StatelessWidget {
const AllCertificate({Key? key, this.isLogin}) : super(key: key);
final bool? isLogin;
@override
Widget build(BuildContext context) {
Future.delayed(Duration(seconds: 0), () async {
await Provider.of<CertificateProvider>(context, listen: false)
.getAllCertif();
});
return isLogin != null
? Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
),
body: Center(
child: Text("Silahkan login terlebih dahulu"),
),
)
: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Sertifikat',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16),
),
),
),
body: RefreshIndicator(
displacement: 40,
color: primaryColor,
onRefresh: () async {
await Provider.of<CertificateProvider>(context, listen: false)
.getAllCertif();
},
child: Padding(
padding: EdgeInsets.only(
top: getProportionateScreenWidth(5),
right: getProportionateScreenWidth(20),
left: getProportionateScreenWidth(20),
),
child: ListView(
children: [
CertificateHeader(),
CertificateItem(),
],
),
),
),
);
}
}

View File

@ -0,0 +1,155 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/certificate/all_certificate.dart';
import 'package:initial_folder/screens/certificate/certificatecheck/certificate_check.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:provider/provider.dart';
import '../../size_config.dart';
import '../../theme.dart';
class Certificate extends StatelessWidget {
const Certificate({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Cek Status Sertifikat',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16)),
)),
body: Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
"assets/images/undraw_certificate.png",
scale: getProportionateScreenHeight(2),
),
SizedBox(height: 10),
Text(
"Cek keaslian sertifikat atau cek sertifikat dari kursus yang anda miliki",
style: TextStyle(
fontSize: getProportionateScreenHeight(12),
fontWeight: reguler),
textAlign: TextAlign.center,
),
SizedBox(height: getProportionateScreenHeight(38)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
backgroundColor: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
padding: EdgeInsets.symmetric(
vertical: 5,
horizontal: getProportionateScreenWidth(5))),
onPressed: () {
Navigator.push(
context,
CustomNavigator(
child: CertificateCheck(),
),
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Verifikasi Sertifikat",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: baruTextutih,
fontWeight: reguler,
),
),
],
),
),
),
SizedBox(height: getProportionateScreenHeight(12)),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0.0,
foregroundColor: primaryColor,
backgroundColor:
Theme.of(context).colorScheme.background,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
side: BorderSide(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
width: getProportionateScreenWidth(1.5),
),
),
padding: EdgeInsets.symmetric(
vertical: 5,
horizontal: getProportionateScreenWidth(5),
),
),
onPressed: (!Condition.loginEmail &&
!Condition.loginFirebase)
? () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AllCertificate(
isLogin: false,
),
),
);
}
: () {
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: AllCertificate(),
),
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Sertifikat Saya",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
fontWeight: bold,
),
),
],
),
),
),
],
),
)
],
),
),
),
);
}
}

View File

@ -0,0 +1,195 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/models/check_certificate.model.dart';
import 'package:initial_folder/providers/certificate_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/certificate/certificatecheck/certificate_check_dialog.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:initial_folder/widgets/login_regist/loading_button.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart'; // Import package ini
class CertificateCheck extends StatefulWidget {
CertificateCheck({Key? key}) : super(key: key);
@override
State<CertificateCheck> createState() => _CertificateCheckState();
}
class _CertificateCheckState extends State<CertificateCheck> {
final certificateController = TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool isLoading = false;
bool failed = false;
bool faileds = false;
String? errorMessage;
String _iconPath = 'assets/icons/not_checklist.svg';
void handleCertificate() async {
final certificateCode = certificateController.text.trim();
if (certificateCode.isNotEmpty) {
final url = "https://vocasia.id?no-certificate=$certificateCode";
if (await canLaunch(url)) {
await launch(url);
} else {
setState(() {
errorMessage = 'Tidak dapat membuka link, coba lagi.';
});
}
} else {
setState(() {
errorMessage = 'Mohon masukkan kode sertifikat.';
});
}
}
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Verifikasi Sertifikat',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16)),
),
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(18),
vertical: getProportionateScreenHeight(10),
),
child: Center(
child: Column(
children: [
SizedBox(height: getProportionateScreenHeight(20)),
Image.asset('assets/images/certificate.png'),
SizedBox(height: getProportionateScreenHeight(50)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Nomor Sertifikat",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12)),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: secondaryColor.withOpacity(0.3),
),
height: 40,
child: Form(
key: _formKey,
child: TextFormField(
autofocus: false,
controller: certificateController,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
),
cursorColor: secondaryColor,
decoration: InputDecoration(
border: InputBorder.none,
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: sevenColor),
borderRadius: BorderRadius.circular(10)),
contentPadding: EdgeInsets.only(
left: getProportionateScreenWidth(20),
bottom: getProportionateScreenHeight(8),
top: getProportionateScreenHeight(2),
),
hintText: 'Masukkan nomor sertifikat',
hintStyle: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: secondaryColor,
letterSpacing: 0.5,
),
suffixIcon: Transform.scale(
scale: 0.5,
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(15)),
child: SvgPicture.asset(_iconPath),
),
),
),
),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
if (errorMessage != null)
Center(
child: Text(
errorMessage!,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.red),
),
),
TextButton(
child: Text(
"Di mana letak nomor sertifikat?",
style: thirdTextStyle.copyWith(
color: Theme.of(context).colorScheme.onPrimary),
),
onPressed: () {
showInfoDialog(context);
},
),
isLoading
? LoadingButton(
backgroundButtonColor: primaryColor,
textButtonColor: Color(0xff050505),
)
: SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
backgroundColor: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
padding: EdgeInsets.symmetric(
vertical: 5,
horizontal: getProportionateScreenWidth(5))),
onPressed: () {
handleCertificate();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Periksa",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: baruTextutih,
fontWeight: reguler,
),
),
],
),
),
),
],
),
),
),
),
);
}
}

View File

@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
showInfoDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
elevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(14.0)),
child: Container(
width: getProportionateScreenHeight(1),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Align(
alignment: Alignment.topRight,
child: IconButton(
padding: EdgeInsets.all(0),
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.clear_rounded),
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenHeight(10)),
child: Image.asset("assets/images/no_sertif_preview.png"),
),
SizedBox(height: getProportionateScreenHeight(15)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenHeight(10)),
child: Text(
"Nomor sertifikat terletak dikiri atas sertifikat, dibawah logo vocasia.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: getProportionateScreenHeight(11),
),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(20)),
child: DefaultButton(
text: "OKE",
press: () {
Navigator.pop(context);
}),
),
SizedBox(height: getProportionateScreenHeight(30)),
],
),
),
);
},
);
}

View File

@ -0,0 +1,77 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:initial_folder/providers/certificate_provider.dart';
import 'package:initial_folder/screens/certificate/component/just_certificate_count.dart';
import 'package:provider/provider.dart';
import '../../../size_config.dart';
import '../../../theme.dart';
class CertificateHeader extends StatelessWidget {
const CertificateHeader({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<CertificateProvider>(
builder: (context, value, _) {
return RefreshIndicator(
onRefresh: () async {
await Provider.of<CertificateProvider>(context, listen: false)
.getAllCertif();
},
child: const Column(
children: [
JustCertificateCount(),
// Visibility(
// visible: value.state != ResultState.Loading,
// child: Container(
// // decoration: BoxDecoration(
// // borderRadius: BorderRadius.circular(10),
// // color: Theme.of(context).brightness == Brightness.dark
// // ? seventeenColor
// // : secondaryColor.withOpacity(0.3),
// // ),
// height: 40,
// // child: TextField(
// // autofocus: false,
// // onSubmitted: (value) async {
// // if (value.trim().isNotEmpty) {
// // Provider.of<CertificateProvider>(context, listen: false)
// // .searchCertif(value);
// // }
// // },
// // style: primaryTextStyle.copyWith(
// // fontSize: getProportionateScreenWidth(14),
// // letterSpacing: 0.5,
// // ),
// // cursorColor: secondaryColor,
// // decoration: InputDecoration(
// // border: InputBorder.none,
// // errorBorder: OutlineInputBorder(
// // borderSide: BorderSide(color: sevenColor),
// // borderRadius: BorderRadius.circular(10)),
// // contentPadding: EdgeInsets.only(
// // top: getProportionateScreenHeight(3.5)),
// // prefixIcon: Icon(
// // FeatherIcons.search,
// // size: 20,
// // color: Colors.grey,
// // ),
// // hintText: 'Cari sertifikat kursus',
// // hintStyle: primaryTextStyle.copyWith(
// // fontSize: getProportionateScreenWidth(12),
// // color: secondaryColor,
// // letterSpacing: 0.5,
// // ),
// // ),
// // ),
// ),
// ),
],
),
);
},
);
}
}

View File

@ -0,0 +1,421 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/models/my_certificate.dart';
import 'package:initial_folder/providers/certificate_provider.dart';
import 'package:initial_folder/screens/course/sertif.dart';
import 'package:initial_folder/screens/course/sertif_view.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:shimmer/shimmer.dart';
import 'package:initial_folder/screens/certificate/component/just_certificate_count.dart';
class CertificateItem extends StatefulWidget {
const CertificateItem({Key? key}) : super(key: key);
@override
State<CertificateItem> createState() => _CertificateItemState();
}
class _CertificateItemState extends State<CertificateItem> {
@override
Widget build(BuildContext context) {
return Consumer<CertificateProvider>(
builder: (context, value, child) {
return certificateCountComponent('assets/icons/gold-medal.png',
value.allCertificateCount.toString(), 'Jumlah Sertifikat', context);
},
);
}
Widget certificateCountComponent(
String icon,
String count,
String content,
BuildContext context,
) {
return ShaderMask(
shaderCallback: (Rect rect) {
return LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black,
Colors.transparent,
Colors.transparent,
Colors.black
],
stops: [0.0, 0.02, 0.98, 1.0],
).createShader(rect);
},
blendMode: BlendMode.dstOut,
child: Consumer<CertificateProvider>(
builder: (context, state, _) {
if (state.state == ResultState.HasData) {
return Column(
children: [
SizedBox(height: getProportionateScreenHeight(10)),
Container(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(10)),
height: getProportionateScreenWidth(550),
child: ListView.builder(
itemCount: state.allCertificate?.length,
itemBuilder: (context, index) {
return allCertificates(state, index, instructorProfile,
buttonOpacity, buttonActivator);
},
),
)
],
);
} else if (state.state == ResultState.Loading) {
return Shimmer.fromColors(
baseColor: Colors.grey,
highlightColor: Colors.white,
child: Column(
children: [
SizedBox(height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
),
SizedBox(width: getProportionateScreenHeight(130)),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenHeight(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
),
],
),
],
),
Container(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(10)),
height: getProportionateScreenWidth(500),
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(20)),
child: Container(
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
),
);
},
),
)
],
),
);
} else if (state.state == ResultState.NoData) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
JustCertificateCount(),
],
),
Center(
child: Padding(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(180)),
child: Text('Sertifikat Tidak Tersedia'),
),
)
],
);
} else if (state.state == ResultState.Error) {
return Center(
child: Text('Terjadi Kesalahan'),
);
} else {
return Center(
child: Text(''),
);
}
},
),
);
}
instructorProfile(DataMyCertificateModel certificate) {
if (certificate.fotoProfile == null) {
return Image.asset(
"assets/images/Profile Image.png",
width: getProportionateScreenWidth(21),
height: getProportionateScreenHeight(21),
);
} else
return CircleAvatar(
radius: getProportionateScreenWidth(10),
backgroundImage: NetworkImage(certificate.fotoProfile!),
);
}
buttonOpacity(int percentage) {
if (percentage == 100) {
return primaryColor;
} else {
return Color.fromRGBO(237, 169, 35, 0.5);
}
}
buttonActivator(int percentage, BuildContext context,
DataMyCertificateModel certificate) {
if (percentage == 100) {
return () {
Navigator.push(
context,
CustomNavigator(
child: Sertif(
idCourse: int.parse(certificate.courseId!),
totalProgress: certificate.progress,
),
),
);
};
} else {
return null;
}
}
buttonActivatorView(int percentage, BuildContext context,
DataMyCertificateModel certificate) {
if (percentage == 100) {
return () {
Navigator.push(
context,
CustomNavigator(
child: SertifView(
idCourse: int.parse(certificate.courseId!),
totalProgress: certificate.progress,
),
),
);
};
} else {
return null;
}
}
allCertificates(
state, index, instructorProfile, buttonOpacity, buttonActivator) {
return Padding(
padding: EdgeInsets.symmetric(vertical: getProportionateScreenHeight(8)),
child: Container(
height: getProportionateScreenHeight(120),
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(10)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
'assets/images/certificate.png',
width: getProportionateScreenWidth(45),
height: getProportionateScreenHeight(45),
),
SizedBox(
width: getProportionateScreenWidth(250),
child: Padding(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(13),
horizontal: getProportionateScreenWidth(3)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
state.allCertificate![index]!.title!,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: TextStyle(
fontSize: getProportionateScreenWidth(13),
fontWeight: reguler),
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
children: [
instructorProfile(state.allCertificate![index]!),
SizedBox(width: getProportionateScreenWidth(5)),
Container(
width: getProportionateScreenHeight(100),
child: Text(
state.allCertificate![index]!.instructor!,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: getProportionateScreenHeight(11)),
),
)
],
),
SizedBox(height: getProportionateScreenHeight(3)),
Row(
children: [
Stack(
children: [
Container(
width: (SizeConfig.screenWidth -
getProportionateScreenWidth(270)),
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.grey),
),
Container(
width: (SizeConfig.screenWidth -
getProportionateScreenWidth(270)) *
state.allCertificate![index]!.progress! /
100,
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: primaryColor),
),
],
),
Text(
" ${state.allCertificate![index]!.progress!.toString()}% ",
style: TextStyle(
fontSize: getProportionateScreenWidth(10),
fontWeight: bold),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size(getProportionateScreenWidth(5),
getProportionateScreenHeight(5)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
backgroundColor: primaryColor,
disabledForegroundColor: Colors.grey,
disabledBackgroundColor: Colors.grey,
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(6)),
),
onPressed: buttonActivatorView(
state.allCertificate![index]!.progress!,
context,
state.allCertificate![index]!),
child: Row(
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(2)),
child: Text(
"Lihat\nSertifikat",
style: TextStyle(
fontSize: getProportionateScreenHeight(5),
color: baruTextutih),
),
),
SizedBox(width: getProportionateScreenWidth(5)),
SvgPicture.asset(
'assets/icons/eye.svg',
fit: BoxFit.fitWidth,
width: getProportionateScreenWidth(12),
)
],
),
),
SizedBox(width: getProportionateScreenWidth(7)),
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size(getProportionateScreenWidth(5),
getProportionateScreenHeight(5)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
backgroundColor: primaryColor,
disabledForegroundColor: Colors.grey,
disabledBackgroundColor: Colors.grey,
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(6)),
),
onPressed: buttonActivator(
state.allCertificate![index]!.progress!,
context,
state.allCertificate![index]!),
child: Row(
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(2)),
child: Text(
"Download\nSertifikat",
style: TextStyle(
fontSize: getProportionateScreenHeight(5),
color: baruTextutih),
),
),
SizedBox(width: getProportionateScreenWidth(5)),
SvgPicture.asset(
'assets/icons/download.svg',
fit: BoxFit.fitWidth,
width: getProportionateScreenWidth(12),
)
],
),
),
SizedBox(width: getProportionateScreenWidth(10)),
],
),
],
),
),
),
],
),
),
);
}
Widget certificateCountComponents(
String count,
BuildContext context,
) {
return Center(
child: ListView(
children: [
Container(
padding: const EdgeInsets.all(20.0),
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height / 1.5),
child: Center(
child: Text(count),
),
)
],
),
);
}
}

View File

@ -0,0 +1,380 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/my_certificate.dart';
import 'package:initial_folder/providers/certificate_provider.dart';
import 'package:initial_folder/screens/certificate/component/all_certificate_header.dart';
import 'package:initial_folder/screens/course/sertif.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
class JustCertificateCount extends StatefulWidget {
const JustCertificateCount({Key? key}) : super(key: key);
@override
State<JustCertificateCount> createState() => _JustCertificateCountState();
}
class _JustCertificateCountState extends State<JustCertificateCount> {
@override
Widget build(BuildContext context) {
return Consumer<CertificateProvider>(
builder: (context, value, child) {
return certificateCountComponent(
'assets/icons/gold-medal.png',
value.allCertificateCount.toString(),
'Jumlah Sertifikat Selesai',
context);
},
);
}
Widget certificateCountComponent(
String icon,
String count,
String content,
BuildContext context,
) {
return ShaderMask(
shaderCallback: (Rect rect) {
return LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black,
Colors.transparent,
Colors.transparent,
Colors.black
],
stops: [0.0, 0.02, 0.98, 1.0],
).createShader(rect);
},
blendMode: BlendMode.dstOut,
child: Consumer<CertificateProvider>(
builder: (context, state, _) {
if (state.state == ResultState.HasData) {
return Column(
children: [
SizedBox(height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Image.asset(
icon,
width: getProportionateScreenWidth(18),
height: getProportionateScreenHeight(18),
),
SizedBox(width: getProportionateScreenWidth(8)),
Text(
content,
style: thirdTextStyle.copyWith(
letterSpacing: 0.42,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12)),
),
SizedBox(width: getProportionateScreenWidth(4)),
Text(
count,
style: thirdTextStyle.copyWith(
letterSpacing: 0.42,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(17)),
),
],
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
],
);
} else if (state.state == ResultState.Loading) {
return Shimmer.fromColors(
baseColor: Colors.grey,
highlightColor: Colors.white,
child: Column(
children: [
SizedBox(height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
),
SizedBox(width: getProportionateScreenHeight(130)),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenHeight(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
),
],
),
],
),
Container(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(10)),
height: getProportionateScreenWidth(500),
child: ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(20)),
child: Container(
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
),
);
},
),
)
],
),
);
} else {
return Column(
children: [],
);
}
},
),
);
}
instructorProfile(DataMyCertificateModel certificate) {
if (certificate.fotoProfile == null) {
return Image.asset(
"assets/images/Profile Image.png",
scale: getProportionateScreenWidth(12),
);
} else
return CircleAvatar(
radius: getProportionateScreenWidth(8),
backgroundImage: NetworkImage(certificate.fotoProfile!),
);
}
buttonOpacity(int percentage) {
if (percentage == 100) {
return primaryColor;
} else {
return Color.fromRGBO(237, 169, 35, 0.5);
}
}
buttonActivator(int percentage, BuildContext context,
DataMyCertificateModel certificate) {
if (percentage == 100) {
return () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Sertif(
idCourse: int.parse(certificate.courseId!),
totalProgress: certificate.progress,
),
),
);
};
} else {
return null;
}
}
allCertificates(
state, index, instructorProfile, buttonOpacity, buttonActivator) {
return Padding(
padding: EdgeInsets.symmetric(vertical: getProportionateScreenHeight(8)),
child: Container(
height: getProportionateScreenHeight(90),
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(8)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Padding(
padding: EdgeInsets.all(getProportionateScreenHeight(10)),
child: Image.asset(
'assets/icons/gold-medal.png',
fit: BoxFit.cover,
scale: getProportionateScreenWidth(2.2),
)),
Padding(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(5)),
child: Container(
height: double.infinity,
child:
VerticalDivider(color: Color.fromRGBO(52, 121, 148, 0.9)),
),
),
SizedBox(
width: getProportionateScreenWidth(150),
child: Padding(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(3),
horizontal: getProportionateScreenWidth(3)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
state.allCertificate![index]!.title!,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: TextStyle(
fontSize: getProportionateScreenHeight(12),
fontWeight: reguler),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
instructorProfile(state.allCertificate![index]!),
SizedBox(width: getProportionateScreenWidth(5)),
Container(
width: getProportionateScreenHeight(100),
child: Text(
state.allCertificate![index]!.instructor!,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: getProportionateScreenHeight(10)),
),
)
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Expanded(
child: Stack(
children: [
Container(
width: (SizeConfig.screenWidth -
getProportionateScreenWidth(245)),
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
),
Container(
width: (SizeConfig.screenWidth -
getProportionateScreenWidth(245)) *
state.allCertificate![index]!.progress! /
100,
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: primaryColor),
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3)),
child: Container(
child: Align(
alignment: Alignment.center,
child: Text(
"${state.allCertificate![index]!.progress!.toString()}%",
style: TextStyle(
fontSize: 10,
color: Colors.white,
fontWeight: bold),
),
),
),
)
],
),
],
),
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
backgroundColor: Color.fromRGBO(45, 45, 45, 1),
disabledForegroundColor:
Color.fromRGBO(150, 150, 150, 1).withOpacity(0.38),
disabledBackgroundColor:
Color.fromRGBO(150, 150, 150, 1).withOpacity(0.12),
padding: EdgeInsets.symmetric(
vertical: 5, horizontal: getProportionateScreenWidth(5))),
onPressed: buttonActivator(
state.allCertificate![index]!.progress!,
context,
state.allCertificate![index]!),
child: Row(
children: [
Text(
"Download\nSertifikat",
style: TextStyle(
fontSize: getProportionateScreenHeight(8),
color: buttonOpacity(
state.allCertificate![index]!.progress!)),
),
SizedBox(width: getProportionateScreenWidth(5)),
Image.asset(
'assets/icons/left-arrow.png',
color:
buttonOpacity(state.allCertificate![index]!.progress!),
fit: BoxFit.fitWidth,
width: getProportionateScreenWidth(20),
)
],
),
)
],
),
),
);
}
Widget certificateCountComponents(
String count,
BuildContext context,
) {
return Center(
child: ListView(
children: [
Container(
padding: const EdgeInsets.all(20.0),
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height / 1.5),
child: Center(
child: Text(count),
),
)
],
),
);
}
}

View File

@ -0,0 +1,782 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_order_model.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/screens/checkout/components/bar_batas_bayar.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/components/tab_bar_batas_bayar.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi_pending.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator_pop.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:pusher_client/pusher_client.dart';
import 'package:shimmer/shimmer.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.dart';
import 'package:initial_folder/providers/payments_provider.dart' as payProv;
class BatasBayar extends StatefulWidget {
BatasBayar({
this.historyTransactionModel,
this.isFromHistory,
this.idCart,
});
final HistoryTransactionModel? historyTransactionModel;
final bool? isFromHistory;
final List<String>? idCart;
@override
State<BatasBayar> createState() => _BatasBayarState();
}
class _BatasBayarState extends State<BatasBayar> {
Channel? _channel;
String? statusTransaction;
String? statusMessage;
PusherClient? pusher;
String capitalize(String s) =>
s[0].toUpperCase() + s.substring(1).toLowerCase();
Future<void> deleteCourse() async {
List<String> idCarts = widget.idCart!;
for (var element in idCarts) {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
}
}
Future<void> initPusher() async {
int? idUser = await UsersInfo().getIdUser();
PusherClient pusher = PusherClient(
'92060797e94ac7033edb', PusherOptions(cluster: 'ap1'),
autoConnect: false);
pusher.connect();
pusher.onConnectionStateChange((state) {
print(state!.currentState);
});
pusher.onConnectionError((error) {
print(error);
});
_channel = pusher.subscribe('payment-channel');
_channel!.bind(
'paid-event-$idUser',
(event) async {
print("Event? ini apaan dah ${event!.data!}");
if (mounted) {
final status = jsonDecode(event.data!);
final newStatusTransaction = status['status_code'];
final newStatusMessage = status['message'];
if (newStatusMessage.contains("Berhasil !") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => SuccessPaidCourse(),
),
(route) => false,
);
}
} else if (newStatusMessage.contains("Dibatalkan") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.pop(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Theme.of(context).colorScheme.background,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding: EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(14)),
child: Text(
textAlign: TextAlign.center,
"Transaksi berhasil dibatalkan",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
),
),
),
),
);
}
}
}
},
);
}
@override
void initState() {
initPusher();
super.initState();
}
Widget _buildBatasBayarHistory() {
List<DetailOrderModel> detailOrder =
Provider.of<payProv.PaymentsProvider>(context).detailOrder;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
var selectedOrder =
Provider.of<payProv.PaymentsProvider>(context, listen: false);
var selected = Provider.of<OrderProvider>(context);
selected.selectedThumbnail = orders[0].imageUrl;
selected.selectedTitle = orders[0].title;
selected.selectedInstructor = orders[0].instructor;
PageProvider pageProviders = Provider.of<PageProvider>(context);
pageProviders.remove();
Widget mandiriPay() {
return detailOrder[0].bankName == 'mandiri'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].billerCode.toString(),
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: detailOrder[0].billerCode.toString()))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
],
)
: Row();
}
Widget indomartPay() {
return detailOrder[0].bankName == 'indomaret'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].merchantId!,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(
ClipboardData(text: detailOrder[0].merchantId!))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Merchant'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
],
)
: Row();
}
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Selesaikan Pembayaran',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: getProportionateScreenWidth(17),
),
onPressed: () {
selectedOrder.selectedIdOrders = '';
Navigator.pop(context);
},
),
),
body: SingleChildScrollView(
child: Consumer<payProv.PaymentsProvider>(
builder: (context, state, _) {
if (state.stateProcess == payProv.Process.loading) {
return Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(20),
bottom: getProportionateScreenHeight(20),
right: getProportionateScreenWidth(20),
),
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: getProportionateScreenWidth(140),
height: getProportionateScreenHeight(7),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Container(
width: getProportionateScreenWidth(110),
height: getProportionateScreenHeight(9),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Container(
width: getProportionateScreenWidth(220),
height: getProportionateScreenHeight(7),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(40)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(250),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(40),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(30)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(170),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
],
),
),
);
} else if (state.state == payProv.ResultState.gagal &&
state.stateProcess == payProv.Process.uninitialized) {
return Center(
child: Text('Gagal Mengambil Pesanan'),
);
} else if (state.state == payProv.ResultState.success &&
state.stateProcess == payProv.Process.uninitialized) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: getProportionateScreenHeight(10)),
Center(
child: Column(
children: [
Text(
'Batas akhir pembayaran sampai',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
DateFormat('E, d MMM y (H:m)')
.format(detailOrder[0].transactionTimeLimit),
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Mohon melakukan pembayaran sebelum batas',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'tanggal yang ditetapkan atau pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'akan otomatis dibatalkan',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(25)),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
detailOrder[0].bankName == 'mandiri'
? 'Mandiri Virtual Account'
: detailOrder[0].bankName == 'permata'
? 'Permata Virtual Account'
: detailOrder[0].bankName == 'bni'
? 'BNI Virtual Account'
: detailOrder[0].bankName == 'bca'
? 'BCA Virtual Account'
: detailOrder[0].bankName ==
'indomaret'
? 'Indomaret'
: 'Alfamart',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.fill,
image: detailOrder[0].bankName ==
'mandiri'
? AssetImage(
"assets/images/mandiri.png")
: detailOrder[0].bankName == 'permata'
? AssetImage(
"assets/images/permata.png")
: detailOrder[0].bankName == 'bni'
? AssetImage(
"assets/images/bni.png")
: detailOrder[0].bankName ==
'bca'
? AssetImage(
"assets/images/bca.png")
: detailOrder[0]
.bankName ==
'alfamart'
? AssetImage(
"assets/images/alfamart.png")
: AssetImage(
"assets/images/indomaret.png"),
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
detailOrder[0].bankName == 'alfamart' ||
detailOrder[0].bankName == 'indomaret'
? 'Nomor Pesanan'
: 'Nomor Virtual Akun',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
detailOrder[0].virtualNumber ?? 'ABCD',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text:
detailOrder[0].virtualNumber!))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(detailOrder[0]
.bankName ==
'alfamart' ||
detailOrder[0].bankName ==
'indomaret'
? 'Berhasil Menyalin Nomor Pesanan'
: 'Berhasil Menyalin Nomor Virtual Akun'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
detailOrder[0].bankName == 'indomaret'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Merchant',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
detailOrder[0].bankName == 'mandiri'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
indomartPay(),
mandiriPay(),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (context) {
return BottomSheetDetail();
},
);
},
child: Text(
"Detail Pembayaran",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Status Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Text(
capitalize(
detailOrder[0].transactionStatus!.toString()),
style: thirdTextStyle.copyWith(
color: primaryColor,
letterSpacing: 1,
fontWeight: medium,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
),
),
SizedBox(height: getProportionateScreenHeight(24)),
DefaultButton(
text: 'Belanja kursus lainnya',
weight: semiBold,
press: () {
pageProviders.currentIndex == 0;
Navigator.pushAndRemoveUntil(
context,
CustomNavigatorPop(child: HomeScreen()),
(route) => false,
);
},
),
SizedBox(height: getProportionateScreenHeight(12)),
SizedBox(
width: getProportionateScreenWidth(300),
height: getProportionateScreenHeight(38),
child: TextButton(
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => RiwayatTransaksiPending(),
),
);
},
child: Text(
"Cek Status Transaksi",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: semiBold,
color: primaryColor,
letterSpacing: 0.5,
),
),
style: TextButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.background,
shape: RoundedRectangleBorder(
side: BorderSide(color: primaryColor),
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(10)),
),
backgroundColor: Colors.transparent,
),
),
),
SizedBox(height: getProportionateScreenHeight(32)),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(16)),
child: Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 0.5,
),
Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(16)),
child: detailOrder[0].bankName == 'indomaret' ||
detailOrder[0].bankName == 'alfamart'
? BarBatasBayar(detailOrder[0].bankName!)
: TabBarBatasBayar()),
],
),
),
SizedBox(height: getProportionateScreenHeight(30)),
],
),
);
} else {
return Center(
child: Text('Terjadi Kesalahan'),
);
}
},
),
),
);
}
@override
Widget build(BuildContext context) {
return _buildBatasBayarHistory();
}
}

View File

@ -0,0 +1,991 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_countdown_timer/current_remaining_time.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_order_model.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/screens/checkout/components/bar_batas_bayar.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/components/tab_bar_batas_bayar.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/services/cancel_payment_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator_pop.dart';
import 'package:initial_folder/widgets/login_regist/default_button_payment.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:pusher_client/pusher_client.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:shimmer/shimmer.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.dart';
import 'package:initial_folder/providers/payments_provider.dart' as payProv;
class BatasBayarBank extends StatefulWidget {
BatasBayarBank({
this.historyTransactionModel,
this.isFromHistory,
this.idCart,
});
final HistoryTransactionModel? historyTransactionModel;
final bool? isFromHistory;
final List<String>? idCart;
@override
State<BatasBayarBank> createState() => _BatasBayarBankState();
}
class _BatasBayarBankState extends State<BatasBayarBank> {
Channel? _channel;
String? statusTransaction;
String? statusMessage;
bool isLoading = false;
PusherClient? pusher;
Duration? remainingTime;
String capitalize(String s) =>
s[0].toUpperCase() + s.substring(1).toLowerCase();
Future<void> saveRemainingTime(Duration remainingTime) async {
final prefs = await SharedPreferences.getInstance();
prefs.setInt('remainingTime', remainingTime.inSeconds);
}
Future<void> deleteCourse() async {
List<String> idCarts = widget.idCart!;
for (var element in idCarts) {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
}
}
Future<void> initPusher() async {
int? idUser = await UsersInfo().getIdUser();
PusherClient pusher = PusherClient(
'92060797e94ac7033edb', PusherOptions(cluster: 'ap1'),
autoConnect: false);
pusher.connect();
pusher.onConnectionStateChange((state) {
print(state!.currentState);
});
pusher.onConnectionError((error) {
print(error);
});
_channel = pusher.subscribe('payment-channel');
_channel!.bind(
'paid-event-$idUser',
(event) async {
print("Event? ini apaan dah ${event!.data!}");
if (mounted) {
final status = jsonDecode(event.data!);
final newStatusTransaction = status['status_code'];
final newStatusMessage = status['message'];
if (newStatusMessage.contains("Berhasil !") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => SuccessPaidCourse(),
),
(route) => false,
);
}
} else if (newStatusMessage.contains("Dibatalkan") &&
newStatusTransaction == '200') {
await deleteCourse();
if (mounted) {
setState(() {
statusTransaction = newStatusTransaction;
statusMessage = newStatusMessage;
});
Navigator.pop(context);
showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Theme.of(context).colorScheme.background,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
contentPadding: EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(14)),
child: Text(
textAlign: TextAlign.center,
"Transaksi berhasil dibatalkan",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
),
),
),
),
);
}
}
}
},
);
}
@override
void initState() {
initPusher();
super.initState();
}
@override
void dispose() {
if (remainingTime != null) {
saveRemainingTime(remainingTime!);
}
super.dispose();
}
Widget _buildBatasBayarHistory() {
List<DetailOrderModel> detailOrder =
Provider.of<payProv.PaymentsProvider>(context).detailOrder;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
var selected = Provider.of<OrderProvider>(context);
selected.selectedThumbnail = orders[0].imageUrl;
selected.selectedTitle = orders[0].title;
selected.selectedInstructor = orders[0].instructor;
PageProvider pageProvider = Provider.of<PageProvider>(context);
Widget mandiriPay() {
return detailOrder[0].bankName == 'mandiri'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].billerCode.toString(),
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: detailOrder[0].billerCode.toString()))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
],
)
: Row();
}
Widget indomartPay() {
return detailOrder[0].bankName == 'indomaret'
? Column(
children: [
Row(
children: [
Text(
detailOrder[0].merchantId!,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(
ClipboardData(text: detailOrder[0].merchantId!))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Berhasil Menyalin Kode Merchant'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
],
)
: Row();
}
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
centerTitle: true,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Menunggu Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: Theme.of(context).colorScheme.onBackground,
size: getProportionateScreenWidth(17),
),
onPressed: () {
pageProvider.currentIndex == 0;
Navigator.pushAndRemoveUntil(
context,
CustomNavigatorPop(child: HomeScreen()),
(route) => false,
);
},
),
),
body: SingleChildScrollView(
child: Consumer<payProv.PaymentsProvider>(
builder: (context, state, _) {
if (state.stateProcess == payProv.Process.loading) {
return Padding(
padding: const EdgeInsets.all(20),
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: getProportionateScreenHeight(40)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(250),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(40),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(30)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(170),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white,
),
),
],
),
),
);
} else if (state.state == payProv.ResultState.gagal &&
state.stateProcess == payProv.Process.uninitialized) {
return Center(
child: Text('Gagal Mengambil Pesanan'),
);
} else if (state.state == payProv.ResultState.success &&
state.stateProcess == payProv.Process.uninitialized) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(8)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: getProportionateScreenHeight(10)),
Center(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 2,
offset:
Offset(0, getProportionateScreenHeight(4)),
),
],
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(15),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Batas Waktu Pembayaran',
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('E, d MMM y H:m WIB').format(
detailOrder[0].transactionTimeLimit),
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
Container(
decoration: BoxDecoration(
color: sevenColor,
borderRadius: BorderRadius.circular(4),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3),
vertical: getProportionateScreenHeight(2),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.access_time,
color: baruTextutih,
size: getProportionateScreenWidth(14),
),
SizedBox(
width:
getProportionateScreenWidth(2)),
CountdownTimer(
endTime: DateTime.now()
.add(Duration(hours: 24))
.millisecondsSinceEpoch,
widgetBuilder:
(_, CurrentRemainingTime? time) {
if (time == null) {
return Text(
'00:00:00',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(
10),
color: baruTextutih,
),
);
} else {
remainingTime = Duration(
hours: time.hours ?? 0,
minutes: time.min ?? 0,
seconds: time.sec ?? 0,
);
return Text(
'${time.hours}:${time.min}:${time.sec}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(
10),
color: baruTextutih,
),
);
}
},
),
],
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Text(
"Kursus",
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: orders.map((e) {
return listCourse(
imageUrl: e.imageUrl,
instructor: e.instructor,
title: e.title,
price: e.price,
discountPrice: e.discountPrice,
);
}).toList(),
),
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
detailOrder[0].bankName == 'mandiri'
? 'Mandiri Virtual Account'
: detailOrder[0].bankName == 'permata'
? 'Permata Virtual Account'
: detailOrder[0].bankName == 'bni'
? 'BNI Virtual Account'
: detailOrder[0].bankName == 'bca'
? 'BCA Virtual Account'
: detailOrder[0].bankName ==
'indomaret'
? 'Indomaret'
: 'Alfamart',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.fill,
image: detailOrder[0].bankName ==
'mandiri'
? AssetImage(
"assets/images/mandiri.png")
: detailOrder[0].bankName == 'permata'
? AssetImage(
"assets/images/permata.png")
: detailOrder[0].bankName == 'bni'
? AssetImage(
"assets/images/bni.png")
: detailOrder[0].bankName ==
'bca'
? AssetImage(
"assets/images/bca.png")
: detailOrder[0]
.bankName ==
'alfamart'
? AssetImage(
"assets/images/alfamart.png")
: AssetImage(
"assets/images/indomaret.png"),
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
detailOrder[0].bankName == 'alfamart' ||
detailOrder[0].bankName == 'indomaret'
? 'Nomor Pesanan'
: 'Nomor Virtual Akun',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
detailOrder[0].virtualNumber ?? 'ABCD',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text:
detailOrder[0].virtualNumber!))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(detailOrder[0]
.bankName ==
'alfamart' ||
detailOrder[0].bankName ==
'indomaret'
? 'Berhasil Menyalin Nomor Pesanan'
: 'Berhasil Menyalin Nomor Virtual Akun'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
detailOrder[0].bankName == 'indomaret'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Merchant',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
detailOrder[0].bankName == 'mandiri'
? Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(16),
bottom: getProportionateScreenHeight(8),
),
child: Text(
'Kode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
)
: SizedBox.shrink(),
indomartPay(),
mandiriPay(),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
showModalBottomSheet(
backgroundColor: Theme.of(context)
.colorScheme
.background,
elevation: 0.0,
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (context) {
return BottomSheetDetail();
},
);
},
child: Text(
"Detail Pembayaran",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
SizedBox(
height:
getProportionateScreenHeight(24)),
DefaultButtonPayment(
text: 'Ubah Metode Pembayaran',
weight: semiBold,
press: () {
state.selectedIdOrders = "";
Navigator.pop(context);
},
width: 320,
height: 44,
),
SizedBox(
height:
getProportionateScreenHeight(12)),
SizedBox(
width: getProportionateScreenWidth(320),
height: getProportionateScreenHeight(38),
child: TextButton(
onPressed: () async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
elevation: 0.0,
backgroundColor:
Theme.of(context)
.colorScheme
.background,
contentPadding:
EdgeInsets.symmetric(
vertical:
getProportionateScreenHeight(
20),
horizontal:
getProportionateScreenWidth(
10),
),
actionsPadding: EdgeInsets.only(
right:
getProportionateScreenWidth(
10),
bottom:
getProportionateScreenHeight(
12),
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
getProportionateScreenWidth(
4)),
),
content: Text(
'Apakah Anda yakin ingin membatalkan transaksi?'),
actions: [
GestureDetector(
child: Text(
'Ya',
style: TextStyle(
color: primaryColor,
fontSize:
getProportionateScreenWidth(
11),
),
),
onTap: () async {
state.selectedIdOrders =
"";
Navigator.of(context)
.pop();
CancelPaymentService
cancelPaymentService =
CancelPaymentService();
setState(() {
isLoading = true;
});
await cancelPaymentService
.cancelPayment(
detailOrder[0]
.idOrder
.toString());
await Future.delayed(
Duration(seconds: 2));
setState(() {
isLoading = false;
});
},
),
SizedBox(
width:
getProportionateScreenWidth(
5)),
GestureDetector(
child: Text(
'Tidak',
style: TextStyle(
color: primaryColor,
fontSize:
getProportionateScreenWidth(
11),
),
),
onTap: () {
Navigator.of(context)
.pop();
},
),
],
);
},
);
},
child: isLoading
? Container(
width:
getProportionateScreenWidth(
15),
height:
getProportionateScreenHeight(
13),
child:
CircularProgressIndicator(
color: primaryColor,
),
)
: Text(
"Batalkan Transaksi",
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
12),
fontWeight: semiBold,
color: primaryColor,
letterSpacing: 0.5,
),
),
style: TextButton.styleFrom(
foregroundColor: Theme.of(context)
.colorScheme
.background,
shape: RoundedRectangleBorder(
side:
BorderSide(color: primaryColor),
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(5),
),
),
backgroundColor: Colors.transparent,
),
),
),
],
),
],
),
],
),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
padding: EdgeInsets.only(
top: getProportionateScreenHeight(15),
bottom: getProportionateScreenHeight(7),
left: getProportionateScreenWidth(18),
),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.2),
spreadRadius: 0,
blurRadius: 2,
offset: Offset(
0, getProportionateScreenHeight(4)),
),
],
),
child: Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(5),
),
child: detailOrder[0].bankName == 'indomaret' ||
detailOrder[0].bankName == 'alfamart'
? BarBatasBayar(detailOrder[0].bankName!)
: TabBarBatasBayar(),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(30)),
],
),
);
} else {
return Center(
child: Text('Terjadi Kesalahan'),
);
}
},
),
),
);
}
@override
Widget build(BuildContext context) {
return _buildBatasBayarHistory();
}
Widget listCourse({
String? imageUrl,
String? title,
String? instructor,
String? price,
String? discountPrice,
int? totalPrices,
}) {
return Container(
padding: EdgeInsets.symmetric(vertical: getProportionateScreenHeight(9)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(60),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: NetworkImage(imageUrl ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'),
fit: BoxFit.cover,
),
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,384 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/order_provider.dart' as provOrder;
import '../../providers/payments_provider.dart';
import 'snap_payment_page.dart';
class CheckoutCartCouponPage extends StatefulWidget {
CheckoutCartCouponPage({
Key? key,
required this.idCart,
this.potonganKupon,
this.discountHarga,
this.isKupon,
}) : super(key: key);
final List<String> idCart;
final int? potonganKupon;
final int? discountHarga;
final bool? isKupon;
@override
State<CheckoutCartCouponPage> createState() => _CheckoutCartCouponPageState();
}
class _CheckoutCartCouponPageState extends State<CheckoutCartCouponPage> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final priceCoupon = Provider.of<TotalPriceProvider>(context).priceCoupon;
final totalPrice2 = Provider.of<TotalPriceProvider>(context).totalPrice;
final totalPrice3 = Provider.of<TotalPriceProvider>(context).totalPrices;
final typeCoupon = Provider.of<TotalPriceProvider>(context).typeCoupon;
final finalPriceCoupon =
Provider.of<TotalPriceProvider>(context).finalPriceCoupon;
final potonganKupon2 =
Provider.of<TotalPriceProvider>(context).potonganKupon;
Widget bottomNav(String totalPrice) {
String totalHarga =
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice == '0' ? widget.discountHarga : double.parse(totalPrice))}";
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onPrimary.withOpacity(0.1),
spreadRadius: 4,
blurRadius: 15,
offset: Offset(0, 4),
),
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
fontWeight: semiBold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
print("Ini id cart? ${widget.idCart}");
if (totalHarga == 'Rp. 0') {
// Jika harga total adalah 0, arahkan ke halaman zero-payment
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(idCart: widget.idCart),
),
);
} else {
// harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(totalHarga.replaceAll('Rp. ', '').replaceAll(',', ''));
// Persiapkan data_invoice berdasarkan pesanan
List<Map<String, dynamic>> dataInvoice = widget.idCart.map((id) {
return {
'id_kursus': id,
'title_kursus': 'Nama Kursus',
'harga': grossAmount.toString(),
'qty': '1',
};
}).toList();
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Jika Snap berhasil, tampilkan halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse['transactionToken'] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(135),
height: getProportionateScreenHeight(35),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
'Pilih Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.5,
color: baruTextutih,
),
),
),
),
)
],
),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Checkout',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Detail Pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Consumer<provOrder.OrderProvider>(
builder: (context, state, _) {
print(state.orders.map((e) => e.idCourse));
return Column(
children: [
...state.orders.map(
(order) => CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isKupon == null
? finalPriceCoupon.toString()
: (potonganKupon2 == 0
? priceCoupon.toString()
: (potonganKupon2! > totalPrice2!
? finalPriceCoupon.toString()
: totalPrice3.toString())),
discountPrice: order.discountPrice,
imageUrl: order.imageUrl,
),
),
],
);
},
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Rincian Harga',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(priceCoupon!)}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon == 0 ? priceCoupon : (potonganKupon2! > totalPrice2! ? finalPriceCoupon : totalPrice3))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Biaya Layanan',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(finalPriceCoupon! < 5000 ? "5000" : "0"))}',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(typeCoupon != "3" ? widget.potonganKupon.toString() : (priceCoupon! - widget.potonganKupon!).toString()))}',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Total Bayar',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
],
),
Row(
children: [
Text(''),
Spacer(),
if (widget.isKupon == null)
Text(
(int.parse(Provider.of<provOrder.OrderProvider>(context)
.totalPrice!) !=
0 &&
int.parse(
Provider.of<provOrder.OrderProvider>(context).totalPrice!) < 50000) ||
finalPriceCoupon! < 50000
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
if (widget.isKupon != null)
Text(
(widget.discountHarga != 0 && widget.discountHarga! < 50000)
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(
(int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)).toString(),
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,296 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart' as provOrder;
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/screens/checkout/snap_payment_page.dart'; // Import SnapPaymentPage
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class CheckoutCartPage extends StatefulWidget {
CheckoutCartPage({
Key? key,
required this.idCart,
this.potonganKupon,
this.discountHarga,
this.isCart,
this.isDetailCourse,
}) : super(key: key);
final List<String> idCart;
final int? potonganKupon;
final int? discountHarga;
final bool? isCart;
final bool? isDetailCourse;
@override
State<CheckoutCartPage> createState() => _CheckoutCartPageState();
}
class _CheckoutCartPageState extends State<CheckoutCartPage> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final subTotal = Provider.of<TotalPriceProvider>(context).subTotal;
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
final themeProvider = Provider.of<ThemeProvider>(context);
Widget bottomNav(String totalPrice) {
String totalHarga =
"Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice == '0' ? widget.discountHarga : double.parse(totalPrice))}";
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onPrimary.withOpacity(0.1),
spreadRadius: 4,
blurRadius: 15,
offset: Offset(0, 4),
),
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
fontWeight: semiBold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(Provider.of<provOrder.OrderProvider>(context).totalPrice as String == "0" ? (widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga) : (int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice!) == widget.discountHarga ? (int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice!) < 50000 ? int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice!) + 5000 : int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)) : int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)))}',
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
fontWeight: bold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = Provider.of<provOrder.OrderProvider>(context, listen: false)
.orders
.fold(0, (sum, order) {
// Gunakan harga diskon jika tersedia, jika tidak ada gunakan harga asli
int harga = (order.discountPrice != null && order.discountPrice != "0")
? int.parse(order.discountPrice)
: int.parse(order.price);
// Tambahkan biaya admin jika harga di bawah 50.000
return sum + (harga < 50000 ? harga + 5000 : harga);
});
// Persiapkan data_invoice berdasarkan kursus yang ada di keranjang
List<Map<String, dynamic>> dataInvoice = [];
Provider.of<provOrder.OrderProvider>(context, listen: false).orders.forEach((order) {
dataInvoice.add({
'id_kursus': order.idCourse.toString(),
'title_kursus': order.title,
// Gunakan harga diskon jika tersedia, jika tidak gunakan harga asli
'harga': (order.discountPrice != null && order.discountPrice != "0")
? order.discountPrice.toString()
: order.price.toString(),
'qty': '1',
});
});
// Panggil Snap melalui provider
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Snap berhasil dibuka, navigasi ke SnapPaymentPage untuk menampilkan WebView
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse['transactionToken'] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(135),
height: getProportionateScreenHeight(35),
decoration: BoxDecoration(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Pilih Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.5,
color: baruTextutih,
),
),
),
),
)
],
),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Checkout',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Detail Pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Consumer<provOrder.OrderProvider>(
builder: (context, state, _) {
return Column(
children: [
...state.orders.map(
(order) => widget.isDetailCourse != null
? CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isCart == null
? order.price
: (order.discountPrice != null
? order.discountPrice
: order.price),
discountPrice: order.discountPrice == null
? order.discountPrice
: order.price,
imageUrl: order.imageUrl,
isDetailCourse: true,
)
: CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isCart == null
? order.price
: (order.discountPrice != null
? order.discountPrice
: order.price),
discountPrice: order.discountPrice == null
? order.discountPrice
: order.price,
imageUrl: order.imageUrl,
),
),
],
);
},
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Rincian Harga',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
RichText(
text: TextSpan(
children: [
if (widget.discountHarga.toString() != subTotal)
TextSpan(
text:
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(int.parse(subTotal!))}',
style: thirdTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.8,
),
),
WidgetSpan(
child: SizedBox(
width: getProportionateScreenWidth(8))),
TextSpan(
text:
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(Provider.of<provOrder.OrderProvider>(context).totalPrice as String == "0" ? (widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga) : int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String))}',
style: thirdTextStyle.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(
(int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice as String)).toString(),
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,415 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/get_it.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/detail_course_coupon_provider.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../../providers/payments_provider.dart';
import 'components/course_list_coupon.dart';
import 'snap_payment_page.dart';
class CheckoutCouponPage extends StatefulWidget {
final idCourse;
final title;
final discountPrice;
final price;
final instructor;
final coupon;
const CheckoutCouponPage(
{Key? key,
required this.idCourse,
required this.instructor,
required this.title,
required this.price,
required this.discountPrice,
required this.coupon})
: super(key: key);
@override
State<CheckoutCouponPage> createState() => _CheckoutCouponPageState();
}
class _CheckoutCouponPageState extends State<CheckoutCouponPage> {
final controller = TextEditingController();
final provider = detailCouponGetIt<DetailCouponProvider>();
Future _showMessage(String text) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
content: Text(
text,
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
),
);
}
@override
Widget build(BuildContext context) {
provider.getDetail(widget.idCourse, widget.coupon);
return StreamBuilder<DataDetailCourseModel>(
stream: provider.detailStream,
builder: (context, AsyncSnapshot<DataDetailCourseModel> snapshot) {
final detail = snapshot.data;
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
case ConnectionState.none:
return Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
case ConnectionState.active:
case ConnectionState.done:
final detail = snapshot.data;
return body(
widget.idCourse,
detail?.title ?? '',
detail?.price ?? '0',
detail?.discountPrice ?? '0',
detail?.thumbnail ?? '',
);
}
}
return Container();
});
}
Widget bottomNav(String discountPrice, String price) {
String total = discountPrice == '0' ? price : discountPrice;
String totalPembayaran =
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - (double.parse(price) - double.parse(discountPrice)))}';
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
border: Border(top: BorderSide(color: fourthColor)),
boxShadow: [
BoxShadow(
offset: Offset(0, -2),
blurRadius: 50,
color: fourthColor.withOpacity(0.15))
]),
child: Row(
children: [
SizedBox(
width: 13,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: getProportionateScreenHeight(6),
),
Text(
"Total",
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
letterSpacing: 1),
),
SizedBox(
height: 2,
),
Builder(
builder: (BuildContext context) {
double total = double.parse(price) -
(double.parse(price) - double.parse(discountPrice));
if (total <= 50000) {
total += 5000;
}
return Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(total)}',
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23),
);
},
),
SizedBox(
height: getProportionateScreenHeight(2),
),
],
),
Spacer(),
GestureDetector(
onTap: () async {
if (totalPembayaran == 'Rp. 0') {
// Jika total pembayaran adalah 0, arahkan ke halaman zero-payment
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(),
),
);
} else {
// Dapatkan total harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(
totalPembayaran.replaceAll('Rp. ', '').replaceAll(',', '')
);
// Persiapkan data_invoice untuk kursus yang dibeli
List<Map<String, dynamic>> dataInvoice = [
{
'id_kursus': widget.idCourse,
'title_kursus': widget.title,
'harga': grossAmount.toString(),
'qty': '1',
}
];
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Jika Snap berhasil, tampilkan halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse['transactionToken'] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(188),
height: getProportionateScreenHeight(41),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Text(
'Lengkapi Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.32,
color: Color(0xff050505),
),
),
),
),
)
],
),
);
}
Widget body(String idCourse, String title, String price, String discountPrice,
String imageUrl) {
return Scaffold(
appBar: AppBar(
title: Text(
'Checkout',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
children: [
Text(
'Detail Pesanan',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
CourseListCoupon(
idCourse: idCourse,
title: title,
price: price,
discountPrice: discountPrice,
imageUrl: imageUrl),
SizedBox(
height: getProportionateScreenHeight(28),
),
Text(
'Rincian Harga',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - double.parse(discountPrice))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(5),
),
Divider(
color: tenthColor,
thickness: 0.5,
),
SizedBox(
height: getProportionateScreenHeight(5),
),
Row(
children: [
Text(
'Total',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
Builder(
builder: (BuildContext context) {
double total = double.parse(price) -
(double.parse(price) - double.parse(discountPrice));
if (total <= 50000) {
total += 5000;
} else {
total = total;
}
return Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(total)}',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
);
},
),
],
),
Row(
children: [
Text(''),
Spacer(),
Builder(
builder: (BuildContext context) {
double total = double.parse(price) -
(double.parse(price) - double.parse(discountPrice));
return total <= 50000
? Text(
'+ admin Rp 5000',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
)
: Container();
},
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(discountPrice, price),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,391 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/order_provider.dart' as provOrder;
import '../../providers/payments_provider.dart';
import 'snap_payment_page.dart';
class CheckoutDetailCoupon extends StatefulWidget {
CheckoutDetailCoupon({
Key? key,
required this.idCart,
this.potonganKupon,
this.discountHarga,
this.isKupon,
}) : super(key: key);
final List<String> idCart;
final int? potonganKupon;
final int? discountHarga;
final bool? isKupon;
@override
State<CheckoutDetailCoupon> createState() => _CheckoutDetailCouponState();
}
class _CheckoutDetailCouponState extends State<CheckoutDetailCoupon> {
final controller = TextEditingController();
@override
Widget build(BuildContext context) {
final priceCoupon = Provider.of<TotalPriceProvider>(context).priceCoupon;
final totalPrice2 = Provider.of<TotalPriceProvider>(context).totalPrice;
final totalPrice3 = Provider.of<TotalPriceProvider>(context).totalPrices;
final typeCoupon = Provider.of<TotalPriceProvider>(context).typeCoupon;
final finalPriceCoupon =
Provider.of<TotalPriceProvider>(context).finalPriceCoupon;
final potonganKupon2 =
Provider.of<TotalPriceProvider>(context).potonganKupon;
Widget bottomNav(String totalPrice) {
String totalHarga =
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice == '0' ? widget.discountHarga : double.parse(totalPrice))}";
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.onPrimary.withOpacity(0.1),
spreadRadius: 4,
blurRadius: 15,
offset: Offset(0, 4),
),
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
fontWeight: semiBold,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
print("Ini id cart? ${widget.idCart}");
if (totalHarga == 'Rp. 0') {
// Jika total harga adalah 0, arahkan ke halaman zero-payment
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(idCart: widget.idCart),
),
);
} else {
// Dapatkan total harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(
totalHarga.replaceAll('Rp. ', '').replaceAll(',', '')
);
// Persiapkan data_invoice berdasarkan kursus yang dibeli
List<Map<String, dynamic>> dataInvoice = [];
widget.idCart.forEach((cartId) {
dataInvoice.add({
'id_kursus': cartId, // Sesuaikan dengan data yang relevan
'title_kursus': 'Nama Kursus', // Nama kursus yang sesuai
'harga': grossAmount.toString(),
'qty': '1', // Sesuaikan jumlah jika diperlukan
});
});
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
Map<String, String>? paymentResponse = await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
);
if (paymentResponse != null) {
// Snap berhasil dibuka, arahkan ke halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: paymentResponse[''] ?? '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
// Jika Snap gagal dibuka
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(135),
height: getProportionateScreenHeight(35),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
'Pilih Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.5,
color: baruTextutih,
),
),
),
),
)
],
),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Checkout',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Detail Pesanan',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Consumer<provOrder.OrderProvider>(
builder: (context, state, _) {
return Column(
children: [
...state.orders.map(
(order) => CourseList(
idCourse: order.idCourse,
title: order.title,
price: widget.isKupon == null
? finalPriceCoupon.toString()
: (potonganKupon2 == 0
? finalPriceCoupon.toString()
: (potonganKupon2! > totalPrice2!
? finalPriceCoupon.toString()
: totalPrice3.toString())),
discountPrice: priceCoupon.toString(),
imageUrl: order.imageUrl,
),
),
],
);
},
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Rincian Harga',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(priceCoupon!)}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon == 0 ? priceCoupon : (potonganKupon2! > totalPrice2! ? finalPriceCoupon : totalPrice3))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Biaya Layanan',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(finalPriceCoupon! < 5000 ? "5000" : "0"))}',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Spacer(),
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(typeCoupon != "3" ? widget.potonganKupon.toString() : (priceCoupon! - finalPriceCoupon).toString()))}',
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Total Bayar',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
if (widget.isKupon == null)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(finalPriceCoupon! < 50000 ? finalPriceCoupon + 5000 : finalPriceCoupon)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
if (widget.isKupon == true)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(widget.discountHarga! < 50000 ? widget.discountHarga! + 5000 : widget.discountHarga)}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
],
),
Row(
children: [
Text(''),
Spacer(),
if (widget.isKupon == null)
Text(
(int.parse(Provider.of<provOrder.OrderProvider>(context)
.totalPrice!) !=
0 &&
int.parse(
Provider.of<provOrder.OrderProvider>(context)
.totalPrice!) < 50000) ||
finalPriceCoupon! < 50000
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
if (widget.isKupon != null)
Text(
(widget.discountHarga != 0 &&
widget.discountHarga! < 50000)
? "+ admin Rp 5000"
: "",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(
(int.parse(Provider.of<provOrder.OrderProvider>(context).totalPrice
as String))
.toString(),
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,559 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/get_it.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/models/detail_course_model.dart';
import 'package:initial_folder/providers/detail_course_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/checkout/components/course_list.dart';
import 'package:initial_folder/screens/checkout/detail_zero_payment.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/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/payments_provider.dart'
as paymentsProvider;
import 'package:initial_folder/providers/my_course_provider.dart'
as myCourseProvider;
import '../../providers/payments_provider.dart';
import 'snap_payment_page.dart';
class CheckoutPage extends StatefulWidget {
final idCourse;
final title;
final discountPrice;
final price;
final instructor;
final thumbnail;
const CheckoutPage({
Key? key,
required this.idCourse,
required this.instructor,
required this.title,
required this.price,
required this.discountPrice,
required this.thumbnail,
}) : super(key: key);
@override
State<CheckoutPage> createState() => _CheckoutPageState();
}
class _CheckoutPageState extends State<CheckoutPage> {
final controller = TextEditingController();
final provider = detailGetIt<DetailProvider>();
Future _showMessage(String text) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
content: Text(
text,
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
),
);
}
@override
Widget build(BuildContext context) {
provider.getDetail(widget.idCourse);
final selectedTotalPrice = Provider.of<TotalPriceProvider>(context);
// String? discountPrice;
return StreamBuilder<DetailCourseModel>(
stream: provider.detailStream,
builder: (context, AsyncSnapshot<DetailCourseModel> snapshot) {
final detail = snapshot.data?.data[0][0];
// discountPrice = detail?.discountPrice ?? '0';
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
break;
case ConnectionState.none:
Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
break;
case ConnectionState.active:
final detail = snapshot.data?.data[0][0];
// discountPrice = detail?.discountPrice ?? '0';
body(widget.idCourse, detail?.title ?? '', detail?.price ?? '0',
detail?.discountPrice ?? '0', detail?.thumbnail ?? '');
break;
case ConnectionState.done:
final detail = snapshot.data?.data[0][0];
// discountPrice = detail?.discountPrice ?? '0';
body(widget.idCourse, detail?.title ?? '', detail?.price ?? '0',
detail?.discountPrice ?? '0', detail?.thumbnail ?? '');
break;
}
}
return body(widget.idCourse, detail?.title ?? '', detail?.price ?? '0',
detail?.discountPrice ?? '0', detail?.thumbnail ?? '');
},
);
}
Widget bottomNav(String discountPrice, String price) {
String total = discountPrice == '0' ? price : discountPrice;
paymentsProvider.PaymentsProvider pay =
Provider.of<paymentsProvider.PaymentsProvider>(context);
final selectedTotalPrice = Provider.of<TotalPriceProvider>(context);
hargaTotalNavBar() {
String hargaTotal =
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - (double.parse(price) - double.parse(discountPrice)))}';
return hargaTotal;
}
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,
);
}
},
),
);
},
);
}
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),
),
),
],
),
);
}
handleNotLoginFree(
String? id,
String? title,
String? thumb,
String? instr,
) async {
var token = await UsersInfo().getToken();
if (token != null || Condition.loginFirebase == true) {
print("ini bisa ya");
if (await pay.freeCourse(int.parse(widget.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);
}
}
int totalPrice;
if (int.parse(discountPrice) != 0 && int.parse(discountPrice) < 50000) {
totalPrice = int.parse(discountPrice) + 5000;
} else {
if (int.parse(price) < 50000) {
totalPrice = int.parse(price) + 5000;
} else {
totalPrice = int.parse(price);
}
}
return Container(
width: double.infinity,
height: getProportionateScreenHeight(64),
decoration: BoxDecoration(
border: Border(top: BorderSide(color: fourthColor)),
boxShadow: [
BoxShadow(
offset: Offset(0, -2),
blurRadius: 50,
color: fourthColor.withOpacity(0.15),
)
],
),
child: Row(
children: [
SizedBox(width: 13),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(6)),
Text(
"Total",
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
letterSpacing: 1),
),
SizedBox(height: 2),
if (int.parse(price) < 50000 || int.parse(discountPrice) < 50000)
Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice)}",
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23),
)
else
Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(discountPrice == "0" ? double.parse(price) : double.parse(discountPrice))}",
style: primaryTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 2.5,
letterSpacing: 0.23),
),
SizedBox(height: getProportionateScreenHeight(2)),
],
),
Spacer(),
GestureDetector(
onTap: () async {
selectedTotalPrice.selectedTotalPrice = totalPrice;
if (price == "0") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DetailZeroPayment(
discountPrice: discountPrice,
price: price,
),
),
);
} else {
// Dapatkan total harga dan id transaksi untuk Snap Midtrans
String orderId = 'order-${DateTime.now().millisecondsSinceEpoch}';
int grossAmount = int.parse(price);
// Persiapkan data invoice berdasarkan pesanan
List<Map<String, dynamic>> dataInvoice = [
{
'id_kursus': widget.idCourse,
'title_kursus': widget.title,
'harga': price.toString(),
'qty': '1',
}
];
// Panggil Snap melalui provider
final paymentProvider = Provider.of<PaymentsProvider>(context, listen: false);
bool success = (await paymentProvider.startSnapPayment(
orderId: orderId,
grossAmount: grossAmount,
dataInvoice: dataInvoice,
)) as bool;
if (success) {
// Jika Snap berhasil, tampilkan halaman WebView Snap
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SnapPaymentPage(
transactionToken: '',
orderId: orderId,
grossAmount: grossAmount, courseTitle: '', courseThumbnail: '', courseInstructor: '', courseId: '',
),
),
);
} else {
print("Pembayaran gagal");
}
}
},
child: Container(
margin: EdgeInsets.only(right: getProportionateScreenWidth(15)),
width: getProportionateScreenWidth(188),
height: getProportionateScreenHeight(41),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Text(
'Lengkapi Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: SizeConfig.blockVertical! * 1.7,
fontWeight: semiBold,
letterSpacing: 0.32,
color: Color(0xff050505),
),
),
),
),
)
],
),
);
}
Widget body(String idCourse, String title, String price, String discountPrice,
String imageUrl) {
int totalPrice;
if (int.parse(discountPrice) != 0 && int.parse(discountPrice) < 50000) {
totalPrice = int.parse(discountPrice) + 5000;
} else {
if (int.parse(price) < 50000) {
totalPrice = int.parse(price) + 5000;
} else {
totalPrice = int.parse(price);
}
}
return Scaffold(
appBar: AppBar(
title: Text(
'Checkout',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
children: [
Text(
'Detail Pesanan',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
CourseList(
idCourse: idCourse,
title: title,
price: price,
discountPrice: discountPrice,
imageUrl: imageUrl),
SizedBox(height: getProportionateScreenHeight(28)),
Text(
'Rincian Harga',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Row(
children: [
Text(
'Subtotal Harga Kursus',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Potongan Kupon',
style: primaryTextStyle.copyWith(
letterSpacing: 1,
color: secondaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
Spacer(),
discountPrice != "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price) - double.parse(discountPrice))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
)
: Text(
'Rp. 0',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: tenthColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Divider(
color: tenthColor,
thickness: 0.5,
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
'Total',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
if (int.parse(price) < 50000 ||
int.parse(discountPrice) < 50000)
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(totalPrice)}',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
)
else
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(discountPrice == "0" ? double.parse(price) : double.parse(discountPrice))}',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
],
),
Row(
children: [
Text(''),
Spacer(),
if (int.parse(price) < 50000 ||
int.parse(discountPrice) < 50000 &&
int.parse(discountPrice) != 0)
Text(
'+ admin Rp 5000',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
color: primaryColor,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
)
else
SizedBox(),
],
),
],
),
),
),
bottomNavigationBar: bottomNav(discountPrice, price),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,317 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class ATMBNI extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: '2. Pilih Bahasa',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: '3. Masukkan <bold>PIN ATM</bold> Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih \"Menu Lainnya\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text: "5. Pilih \"Transfer\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '6. The billing information will appear on the payment validation page',
'6. Pilih Jenis rekening yang akan Anda gunakan',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '7. If the information is correct, enter your password to proceed the payment',
'7. Pilih \"Virtual Account Billing\"',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '8. Your transaction will be processed',
text: '8. Masukkan nomor Virtual Account Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class ATMBCA extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu anda ATM dan PIN BCA anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu utama, pilih menu \"Transaksi lainnya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Transfer\" dan kemudian pilih \"BCA Virtual Account\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Masukkan no. BCA Virtual Account & klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text: "5. Periksa kembali rincian pembayaran anda, lalu pilih Ya",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class AtmMandiri extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu anda ATM dan PIN anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu utama, pilih menu \"Bayar/Beli\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Multi Payment\" (jika di layar belum tersedia tekan menu \"Lainnya\" dan pilih \"Multi Payment\") ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"4. Masukkan nomor Biller Code pada kode perusahaan & klik \"Benar\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"5. Masukkan kode pembayaran (kode pembayaran Mandiri billpayment anda)",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"6. Periksa kembali data transaksi anda dan selesaikan proses pembayaran.",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class AtmPermata extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masukkan kartu ATM dan PIN anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu \"Transaksi Lainnya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Pembayaran\" kemudian Pilih \"Menu Pembayaran Lainnya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih menu \"VIRTUAL ACCOUNT\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text: "5. Masukkan nomor \"VIRTUAL ACCOUNT\", dan tekan \"BENAR\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"6. Pilih rekening yang menjadi sumber dana yang akan didebet, lalu tekan YA untuk konfirmasi transaksi",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}

View File

@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class BarBatasBayar extends StatelessWidget {
String storeName;
BarBatasBayar(this.storeName);
final TextStyle baris = thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(13),
);
@override
Widget build(BuildContext context) {
String store = storeName == 'indomaret' ? 'Indomaret' : 'Alfamart';
return Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(12),
vertical: getProportionateScreenHeight(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
text: '1. Datang ke<bold> $store</bold>',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text: '2. Tunjukkan <bold>kode pembayaran</bold> ke kasir',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
'3. Bayar dengan uang tunai sesuai dengan total pembayaran (sudah termasuk biaya layanan)',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text: '4. Transaksi selesai, simpan bukti pembayaran Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: 4)
],
),
);
}
}

View File

@ -0,0 +1,263 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart' as orderProvider;
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/providers/user_info_provider.dart'
as userInfoProvider;
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class BottomSheetDetail extends StatelessWidget {
Map<String, String> paymentMethod = {
'echannel': 'Bank Transfer',
'bank_transfer': 'Bank Transfer',
'credit_card': 'Kartu Kredit',
'gopay': 'GoPay',
'cstore': 'Gerai'
};
Widget listCourse({String? title, String? instructor, String? price}) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
// "428 Menit Menjadi Pengusaha Sukses",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
color: tenthColor,
),
),
SizedBox(height: 4),
Text(
'Oleh $instructor',
// 'Oleh Farid Subkhan',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(9.5),
color: secondaryColor,
),
),
],
),
),
Flexible(
flex: 3,
child: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}',
// 'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(50000.0)}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
var dataOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
var dataCourse =
Provider.of<orderProvider.OrderProvider>(context, listen: false).orders;
var dataUser =
Provider.of<userInfoProvider.UserInfoProvider>(context, listen: false)
.result;
return Container(
decoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
foregroundDecoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(20))),
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
Row(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.keyboard_arrow_down)),
Text('Detail Pembayaran')
],
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
height: MediaQuery.of(context).size.height * 0.4,
child: ListView(
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembeli'),
Divider(),
Text(
'Order ID',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataOrder[0].idOrder,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Nama Lengkap',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser!.data[0].fullname!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Email',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser.data[0].email!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembayaran'),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Metode Pembayaran',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(paymentMethod[dataOrder[0].paymentType]!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Harga',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(dataOrder[0].totalPayment))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Potongan Kupon',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text('Rp. 0',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Bayar',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(dataOrder[0].totalPayment))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Kursus Yang Dibeli'),
Divider(),
Column(
children: dataCourse.map((course) {
return listCourse(
title: course.title,
instructor: course.instructor,
price: course.discountPrice == "0"
? course.price
: course.discountPrice,
);
}).toList()),
// listCourse(),
// listCourse(),
// listCourse(),
// Text('Halo'),
// Text('Halo'),
// Text('Halo'),
// Text('Halo')
],
),
)
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,262 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart' as orderProvider;
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/providers/user_info_provider.dart'
as userInfoProvider;
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class BottomSheetHistory extends StatelessWidget {
Map<String, String> paymentMethod = {
'echannel': 'Bank Transfer',
'bank_transfer': 'Bank Transfer',
'credit_card': 'Kartu Kredit',
'gopay': 'GoPay',
'cstore': 'Gerai'
};
Widget listCourse({String? title, String? instructor, String? price}) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
// "428 Menit Menjadi Pengusaha Sukses",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
color: tenthColor,
),
),
SizedBox(height: 4),
Text(
'Oleh $instructor',
// 'Oleh Farid Subkhan',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(9.5),
color: secondaryColor,
),
),
],
),
),
Flexible(
flex: 3,
child: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}',
// 'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(50000.0)}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
var dataOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
var dataCourse =
Provider.of<orderProvider.OrderProvider>(context, listen: false).orders;
var dataUser =
Provider.of<userInfoProvider.UserInfoProvider>(context, listen: false)
.result;
int totalPrices = Provider.of<TotalPriceProvider>(context).totalPrices!;
return Container(
decoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
foregroundDecoration: BoxDecoration(
// color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(20))),
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
Row(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.keyboard_arrow_down)),
Text('Detail Pembayaran')
],
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
height: MediaQuery.of(context).size.height * 0.4,
child: ListView(
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembeli'),
Divider(),
Text(
'Order ID',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataOrder[0].idOrder,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Nama Lengkap',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser!.data[0].fullname!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
SizedBox(
height: 15,
),
Text(
'Email',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf)),
),
Text(
dataUser.data[0].email!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4)),
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Informasi Pembayaran'),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Metode Pembayaran',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(paymentMethod[dataOrder[0].paymentType]!,
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Harga',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(Provider.of<TotalPriceProvider>(context).totalPrices.toString()))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Potongan Kupon',
style: primaryTextStyle.copyWith(
fontSize: 10, color: Color(0xffbfbfbf))),
Text('Rp. 0',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Total Bayar',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffbfbfbf))),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(Provider.of<TotalPriceProvider>(context).totalPrices.toString()))}',
style: primaryTextStyle.copyWith(
fontSize: 12, color: Color(0xffF4f4f4))),
],
),
],
),
),
Container(
height: 6,
color: Color(0xff181818),
),
// Container(
// padding: EdgeInsets.symmetric(horizontal: 15, vertical: 20),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text('Kursus Yang Dibeli'),
// Divider(),
// Column(
// children: dataCourse.map((course) {
// return listCourse(
// title: course.title,
// instructor: course.instructor,
// price: course.discountPrice);
// }).toList()),
// listCourse(),
// listCourse(),
// listCourse(),
// Text('Halo'),
// Text('Halo'),
// Text('Halo'),
// Text('Halo')
// ],
// ),
// )
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CardMonthInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
var masaController = newValue.text;
if (newValue.selection.baseOffset == 0) {
return newValue;
}
var buffer = new StringBuffer();
for (int i = 0; i < masaController.length; i++) {
buffer.write(masaController[i]);
var nonZeroIndex = i + 1;
if (nonZeroIndex % 2 == 0 && nonZeroIndex != masaController.length) {
buffer.write('/');
}
}
var string = buffer.toString();
return newValue.copyWith(
text: string,
selection: new TextSelection.collapsed(offset: string.length));
}
}

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CardNumberInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
var text = newValue.text;
if (newValue.selection.baseOffset == 0) {
return newValue;
}
var buffer = new StringBuffer();
for (int i = 0; i < text.length; i++) {
buffer.write(text[i]);
var nonZeroIndex = i + 1;
if (nonZeroIndex % 4 == 0 && nonZeroIndex != text.length) {
buffer.write(' '); // Add double spaces.
}
}
var string = buffer.toString();
return newValue.copyWith(
text: string,
selection: new TextSelection.collapsed(offset: string.length));
}
}

View File

@ -0,0 +1,159 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
class CourseList extends StatelessWidget {
const CourseList({
Key? key,
required this.idCourse,
required this.title,
required this.price,
required this.discountPrice,
required this.imageUrl,
this.isDetailCourse,
}) : super(key: key);
final String idCourse;
final String title;
final String price;
final String discountPrice;
final String imageUrl;
final bool? isDetailCourse;
@override
Widget build(BuildContext context) {
print("Ini price ${price}");
print("Ini discountPrice ${discountPrice}");
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 10,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(70),
height: getProportionateScreenWidth(39),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(imageUrl),
),
),
),
],
)),
SizedBox(width: getProportionateScreenWidth(10)),
Expanded(
flex: 15,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
)),
Spacer(),
Flexible(
flex: 10,
child: Align(
alignment: Alignment.centerRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (isDetailCourse == null)
discountPrice == "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
)
: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
)
else
discountPrice == "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
)
: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price == "0" ? discountPrice : price))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
if (isDetailCourse == null)
if (discountPrice != "0" && discountPrice != price)
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.7,
),
)
else
SizedBox.shrink()
else if (price != "0")
Text(
'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice))}',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
decoration: TextDecoration.lineThrough,
color: fourthColor,
fontWeight: reguler,
fontSize: SizeConfig.blockHorizontal! * 2.7,
),
)
else
SizedBox.shrink(),
SizedBox(height: getProportionateScreenHeight(2)),
discountPrice != "0" && discountPrice != price
? SizedBox()
: SizedBox(),
],
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Divider(color: fourthColor),
SizedBox(height: getProportionateScreenHeight(5)),
],
);
}
}

View File

@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class CourseListCoupon extends StatelessWidget {
final String idCourse;
final String title;
final String price;
final String discountPrice;
final String imageUrl;
const CourseListCoupon({
Key? key,
required this.idCourse,
required this.title,
required this.price,
required this.discountPrice,
required this.imageUrl,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final priceCoupon = Provider.of<TotalPriceProvider>(context).priceCoupon;
return Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 10,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(70),
height: getProportionateScreenWidth(39),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(imageUrl),
),
),
),
],
)),
SizedBox(width: getProportionateScreenWidth(10)),
Expanded(
flex: 15,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
)),
Spacer(),
Flexible(
flex: 10,
child: Align(
alignment: Alignment.centerRight,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
discountPrice == "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
)
: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
),
),
// Text(
// 'Rp ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price))}',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(12),
// ),
// ),
SizedBox(
height: getProportionateScreenHeight(2),
),
priceCoupon.toString() != "0"
? Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(priceCoupon.toString()))}',
style: primaryTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
)
: SizedBox(),
],
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Divider(color: fourthColor),
SizedBox(height: getProportionateScreenHeight(5)),
],
);
}
}

View File

@ -0,0 +1,105 @@
import 'package:flutter/material.dart';
import '../../../../theme.dart';
import '../../../../size_config.dart';
class FieldKupon extends StatelessWidget {
final TextEditingController controler;
final IconButton? prefix;
const FieldKupon({Key? key, required this.controler, this.prefix})
: super(key: key);
@override
Widget build(BuildContext context) {
OutlineInputBorder outlineInputBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent),
gapPadding: 10,
);
// width: SizeConfig.screenWidth * 0.9,
// height: 33,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(15),
// border: Border.all(
// color: kSecondaryColor.withOpacity(0.5),
// width: 2,
// return Scaffold(
// body: Container(
// height: 36,
// //padding: EdgeInsets.only(top: getProportionateScreenWidth(20)),
// child: TextField(
// controller: controler,
// cursorColor: secondaryColor,
// enabled: true,
// //obscureText: true,
// textAlignVertical: TextAlignVertical.center,
// style: TextStyle(fontSize: 12, color: Colors.white),
// onChanged: (value) => print(value),
// decoration: InputDecoration(
// //isDense: true,
// contentPadding: EdgeInsets.only(top: 10, left: 15),
// filled: true,
// fillColor: Colors.transparent,
// enabledBorder: outlineInputBorder,
// focusedBorder: outlineInputBorder,
// border: outlineInputBorder,
// hintText: "Masukkan kode kupon",
// hintStyle: primaryTextStyle.copyWith(
// fontSize: 12,
// color: fourthColor,
// fontWeight: reguler,
// letterSpacing: 0.5),
// ),
// ),
// ),
// // SizedBox(height: getProportionateScreenHeight(16)),
// );
return Column(
children: [
Container(
height: getProportionateScreenHeight(32),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor.withOpacity(0.9)
: secondaryColor.withOpacity(0.2),
),
child: TextField(
controller: controler,
cursorColor: Theme.of(context).colorScheme.onPrimary,
enabled: true,
textAlignVertical: TextAlignVertical.center,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.onPrimary,
),
onChanged: (value) => print(value),
decoration: InputDecoration(
prefix: prefix,
contentPadding: EdgeInsets.only(
top: getProportionateScreenHeight(10),
left: getProportionateScreenWidth(15),
),
filled: true,
fillColor: Colors.transparent,
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
border: outlineInputBorder,
hintText: "Masukkan kode kupon",
hintStyle: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
color: Theme.of(context).brightness == Brightness.dark
? baruTextutih.withOpacity(0.5)
: Colors.grey,
fontWeight: reguler,
letterSpacing: 0.5,
),
),
),
),
SizedBox(height: getProportionateScreenHeight(16)),
],
);
}
}

View File

@ -0,0 +1,337 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class InternetBankBNI extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Masuk ke https://ibank.bni.co.id',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: '2. Masukkan User ID dan Password',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Transfer\", lalu pilih \"Tambah Rekening Favorit\". Jika menggunakan Desktop. tambah rekening pada menu \"Transaksi\" kemudian \"Atur Rekening Tujuan\" lalu pilih \"Tambah Rekening Tujuan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Masukkan nomor Virtual Account",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"5. Masukkan Kode Otentikasi dan Nomor Rekening berhasil ditambahkan",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '6. The billing information will appear on the payment validation page',
"6. Pilih menu \"Transfer\", lalu pilih \"Transfer Antar Rekening BNI\", pilih \"Rekening Tujuan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '7. If the information is correct, enter your password to proceed the payment',
"7. Pilih Rekening Debit",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '8. Your transaction will be processed',
text: "8. Masukkan jumlah pembayaran sesuai tagihan",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '8. Your transaction will be processed',
text: "9. Masukkan Kode Otentikasi",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class InternetBankBCA extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Login pada aplikasi KlikBCA, masukkan user ID & PIN.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text:
"2. Pilih \"Transfer Dana\", kemudian pilih \"Transfer ke BCA Virtual Account\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Masukkan no. BCA Virtual Account & klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"4. Pastikan data yang dimasukkan sudah benar, dan Input \"Respon KeyBCA\", lalu klik \"Kirim\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class InternetBankMandiri extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Lakukan Login ke Internet Banking Mandiri kamu.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text:
"2. Pada menu utama, pilih menu \"Bayar\" lalu pilih menu \"Multi Payment\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih akun anda di bagian Dari Rekening, kemudian di Penyedia Jasa ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"4. Masukkan kode pembayaran (kode pembayaran Mandiri billpayment kamu), dan klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"5. Periksa kembali nama perusahaan, nomor pesanan, dan jumlah pembayaran anda ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Selesaikan pembayaran dengan menggunakan Token Mandiri ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class InternetBankPermata extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Buka Website PermataNet',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Masukan User ID dan Password ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Pilih Pembayaran Tagihan ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih Virtual Account ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "5. Masukkan 16 digit kode bayar ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Masukkan nominal pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "7. Muncul konfirmasi pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "8. Masukan Mobile PIN",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}

View File

@ -0,0 +1,351 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:styled_text/styled_text.dart';
class MobileBankBNI extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: "1. Akses BNI Mobile Banking melalui handphone",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Masukkan User ID dan Password",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text:
"3. Pilih menu \"Transfer\", lalu pilih \"Antar Rekening BNI\", pilih \"Input Rekening Baru\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Masukkan nomor Virtual Account",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '5. Enter the 16 digits <bold>virtual account number</bold>',
text:
"5.Di halaman konfirmasi, pastikan data transaksi sudah benar kemudian pilih \"Ya\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
text:
// '6. The billing information will appear on the payment validation page',
"6. Masukkan password anda ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class MobileBankBCA extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Lakukan log in pada aplikasi BCA mobile.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pilih \"m-BCA\" masukan kode akses m-BCA. ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Pilih \"m-Transfer\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih \"BCA Virtual Account\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "5. Masukkan nomor BCA Virtual Account dan klik \"OK\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Konfirmasi no virtual account dan rekening pendebetan ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"7. Periksa kembalian rincian pembayaran kamu, lalu klik \"Ya\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "8. Masukan pin m-BCA ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class MobileBankMandiri extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Lakukan Login ke Mandiri Online kamu',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Pada menu utama, pilih menu \"Bayar\"",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Lalu pilih menu \"Multi Payment\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. kemudian pilih Penyedia Jasa ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"5. Masukkan kode pembayaran [Kode pembayaran Mandiri billpayment], dan klik \"Lanjutkan\" ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text:
"6. Periksa kembali data transaksi kamu dan selesaikan proses pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}
class MobileBankPermata extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
Widget build(BuildContext context) {
return Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
// text: '1. Open the <bold>BNI Mobile Banking</bold> app and login',
text: '1. Buka aplikasi PermataMobile X',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '2. Choose menu <bold>Transfer</bold>',
text: "2. Masukan Password ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '3. Choose menu <bold>Virtual Account Billing</bold>',
text: "3. Pilih Pembayaran Tagihan ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "4. Pilih Virtual Account ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "5. Masukan Nomor Virtual Account ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "6. Pilih Rekening",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "7. Masukkan nominal pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "8. Muncul konfirmasi pembayaran ",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
Divider(color: Color(0xff2D2D2D), thickness: 0.5, height: 35),
StyledText(
// text: '4. Choose the bank account you want to use',
text: "9. Masukan Mobile PIN",
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
);
}
}

View File

@ -0,0 +1,145 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/detail_order_model.dart';
import 'package:initial_folder/providers/payments_provider.dart' as payProv;
import 'package:initial_folder/providers/tab_provider.dart';
import 'package:initial_folder/screens/checkout/components/atm.dart';
import 'package:initial_folder/screens/checkout/components/internet_banking.dart';
import 'package:initial_folder/screens/checkout/components/mobile_banking.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class TabBarBatasBayar extends StatelessWidget {
TabBarBatasBayar({
Key? key,
this.bank,
}) : super(key: key);
final String? bank;
@override
Widget build(BuildContext context) {
print("Apa hayoo ${bank}");
List<DetailOrderModel> detailOrder =
Provider.of<payProv.PaymentsProvider>(context).detailOrder;
String? bankName = detailOrder.isNotEmpty ? detailOrder[0].bankName : null;
print("Apa hayoo2 ${bankName}");
TabProvider tab = Provider.of<TabProvider>(context);
Widget buildContent(int currentIndex) {
switch (currentIndex) {
case 0:
switch (bank ?? bankName) {
case 'bni':
return ATMBNI();
case 'bca':
return ATMBCA();
case 'mandiri':
case 'echannel':
return AtmMandiri();
case 'permata':
return AtmPermata();
default:
return SizedBox();
}
case 1:
switch (bank ?? bankName) {
case 'bni':
return InternetBankBNI();
case 'bca':
return InternetBankBCA();
case 'mandiri':
case 'echannel':
return InternetBankMandiri();
case 'permata':
return InternetBankPermata();
default:
return SizedBox();
}
case 2:
switch (bank ?? bankName) {
case 'bni':
return MobileBankBNI();
case 'bca':
return MobileBankBCA();
case 'mandiri':
case 'echannel':
return MobileBankMandiri();
case 'permata':
return MobileBankPermata();
default:
return SizedBox();
}
default:
return SizedBox();
}
}
return Column(
children: [
ExpansionTile(
title: Text(
'ATM',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13)),
),
children: [
buildContent(0),
],
),
Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(8)),
height: getProportionateScreenHeight(3),
decoration: BoxDecoration(
color: secondaryColor.withOpacity(0.1),
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 1,
offset: Offset(0, 1),
),
],
),
),
ExpansionTile(
title: Text(
'Internet Banking',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13)),
),
children: [
buildContent(1),
],
),
Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(8)),
height: getProportionateScreenHeight(3),
decoration: BoxDecoration(
color: secondaryColor.withOpacity(0.1),
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 1,
offset: Offset(0, 1),
),
],
),
),
ExpansionTile(
title: Text(
'Mobile Banking',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13)),
),
children: [
buildContent(2),
],
),
],
);
}
}

View File

@ -0,0 +1,435 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/zero_price_model.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/my_course_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/providers/user_info_provider.dart' as userInfo;
import 'package:initial_folder/screens/checkout/batas_bayar.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.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:intl/intl.dart';
import 'package:provider/provider.dart';
class DetailZeroPayment extends StatelessWidget {
final String? discountPrice;
final String? price;
final List<String>? idCart;
const DetailZeroPayment(
{Key? key, this.idCart, this.discountPrice, this.price})
: super(key: key);
@override
Widget build(BuildContext context) {
Future<void> deleteCourse() async {
List<String> idCarts = idCart!;
idCarts.forEach((element) async {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
});
}
var invoice = Provider.of<OrderProvider>(context, listen: false).invoice;
var totalPrice =
Provider.of<OrderProvider>(context, listen: false).totalPrice!;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
print(orders);
var zero = Provider.of<PaymentsProvider>(context).zeroPrice;
Widget bottomNav() {
return Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(90),
vertical: getProportionateScreenHeight(10)),
child: DefaultButton(
text: 'Lanjutkan',
press: () {
Provider.of<PaymentsProvider>(context, listen: false)
.zeroPayment(invoice, totalPrice.toString());
deleteCourse();
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SuccessPaidCourse()));
},
),
);
}
Widget listCourse({String? title, String? instructor, String? price}) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
color: tenthColor,
),
),
SizedBox(height: 4),
Text(
'Oleh $instructor',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(9.5),
color: secondaryColor,
),
),
],
),
),
Flexible(
flex: 3,
child: Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
),
],
),
);
}
var user = Provider.of<userInfo.UserInfoProvider>(context).result;
// var zero = Provider.of<PaymentsProvider>(context).zeroPrice;
return Scaffold(
//backgroundColor: Colors.black,
appBar: AppBar(
title: Text(
'Checkout',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Text(
'Informasi Pembeli',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
Container(
padding: EdgeInsets.symmetric(
vertical: 10,
horizontal: getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Text(
// 'Order ID',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(10),
// color: secondaryColor,
// ),
// ),
// Text(
// // state.detailOrder[0].idOrder,
// // zero!.data![0].orderId as String,
// '123',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(12),
// color: tenthColor,
// ),
// ),
// SizedBox(height: 16),
Text(
'Nama Lengkap',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
color: secondaryColor,
),
),
Text(
user!.data[0].fullname as String,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
SizedBox(height: 16),
Text(
'Email',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
color: secondaryColor,
),
),
Text(
user.data[0].email as String,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(12),
color: tenthColor,
),
),
SizedBox(height: 12),
],
),
),
],
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Text(
'Informasi Pembeli',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Harga',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
color: secondaryColor,
),
),
discountPrice != "0"
? Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(discountPrice!))}",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
12),
color: tenthColor,
),
)
: Text(
"Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(price!))}",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
12),
color: tenthColor,
),
),
],
),
SizedBox(height: 16),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
SizedBox(height: 16),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Bayar',
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(12),
color: secondaryColor,
),
),
Text(
'Rp. 0',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize:
getProportionateScreenWidth(14),
color: tenthColor,
),
),
],
),
],
),
),
],
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Text(
'Kursus yang dibeli',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
),
),
Divider(
color: Color(0xff2D2D2D),
thickness: 0.5,
height: 1),
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal: getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: orders.map((e) {
return listCourse(
instructor: e.instructor,
title: e.title,
price: e.discountPrice);
}).toList(),
),
)
],
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
bottomNav(),
SizedBox(
height: getProportionateScreenHeight(15),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,377 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/providers/cart_provider.dart';
import 'package:initial_folder/providers/carts_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.dart';
import 'package:initial_folder/screens/checkout/gopay/qr_code_gopay.dart';
import 'package:initial_folder/screens/checkout/success_paid_course.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:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:pusher_client/pusher_client.dart';
class BatasBayarGopay extends StatefulWidget {
final List<String>? idCart;
BatasBayarGopay({this.idCart});
@override
State<BatasBayarGopay> createState() => _BatasBayarGopayState();
}
class _BatasBayarGopayState extends State<BatasBayarGopay> {
Channel? _channel;
String? statusTransaction;
Future<void> deleteCourse() async {
List<String> idCarts = widget.idCart ?? [];
idCarts.forEach((element) async {
await Provider.of<CartProvider>(context, listen: false)
.deleteCart(element);
await Provider.of<CartsProvider>(context, listen: false).getCarts();
});
}
Future<void> initPusher() async {
int? idUser = await UsersInfo().getIdUser();
PusherClient pusher = PusherClient(
'92060797e94ac7033edb', PusherOptions(cluster: 'ap1'),
autoConnect: false);
pusher.connect();
// pusher.onConnectionStateChange((state) {
// print(state!.currentState);
// });
// pusher.onConnectionError((error) {
// print(error);
// });
_channel = pusher.subscribe('payment-channel');
_channel!.bind('paid-event-$idUser', (event) {
if (mounted) {
final status = jsonDecode(event!.data!);
setState(() {
statusTransaction = status['status_code'];
if (statusTransaction == "201") {
print(status['message']);
print(widget.idCart);
deleteCourse();
// Navigator.of(context).pushAndRemoveUntil(
// MaterialPageRoute(
// builder: (context) => SuccessPaidCourse(),
// ),
// (route) => false,
// );
}
});
}
});
}
@override
void initState() {
initPusher();
super.initState();
}
@override
Widget build(BuildContext context) {
var detailOrder = Provider.of<PaymentsProvider>(context).detailOrder;
return Scaffold(
appBar: AppBar(
title: Text(
'Selesaikan Pembayaran',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: SingleChildScrollView(
child: Container(
margin:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: getProportionateScreenHeight(10)),
Center(
child: Column(
children: [
Text(
'Batas akhir pembayaran sampai',
style: primaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
// 'Rabu, 13 Oktober 2021 (Pukul 19:32)',
DateFormat('E, d MMM y (H:m)')
.format(detailOrder[0].transactionTimeLimit),
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
color: tenthColor,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Segera selesaikan pembayaran atau pesananmu',
style: primaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'akan dibatalkan secara otomatis',
style: primaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
],
),
),
SizedBox(
height: getProportionateScreenHeight(30),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Metode Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'GoPay',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.scaleDown,
image: AssetImage('assets/images/gopay2.png'),
),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(16),
),
Text(
'Kode QR',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
children: [
Icon(Icons.qr_code),
Spacer(),
GestureDetector(
onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => QRCodeGopay()));
Navigator.pop(context);
},
child: Text(
"Scan Kode QR",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(16),
),
Text(
'Total Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20))),
builder: (context) {
return BottomSheetDetail();
});
},
child: Text(
"Detail Pembayaran",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(16),
),
Text(
'Status Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(
height: getProportionateScreenHeight(8),
),
Text(
statusTransaction == '201' || statusTransaction == null
? 'Pending'
: 'Success',
style: primaryTextStyle.copyWith(
color: Color(0xffEDA923),
letterSpacing: 1,
fontWeight: medium,
fontSize: getProportionateScreenWidth(12),
),
),
],
),
),
),
SizedBox(
height: getProportionateScreenHeight(24),
),
DefaultButton(
text: 'Belanja kursus lainnya',
weight: reguler,
press: () {
Navigator.pushNamedAndRemoveUntil(
context, "/home", (r) => false);
},
),
SizedBox(
height: getProportionateScreenHeight(32),
),
Container(
decoration: BoxDecoration(
color: Color(0xFF212121),
borderRadius: BorderRadius.circular(8),
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 16,
horizontal: getProportionateScreenWidth(16)),
child: Text(
'Cara Pembayaran',
style: secondaryTextStyle.copyWith(
color: tenthColor,
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Divider(
color: Color(0xff2D2D2D), thickness: 0.5, height: 0.5),
PaymentInstructionGopay()
],
),
),
SizedBox(
height: getProportionateScreenHeight(30),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,249 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.dart';
import 'package:initial_folder/screens/checkout/gopay/qr_code_gopay.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:intl/intl.dart';
import 'package:provider/provider.dart';
class BayarGopay extends StatelessWidget {
BayarGopay({this.idCart});
final List<String>? idCart;
static String routeName = "/bayarGopay";
@override
Widget build(BuildContext context) {
Widget bottomNav() {
return DefaultButton(
text: 'Bayar dengan QRIS',
press: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => GopaySplashScreen(idCart: idCart),
),
);
},
);
}
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Bayar Dengan QRIS',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Consumer<PaymentsProvider>(
builder: (context, state, _) {
if (state.stateProcess == Process.loading) {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: Center(child: CircularProgressIndicator()));
} else if (state.state == ResultState.gagal) {
return Center(child: Text('Terjadi Kesalahan'));
} else {
return SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 10),
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: 15,
horizontal:
getProportionateScreenWidth(15)),
child: Text(
'Informasi Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: Theme.of(context)
.colorScheme
.onBackground,
),
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal:
getProportionateScreenWidth(15)),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'Order ID',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
fontFamily: "Poppins",
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
state.detailOrder[0].idOrder,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
12),
),
),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: state
.detailOrder[0].idOrder,
)).then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Kode Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(
10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height:
getProportionateScreenHeight(10)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
fontFamily: "Poppins",
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '').format(double.parse(state.detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize:
getProportionateScreenWidth(
12),
),
),
GestureDetector(
onTap: () {
showModalBottomSheet(
backgroundColor:
Theme.of(context)
.colorScheme
.background,
elevation: 0.0,
context: context,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (context) {
return BottomSheetDetail();
},
);
},
child: Text(
"Detail Pembayaran",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize:
getProportionateScreenWidth(
10),
fontWeight: reguler),
),
),
],
),
SizedBox(
height:
getProportionateScreenHeight(12)),
],
),
),
],
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(30)),
PaymentInstructionGopay(),
SizedBox(height: getProportionateScreenHeight(15)),
bottomNav(),
SizedBox(height: getProportionateScreenHeight(15)),
],
),
),
);
}
},
),
);
}
}

View File

@ -0,0 +1,395 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_countdown_timer/current_remaining_time.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/components/bottom_sheet_detail.dart';
import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../../../size_config.dart';
import '../../../theme.dart';
class GopayPaymentConfirmation extends StatelessWidget {
@override
Widget build(BuildContext context) {
var detailOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
var orders = Provider.of<OrderProvider>(context, listen: false).orders;
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
scrolledUnderElevation: 0.0,
title: Text(
'Cara Pembayaran',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(10)),
child: SingleChildScrollView(
child: Column(
children: [
Container(
height: getProportionateScreenHeight(290),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
margin: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(9),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(15),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Batas Waktu Pembayaran',
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('E, d MMM y H:m WIB')
.format(detailOrder[0].transactionTimeLimit),
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: SizeConfig.blockHorizontal! * 3,
),
),
Container(
decoration: BoxDecoration(
color: sevenColor,
borderRadius: BorderRadius.circular(4),
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3),
vertical: getProportionateScreenHeight(2),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.access_time,
color: baruTextutih,
size: getProportionateScreenWidth(14),
),
SizedBox(width: getProportionateScreenWidth(2)),
CountdownTimer(
endTime: DateTime.now()
.add(Duration(hours: 24))
.millisecondsSinceEpoch,
widgetBuilder: (_, CurrentRemainingTime? time) {
if (time == null) {
return Text(
'00:00:00',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(10),
color: baruTextutih,
),
);
} else {
return Text(
'${time.hours}:${time.min}:${time.sec}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(10),
color: baruTextutih,
),
);
}
},
),
],
),
),
],
),
SizedBox(height: getProportionateScreenHeight(4)),
Divider(
color: secondaryColor,
thickness: 1,
),
Text(
"Kursus",
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: orders.map((e) {
return listCourse(
imageUrl: e.imageUrl,
instructor: e.instructor,
title: e.title,
price: e.price,
discountPrice: e.discountPrice,
);
}).toList(),
),
SizedBox(height: getProportionateScreenHeight(10)),
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"QRIS",
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color:
Theme.of(context).colorScheme.brightness ==
Brightness.dark
? Colors.transparent
: baruTexthitam.withOpacity(0.3),
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 1),
),
],
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage("assets/images/qris.png"),
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(15)),
Text(
"Order ID",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
Text(
detailOrder[0].idOrder,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(
ClipboardData(text: detailOrder[0].idOrder))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Berhasil Menyalin Order ID'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(15)),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(6)),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: detailOrder[0].totalPayment))
.then(
(_) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Total Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: primaryColor,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler),
),
),
],
),
],
),
),
SizedBox(height: getProportionateScreenHeight(13)),
PaymentInstructionGopay(),
SizedBox(height: getProportionateScreenHeight(17)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(42),
decoration: BoxDecoration(
color: primaryColor,
border: Border.all(
color: primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Lihat QRIS',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
fontWeight: semiBold,
color: baruTextutih,
),
),
),
),
onTap: () {
Navigator.pop(context);
},
),
),
SizedBox(height: getProportionateScreenHeight(21)),
],
),
),
),
);
}
Widget listCourse({
String? imageUrl,
String? title,
String? instructor,
String? price,
String? discountPrice,
int? totalPrices,
}) {
return Container(
padding: EdgeInsets.symmetric(vertical: getProportionateScreenHeight(9)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(60),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: NetworkImage(imageUrl ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'),
fit: BoxFit.cover,
),
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,102 @@
import 'package:flutter/material.dart';
import 'package:styled_text/styled_text.dart';
import '../../../size_config.dart';
import '../../../theme.dart';
class PaymentInstructionGopay extends StatelessWidget {
final TextStyle baris = thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(14),
);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(2),
right: getProportionateScreenWidth(2)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(15),
horizontal: getProportionateScreenWidth(16),
),
child: Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StyledText(
text:
'1. Buka aplikasi <bold>Gojek</bold> atau <bold>e-Wallet</bold> apapun milik anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text:
'2. Scan <bold>QR Code</bold> yang tertera dan masukkan nominal sesuai tagihan transaksi',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text:
'3. Periksa detail transaksi Anda pada aplikasi, lalu tap tombol Bayar.',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text: '4. Masukkan pin Anda',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
StyledText(
text: '5. Transaksi Anda telah selesai',
style: baris,
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: bold)),
},
),
SizedBox(height: getProportionateScreenHeight(15)),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,345 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/checkout/batas_bayar.dart';
import 'package:initial_folder/screens/checkout/gopay/batas_bayar_gopay.dart';
import 'package:initial_folder/screens/checkout/gopay/gopay_payment_confirmation.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi_pending.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';
class QRCodeGopay extends StatelessWidget {
final List<String>? idCart;
QRCodeGopay({this.idCart});
@override
Widget build(BuildContext context) {
var detailOrder =
Provider.of<PaymentsProvider>(context, listen: false).detailOrder;
return Scaffold(
backgroundColor: Theme.of(context).colorScheme.background,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
scrolledUnderElevation: 0.0,
leading: IconButton(
icon: Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
},
),
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(10),
),
child: Column(
children: [
Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
"assets/images/qris_background.png",
width: getProportionateScreenWidth(328),
height: getProportionateScreenHeight(470),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: getProportionateScreenHeight(45)),
Text(
"VOCASIA",
style: secondaryTextStyle.copyWith(
fontWeight: bold,
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(40)),
child: Text(
"Lakukan pembayaran dengan cara scan code dibawah ini dan lakukan pembayaran sesuai dengan tagihan yang diterima.",
textAlign: TextAlign.center,
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(9),
color: baruTexthitam,
),
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Center(
child: Container(
height: getProportionateScreenHeight(150),
width: getProportionateScreenWidth(150),
child: Image.network(detailOrder[0].qrCodeUrl!
// 'https://api.sandbox.midtrans.com/v2/gopay/916c417c-dd69-455f-9f8d-997b31d38c21/qr-code'
),
),
),
// Image.network(),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Order ID',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Text(
detailOrder[0].idOrder,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
fontWeight: semiBold,
letterSpacing: 1,
),
),
SizedBox(height: getProportionateScreenHeight(6)),
Text(
'Total',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '').format(double.parse(detailOrder[0].totalPayment))}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: baruTexthitam,
fontWeight: semiBold,
letterSpacing: 2,
),
),
// Center(
// child: Text(
// detailOrder[0].qrCodeUrl!.toString(),
// style: thirdTextStyle.copyWith(
// fontWeight: semiBold,
// fontSize: 14,
// color: Color(0xff181818)),
// ),
// ),
// GestureDetector(
// child: Container(
// padding: EdgeInsets.all(16),
// width: double.infinity,
// height: getProportionateScreenHeight(44),
// decoration: BoxDecoration(
// color: Color(0xff25D366),
// border: Border.all(color: Color(0xff25D366), width: 1),
// borderRadius: BorderRadius.circular(10)),
// child: Center(
// child: Text(
// 'Pembayaran Gojek',
// style: thirdTextStyle.copyWith(
// fontSize: 14, color: Color(0xfff4f4f4)),
// ),
// ),
// ),
// onTap: () async {
// await openUrl(detailOrder[0].urlGopay!.toString());
// },
// ),
],
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(40),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Cara Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
fontWeight: semiBold,
),
),
Icon(
Icons.keyboard_arrow_down_outlined,
size: getProportionateScreenWidth(22),
color: Theme.of(context).colorScheme.onBackground,
),
],
),
),
onTap: () {
Navigator.push(
context,
CustomNavigator(
child: GopayPaymentConfirmation(),
),
);
},
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(43),
decoration: BoxDecoration(
color: primaryColor,
border: Border.all(
color: primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Unduh QRIS',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
fontWeight: semiBold,
color: baruTextutih,
),
),
),
),
onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => GopayPaymentConfirmation()));
},
),
),
SizedBox(height: 16),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: GestureDetector(
child: Container(
padding: EdgeInsets.all(16),
width: double.infinity,
height: getProportionateScreenHeight(43),
decoration: BoxDecoration(
border: Border.all(
color: primaryColor,
width: 1,
),
borderRadius: BorderRadius.circular(10)),
child: Center(
child: Text(
'Cek Status Transaksi',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: primaryColor,
fontWeight: semiBold,
),
),
),
),
onTap: () {
print(idCart);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => BatasBayarGopay(idCart: idCart),
// ),
// );
Navigator.pushReplacement(
context,
CustomNavigator(
child: RiwayatTransaksiPending(),
),
);
},
),
),
SizedBox(height: getProportionateScreenHeight(20)),
],
),
),
),
);
}
}
class GopaySplashScreen extends StatefulWidget {
final List<String>? idCart;
GopaySplashScreen({this.idCart});
@override
State<GopaySplashScreen> createState() => _GopaySplashScreenState();
}
class _GopaySplashScreenState extends State<GopaySplashScreen> {
@override
void initState() {
super.initState();
Timer(
Duration(seconds: 2),
() => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => QRCodeGopay(idCart: widget.idCart),
),
),
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: SafeArea(
child: Container(
color: Color(0xff4DC256),
alignment: Alignment.center,
child: Image(
image: AssetImage('assets/images/gopay1.png'),
height: 50,
),
)),
);
}
}
Future<void> openUrl(String url,
{bool forceWebView = false, enableJavaScript = false}) async {
await launchUrl(Uri.parse(url));
}

View File

@ -0,0 +1,151 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/my_course_provider.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/providers/payments_provider.dart';
import 'package:initial_folder/screens/home/components/body_comp/latest_course.dart';
import 'package:initial_folder/screens/home/components/home_page.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
// import 'package:initial_folder/models/course_model.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:provider/provider.dart';
class NotSuccessPaidCourse extends StatelessWidget {
const NotSuccessPaidCourse({
Key? key,
this.title,
this.id,
this.thumbnail,
this.instructor,
}) : super(key: key);
final String? instructor, id, thumbnail, title;
@override
Widget build(BuildContext context) {
PageProvider pageProvider = Provider.of<PageProvider>(context);
var orders = Provider.of<OrderProvider>(context).orders;
return Scaffold(
appBar: AppBar(
leadingWidth: 14,
),
body: ListView(
children: [
SizedBox(height: getProportionateScreenHeight(8)),
Text(
'TRANSAKSI DIBATALKAN',
style: secondaryTextStyle.copyWith(
fontWeight: bold,
color: primaryColor,
fontSize: getProportionateScreenWidth(20),
letterSpacing: 1),
textAlign: TextAlign.center,
),
SizedBox(
height: getProportionateScreenHeight(16),
),
// Column(
// children: [
// Text(
// 'Order ID',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: bold,
// fontSize: getProportionateScreenWidth(10),
// color: secondaryColor,
// ),
// ),
// Text(
// '123',
// style: primaryTextStyle.copyWith(
// letterSpacing: 0.5,
// fontWeight: reguler,
// fontSize: getProportionateScreenWidth(12),
// color: tenthColor,
// ),
// ),
// ],
// ),
// SizedBox(
// height: getProportionateScreenHeight(16),
// ),
Container(
margin: EdgeInsets.only(left: 16, right: 16),
width: SizeConfig.screenWidth,
height: getProportionateScreenHeight(180),
child: Column(
children: [
Container(
width: getProportionateScreenWidth(278),
height: getProportionateScreenHeight(156),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
image: NetworkImage(thumbnail ??
// '$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg'
orders[0].imageUrl),
fit: BoxFit.fill)),
),
],
),
),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
bottom: getProportionateScreenHeight(8),
),
child: Center(
child: Text(
title ?? '',
style: secondaryTextStyle.copyWith(
fontSize: 20, letterSpacing: 0.2),
textAlign: TextAlign.center,
),
),
),
Container(
child: Center(
child: Text(
instructor == null
? 'Oleh ${orders[0].instructor}'
: 'Oleh $instructor ',
style:
primaryTextStyle.copyWith(fontSize: 14, letterSpacing: 0.5),
textAlign: TextAlign.center,
),
),
),
Container(
child: Text(
orders.length == 1 ? '' : '(${orders.length} kursus lainnya)'),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Container(
margin: EdgeInsets.only(left: 16, right: 16),
child: DefaultButton(
text: 'Kembali Ke Home',
press: () async {
await Provider.of<MyCourseProvider>(context, listen: false)
.getMyCourse();
pageProvider.currentIndex = 0;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => HomePage()),
(route) => false);
},
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
LatestCourse(text: "Kursus Terbaru")
],
),
);
}
}

View File

@ -0,0 +1,361 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi_pending.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:initial_folder/theme.dart';
import 'package:url_launcher/url_launcher.dart'; // Import url_launcher
import 'success_paid_course.dart';
class SnapPaymentPage extends StatefulWidget {
final String transactionToken;
final String orderId;
final int grossAmount;
final String courseTitle;
final String courseThumbnail;
final String courseInstructor;
final String courseId;
SnapPaymentPage({
required this.transactionToken,
required this.orderId,
required this.grossAmount,
required this.courseTitle,
required this.courseThumbnail,
required this.courseInstructor,
required this.courseId,
});
@override
_SnapPaymentPageState createState() => _SnapPaymentPageState();
}
class _SnapPaymentPageState extends State<SnapPaymentPage> {
// Controller untuk WebView
late WebViewController _controller;
double _progress = 0; // Menyimpan progress loading WebView
bool _isLoading = true; // Status loading halaman
String? baseUrlmidtrans = dotenv.env['BASE_URL_MIDTRANS']; // Base URL Midtrans
@override
void initState() {
super.initState();
// Inisialisasi WebViewController dan pengaturan event handler
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: _onProgress, // Handler progress loading
onPageStarted: _onPageStarted, // Handler saat halaman mulai dimuat
onPageFinished: _onPageFinished, // Handler saat halaman selesai dimuat
onWebResourceError: _onWebResourceError, // Handler error resource
onNavigationRequest: _onNavigationRequest, // Handler navigasi
),
)
..addJavaScriptChannel(
'BlobDataChannel',
// Handler pesan dari JavaScript untuk download QRIS
onMessageReceived: (JavaScriptMessage message) async {
if (message.message.startsWith('error:')) {
// Jika error saat fetch blob
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Download Sedang Tidak Tersedia'),
content: Text(
'Silahkan screenshot Qris tersebut untuk menyimpan ke perangkat kamu.'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text('Gagal mengunduh QRIS. Silakan coba lagi.')),
// );
} else {
// Jika berhasil, proses data blob
await _handleBlobData(message.message);
}
},
)
// Memuat halaman pembayaran Midtrans
..loadRequest(Uri.parse(
"$baseUrlmidtrans/snap/v2/vtweb/${widget.transactionToken}",
));
}
// Handler progress loading WebView
void _onProgress(int progressValue) {
setState(() {
_progress = progressValue / 100;
});
}
// Handler saat halaman mulai dimuat
void _onPageStarted(String url) {
setState(() {
_isLoading = true;
});
}
// Handler saat halaman selesai dimuat
void _onPageFinished(String url) {
setState(() {
_isLoading = false;
_progress = 0;
});
}
// Handler jika terjadi error pada resource WebView
void _onWebResourceError(WebResourceError error) {
setState(() {
_isLoading = false;
});
_showErrorDialog(error.description ?? 'Unknown Error');
}
// Handler navigasi pada WebView
NavigationDecision _onNavigationRequest(NavigationRequest request) {
// Redirect ke aplikasi pembayaran jika diperlukan
if (request.url.startsWith('https://gopay.co.id/') ||
request.url.startsWith('https://app.shopeepay.co.id/')) {
print('Redirecting to GoPay/GoJek app');
_launchURL(request.url);
return NavigationDecision.prevent;
}
// Jika link blob (download QRIS), jalankan fetch blob
if (request.url.startsWith('blob:')) {
print('Redirecting download qris');
_fetchBlobData(baseUrlmidtrans ?? "https://app.sandbox.midtrans.com",
widget.transactionToken);
return NavigationDecision.prevent;
}
// Redirect ke halaman riwayat transaksi jika status pending
if (request.url.contains('transaction_status=pending') ||
request.url.contains('https://vocasia.id/')) {
Navigator.of(context)
.pushReplacementNamed(RiwayatTransaksiPending.routeName);
return NavigationDecision.prevent;
}
// Jika pembayaran sukses, tambahkan order dan redirect ke halaman sukses
if (request.url.contains('transaction_status=settlement') ||
request.url.contains('transaction_status=capture')) {
var orderProvider = Provider.of<OrderProvider>(context, listen: false);
orderProvider.addOrder(
id: widget.courseId,
title: widget.courseTitle,
price: widget.grossAmount.toString(),
imageUrl: widget.courseThumbnail,
instructor: widget.courseInstructor,
discountPrice: '',
);
Navigator.of(context).pushReplacementNamed(
SuccessPaidCourse.routeName,
);
return NavigationDecision.prevent;
}
// Jika user menekan tombol kembali di halaman pembayaran
if (request.url.contains('action=back')) {
Navigator.of(context).pop();
return NavigationDecision.prevent;
}
// Default: lanjutkan navigasi
return NavigationDecision.navigate;
}
// Menjalankan JavaScript untuk mengambil data blob QRIS dari WebView
Future<void> _fetchBlobData(String baseUrl, String transactionId) async {
print('Fetching transaction URL: $transactionId');
final realUrl =
baseUrl + "/snap/v1/transactions/" + transactionId + "/qr-code";
final script = '''
(async function() {
try {
const response = await fetch('$baseUrl')
const blob = await response.blob();
const reader = new FileReader();
reader.onloadend = function() {
const base64data = reader.result.split(',')[1];
BlobDataChannel.postMessage(base64data);
};
reader.readAsDataURL(blob);
} catch (error) {
console.error('Failed to fetch blob:', error);
BlobDataChannel.postMessage('error: ' + error.message);
}
})();
''';
_controller.runJavaScript(script);
}
// Menyimpan data QRIS hasil download ke file lokal
Future<void> _handleBlobData(String base64Data) async {
try {
final decodedBytes = base64Decode(base64Data);
final directory = await getApplicationDocumentsDirectory();
final path = directory.path;
final file = File('$path/qris_download.png');
await file.writeAsBytes(decodedBytes);
await FileSaver.instance.saveAs(
name: 'qris_download',
ext: 'png',
mimeType: MimeType.png,
file: file,
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('QRIS berhasil diunduh')),
);
} catch (e) {
_showErrorDialog('Gagal mengunduh QRIS: $e');
}
}
// Menampilkan dialog error
void _showErrorDialog(String errorMessage) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Error'),
content: Text(errorMessage),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
}
// Membuka aplikasi eksternal (misal: GoPay/ShopeePay)
Future<void> _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
_showErrorDialog('Could not open the app');
}
}
// Handler ketika user menekan tombol back (hardware/software)
Future<bool> _onWillPop() async {
return (await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Pembayaran Belum Selesai'),
content: Text('Apakah Anda yakin ingin keluar dari halaman ini?'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('Batal'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
Navigator.of(context)
.pushReplacementNamed(RiwayatTransaksi.routeName);
},
child: Text('Keluar'),
),
],
),
)) ??
false;
}
// Melakukan reload halaman pembayaran
void _refreshPage() {
_controller.reload();
}
@override
Widget build(BuildContext context) {
// Widget utama halaman pembayaran
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: AppBar(
elevation: 5,
title: Center(
child: Text(
'Pembayaran',
style: primaryTextStyle.copyWith(
color: Colors.white,
),
),
),
backgroundColor: primaryColor,
iconTheme: IconThemeData(color: Colors.white),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () async {
bool shouldExit = await _onWillPop();
if (shouldExit) {
Navigator.of(context)
.pushReplacementNamed(RiwayatTransaksi.routeName);
}
},
),
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: _refreshPage,
),
],
),
),
body: Stack(
children: [
// Widget WebView untuk menampilkan halaman pembayaran
RefreshIndicator(
onRefresh: () async {
_refreshPage();
},
child: WebViewWidget(controller: _controller),
),
// Progress bar saat loading
if (_isLoading)
LinearProgressIndicator(
value: _progress,
color: sevenColor,
backgroundColor: secondaryColor,
),
// Spinner loading di tengah layar
if (_isLoading)
Center(
child: CircularProgressIndicator(),
),
],
),
),
);
}
}

View File

@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/order_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/default_button_payment.dart';
import 'package:provider/provider.dart';
import '../../providers/my_course_provider.dart';
class SuccessPaidCourse extends StatefulWidget {
static const String routeName = "/success-paid-course";
@override
State<SuccessPaidCourse> createState() => _SuccessPaidCourseState();
}
class _SuccessPaidCourseState extends State<SuccessPaidCourse> {
@override
Widget build(BuildContext context) {
var orders = Provider.of<OrderProvider>(context).orders;
var pageProvider = Provider.of<PageProvider>(context);
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
leadingWidth: 14,
),
body: ListView(
children: [
Image.asset(
"assets/images/success_pay.png",
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(100),
),
SizedBox(height: getProportionateScreenHeight(15)),
Text(
'Pembayaran Berhasil',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
textAlign: TextAlign.center,
),
SizedBox(height: getProportionateScreenHeight(15)),
Container(
margin: EdgeInsets.symmetric(horizontal: 16),
width: SizeConfig.screenWidth,
height: getProportionateScreenHeight(169),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
),
child: Column(
children: [
Container(
width: getProportionateScreenWidth(278),
height: getProportionateScreenHeight(145),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
image: DecorationImage(
image: NetworkImage(
orders[0].imageUrl, // Ambil dari OrderProvider
),
fit: BoxFit.cover,
),
),
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(15)),
child: Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(8),
),
child: Center(
child: Text(
orders[0].title ?? '', // Ambil dari OrderProvider
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.2,
),
textAlign: TextAlign.center,
),
),
),
),
Container(
child: Center(
child: Text(
'Oleh ${orders[0].instructor}', // Ambil dari OrderProvider
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
letterSpacing: 0.5,
fontFamily: "Poppins",
),
textAlign: TextAlign.center,
),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Container(
margin: EdgeInsets.symmetric(horizontal: 16),
child: DefaultButtonPayment(
width: double.infinity,
height: getProportionateScreenHeight(34),
text: 'Lihat Kursus',
press: () async {
await Provider.of<MyCourseProvider>(context, listen: false)
.getMyCourse();
pageProvider.currentIndex = 2;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
(route) => false,
);
},
),
),
],
),
);
}
}

View File

@ -0,0 +1,205 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/screens/coupon/success_radem_coupon_page.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator_bottom.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:initial_folder/widgets/login_regist/loading_button.dart';
import 'package:tap_debouncer/tap_debouncer.dart';
class CouponPage extends StatefulWidget {
CouponPage({Key? key}) : super(key: key);
@override
State<CouponPage> createState() => _CouponPageState();
}
class _CouponPageState extends State<CouponPage> {
final kuponController = TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool isLoading = false;
bool failed = false;
String _iconPath = 'assets/icons/not_checklist.svg';
String? errorMessage;
handleRadeem() {
setState(() {
isLoading = true;
});
if (kuponController.text.isEmpty) {
setState(() {
isLoading = false;
errorMessage = 'Kupon tidak boleh kosong';
});
} else if (kuponController.text.length <= 3) {
setState(() {
isLoading = false;
errorMessage = 'Kupon tidak valid';
});
} else {
setState(() {
errorMessage = null;
});
Navigator.pushReplacement(
context,
CustomNavigatorBottom(
child: SuccessRademCouponPage(
coupon: kuponController.text,
),
),
);
setState(() {
_iconPath = 'assets/icons/not_checklist.svg';
isLoading = false;
});
}
}
void _validateInputs() {
if (this._formKey.currentState!.validate()) {
handleRadeem();
}
}
@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).viewInsets.bottom > 0
? MediaQuery.of(context).size.height / 1.6
: MediaQuery.of(context).size.height / 2.4,
child: SingleChildScrollView(
child: Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(5),
top: getProportionateScreenHeight(5),
),
child: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.close),
),
),
],
),
Text(
'Tukarkan Voucher',
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12)),
),
SizedBox(height: getProportionateScreenHeight(5)),
Text(
'Masukkan kode voucher untuk klaim promo menarik dari\nVocasia',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10)),
),
SizedBox(height: getProportionateScreenHeight(20)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(30)),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: secondaryColor.withOpacity(0.3),
),
height: 40,
child: Form(
key: _formKey,
child: TextFormField(
autofocus: false,
controller: kuponController,
onChanged: (value) {
setState(() {
if (value.isEmpty) {
_iconPath = 'assets/images/not_checklist.svg';
} else if (value.length > 2) {
_iconPath = 'assets/icons/checklist.svg';
} else {
_iconPath = 'assets/icons/wrong.svg';
}
});
},
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
),
cursorColor: secondaryColor,
decoration: InputDecoration(
border: InputBorder.none,
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: sevenColor),
borderRadius: BorderRadius.circular(10)),
contentPadding: EdgeInsets.only(
left: getProportionateScreenWidth(20),
bottom: getProportionateScreenHeight(8),
top: getProportionateScreenHeight(2),
),
hintText: 'Masukkan Kode Voucher',
hintStyle: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: secondaryColor,
letterSpacing: 0.5,
),
suffixIcon: Transform.scale(
scale: 0.5,
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(15)),
child: SvgPicture.asset(_iconPath),
),
),
),
),
),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
if (errorMessage != null)
Text(
errorMessage!,
style: TextStyle(color: Colors.red),
),
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
top: getProportionateScreenHeight(10),
),
child: isLoading
? LoadingButton(
backgroundButtonColor: primaryColor,
textButtonColor: Colors.white,
)
: TapDebouncer(
cooldown: const Duration(milliseconds: 3000),
onTap: () async => await {_validateInputs()},
builder:
(BuildContext context, TapDebouncerFunc? onTap) {
return DefaultButton(
text: 'Tukarkan',
press: onTap,
);
},
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,369 @@
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
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/validator.dart';
import 'package:initial_folder/models/discount_course_model.dart';
import 'package:initial_folder/providers/search_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_voucher_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card_coupon.dart';
import 'package:initial_folder/screens/search_course/component/filter.dart';
import 'package:initial_folder/services/coupon_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:initial_folder/widgets/search_not_found.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/filters_course_provider.dart'
as filterCourseProvider;
import 'package:initial_folder/providers/coupon_course_provider.dart'
as couponProv;
class SuccessRademCouponPage extends StatefulWidget {
const SuccessRademCouponPage({
required this.coupon,
Key? key,
}) : super(key: key);
final coupon;
@override
State<SuccessRademCouponPage> createState() => _SuccessRademCouponPageState();
}
class _SuccessRademCouponPageState extends State<SuccessRademCouponPage> {
bool _hasShownErrorToast = false;
@override
Widget build(BuildContext context) {
final selected = Provider.of<TotalPriceProvider>(context);
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
),
body: SingleChildScrollView(
child: ChangeNotifierProvider(
create: (_) => couponProv.CouponCourseProvider(
couponService: CouponService(), coupon: widget.coupon),
child: Consumer<couponProv.CouponCourseProvider>(
builder: (context, state, _) {
if (state.state == couponProv.ResultState.Loading) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
),
);
} else if (state.state == couponProv.ResultState.HasData) {
_hasShownErrorToast = false;
if (state.result is List) {
List<DiscountCourseModel> discountCourse = state.result;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(10)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: getProportionateScreenHeight(110),
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(8),
vertical: getProportionateScreenHeight(16)),
decoration: BoxDecoration(
color: Theme.of(context).brightness ==
Brightness.dark
? fifteenColor
: baruTextutih,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.25),
spreadRadius: 0,
blurRadius: 4,
offset: Offset(0, 4),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Voucher Berhasil DItukar',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize:
getProportionateScreenWidth(12)),
),
Text(
'Ayo pilih kursus yang sesuai dengan keinginan kamu',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10)),
),
],
),
),
// SizedBox(height: getProportionateScreenHeight(15)),
// PreferredSize(
// preferredSize: Size.fromHeight(
// getProportionateScreenWidth(57)),
// child: AppBar(
// automaticallyImplyLeading: false,
// scrolledUnderElevation: 0,
// backgroundColor:
// Theme.of(context).colorScheme.background,
// leadingWidth: 30,
// actions: [
// IconButton(
// padding: EdgeInsets.zero,
// onPressed: () => Navigator.of(context,
// rootNavigator: true)
// .push(
// CustomNavigator(
// child: const Filter(),
// ),
// ),
// icon: Icon(
// Icons.tune_rounded,
// color: primaryColor,
// ),
// ),
// ],
// title: Container(
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(10),
// color: Theme.of(context).brightness ==
// Brightness.dark
// ? seventeenColor
// : secondaryColor.withOpacity(0.3),
// ),
// height: 40,
// child: Consumer<SearchProvider>(
// builder: (context, state, _) => TextField(
// autofocus: false,
// onSubmitted: (value) {
// Provider.of<
// filterCourseProvider
// .FilterCourseProvider>(
// context,
// listen: false)
// .isSearchsFalse();
// filterCourseProvider
// .FilterCourseProvider
// filterCourseProv = Provider.of<
// filterCourseProvider
// .FilterCourseProvider>(
// context,
// listen: false);
// state.searchText =
// validatorSearch(value);
// state.initSearchCourse(
// price: filterCourseProv
// .currentIndexPrice,
// level:
// filterCourseProv.levels.join(','),
// rating: filterCourseProv
// .currentIndexRating,
// );
// },
// style: primaryTextStyle.copyWith(
// fontSize:
// getProportionateScreenWidth(14),
// letterSpacing: 0.5,
// ),
// onChanged: (value) {
// state.searchText =
// validatorSearch(value);
// },
// cursorColor: secondaryColor,
// decoration: InputDecoration(
// border: InputBorder.none,
// errorBorder: OutlineInputBorder(
// borderSide:
// BorderSide(color: sevenColor),
// borderRadius:
// BorderRadius.circular(10)),
// contentPadding: EdgeInsets.only(
// top: getProportionateScreenHeight(
// 2)),
// prefixIcon: Icon(
// FeatherIcons.search,
// size: 20,
// color: primaryColor,
// ),
// hintText: 'Cari Kursus',
// hintStyle: primaryTextStyle.copyWith(
// fontSize:
// getProportionateScreenWidth(12),
// color: secondaryColor,
// letterSpacing: 0.5,
// ),
// ),
// ),
// ),
// ),
// ),
// ),
SizedBox(height: getProportionateScreenHeight(24)),
Text(
'Kursus Terkait',
textAlign: TextAlign.start,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(16)),
GridView.builder(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(20),
left: getProportionateScreenWidth(5),
bottom: getProportionateScreenHeight(13),
),
physics: ScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: discountCourse[0].typeCoupon == "1"
? 3.1 / 4
: 2.8 / 4,
crossAxisSpacing: 16,
mainAxisSpacing: 14,
),
itemCount: discountCourse.length,
itemBuilder: (context, index) {
var course = discountCourse[index];
var finalPriceReal =
course.finalPrice.toString().replaceAll(".", "");
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(12)),
child: ProductCardCoupon(
totalDiscount: int.parse(course.value!) > 99 ||
course.typeCoupon == "1"
? 0
: int.parse(course.value!),
students: course.students ?? '0',
id: course.idCourse,
thumbnail: course.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: course.title,
instructorName: course.instructorName,
specificRating: (course.rating.isNotEmpty &&
course.rating[0]?.avgRating != null)
? course.rating[0]!.avgRating.toString()
: '0',
rating: (course.rating.isNotEmpty &&
course.rating[0]?.avgRating != null)
? course.rating[0]!.avgRating.toString()
: '5.0',
numberOfRatings: (course.rating.isNotEmpty &&
course.rating[0]?.totalReview != null)
? course.rating[0]!.totalReview!
: '0',
isTopCourse: course.topCourse ?? '',
price: (course.finalPrice.toString() == '0')
? 'Gratis'
: numberFormat(course.finalPrice.toString()),
realPrice: (course.price == '0')
? ''
: course.typeCoupon != "1"
? numberFormat(course.price)
: "",
press: () {
selected.selectedPriceCoupon =
int.parse(course.price);
selected.selectedTypeCoupon =
course.typeCoupon.toString();
selected.selectedCouponText = widget.coupon;
selected.selectedFinalPriceCoupon =
int.parse(finalPriceReal);
selected.selectedTotalPrice =
int.parse(finalPriceReal);
selected.selectedPotonganKupon = int.parse(
course.hargaTotalDiscount.toString());
selected.selectedValuePrice =
course.value.toString();
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: DetailVoucherScreen(
idcourse: course.idCourse,
coupon: widget.coupon,
),
),
);
},
),
);
},
)
],
);
} else if (state.result is String) {
String message = state.result;
return Center(
child: Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(15),
right: getProportionateScreenWidth(15),
top: getProportionateScreenHeight(140),
),
child: Text(
textAlign: TextAlign.center,
message,
style: thirdTextStyle,
),
),
);
} else {
return Center(child: Text(''));
}
} else if (state.state == couponProv.ResultState.NoData) {
_hasShownErrorToast = false;
return SearchNotFound();
} else if (state.state == couponProv.ResultState.Error) {
if (!_hasShownErrorToast) {
_hasShownErrorToast = true;
Future.delayed(Duration.zero, () {
Navigator.pop(context);
CherryToast.error(
animationDuration: Durations.long1,
title: Text(
"Kupon Tidak Valid",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
),
animationType: AnimationType.fromTop,
).show(context);
});
}
return SearchNotFound();
} else {
return Center(child: Text(''));
}
},
),
),
),
);
}
}

View File

@ -0,0 +1,134 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/models/section_model.dart';
import 'package:initial_folder/providers/selected_title_provider.dart';
import 'package:initial_folder/services/announcement_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/announcement_user_page.dart';
import 'package:provider/provider.dart';
class Announcement extends StatefulWidget {
const Announcement({
Key? key,
required this.id,
required this.lesonOper,
required this.sectionOper,
required this.lessonMapIdoper,
required this.dataLessonOper,
}) : super(key: key);
final id;
final lesonOper;
final sectionOper;
final lessonMapIdoper;
final List<DataLesson> dataLessonOper;
@override
State<Announcement> createState() => _AnnouncementState();
String? showSummary(String? selectedTitle) {
String? selectedSummary = dataLessonOper
.firstWhere((data) => data.title == selectedTitle,
orElse: () => DataLesson(
summary: ' Tidak ada ringkasan'))
.summary;
return selectedSummary;
}
}
class _AnnouncementState extends State<Announcement> {
double value = 0;
final _controller = TextEditingController();
@override
void initState() {
super.initState();
AnnouncementService().getAnnouncement(widget.id);
}
@override
Widget build(BuildContext context) {
final selectedTitle =
Provider.of<SelectedTitleProvider>(context).selectedTitle;
return SingleChildScrollView(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
top: getProportionateScreenWidth(16),
),
child: Text(
'Ringkasan Kursus',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(14),
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
top: getProportionateScreenWidth(10),
),
child: Column(
children: [
if (widget.showSummary(selectedTitle) != "")
Text(
widget.showSummary(selectedTitle)!,
style: thirdTextStyle,
)
else
Center(
child: Text(
'Tidak Ada Ringkasan',
style: thirdTextStyle,
),
),
],
),
),
],
),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
top: getProportionateScreenWidth(16),
),
child: Text(
'Pengumuman',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(14),
),
),
),
SizedBox(height: getProportionateScreenHeight(14)),
AnnouncementUserPage(idCourse: widget.id),
],
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,710 @@
import 'dart:convert';
import 'package:expandable/expandable.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/detail_course_provider.dart';
import 'package:initial_folder/providers/section_lesson_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/detail_course/components/instruktur.dart';
import 'package:initial_folder/screens/detail_course/components/kursus_include_item.dart';
import 'package:provider/provider.dart';
import '../../../size_config.dart';
import '../../../theme.dart';
class DetailPlayCourse extends StatefulWidget {
const DetailPlayCourse({super.key});
@override
State<DetailPlayCourse> createState() => _DetailPlayCourseState();
}
class _DetailPlayCourseState extends State<DetailPlayCourse> {
bool isExpanded = false;
bool isExpanded2 = false;
@override
Widget build(BuildContext context) {
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
bool isDarkMode = brightnessValue == Brightness.dark;
SectionLessonProvider sectionLessonProvider =
Provider.of<SectionLessonProvider>(context);
final themeProvider = Provider.of<ThemeProvider>(context);
Widget kemampuanDiraih(String title) {
return Container(
margin: EdgeInsets.only(bottom: 10),
child: Row(
children: [
Icon(Icons.check,
size: getProportionateScreenHeight(13), color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,),
SizedBox(
width: 10,
),
Expanded(
child: Align(
alignment: Alignment.topLeft,
child: Text(
title,
style: thirdTextStyle.copyWith(
fontWeight: light,
color: Theme.of(context).colorScheme.onBackground,
fontSize: getProportionateScreenWidth(12),
),
),
),
),
],
),
);
}
Widget persyaratan(String title) {
return Container(
margin: EdgeInsets.only(bottom: 10),
child: Row(
children: [
title.isNotEmpty
? Icon(
Icons.brightness_1,
size: getProportionateScreenHeight(13),
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
)
: SizedBox.shrink(),
SizedBox(
width: 10,
),
Expanded(
child: Align(
alignment: Alignment.topLeft,
child: Text(
title,
style: thirdTextStyle.copyWith(
fontWeight: light,
color: Theme.of(context).colorScheme.onBackground,
fontSize: getProportionateScreenWidth(12),
),
),
),
),
],
),
);
}
return Consumer<DetailCourseProvider>(builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
var detailCourse = state.result!.data[0][0];
print(detailCourse.outcome);
print(detailCourse.requirement);
List requirement;
List outcomes = [];
if (detailCourse.outcome != '') {
outcomes = jsonDecode(detailCourse.outcome ?? 'gagal');
}
try {
requirement = jsonDecode(detailCourse.requirement ?? '[]');
} catch (e) {
requirement = [];
}
final bool hasDescription = detailCourse.description!.isNotEmpty;
return SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(9)),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10),
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:
'${detailCourse.totalDuration} video pembelajaran'),
KursusIncludeItems(
svg: 'assets/icons/lesson.svg',
text: '${detailCourse.totalLesson} pelajaran'),
KursusIncludeItems(
svg: 'assets/icons/calendar.svg',
text: 'Akses full seumur hidup'),
KursusIncludeItems(
svg: 'assets/icons/phone.svg',
text: ' Akses di ponsel dan TV '),
],
),
),
SizedBox(
height: 5,
),
ExpandableNotifier(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 12,
),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(106),
bottom: getProportionateScreenWidth(8),
),
child: Text('Kemampuan Yang Akan Diraih',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(14))),
),
Expandable(
collapsed: ExpandableButton(
child: Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
outcomes.isEmpty
? Row(
children: [
Expanded(
child: Align(
alignment: Alignment.topLeft,
child: Text(
'',
),
),
),
],
)
: Column(children: [
...outcomes
.map((e) => kemampuanDiraih(e))
.take(2)
]),
if (outcomes.isNotEmpty && outcomes.length >= 3)
SizedBox(height: 8),
if (outcomes.isNotEmpty && outcomes.length >= 3)
Container(
child: Text(
"Tampilkan Lebih Banyak",
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
fontSize:
getProportionateScreenWidth(12),
),
),
),
],
),
),
),
expanded: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ExpandableButton(
child: Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
outcomes.isEmpty
? Row(
children: [
Expanded(
child: Align(
alignment: Alignment.topLeft,
child: Text(
'',
),
),
),
],
)
: Column(
children: outcomes
.map((e) => kemampuanDiraih(e))
.toList(),
),
if (outcomes.isNotEmpty &&
outcomes.length >= 3)
SizedBox(
height: 16,
),
if (outcomes.isNotEmpty &&
outcomes.length >= 3)
Container(
child: Text(
"Tampilkan Lebih Sedikit",
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
color:
Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
fontSize:
getProportionateScreenWidth(12),
),
),
)
],
),
),
)
],
),
),
],
),
),
ExpandableNotifier(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 12,
),
Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(106),
bottom: getProportionateScreenWidth(8),
),
child: Text('Persyaratan',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(14))),
),
Expandable(
collapsed: ExpandableButton(
child: Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
requirement.isEmpty
? Row(
children: [
Expanded(
child: Align(
alignment: Alignment.topLeft,
child: Text(
'',
),
),
),
],
)
: Column(children: [
...requirement
.map((e) => persyaratan(e))
.take(2)
]),
if (requirement.isNotEmpty &&
requirement.length >= 3)
SizedBox(height: 8),
if (requirement.isNotEmpty &&
requirement.length >= 3)
Container(
child: Text(
"Tampilkan Lebih Banyak",
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
fontSize:
getProportionateScreenWidth(12),
),
),
),
],
),
),
),
expanded: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ExpandableButton(
child: Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
requirement.isEmpty
? Row(
children: [
Expanded(
child: Align(
alignment: Alignment.topLeft,
child: Text(
'',
),
),
),
],
)
: Column(
children: requirement
.map((e) => persyaratan(e))
.toList(),
),
if (requirement.isNotEmpty &&
requirement.length >= 3)
SizedBox(
height: 16,
),
if (requirement.isNotEmpty &&
requirement.length >= 3)
Container(
child: Text(
"Tampilkan Lebih Sedikit",
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
color:
Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
fontSize:
getProportionateScreenWidth(12),
),
),
)
],
),
),
)
],
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(5)),
SizedBox(
height: 14,
),
Align(
alignment: Alignment.topLeft,
child: Container(
margin:
EdgeInsets.only(left: getProportionateScreenWidth(10)),
child: Text(
'Deskripsi',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(14),
),
),
),
),
AnimatedSize(
curve: Curves.fastOutSlowIn,
duration: const Duration(milliseconds: 300),
child: detailCourse.description!.isNotEmpty
? Container(
height: sectionLessonProvider.isExpanded ? 55 : null,
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(5)),
child: Html(
data: detailCourse.description!
.split('\n')
.take(2)
.join('\n'),
style: {
"body": Style(
fontSize:
FontSize(getProportionateScreenWidth(12)),
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
textAlign: TextAlign.justify,
color: Theme.of(context).brightness ==
Brightness.dark
? Colors.grey[100]
: Colors.grey[600],
),
},
),
)
: SizedBox(),
),
Padding(
padding:
EdgeInsets.only(left: getProportionateScreenWidth(3)),
child: detailCourse.description!.length > 140
? TextButton(
style: TextButton.styleFrom(
foregroundColor: primaryColor),
onPressed: () => sectionLessonProvider.expanded(),
child: sectionLessonProvider.isExpanded
? Text(
'Tampilkan Lebih Banyak',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
fontSize: getProportionateScreenWidth(12),
),
textAlign: TextAlign.left,
)
: Text(
'Tampilkan Lebih Sedikit',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
fontSize: getProportionateScreenWidth(12),
),
),
)
: SizedBox(),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (hasDescription &&
detailCourse.description!.length > 120)
SizedBox(height: getProportionateScreenHeight(10)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: Row(
children: [
CircleAvatar(
radius: 20,
backgroundColor: primaryColor,
backgroundImage: detailCourse.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(detailCourse.fotoProfile!)
as ImageProvider,
),
SizedBox(width: getProportionateScreenWidth(10)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
detailCourse.instructor ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: bold,
),
),
Row(
children: [
Text(
'Instructor, ',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
),
Text(
'${detailCourse.totalStudents ?? '0'} Murid, ',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
),
Text(
'${detailCourse.totalLesson ?? ''} Kursus',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: light,
),
)
],
),
],
),
],
),
),
// SizedBox(height: 2),
// widget.headline != null
// ? Container(
// margin: EdgeInsets.only(left: 10),
// child: Text(
// widget.headline!,
// style: TextStyle(fontSize: 13),
// ),
// )
// : const SizedBox.shrink(),
// 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),
// ),
// ],
// ),
// ),
if (detailCourse.bio == null || detailCourse.bio!.isEmpty)
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenHeight(10),
right: getProportionateScreenHeight(10),
bottom: getProportionateScreenHeight(10),
),
child: const SizedBox(height: 10)
)
else
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(5),
right: getProportionateScreenWidth(10),
),
child: isExpanded2
? Html(
data: detailCourse.bio,
style: {
"body": Style(
fontSize: FontSize(
getProportionateScreenWidth(12)),
fontWeight: light,
fontFamily: 'Poppins',
),
},
)
: Html(
data: detailCourse.bio != null &&
detailCourse.bio!.length > 100
? detailCourse.bio!.substring(0, 200)
: detailCourse.bio!,
style: {
"body": Style(
fontSize: FontSize(
getProportionateScreenWidth(12)),
fontWeight: reguler,
fontFamily: 'Poppins',
),
},
),
),
if (detailCourse.bio!.isNotEmpty &&
detailCourse.bio!.length > 100)
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(12),
bottom: getProportionateScreenHeight(10),
),
child: GestureDetector(
onTap: () {
setState(() {
isExpanded2 = !isExpanded2;
print('asdasd');
});
},
child: Text(
isExpanded2
? 'Tampilkan Lebih Sedikit'
: 'Tampilkan Lebih Banyak',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: fourthColor,
fontSize: getProportionateScreenWidth(12),
),
),
),
),
],
),
],
),
// Instruktur(
// id: detailCourse.instructorId ?? '1',
// bio: detailCourse.bio,
// instructor: detailCourse.instructor,
// rating: detailCourse.rating[0].avgRating.toString(),
// review: detailCourse.rating[0].totalReview ?? '',
// fotoProfile: detailCourse.fotoProfile,
// totalLesson: detailCourse.totalLesson,
// totalStudent: detailCourse.totalStudents,
// headline: detailCourse.headlineInstructor,
// ),
],
),
),
);
} else if (state.state == ResultState.Error) {
return Center(
child: Text('Terjadi Kesalahan'),
);
} else {
return Center(child: Text('error'));
}
});
}
}

View File

@ -0,0 +1,400 @@
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:initial_folder/models/qna_model.dart';
import 'package:initial_folder/providers/like_or_unlike_provider.dart';
import 'package:initial_folder/providers/posting_qna_reply_provider.dart';
import 'package:initial_folder/providers/qna_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/reply_qna_user_page.dart';
import 'package:provider/provider.dart';
import '../../../get_it.dart';
import '../../../models/comment_qna_model.dart';
// import '../../../widgets/qna_user.dart';
final scaffoldKey = GlobalKey<ScaffoldState>();
class DetailQuestAndAnswer extends StatefulWidget {
const DetailQuestAndAnswer({
Key? key,
required this.id,
required this.qnaDataModel,
required this.index,
required this.userId,
}) : super(key: key);
final QnaDataModel qnaDataModel;
final id;
final int index;
final int userId;
@override
State<DetailQuestAndAnswer> createState() => _DetailQuestAndAnswerState();
}
class _DetailQuestAndAnswerState extends State<DetailQuestAndAnswer> {
final _controller = TextEditingController();
final provider = qnaGetIt<QnaProvider>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
void onReplyDeleted(String idRep) {
setState(() {
// Temukan indeks balasan yang akan dihapus
final int indexToRemove = widget.qnaDataModel.comment.indexWhere((comment) => comment.idRep == idRep);
// Jika balasan ditemukan, hapus dan perbarui jumlah komentar
if (indexToRemove != -1) {
widget.qnaDataModel.comment.removeAt(indexToRemove);
widget.qnaDataModel.countComment = (widget.qnaDataModel.countComment ?? 1) - 1;
}
});
}
@override
Widget build(BuildContext context) {
PostingQnaReplyProvider postingQnaReplyProvider = Provider.of<PostingQnaReplyProvider>(context);
LikeOrUnlikeProvider _likeOrUnlikeProvider = Provider.of<LikeOrUnlikeProvider>(context);
likeOrUnlikes(int idQna) async {
final provider = qnaGetIt<QnaProvider>();
if (await _likeOrUnlikeProvider.likeOrUnlike(idQna)) {
provider.getQna(widget.id);
print("Respon Baik");
}
}
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text(
'Pertanyaan',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16),
letterSpacing: 0.2,
),
),
),
body: GestureDetector(
child: Stack(
children: [
ListView(
children: [
// Tampilan pertanyaan utama
Padding(
padding: EdgeInsets.all(getProportionateScreenWidth(0)),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Padding(
padding: EdgeInsets.all(getProportionateScreenWidth(16)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
backgroundColor: primaryColor,
backgroundImage: widget.qnaDataModel.fotoProfile == null
? AssetImage("assets/images/Profile Image.png")
: NetworkImage(widget.qnaDataModel.fotoProfile ?? '') as ImageProvider,
),
SizedBox(width: getProportionateScreenWidth(8)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.qnaDataModel.username ?? '',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
color: Theme.of(context).colorScheme.onBackground,
),
),
Text(
widget.qnaDataModel.date ?? '',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).colorScheme.onBackground,
),
),
],
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
if (widget.qnaDataModel.title != '')
Text(
widget.qnaDataModel.title!,
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(16),
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onBackground,
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Html(
data: widget.qnaDataModel.quest ?? 'Pertanyaan tidak tersedia',
style: {
"*": Style(margin: Margins.zero),
},
),
SizedBox(height: getProportionateScreenHeight(16)),
Row(
children: [
kLike(
widget.qnaDataModel.selfLiked ?? false,
int.parse(widget.qnaDataModel.countLike ?? '0'),
() async {
await likeOrUnlikes(int.parse(widget.qnaDataModel.idQna.toString()));
setState(() {
widget.qnaDataModel.selfLiked = !(widget.qnaDataModel.selfLiked ?? false);
widget.qnaDataModel.countLike = widget.qnaDataModel.selfLiked!
? (int.parse(widget.qnaDataModel.countLike ?? '0') + 1).toString()
: (int.parse(widget.qnaDataModel.countLike ?? '0') - 1).toString();
});
},
),
SizedBox(width: getProportionateScreenWidth(13)),
kComment(widget.qnaDataModel.comment.length),
],
),
],
),
),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
// Divider(),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
vertical: getProportionateScreenWidth(8),
),
child: Text(
'Balasan',
style: thirdTextStyle.copyWith(
color: Theme.of(context).colorScheme.onBackground,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16),
letterSpacing: 1,
),
),
),
SizedBox(height: getProportionateScreenHeight(13)),
ReplyQnaUserPage(
idCourse: widget.id,
idQna: widget.qnaDataModel.idQna ?? '',
userId: widget.userId,
onReplyDeleted: onReplyDeleted,
),
SizedBox(height: getProportionateScreenHeight(65)),
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? Color.fromARGB(255, 54, 61, 96)
: Color.fromARGB(255, 221, 221, 221),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
height: getProportionateScreenWidth(72),
width: double.infinity,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
vertical: getProportionateScreenWidth(16),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: SizeConfig.screenWidth * 0.65,
child: TextFormField(
scrollPhysics: AlwaysScrollableScrollPhysics(),
textAlignVertical: TextAlignVertical.center,
controller: _controller,
scrollPadding: EdgeInsets.zero,
cursorColor: secondaryColor,
maxLines: 1,
minLines: 1,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
filled: true,
fillColor: Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
hintStyle: secondaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontSize: getProportionateScreenWidth(12),
),
hintText: "Balas Pertanyaan",
),
),
),
ElevatedButton(
onPressed: () async {
if (_controller.text.trim().isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: Colors.orange,
content: Text(
'Ups, balasan masih kosong. isi dulu yuk!',
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
} else {
bool isSuccessful = await postingQnaReplyProvider.postQnaReply(
_controller.text,
widget.qnaDataModel.idQna.toString(),
);
if (isSuccessful) {
setState(() {
// Tambahkan balasan baru ke dalam komentar
widget.qnaDataModel.comment.add(
Comment(
textRep: _controller.text,
username: '',
createAt: DateTime.now().toString(),
),
);
});
provider.getQna(widget.id);
_controller.clear();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: Colors.green,
content: Text(
'Balasan berhasil dikirim',
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: Colors.red,
content: Text(
'Gagal mengirim balasan, silakan coba lagi',
style: primaryTextStyle.copyWith(color: Colors.white),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
}
}
},
child: Text(
'Kirim',
style: thirdTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.3,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
minimumSize: Size(
getProportionateScreenWidth(35),
getProportionateScreenWidth(35),
),
),
)
],
),
),
),
),
],
),
),
);
}
}
Widget kLike(bool isLiked, int likeCount, Function onTap) {
return GestureDetector(
onTap: () => onTap(),
child: Row(
children: [
Icon(
isLiked ? Icons.favorite : Icons.favorite_border_rounded,
color: isLiked ? Colors.red : secondaryColor,
size: 25,
),
SizedBox(width: 5),
Text(
"$likeCount",
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 0.3,
),
),
],
),
);
}
Widget kComment(int? commentCount) {
return Row(
children: [
Icon(
FontAwesomeIcons.comment,
color: secondaryColor,
size: 25,
),
SizedBox(width: 5),
Text(
"${commentCount ?? 0}",
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 0.3,
),
),
],
);
}

View File

@ -0,0 +1,32 @@
import 'dart:js';
import 'package:flutter/material.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:initial_folder/screens/course/sertif.dart';
import 'package:initial_folder/providers/user_info_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/certificate_provider.dart';
class DownloadCertificate extends StatelessWidget {
final int? idCourse;
const DownloadCertificate({Key? key, this.idCourse}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
Row(
children: [
ElevatedButton(onPressed: () {}, child: Text('PNG')),
ElevatedButton(onPressed: () {}, child: Text('PDF'))
],
)
],
),
);
}
}

View File

@ -0,0 +1,487 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:initial_folder/theme.dart';
const Duration _kExpand = Duration(milliseconds: 200);
/// A single-line [ListTile] with an expansion arrow icon that expands or collapses
/// the tile to reveal or hide the [children].
///
/// This widget is typically used with [ListView] to create an
/// "expand / collapse" list entry. When used with scrolling widgets like
/// [ListView], a unique [PageStorageKey] must be specified to enable the
/// [ExpansionTile] to save and restore its expanded state when it is scrolled
/// in and out of view.
///
/// This class overrides the [ListTileThemeData.iconColor] and [ListTileThemeData.textColor]
/// theme properties for its [ListTile]. These colors animate between values when
/// the tile is expanded and collapsed: between [iconColor], [collapsedIconColor] and
/// between [textColor] and [collapsedTextColor].
///
/// The expansion arrow icon is shown on the right by default in left-to-right languages
/// (i.e. the trailing edge). This can be changed using [controlAffinity]. This maps
/// to the [leading] and [trailing] properties of [ExpansionTile].
///
/// {@tool dartpad}
/// This example demonstrates different configurations of ExpansionTile.
///
/// ** See code in examples/api/lib/material/expansion_tile/expansion_tile.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [ListTile], useful for creating expansion tile [children] when the
/// expansion tile represents a sublist.
/// * The "Expand and collapse" section of
/// <https://material.io/components/lists#types>
class ExpansionTileCopy extends StatefulWidget {
/// Creates a single-line [ListTile] with an expansion arrow icon that expands or collapses
/// the tile to reveal or hide the [children]. The [initiallyExpanded] property must
/// be non-null.
const ExpansionTileCopy({
Key? key,
this.leading,
required this.title,
this.subtitle,
this.onExpansionChanged,
this.children = const <Widget>[],
this.trailing,
this.initiallyExpanded = false,
this.maintainState = false,
this.tilePadding,
this.expandedCrossAxisAlignment,
this.expandedAlignment,
this.childrenPadding,
this.backgroundColor,
this.collapsedBackgroundColor,
this.textColor,
this.collapsedTextColor,
this.iconColor,
this.collapsedIconColor,
this.controlAffinity,
}) : assert(
expandedCrossAxisAlignment != CrossAxisAlignment.baseline,
'CrossAxisAlignment.baseline is not supported since the expanded children '
'are aligned in a column, not a row. Try to use another constant.',
),
super(key: key);
/// A widget to display before the title.
///
/// Typically a [CircleAvatar] widget.
///
/// Note that depending on the value of [controlAffinity], the [leading] widget
/// may replace the rotating expansion arrow icon.
final Widget? leading;
/// The primary content of the list item.
///
/// Typically a [Text] widget.
final Widget title;
/// Additional content displayed below the title.
///
/// Typically a [Text] widget.
final Widget? subtitle;
/// Called when the tile expands or collapses.
///
/// When the tile starts expanding, this function is called with the value
/// true. When the tile starts collapsing, this function is called with
/// the value false.
final ValueChanged<bool>? onExpansionChanged;
/// The widgets that are displayed when the tile expands.
///
/// Typically [ListTile] widgets.
final List<Widget> children;
/// The color to display behind the sublist when expanded.
///
/// If this property is null then [ExpansionTileThemeData.backgroundColor] is used. If that
/// is also null then Colors.transparent is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? backgroundColor;
/// When not null, defines the background color of tile when the sublist is collapsed.
///
/// If this property is null then [ExpansionTileThemeData.collapsedBackgroundColor] is used.
/// If that is also null then Colors.transparent is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? collapsedBackgroundColor;
/// A widget to display after the title.
///
/// Note that depending on the value of [controlAffinity], the [trailing] widget
/// may replace the rotating expansion arrow icon.
final Widget? trailing;
/// Specifies if the list tile is initially expanded (true) or collapsed (false, the default).
final bool initiallyExpanded;
/// Specifies whether the state of the children is maintained when the tile expands and collapses.
///
/// When true, the children are kept in the tree while the tile is collapsed.
/// When false (default), the children are removed from the tree when the tile is
/// collapsed and recreated upon expansion.
final bool maintainState;
/// Specifies padding for the [ListTile].
///
/// Analogous to [ListTile.contentPadding], this property defines the insets for
/// the [leading], [title], [subtitle] and [trailing] widgets. It does not inset
/// the expanded [children] widgets.
///
/// If this property is null then [ExpansionTileThemeData.tilePadding] is used. If that
/// is also null then the tile's padding is `EdgeInsets.symmetric(horizontal: 16.0)`.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final EdgeInsetsGeometry? tilePadding;
/// Specifies the alignment of [children], which are arranged in a column when
/// the tile is expanded.
///
/// The internals of the expanded tile make use of a [Column] widget for
/// [children], and [Align] widget to align the column. The `expandedAlignment`
/// parameter is passed directly into the [Align].
///
/// Modifying this property controls the alignment of the column within the
/// expanded tile, not the alignment of [children] widgets within the column.
/// To align each child within [children], see [expandedCrossAxisAlignment].
///
/// The width of the column is the width of the widest child widget in [children].
///
/// If this property is null then [ExpansionTileThemeData.expandedAlignment]is used. If that
/// is also null then the value of `expandedAlignment` is [Alignment.center].
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Alignment? expandedAlignment;
/// Specifies the alignment of each child within [children] when the tile is expanded.
///
/// The internals of the expanded tile make use of a [Column] widget for
/// [children], and the `crossAxisAlignment` parameter is passed directly into the [Column].
///
/// Modifying this property controls the cross axis alignment of each child
/// within its [Column]. Note that the width of the [Column] that houses
/// [children] will be the same as the widest child widget in [children]. It is
/// not necessarily the width of [Column] is equal to the width of expanded tile.
///
/// To align the [Column] along the expanded tile, use the [expandedAlignment] property
/// instead.
///
/// When the value is null, the value of `expandedCrossAxisAlignment` is [CrossAxisAlignment.center].
final CrossAxisAlignment? expandedCrossAxisAlignment;
/// Specifies padding for [children].
///
/// If this property is null then [ExpansionTileThemeData.childrenPadding] is used. If that
/// is also null then the value of `childrenPadding` is [EdgeInsets.zero].
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final EdgeInsetsGeometry? childrenPadding;
/// The icon color of tile's expansion arrow icon when the sublist is expanded.
///
/// Used to override to the [ListTileThemeData.iconColor].
///
/// If this property is null then [ExpansionTileThemeData.iconColor] is used. If that
/// is also null then the value of [ListTileThemeData.iconColor] is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? iconColor;
/// The icon color of tile's expansion arrow icon when the sublist is collapsed.
///
/// Used to override to the [ListTileThemeData.iconColor].
final Color? collapsedIconColor;
/// The color of the tile's titles when the sublist is expanded.
///
/// Used to override to the [ListTileThemeData.textColor].
///
/// If this property is null then [ExpansionTileThemeData.textColor] is used. If that
/// is also null then the value of [ListTileThemeData.textColor] is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? textColor;
/// The color of the tile's titles when the sublist is collapsed.
///
/// Used to override to the [ListTileThemeData.textColor].
///
/// If this property is null then [ExpansionTileThemeData.collapsedTextColor] is used. If that
/// is also null then the value of [ListTileThemeData.textColor] is used.
///
/// See also:
///
/// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
/// [ExpansionTileThemeData].
final Color? collapsedTextColor;
/// Typically used to force the expansion arrow icon to the tile's leading or trailing edge.
///
/// By default, the value of `controlAffinity` is [ListTileControlAffinity.platform],
/// which means that the expansion arrow icon will appear on the tile's trailing edge.
final ListTileControlAffinity? controlAffinity;
@override
State<ExpansionTileCopy> createState() => _ExpansionTileCopyState();
}
class _ExpansionTileCopyState extends State<ExpansionTileCopy>
with SingleTickerProviderStateMixin {
static final Animatable<double> _easeOutTween =
CurveTween(curve: Curves.easeOut);
static final Animatable<double> _easeInTween =
CurveTween(curve: Curves.easeIn);
static final Animatable<double> _halfTween =
Tween<double>(begin: 0.0, end: 0.5);
final ColorTween _borderColorTween = ColorTween();
final ColorTween _headerColorTween = ColorTween();
final ColorTween _iconColorTween = ColorTween();
final ColorTween _backgroundColorTween = ColorTween();
late AnimationController _controller;
late Animation<double> _iconTurns;
late Animation<double> _heightFactor;
late Animation<Color?> _borderColor;
late Animation<Color?> _headerColor;
late Animation<Color?> _iconColor;
late Animation<Color?> _backgroundColor;
bool _isExpanded = false;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _kExpand, vsync: this);
_heightFactor = _controller.drive(_easeInTween);
_iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
_borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween));
_headerColor = _controller.drive(_headerColorTween.chain(_easeInTween));
_iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
_backgroundColor =
_controller.drive(_backgroundColorTween.chain(_easeOutTween));
_isExpanded = PageStorage.of(context)?.readState(context) as bool? ??
widget.initiallyExpanded;
if (_isExpanded) {
_controller.value = 1.0;
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _handleTap() {
setState(() {
_isExpanded = !_isExpanded;
if (_isExpanded) {
_controller.forward();
} else {
_controller.reverse().then<void>((void value) {
if (!mounted) {
return;
}
setState(() {
// Rebuild without widget.children.
});
});
}
PageStorage.of(context)?.writeState(context, _isExpanded);
});
widget.onExpansionChanged?.call(_isExpanded);
}
// Added to class
void closeExpansion() {
if (_isExpanded) _handleTap();
}
// Added to class
void openExpansion() {
if (!_isExpanded) _handleTap();
}
// Platform or null affinity defaults to trailing.
ListTileControlAffinity _effectiveAffinity(
ListTileControlAffinity? affinity) {
switch (affinity ?? ListTileControlAffinity.trailing) {
case ListTileControlAffinity.leading:
return ListTileControlAffinity.leading;
case ListTileControlAffinity.trailing:
case ListTileControlAffinity.platform:
return ListTileControlAffinity.trailing;
}
}
Widget? _buildIcon(BuildContext context) {
return RotationTransition(
turns: _iconTurns,
child: const Icon(Icons.expand_more),
);
}
Widget? _buildLeadingIcon(BuildContext context) {
if (_effectiveAffinity(widget.controlAffinity) !=
ListTileControlAffinity.leading) {
return null;
}
return _buildIcon(context);
}
// Ubah trailing menjadi "+" dan "-" saat ExpansionTileCopy dibuka
Widget? _buildTrailingIcon(BuildContext context) {
if (_effectiveAffinity(widget.controlAffinity) !=
ListTileControlAffinity.trailing) {
return null;
}
final Color trailingIconColor = Theme.of(context).brightness == Brightness.light
? primaryColor
: primaryColorligtmode;
return _isExpanded
? Icon(
Icons.remove,
color: trailingIconColor,
)
: Icon(
Icons.add,
color: trailingIconColor,
);
}
Widget _buildChildren(BuildContext context, Widget? child) {
final ExpansionTileThemeData expansionTileTheme =
ExpansionTileTheme.of(context);
final Color borderSideColor = _borderColor.value ?? Colors.transparent;
return Container(
decoration: BoxDecoration(
color: _backgroundColor.value ??
expansionTileTheme.backgroundColor ??
Colors.transparent,
border: Border(
top: BorderSide(color: borderSideColor),
bottom: BorderSide(color: borderSideColor),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTileTheme.merge(
iconColor: _iconColor.value ?? expansionTileTheme.iconColor,
textColor: _headerColor.value,
child: ListTile(
onTap: _handleTap,
contentPadding:
widget.tilePadding ?? expansionTileTheme.tilePadding,
leading: widget.leading ?? _buildLeadingIcon(context),
title: widget.title,
subtitle: widget.subtitle,
trailing: widget.trailing ?? _buildTrailingIcon(context),
),
),
ClipRect(
child: Align(
alignment: widget.expandedAlignment ??
expansionTileTheme.expandedAlignment ??
Alignment.center,
heightFactor: _heightFactor.value,
child: child,
),
),
],
),
);
}
@override
void didChangeDependencies() {
final ThemeData theme = Theme.of(context);
final ExpansionTileThemeData expansionTileTheme =
ExpansionTileTheme.of(context);
final ColorScheme colorScheme = theme.colorScheme;
_borderColorTween.end = theme.dividerColor;
_headerColorTween
..begin = widget.collapsedTextColor ??
expansionTileTheme.collapsedTextColor ??
theme.textTheme.subtitle1!.color
..end = widget.textColor ??
expansionTileTheme.textColor ??
colorScheme.primary;
_iconColorTween
..begin = widget.collapsedIconColor ??
expansionTileTheme.collapsedIconColor ??
theme.unselectedWidgetColor
..end = widget.iconColor ??
expansionTileTheme.iconColor ??
colorScheme.primary;
_backgroundColorTween
..begin = widget.collapsedBackgroundColor ??
expansionTileTheme.collapsedBackgroundColor
..end = widget.backgroundColor ?? expansionTileTheme.backgroundColor;
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final ExpansionTileThemeData expansionTileTheme =
ExpansionTileTheme.of(context);
final bool closed = !_isExpanded && _controller.isDismissed;
final bool shouldRemoveChildren = closed && !widget.maintainState;
final Widget result = Offstage(
offstage: closed,
child: TickerMode(
enabled: !closed,
child: Padding(
padding: widget.childrenPadding ??
expansionTileTheme.childrenPadding ??
EdgeInsets.zero,
child: Column(
crossAxisAlignment:
widget.expandedCrossAxisAlignment ?? CrossAxisAlignment.center,
children: widget.children,
),
),
),
);
return AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: shouldRemoveChildren ? null : result,
);
}
}

View File

@ -0,0 +1,308 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/announcement_model.dart';
import 'package:initial_folder/providers/announcement_provider.dart';
import 'package:initial_folder/providers/posting_announcement_reply_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/announcement_user.dart';
import 'package:initial_folder/widgets/reply_announcement_user_page.dart';
import 'package:provider/provider.dart';
import '../../../get_it.dart';
final scaffoldKey = GlobalKey<ScaffoldState>();
class InsideAnnouncement extends StatefulWidget {
const InsideAnnouncement({
Key? key,
required this.id,
required this.announcementDataModel,
required this.index,
required this.userId,
}) : super(key: key);
final AnnouncementDataModel announcementDataModel;
final id;
final int index;
final int userId;
@override
State<InsideAnnouncement> createState() => _InsideAnnouncementState();
}
class _InsideAnnouncementState extends State<InsideAnnouncement> {
final _controller = TextEditingController();
final provider = announcementGetIt<AnnouncementProvider>();
late Widget announcement;
@override
Widget build(BuildContext context) {
PostingAnnouncementReplyProvider postingAnnouncementReplyProvider =
Provider.of<PostingAnnouncementReplyProvider>(context);
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: Text(
'Pengumuman',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16),
letterSpacing: 0.2,
),
),
),
body: GestureDetector(
// onTap: () => FocusScope.of(context).unfocus(),
child: Stack(
children: [
ListView(
children: [
// QnaUser(
// qnaDataModel: widget.qnaDataModel,
// id: widget.id,
// index: widget.index,
// userId: widget.userId,
// ),
StreamBuilder<AnnouncementModel>(
stream: provider.announcementStream,
builder:
(context, AsyncSnapshot<AnnouncementModel> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
announcement = Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
break;
case ConnectionState.none:
announcement = Center(
child: Text(
'Tidak ada koneksi',
style: thirdTextStyle,
),
);
break;
case ConnectionState.active:
print('masuk siniiiiiiiiiii active' +
snapshot.data!.error.toString());
announcement = snapshot.data!.data[0].length > 0
? Container(
padding: EdgeInsets.only(top: 12),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(10),
bottomLeft: Radius.circular(10)),
color: Theme.of(context)
.colorScheme
.primaryContainer,
boxShadow: [
BoxShadow(
color: Theme.of(context)
.brightness ==
Brightness.dark
? Color(0xff212643)
: Colors.grey,
blurRadius: 0.5,
offset: Offset(0, 2),
spreadRadius: 0.001)
]),
child: AnnouncementUser(
announcementDataModel:
snapshot.data!.data[0][widget.index],
id: widget.id,
index: widget.index,
userId: widget.userId,
))
: Center(
child: Text(
'Belum ada pengumuman',
style: thirdTextStyle,
),
);
break;
case ConnectionState.done:
announcement = snapshot.data!.data[0].length > 0
? AnnouncementUser(
announcementDataModel:
snapshot.data!.data[0][widget.index],
id: widget.id,
index: widget.index,
userId: widget.userId,
)
: Center(
child: Text(
'Belum ada pertanyaan',
style: thirdTextStyle,
),
);
break;
}
}
return announcement;
}),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
vertical: getProportionateScreenWidth(8)),
child: InkWell(
onTap: () {},
child: Text(
'Balasan',
style: thirdTextStyle.copyWith(
color: Theme.of(context).colorScheme.onBackground,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16),
letterSpacing: 1),
),
),
),
SizedBox(height: getProportionateScreenHeight(13)),
ReplyAnnouncementUserPage(
idCourse: widget.id,
index: widget.index,
userId: widget.userId,
),
SizedBox(height: 50)
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? Color.fromARGB(255, 54, 61, 96)
: Color.fromARGB(255, 221, 221, 221),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
height: getProportionateScreenWidth(72),
width: double.infinity,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
vertical: getProportionateScreenWidth(16),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: SizeConfig.screenWidth * 0.65,
child: TextFormField(
controller: _controller,
scrollPadding: EdgeInsets.zero,
cursorColor: secondaryColor,
decoration: InputDecoration(
filled: true,
fillColor:
Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10,
),
borderSide: BorderSide.none),
hintStyle: secondaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontSize: getProportionateScreenWidth(12),
),
hintText: "Balas",
),
),
),
ElevatedButton(
onPressed: () async {
if (await postingAnnouncementReplyProvider
.postAnnouncementReply(
_controller.text,
widget.announcementDataModel.idAnnouncement
.toString(),
widget.announcementDataModel.tokenAnnouncement
.toString(),
widget.announcementDataModel.idAnnouncement
.toString(),
)) {
provider.getAnnouncement(widget.id);
_controller.clear();
ScaffoldMessenger.of(scaffoldKey.currentContext!)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Balasan Terkirim',
style: primaryTextStyle.copyWith(
color: backgroundColor),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
action: SnackBarAction(
label: 'Lihat',
onPressed: () {
ScaffoldMessenger.of(
scaffoldKey.currentContext!)
.hideCurrentSnackBar();
},
),
),
);
} else {
ScaffoldMessenger.of(scaffoldKey.currentContext!)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Terjadi kesalahan',
style: primaryTextStyle.copyWith(
color: backgroundColor,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
);
}
},
child: Text(
'Kirim',
style: thirdTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.3,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: primaryColor,
minimumSize: Size(
getProportionateScreenWidth(35),
getProportionateScreenWidth(35),
),
),
)
],
),
),
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
import 'package:easy_pdf_viewer/easy_pdf_viewer.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class pdfReader extends StatefulWidget {
final String link;
final String title;
const pdfReader({super.key, required this.link, required this.title});
@override
State<pdfReader> createState() => _pdfReaderState();
}
class _pdfReaderState extends State<pdfReader> {
late PDFDocument document;
bool _isLoading = true;
@override
void initState() {
super.initState();
// Load from URL
loadPDF();
}
void loadPDF() async {
document = await PDFDocument.fromURL(widget.link);
setState(() {
_isLoading = false;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
widget.title,
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(16)),
),
),
body: Center(
child: _isLoading
? Center(child: CircularProgressIndicator())
: PDFViewer(
document: document,
pickerButtonColor: primaryColor,
)),
);
}
}

View File

@ -0,0 +1,338 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/main.dart';
import 'package:initial_folder/providers/qna_provider.dart';
import 'package:initial_folder/services/qna_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/providers/posting_qna_provider.dart';
import 'package:initial_folder/widgets/qna_user_page.dart';
import 'package:provider/provider.dart';
import 'package:quill_html_editor/quill_html_editor.dart';
class QuestAndAnswer extends StatefulWidget {
const QuestAndAnswer({
Key? key,
required this.id,
required this.idLesson,
}) : super(key: key);
final id;
final idLesson;
@override
State<QuestAndAnswer> createState() => _QuestAndAnswerState();
}
class _QuestAndAnswerState extends State<QuestAndAnswer> {
double value = 0;
final _controllerTitle = TextEditingController();
final _controller = TextEditingController();
final QuillEditorController _controllerQuest = QuillEditorController();
final customToolbar = [
ToolBarStyle.headerOne,
ToolBarStyle.headerTwo,
ToolBarStyle.bold,
ToolBarStyle.italic,
ToolBarStyle.underline,
ToolBarStyle.color,
ToolBarStyle.listBullet,
ToolBarStyle.listOrdered,
];
@override
void initState() {
// TODO: implement initState
QnaService().getMyQna(widget.id);
super.initState();
}
@override
Widget build(BuildContext context) {
PostingQnaProvider postingQnaProvider =
Provider.of<PostingQnaProvider>(context);
return SingleChildScrollView(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Column(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: getProportionateScreenWidth(16),
),
Text(
'Ajukan Pertanyaan',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 0.1,
fontSize: getProportionateScreenWidth(16),
),
),
SizedBox(
height: getProportionateScreenWidth(8),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color:
Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 0.5,
offset: Offset(0, 2),
spreadRadius: 0.001)
]),
child: TextField(
controller: _controllerTitle,
cursorColor: secondaryColor,
scrollPadding: EdgeInsets.zero,
decoration: InputDecoration(
filled: true,
fillColor:
Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
10,
),
borderSide: BorderSide.none),
hintStyle: secondaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontSize: getProportionateScreenWidth(12),
),
hintText: "Masukan Judul Pertanyaan",
),
),
),
SizedBox(
height: getProportionateScreenWidth(18),
),
ToolBar(
toolBarColor:
Theme.of(context).brightness == Brightness.dark
? seventeenColor
: Colors.grey[200]!,
activeIconColor: primaryColor,
iconColor: secondaryColor,
padding: const EdgeInsets.all(8),
iconSize: 20,
controller: _controllerQuest,
toolBarConfig: customToolbar,
),
Container(
height: 180,
width: double.infinity,
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
color:
Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 0.5,
offset: Offset(0, 2),
spreadRadius: 0.001)
]),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: QuillHtmlEditor(
hintText: 'Ketik pertanyaan mu',
controller: _controllerQuest,
isEnabled: true,
minHeight: 100,
backgroundColor: Theme.of(context).brightness ==
Brightness.dark
? seventeenColor
: Colors.grey[200]!,
textStyle: secondaryTextStyle.copyWith(
color: secondaryColor,
fontSize: getProportionateScreenWidth(16),
),
hintTextStyle: secondaryTextStyle.copyWith(
color: secondaryColor,
fontSize: getProportionateScreenWidth(16),
),
hintTextAlign: TextAlign.start,
padding: const EdgeInsets.all(3),
hintTextPadding: const EdgeInsets.all(0),
loadingBuilder: (context) {
return const Center(
child: CircularProgressIndicator(
strokeWidth: 0.4,
));
},
),
),
// TextField(
// controller: _controller,
// cursorColor: secondaryColor,
// scrollPadding: EdgeInsets.zero,
// minLines: 2,
// keyboardType: TextInputType.multiline,
// maxLines: 2,
// decoration: InputDecoration(
// filled: true,
// fillColor: Theme.of(context).brightness ==
// Brightness.dark
// ? seventeenColor
// : Colors.grey[200],
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(
// 10,
// ),
// borderSide: BorderSide.none),
// hintStyle: secondaryTextStyle.copyWith(
// color: secondaryColor,
// letterSpacing: 0.5,
// fontSize: getProportionateScreenWidth(12),
// ),
// hintText: "Ketikkan Pertanyaanmu disini",
// ),
// ),
Align(
alignment: Alignment.topRight,
child: ElevatedButton(
onPressed: () async {
if (await postingQnaProvider.postingQna(
_controllerTitle.text,
await _controllerQuest.getText(),
widget.id,
widget.idLesson)) {
_controllerQuest.clear();
_controllerTitle.clear();
ScaffoldMessenger.of(
globalScaffoldKey.currentContext!)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Pertanyaan berhasil dikirimkan',
style: primaryTextStyle.copyWith(
color: backgroundColor,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5),
),
action: SnackBarAction(
label: 'Lihat',
onPressed: () {
ScaffoldMessenger.of(
globalScaffoldKey
.currentContext!)
.hideCurrentSnackBar();
},
),
),
);
} else {
ScaffoldMessenger.of(
globalScaffoldKey.currentContext!)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Terjadi kesalahan',
style: primaryTextStyle.copyWith(
color: backgroundColor,
),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5),
),
),
);
}
},
child: Text(
'Kirim',
style: thirdTextStyle.copyWith(
color: Colors.white,
fontSize: SizeConfig.blockHorizontal! * 4,
),
),
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
backgroundColor: primaryColor,
),
),
),
],
)),
),
],
),
],
),
),
SizedBox(
height: 15,
),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: Text(
'Pertanyaan Dan Jawaban',
style: primaryTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(16),
),
),
),
SizedBox(
height: getProportionateScreenHeight(14),
),
QnaUserPage(idCourse: widget.id),
SizedBox(
height: getProportionateScreenHeight(14),
),
// QandA(
// divider: Divider(),
// ),
// QandA(
// divider: Divider(),
// ),
],
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,46 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:easy_pdf_viewer/easy_pdf_viewer.dart';
import 'package:flutter_text_viewer/model/text_viewer.dart';
import 'package:flutter_text_viewer/screen/text_viewer_page.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
class txtReader extends StatefulWidget {
final String link;
// final String title;
const txtReader({Key? key, required this.link});
@override
State<txtReader> createState() => _txtReaderState();
}
class _txtReaderState extends State<txtReader> {
@override
void initState() {
super.initState();
print(widget.link);
}
@override
void dispose() {
super.dispose();
// Hapus file .txt saat widget di-dispose
File(widget.link).deleteSync(recursive: true);
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextViewerPage(
textViewer: TextViewer.asset(
widget.link,
highLightColor: Colors.yellow,
focusColor: Colors.orange,
ignoreCase: true,
),
showSearchAppBar: true,
)));
}
}

View File

@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import 'package:chewie/chewie.dart';
import 'package:video_player/video_player.dart';
class Html5Vid extends StatefulWidget {
const Html5Vid({Key? key, required this.link, required this.title});
final String link;
final String title;
@override
State<Html5Vid> createState() => Html5VidState();
}
class Html5VidState extends State<Html5Vid> {
late VideoPlayerController _videoPlayerController;
late ChewieController _chewieController;
bool _isVideoLoading = true;
@override
void initState() {
super.initState();
print(widget.link);
print(widget.title);
_videoPlayerController = VideoPlayerController.network('${widget.link}');
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
aspectRatio: 16 / 9,
autoPlay: true,
looping: false,
);
_videoPlayerController.addListener(() {
if (_videoPlayerController.value.isInitialized &&
!_videoPlayerController.value.isBuffering) {
setState(() {
_isVideoLoading = false;
});
}
});
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text('${widget.title}'),
),
body: Stack(
children: [
Center(
child: Chewie(
controller: _chewieController,
),
),
if (_isVideoLoading)
Center(
child: CircularProgressIndicator(),
),
],
),
),
);
}
Future<bool> _onWillPop() async {
await _videoPlayerController.pause();
await _videoPlayerController.dispose();
// await _chewieController.dispose();
return true;
}
@override
void dispose() {
_videoPlayerController.dispose();
_chewieController.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,198 @@
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:initial_folder/providers/my_course_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/course/search_my_course_page.dart';
import 'package:initial_folder/screens/home/components/body_comp/latest_course.dart';
import 'package:initial_folder/screens/home/components/body_comp/populer_course.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/widgets/loading/loading_my_course.dart';
import 'package:initial_folder/widgets/my_course_list.dart';
import 'package:provider/provider.dart';
import '../../theme.dart';
class MyCoursePage extends StatelessWidget {
const MyCoursePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
Widget notLogin() {
return Center(
child: Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(40),
),
child: Text(
'Kamu belum login, silahkan login untuk melihat kursus mu',
textAlign: TextAlign.center,
style: primaryTextStyle,
),
),
);
}
Widget myCourse() {
return RefreshIndicator(
displacement: 40,
color: primaryColor,
onRefresh: () async {
await Provider.of<MyCourseProvider>(context, listen: false)
.getMyCourse();
},
child: Consumer<MyCourseProvider>(
builder: (BuildContext context, state, _) {
if (state.state == ResultState.Loading) {
return Column(
children: [
LoadingMyCourse(),
LoadingMyCourse(),
LoadingMyCourse(),
],
);
} else if (state.state == ResultState.HasData) {
return Container(
margin:
EdgeInsets.only(bottom: getProportionateScreenHeight(4)),
child: ListView.builder(
shrinkWrap: true,
itemCount: state.result!.data[0].length,
itemBuilder: (context, index) {
var myCourse = state.result!.data[0][index];
return MyCourseList(
dataMyCourseModel: myCourse,
);
},
),
);
} else if (state.state == ResultState.NoData) {
return ListView(
children: [
Container(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(47)),
Container(
width: getProportionateScreenWidth(120),
height: getProportionateScreenWidth(120),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
),
child: Image.asset(
'assets/images/kursuskosong.png',
scale: 1,
color: Theme.of(context).colorScheme.onBackground,
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Text(
"Kursus tidak tersedia",
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
color: tenthColor,
),
),
SizedBox(height: getProportionateScreenHeight(3)),
Container(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Text(
"Kamu belum memiliki kursus, daftar kursus sekarang agar kamu dapat mengikuti kursus",
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(12),
),
),
),
SizedBox(height: getProportionateScreenHeight(15)),
PopulerCourse(text: 'Kursus Teratas'),
LatestCourse(text: 'Kursus Terbaru'),
],
),
),
),
],
);
} else if (state.state == ResultState.Error) {
return Center(
child: ListView(
children: [
Container(
padding: const EdgeInsets.all(20.0),
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height / 1.5),
child: Center(
child: Text('Terjadi Kesalahan'),
),
)
],
),
);
} else {
return Center(child: Text(''));
}
},
),
);
}
return Scaffold(
appBar: (Condition.loginEmail || Condition.loginFirebase)
? AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Kursusku',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(20),
),
),
actions: [
IconButton(
onPressed: () {
Provider.of<MyCourseProvider>(context, listen: false)
.clearSearch();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchMyCourse(),
),
);
},
icon: Icon(
FeatherIcons.search,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
),
),
SizedBox(width: getProportionateScreenWidth(5)),
],
)
: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Kursusku',
style: secondaryTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 2.3,
fontSize: getProportionateScreenWidth(16),
),
),
),
body: (Condition.loginEmail || Condition.loginFirebase)
? myCourse()
: notLogin(),
);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,161 @@
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/models/quiz_model.dart';
import 'package:initial_folder/screens/course/quiz_question_page.dart';
import 'package:initial_folder/services/quiz_service.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:tap_debouncer/tap_debouncer.dart';
class quizPage extends StatefulWidget {
final String judulQuiz;
final String lessonId;
const quizPage({super.key, required this.judulQuiz, required this.lessonId});
@override
State<quizPage> createState() => _quizPageState();
}
class _quizPageState extends State<quizPage> {
QuizModel? quizModel;
@override
void initState() {
super.initState();
print(widget.judulQuiz);
print(widget.lessonId);
getQuiz();
}
void getQuiz() {
quiz_service().get_quiz_info(widget.lessonId).then((value) => {
setState(() {
quizModel = value;
print("ini id apa gatau" + quizModel!.data.first.quizId);
})
});
}
Widget build(BuildContext context) {
return quizModel == null
? Center(
child: Scaffold(
body: Center(
child: CircularProgressIndicator(
color: primaryColor,
),
),
))
: Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.transparent,
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: [
Container(
margin: EdgeInsets.all(25),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness ==
Brightness.dark
? Colors.black
: Colors.grey,
blurRadius: 2,
spreadRadius: 1,
offset: Offset(0, 3))
]),
child: Column(
children: [
SizedBox(
height: getProportionateScreenHeight(71),
),
Image.asset(
'assets/images/quizLogo-page.png',
scale: 0.8,
),
SizedBox(
height: getProportionateScreenHeight(36),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 30),
child: Text(
widget.judulQuiz,
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: bold,
fontSize: getProportionateScreenWidth(15)),
),
),
SizedBox(
height: getProportionateScreenHeight(10),
),
Text(
"Jumlah Pertanyaan : " +
quizModel!.total.toString(),
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: bold,
fontSize: getProportionateScreenWidth(15)),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Padding(
padding: EdgeInsets.all(
getProportionateScreenHeight(15)),
child: TapDebouncer(
cooldown: const Duration(milliseconds: 1000),
onTap: () async => await {
if (quizModel!.total.toString() != "0")
{
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
quiz_questionPage(
judulQuiz: widget.judulQuiz,
lessonId: widget.lessonId,
totalQuiz: quizModel!.total,
quizId: int.parse(quizModel!
.data.first.quizId),
)))
}
else
{
CherryToast.error(
animationDuration: Durations.long1,
title: Text(
"Pertanyaan untuk quiz ini \nbelum tersedia",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
),
animationType: AnimationType.fromTop,
).show(context)
}
},
builder: (BuildContext context,
TapDebouncerFunc? onTap) {
return DefaultButton(
text: 'Mulai Quiz', press: onTap);
},
))
],
),
)
],
),
),
),
);
}
}

View File

@ -0,0 +1,225 @@
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/models/quiz_model.dart';
import 'package:initial_folder/models/quiz_question_model.dart';
import 'package:initial_folder/screens/course/quiz_result_page.dart';
import 'package:initial_folder/services/quiz_service.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:tap_debouncer/tap_debouncer.dart';
import 'package:html/parser.dart';
class quiz_questionPage extends StatefulWidget {
final String judulQuiz;
final String lessonId;
final int totalQuiz;
final int quizId;
const quiz_questionPage(
{super.key,
required this.judulQuiz,
required this.lessonId,
required this.totalQuiz,
required this.quizId});
@override
State<quiz_questionPage> createState() => _quiz_questionPageState();
}
class _quiz_questionPageState extends State<quiz_questionPage> {
int currentQuestionIndex = 0; // Menyimpan indeks pertanyaan saat ini
QuizModel? quizModel;
String? selectedOption;
bool isSelected = false;
List<Map<String, dynamic>> savedAnswers = [];
@override
void initState() {
super.initState();
getQuiz();
}
void getQuiz() {
quiz_service().get_quiz_info(widget.lessonId).then((value) {
setState(() {
quizModel = value;
});
});
}
Widget build(BuildContext context) {
String _parseHtmlString(String htmlText) {
RegExp exp =
RegExp(r"<[^>]*>|&nbsp;", multiLine: true, caseSensitive: true);
return htmlText.replaceAll(exp, '');
}
return quizModel == null
? Center(
child: Scaffold(
body: Center(
child: CircularProgressIndicator(
color: primaryColor,
),
),
))
: Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Pertanyaan ${currentQuestionIndex + 1}', // Menampilkan nomor pertanyaan
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(15),
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 30),
child: Text(
_parseHtmlString(quizModel!.data[currentQuestionIndex]
.title), // Menampilkan judul pertanyaan
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(15),
),
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Container(
width: getProportionateScreenWidth(350),
height: getProportionateScreenHeight(400),
// color: Colors.amber,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: quizModel!.data[currentQuestionIndex].options
.map((option) {
return Padding(
padding: EdgeInsets.fromLTRB(
getProportionateScreenWidth(15),
getProportionateScreenHeight(5),
getProportionateScreenWidth(15),
getProportionateScreenHeight(5)),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness ==
Brightness.dark
? Colors.black
: Colors.grey,
blurRadius: 2,
spreadRadius: 1,
offset: Offset(0, 3))
]),
child: CheckboxListTile(
activeColor: primaryColor,
checkColor: Colors.white,
checkboxShape: RoundedRectangleBorder(
side: BorderSide(
color:
primaryColor), // Mengatur warna dan ketebalan outline checkbox
borderRadius: BorderRadius.circular(2),
),
title: Text(
option,
style: thirdTextStyle.copyWith(fontSize: 14),
),
value: selectedOption == option,
controlAffinity: ListTileControlAffinity
.leading, // Checkbox di sebelah kiri
onChanged: (value) {
setState(() {
selectedOption = value! ? option : null!;
isSelected = true;
});
},
),
),
);
}).toList(),
),
)),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(100),
right: getProportionateScreenWidth(100)),
child: TapDebouncer(
cooldown: const Duration(milliseconds: 1000),
onTap: () async => await {
setState(() {
//ini save quiz
if (isSelected != false) {
savedAnswers.add({
'"question_id"':
quizModel!.data[currentQuestionIndex].id,
'"answers"': [
'"${quizModel!.data[currentQuestionIndex].options.indexOf(selectedOption!) + 1}"'
]
});
if (currentQuestionIndex <
quizModel!.data.length - 1) {
currentQuestionIndex++;
} else {
if (widget.totalQuiz ==
currentQuestionIndex + 1) {
print('sudah habis');
// print(savedAnswers);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => quiz_resultPage(
judulQuiz: widget.judulQuiz,
lessonId: widget.lessonId,
totalQuiz: quizModel!.total,
allAnswer:
savedAnswers.toString(),
IdQuiz: widget.quizId,
)));
}
}
} else {
CherryToast.error(
animationDuration: Durations.long1,
title: Text(
"Silakhan Pilih salah satu \nJawaban yang tersedia",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
),
animationType: AnimationType.fromTop,
).show(context);
print('object');
}
// print(savedAnswers);
isSelected = false;
})
},
builder: (BuildContext context, TapDebouncerFunc? onTap) {
return DefaultButton(
text: 'Submit & Next', press: onTap);
},
))
],
),
);
}
}

View File

@ -0,0 +1,500 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:initial_folder/models/quiz_model.dart';
import 'package:initial_folder/models/quiz_perquestion_result_model.dart';
import 'package:initial_folder/models/quiz_question_model.dart';
import 'package:initial_folder/models/quiz_question_result_model.dart';
import 'package:initial_folder/screens/course/play_course_page.dart';
import 'package:initial_folder/screens/course/quiz_page.dart';
import 'package:initial_folder/services/quiz_service.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:tap_debouncer/tap_debouncer.dart';
import 'package:html/parser.dart';
class quiz_resultPage extends StatefulWidget {
final String judulQuiz;
final String lessonId;
final int totalQuiz;
final String allAnswer;
final int IdQuiz;
const quiz_resultPage(
{super.key,
required this.judulQuiz,
required this.lessonId,
required this.totalQuiz,
required this.allAnswer,
required this.IdQuiz});
@override
State<quiz_resultPage> createState() => _quiz_resultPageState();
}
class _quiz_resultPageState extends State<quiz_resultPage> {
QuizQuestionResult? quizQuestionResult;
QuizPerQuestionResult? quizPerQuestionResult;
int currentQuestionIndex = 1; // Menyimpan indeks pertanyaan saat ini
bool fromAmbilLagi = false;
int _selectedQuesNum = 1;
String _selectedQuesText = "";
List<Map<String, dynamic>> allAnswersList = [];
@override
void initState() {
super.initState();
print("ini id apa gatau" + widget.IdQuiz.toString());
// Parsing the allAnswer JSON string to List
allAnswersList =
List<Map<String, dynamic>>.from(json.decode(widget.allAnswer));
getAnswerQuiz();
getQuestionPerNumber();
}
void getAnswerQuiz() {
quiz_service().get_result_quiz(widget.allAnswer).then((value) {
setState(() {
quizQuestionResult = value;
});
});
}
void getQuestionPerNumber() {
print(_selectedQuesNum);
quiz_service()
.get_result_quiz_pernumber(widget.IdQuiz, _selectedQuesNum)
.then((value) {
setState(() {
quizPerQuestionResult = value;
});
});
}
bool _isUserSelectedAnswer(int questionId, int optionIndex) {
for (var answer in allAnswersList) {
if (answer['question_id'] == questionId &&
answer['answers'].contains(optionIndex.toString())) {
return true;
}
}
return false;
}
Widget build(BuildContext context) {
String _parseHtmlString(String htmlText) {
RegExp exp =
RegExp(r"<[^>]*>|&nbsp;", multiLine: true, caseSensitive: true);
return htmlText.replaceAll(exp, '');
}
int countCorrectAnswers() {
if (quizQuestionResult != null && quizQuestionResult!.data.isNotEmpty) {
// Menggunakan metode where untuk menyaring data yang memiliki is_correct true
int correctCount = quizQuestionResult!.data
.where((question) => question.isCorrect == true)
.length;
return correctCount;
} else {
return 0;
}
}
return quizQuestionResult == null
? Center(
child: Scaffold(
body: Center(
child: CircularProgressIndicator(
color: primaryColor,
),
),
))
: PopScope(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.transparent,
automaticallyImplyLeading:
false, // Menonaktifkan tombol kembali default
leading: IconButton(
// Menambahkan tombol kustom
icon: Icon(Icons.arrow_back),
onPressed: () {
// Tambahkan fungsi yang diinginkan saat tombol kembali ditekan
Future.delayed(Duration.zero, () {
Navigator.of(context).pop();
});
},
),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness == Brightness.dark
? Colors.black
: Colors.grey,
spreadRadius: 1,
blurRadius: 5,
offset: Offset(0, 1), // Shadow position
),
],
),
child: Column(
children: [
Container(
margin: EdgeInsetsDirectional.only(
top: getProportionateScreenHeight(15)),
height: getProportionateScreenHeight(110),
width: getProportionateScreenWidth(320),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness ==
Brightness.dark
? Colors.black
: Colors.grey,
blurRadius: 2,
spreadRadius: 1,
offset: Offset(0, 0))
]),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Tinjau materi kursus untuk memperluas pembelajaran kamu.', // Menampilkan nomor pertanyaan
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: FontWeight.w200,
fontSize: getProportionateScreenWidth(13),
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Text(
'Kamu mendapatkan ${countCorrectAnswers()} Dari ${widget.totalQuiz} Benar', // Menampilkan nomor pertanyaan
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: FontWeight.w200,
fontSize: getProportionateScreenWidth(13),
),
),
],
),
),
SizedBox(
height: 25,
),
SizedBox(
height: 90, // Adjust height to control the size
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: quizQuestionResult!.data.length,
itemBuilder: (context, index) {
var dataques = quizQuestionResult!.data[index];
return GestureDetector(
onTap: () {
setState(() {
_selectedQuesNum = index + 1;
// getQuestionPerNumber()
_selectedQuesText = dataques.question;
});
getQuestionPerNumber();
// print(
// quizPerQuestionResult!.data.first.title);
// print(dataques.question);
// print(dataques.questionId);
},
child: SizedBox(
width: 80, // Adjust width here
height: 65, // Adjust height here
child: Container(
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
borderRadius:
BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Theme.of(context)
.brightness ==
Brightness.dark
? Colors.black
: Colors.grey,
blurRadius: 2,
spreadRadius: 1,
offset: Offset(0, 3))
]),
child: Column(
mainAxisAlignment:
MainAxisAlignment.end,
children: [
Center(
child: Text(
'${index + 1}',
// dataques.isCorrect.toString(),
style: thirdTextStyle.copyWith(
fontSize: 16,
fontWeight: FontWeight.w800),
),
),
SizedBox(
height: 5,
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height:
getProportionateScreenHeight(
18),
decoration: BoxDecoration(
color: dataques.isCorrect ==
true
? Colors.green
: dataques.isCorrect != true
? Colors.red
: Colors.red,
borderRadius:
BorderRadius.vertical(
bottom: Radius.circular(
15)),
),
child: Center(
child: dataques.isCorrect ==
true
? Icon(
Icons
.check_circle_outline,
color: Colors.white,
size:
getProportionateScreenHeight(
13),
)
: dataques.isCorrect !=
true
? Icon(
Icons
.cancel_outlined,
color:
Colors.white,
size:
getProportionateScreenHeight(
13),
)
: Icon(
Icons
.cancel_outlined,
color:
Colors.white,
size:
getProportionateScreenHeight(
13),
)),
),
),
],
)),
),
);
},
),
),
SizedBox(
height: 15,
)
],
),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Text(
'Pertanyaan ${_selectedQuesNum}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14)),
),
SizedBox(
height: getProportionateScreenHeight(15),
),
Text(
_parseHtmlString(quizPerQuestionResult!.data.first.title),
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14)),
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount:
quizPerQuestionResult!.data.first.options.length,
itemBuilder: (context, index) {
var dataques = quizPerQuestionResult!.data.first;
bool isCorrectAnswer = dataques.correctAnswers
.contains((index + 1).toString());
return Padding(
padding: EdgeInsets.all(10),
child: Container(
decoration: BoxDecoration(
color: fourthColor,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: getProportionateScreenHeight(45),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
borderRadius:
BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Theme.of(context)
.brightness ==
Brightness.dark
? Colors.black
: Colors.grey,
blurRadius: 5,
spreadRadius: 3,
offset: Offset(0, 0))
]),
child: Row(
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 25),
height:
getProportionateScreenHeight(
20),
width:
getProportionateScreenWidth(25),
decoration: BoxDecoration(
color: isCorrectAnswer
? Colors.green
: _isUserSelectedAnswer(
int.parse(
dataques.id),
index + 1)
? Colors.red
: Colors.transparent,
borderRadius: BorderRadius.all(
Radius.circular(10)),
border: Border.all(
color: isCorrectAnswer
? Colors.green
: _isUserSelectedAnswer(
int.parse(
dataques
.id),
index + 1)
? Colors.red
: Colors.grey,
width: 2)),
child: Center(
child: isCorrectAnswer
? Icon(
Icons.check,
color: Colors.white,
weight: 5,
)
: _isUserSelectedAnswer(
int.parse(
dataques.id),
index + 1)
? Icon(
Icons.check,
color: Colors.white,
weight: 5,
)
: SizedBox(),
),
),
Text(
' ${_parseHtmlString(dataques.options[index])}',
style: thirdTextStyle.copyWith(
color: isCorrectAnswer
? Colors.green
: _isUserSelectedAnswer(
int.parse(
dataques.id),
index + 1)
? Colors.red
: Colors.grey,
fontSize:
getProportionateScreenWidth(
12)),
),
],
),
),
],
)));
// Helper function to check if the current option is the user's selected answer
},
),
),
// SingleChildScrollView(child: ,),
Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(20),
top: getProportionateScreenHeight(10)),
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(100),
right: getProportionateScreenWidth(100)),
child: DefaultButton(
text: 'Ambil Lagi',
press: () {
setState(() {
fromAmbilLagi = true;
_quizscr(context);
});
},
),
),
),
)
],
),
),
onPopInvoked: (didPop) => _willPop(context),
);
}
void _willPop(BuildContext context) {
Future.delayed(Duration.zero, () {
if (fromAmbilLagi != true) {
Navigator.of(context)..pop();
}
Navigator.of(context)
.pop(); // Hanya pop satu halaman jika tidak dari _quizscr
fromAmbilLagi = false;
});
}
void _quizscr(BuildContext context) {
Navigator.pop(context);
}
}

View File

@ -0,0 +1,90 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/providers/my_course_provider.dart';
import 'package:initial_folder/widgets/loading/loading_my_course.dart';
import 'package:initial_folder/widgets/my_course_list.dart';
import 'package:provider/provider.dart';
import '../../theme.dart';
class SearchMyCourse extends StatelessWidget {
const SearchMyCourse({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
TextEditingController controller = TextEditingController();
void refreshCourseList() {
Provider.of<MyCourseProvider>(context, listen: false)
.getSearchMyCourse(controller.text);
}
return Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: TextField(
autofocus: true,
decoration: new InputDecoration.collapsed(
hintText: 'Cari Kursusku',
),
controller: controller,
onSubmitted: (value) => refreshCourseList(),
),
),
body: RefreshIndicator(
displacement: 40,
color: primaryColor,
onRefresh: () async {
refreshCourseList();
},
child: Consumer<MyCourseProvider>(
builder: (BuildContext context, state, _) {
if (state.searchResultState == SearchResultState.Loading) {
return SingleChildScrollView(
child: Column(
children: [
LoadingMyCourse(),
LoadingMyCourse(),
LoadingMyCourse(),
],
),
);
} else if (state.searchResultState == SearchResultState.HasData) {
return ListView.builder(
shrinkWrap: true,
itemCount: state.searchResult!.data[0].length,
itemBuilder: (context, index) {
var myCourse = state.searchResult!.data[0][index];
return MyCourseList(
dataMyCourseModel: myCourse,
onDialogClose: refreshCourseList,
);
},
);
} else if (state.searchResultState == SearchResultState.NoData) {
Provider.of<MyCourseProvider>(context, listen: false)
.clearSearch();
return Center(
child: Text(
'Kursus Tidak Ditemukan',
style: thirdTextStyle,
),
);
} else if (state.searchResultState == SearchResultState.Error) {
Provider.of<MyCourseProvider>(context, listen: false)
.clearSearch();
return Center(
child: Text(
'Terjadi Kesalahan',
style: thirdTextStyle,
),
);
} else {
return Center(child: Text(''));
}
},
),
),
);
}
}

View File

@ -0,0 +1,784 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/services/all_certificate_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/certificate_provider.dart'
as certifProvider;
import 'package:qr_flutter/qr_flutter.dart';
class Sertif extends StatefulWidget {
Sertif({
Key? key,
this.totalProgress,
this.idCourse,
this.idPayment,
this.finishDate,
this.text,
this.pdfBytes,
this.saving,
}) : super(key: key);
static String routeName = "/sertif";
final int? totalProgress;
final int? idCourse;
final String? idPayment;
final String? text;
final dynamic finishDate;
bool? saving = false;
final Uint8List? pdfBytes;
@override
State<Sertif> createState() => _SertifState();
}
class _SertifState extends State<Sertif> {
final _globalKeySertif = GlobalKey();
bool _isLoading = false;
@override
Widget build(BuildContext context) {
Future.delayed(Duration(seconds: 0), () {
if (widget.text == null) {
Provider.of<certifProvider.CertificateProvider>(context, listen: false)
.getCertif(widget.idCourse.toString());
} else {
Provider.of<certifProvider.CertificateProvider>(context, listen: false)
.checkSertif(widget.text!);
}
});
certifProvider.CertificateProvider? certifProv =
Provider.of<certifProvider.CertificateProvider>(context, listen: false);
Widget notFinish() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
),
body: Center(
child: Container(
height: getProportionateScreenHeight(270),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness == Brightness.dark
? Colors.black
: Colors.grey,
blurRadius: 2,
spreadRadius: 1,
offset: Offset(0, 3))
]),
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Sertifikat',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
letterSpacing: -0.5,
color: Theme.of(context).colorScheme.onBackground,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(28),
),
),
Text(
'Belum Tersedia',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
letterSpacing: -0.5,
color: Theme.of(context).colorScheme.onBackground,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(28),
),
),
SizedBox(height: getProportionateScreenHeight(24)),
Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: Stack(
children: [
Container(
width: double.infinity,
height: getProportionateScreenWidth(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.grey[300],
),
),
Container(
width: (SizeConfig.screenWidth -
getProportionateScreenWidth(32)) *
(widget.totalProgress ?? 0) /
100,
height: getProportionateScreenWidth(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: primaryColor,
),
child: Text(
'${widget.totalProgress ?? 0}%',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: reguler,
color: Colors.white,
letterSpacing: 0.5,
),
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Anda baru menyelesaikan ${widget.totalProgress ?? 0}% kursus',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: Theme.of(context).colorScheme.onBackground,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(13),
),
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Anda belum memenuhi persyaratan untuk mendapatkan sertfikat. Selesaikan kursus anda untuk mendapatkan sertifikat penyelesaian kursus.',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: Theme.of(context).colorScheme.onBackground,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(13),
),
),
],
),
),
),
),
);
}
Widget checkCertificateFinish() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'Sertifikat',
style: thirdTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
)),
body: Center(
child: Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
),
child: Consumer<certifProvider.CertificateProvider>(
builder: (context, state, _) {
if (state.state == certifProvider.ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
);
} else if (state.state ==
certifProvider.ResultState.HasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(15),
width: double.infinity,
height: 280,
child: LayoutBuilder(
builder: (context, constraint) {
return Stack(
alignment: Alignment.center,
children: [
Image.asset(
'assets/images/certif_template_new.png'),
Positioned(
top: constraint.maxHeight / 2.55,
left: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 25),
child: Text(
certifProv.name!,
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Color(0xff575553)),
),
),
),
Positioned(
top: constraint.maxHeight / 1.9,
left: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 33),
child: Text('"${certifProv.title}"',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.bold,
fontSize:
(certifProv.title!.length >
20)
? 9
: 12,
color: Color(0xff575553)),
textAlign: TextAlign.center),
),
),
Positioned(
top: constraint.maxHeight / 1.6,
left: 0,
right: 0,
child: Center(
child: Text(
'${DateFormat('dd MMMM yyyy ').format(DateTime.fromMillisecondsSinceEpoch(certifProv.finishDate * 1000))}',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.normal,
fontSize: 8,
color: Color(0xff575553)),
),
),
),
Positioned(
bottom: constraint.maxHeight / 5.6,
left: constraint.maxWidth / 10,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'Certificate no : ${certifProv.certificateNo}',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.normal,
fontSize: 4,
color: Color(0xff575553),
),
),
Text(
'Certificate URL : https://vocasia-v4-develop.vercel.app/certificate/${certifProv.certificateNo}',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.normal,
fontSize: 4,
color: Color(0xff575553),
),
),
],
),
)
],
);
},
),
),
],
);
} else if (state.state == certifProvider.ResultState.Error) {
return Center(
child: Column(
children: [
Text(
'Terjadi Kesalahan Coba Lagi',
style: thirdTextStyle,
),
],
),
);
} else {
return Center(
child: Text(
'Terjadi kesalahan',
style: thirdTextStyle,
),
);
}
},
),
),
),
),
);
}
Widget checkCertificateNotFinished() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'Sertifikat',
style: thirdTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Center(
child: Text(
'Sertifikat Belum Diterbitkan',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
letterSpacing: 0.5,
color: Theme.of(context).colorScheme.onBackground,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(20),
),
),
),
),
);
}
Widget buildCertificate() {
return Container(
color: Colors.red,
margin: EdgeInsets.all(15),
width: double.infinity,
height: 300,
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('assets/certif_template_new.png'),
Positioned(
top: 120,
left: 0,
right: 0,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenHeight(25)),
child: Text(
'Safinatun Najah Unju',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: getProportionateScreenWidth(14)),
),
),
),
Positioned(
top: 155,
left: 0,
right: 0,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenHeight(33)),
child: Column(
children: [
Text(
'"Basic Excel Trainig For Professional Employees & Recruitment Selection Candidates"',
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 12),
textAlign: TextAlign.center),
SizedBox(height: getProportionateScreenHeight(10)),
Text(
'Jakarta, 24 October 2021',
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: getProportionateScreenWidth(8)),
)
],
),
),
),
Positioned(
bottom: getProportionateScreenHeight(50),
left: (65 / 640) * MediaQuery.of(context).size.width,
child: Column(
children: [
Text(
'Certificate no : 257911829183',
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: getProportionateScreenWidth(6)),
),
Text(
'Certificate no : 257911829183',
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: getProportionateScreenWidth(6)),
),
],
),
)
],
),
);
}
Widget finish() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Sertifikat',
style: thirdTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: Center(
child: Container(
child: Consumer<certifProvider.CertificateProvider>(
builder: (context, state, _) {
if (state.state == certifProvider.ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
} else if (state.state ==
certifProvider.ResultState.HasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InteractiveViewer(
child: RepaintBoundary(
key: _globalKeySertif,
child: Container(
width: getProportionateScreenWidth(300),
height: getProportionateScreenHeight(173),
child: LayoutBuilder(
builder: (context, constraint) {
return Stack(
alignment: Alignment.center,
children: [
Image.asset(
'assets/images/certif_template_new.png'),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.center,
widthFactor: 1.0,
heightFactor: 0.6,
child: Padding(
padding: EdgeInsets.only(
left:
getProportionateScreenWidth(28.5),
right:
getProportionateScreenWidth(240),
top: getProportionateScreenHeight(10),
bottom: getProportionateScreenHeight(90)
),
child: Text(
certifProv.certificateNo!.toUpperCase(),
textAlign: TextAlign.left,
style: primaryTextStyle.copyWith(
fontFamily: 'Arial',
fontWeight: FontWeight.w500,
fontSize:
getProportionateScreenWidth(
4),
color: Color.fromARGB(255, 255, 255, 255),
),
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.center,
widthFactor: 1.0,
heightFactor: 0.3,
child: Padding(
padding: EdgeInsets.only(
left:
getProportionateScreenWidth(27.5),
right:
getProportionateScreenHeight(
80),
top: getProportionateScreenHeight(
6),
),
child: Text(
certifProv.name!.toUpperCase(),
textAlign: TextAlign.left,
style: primaryTextStyle.copyWith(
fontFamily: 'Arial',
fontWeight: FontWeight.bold,
fontSize:
getProportionateScreenWidth(
9),
color: Color.fromARGB(255, 248, 124, 0),
),
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomCenter,
widthFactor: 1.0,
heightFactor: 0.5,
child: Padding(
padding: EdgeInsets.only(
right:
getProportionateScreenWidth(
85),
left: 27.5),
child: Text('"${certifProv.title}"',
style: primaryTextStyle.copyWith(
fontFamily: 'Arial',
fontWeight: FontWeight.bold,
fontSize: certifProv
.title!.length >
40
? getProportionateScreenWidth(
9)
: getProportionateScreenWidth(
11),
color: Color.fromARGB(255, 248, 124, 0)),
textAlign: TextAlign.left,
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomLeft,
widthFactor: 0.299,
heightFactor: 0.62,
child: Center(
child: Padding(
padding: EdgeInsets.only(
bottom:
getProportionateScreenHeight(
2),
left: 5),
child: Text(
'Jakarta, ${DateFormat('dd MMMM yyyy ').format(DateTime.fromMillisecondsSinceEpoch(certifProv.finishDate * 1000))}',
style: primaryTextStyle.copyWith(
fontWeight:
FontWeight.normal,
fontSize:
getProportionateScreenWidth(
4),
color: Color.fromARGB(255, 0, 0, 0)),
),
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomRight,
// widthFactor
heightFactor: 0.495,
child: Padding(
padding: EdgeInsets.only(
right: 19
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
QrImageView(
data: "https://vocasia.id/?no-certificate=${certifProv.certificateNo}",
version: QrVersions.auto,
size: getProportionateScreenHeight(48),
gapless: false,),
],
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomRight,
// widthFactor
heightFactor: 0.18,
child: Padding(
padding: EdgeInsets.only(
right: 25
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
RichText(
text:
TextSpan(
text:
'Issued : ${DateFormat('dd MMMM yyyy ').format(DateTime.fromMillisecondsSinceEpoch(certifProv.finishDate * 1000))}',
style: primaryTextStyle
.copyWith(
fontWeight:
FontWeight.normal,
fontSize:
getProportionateScreenWidth(
3),
color:
Color(0xff575553),
),
),
)
],
),
),
),
),
],
);
},
),
),
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(70)),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
minimumSize: Size(double.infinity,
getProportionateScreenHeight(40)),
backgroundColor: primaryColor,
),
onPressed: _isLoading
? null
: () async {
setState(() {
_isLoading = true;
});
try {
await AllCertificateServices()
.convertAndUpload(_globalKeySertif,
certifProv.idPayment!);
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
backgroundColor: primaryColor,
content: Text(
'Cek email anda!',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
color: baruTextutih),
),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5),
),
),
);
} catch (e) {
print('Error: $e');
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Gagal mengunduh sertifikat')),
);
} finally {
setState(() {
_isLoading = false;
});
}
},
child: _isLoading
? CircularProgressIndicator(color: baruTextutih)
: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
'assets/icons/download.svg',
color: baruTextutih,
width: 18,
height: 18,
),
Text(
'Download Sertifikat',
style: thirdTextStyle.copyWith(
color: baruTextutih,
fontSize:
getProportionateScreenWidth(12),
),
),
],
),
),
)
],
);
} else if (state.state == certifProvider.ResultState.Error) {
return Center(
child: Column(
children: [
Text(
'Terjadi Kesalahan Coba Lagi',
style: thirdTextStyle,
),
],
),
);
} else {
return Center(
child: Text(
'Terjadi kesalahan',
style: thirdTextStyle,
),
);
}
},
),
),
),
),
);
}
if (widget.totalProgress == 100 && widget.idCourse != null) {
return finish();
} else if (widget.totalProgress != 100 && widget.idCourse != null) {
return notFinish();
} else if (widget.finishDate != false) {
return checkCertificateFinish();
} else {
return checkCertificateNotFinished();
}
}
}

View File

@ -0,0 +1,676 @@
import 'dart:async';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:initial_folder/providers/certificate_provider.dart'
as certifProvider;
class SertifView extends StatelessWidget {
final _globalKeySertif = GlobalKey();
static String routeName = "/sertif";
final int? totalProgress;
final int? idCourse;
final String? idPayment;
final String? text;
final dynamic finishDate;
SertifView({
Key? key,
this.totalProgress,
this.idCourse,
this.idPayment,
this.finishDate,
this.text,
}) : super(key: key);
@override
Widget build(BuildContext context) {
Future.delayed(Duration(seconds: 0), () {
if (text == null) {
Provider.of<certifProvider.CertificateProvider>(context, listen: false)
.getCertif(idCourse.toString());
} else {
Provider.of<certifProvider.CertificateProvider>(context, listen: false)
.checkSertif(text!);
}
});
certifProvider.CertificateProvider? certifProv =
Provider.of<certifProvider.CertificateProvider>(context, listen: false);
Widget finish() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Sertifikat',
style: secondaryTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
),
),
body: Center(
child: Container(
child: Consumer<certifProvider.CertificateProvider>(
builder: (context, state, _) {
if (state.state == certifProvider.ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
} else if (state.state ==
certifProvider.ResultState.HasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InteractiveViewer(
child: RepaintBoundary(
key: _globalKeySertif,
child: Container(
width: getProportionateScreenWidth(300),
height: getProportionateScreenHeight(173),
child: LayoutBuilder(
builder: (context, constraint) {
return Stack(
alignment: Alignment.center,
children: [
Image.asset(
'assets/images/certif_template_new.png'),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.center,
widthFactor: 1.0,
heightFactor: 0.6,
child: Padding(
padding: EdgeInsets.only(
left:
getProportionateScreenWidth(28.5),
right:
getProportionateScreenWidth(240),
top: getProportionateScreenHeight(10),
bottom: getProportionateScreenHeight(90)
),
child: Text(
certifProv.certificateNo!.toUpperCase(),
textAlign: TextAlign.left,
style: primaryTextStyle.copyWith(
fontFamily: 'Arial',
fontWeight: FontWeight.w500,
fontSize:
getProportionateScreenWidth(
4),
color: Color.fromARGB(255, 255, 255, 255),
),
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.center,
widthFactor: 1.0,
heightFactor: 0.3,
child: Padding(
padding: EdgeInsets.only(
left:
getProportionateScreenWidth(27.5),
right:
getProportionateScreenHeight(
80),
top: getProportionateScreenHeight(
6),
),
child: Text(
certifProv.name!.toUpperCase(),
textAlign: TextAlign.left,
style: primaryTextStyle.copyWith(
fontFamily: 'Arial',
fontWeight: FontWeight.bold,
fontSize:
getProportionateScreenWidth(
9),
color: Color.fromARGB(255, 248, 124, 0),
),
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomCenter,
widthFactor: 1.0,
heightFactor: 0.5,
child: Padding(
padding: EdgeInsets.only(
right:
getProportionateScreenWidth(
85),
left: 27.5),
child: Text('"${certifProv.title}"',
style: primaryTextStyle.copyWith(
fontFamily: 'Arial',
fontWeight: FontWeight.bold,
fontSize: certifProv
.title!.length >
40
? getProportionateScreenWidth(
9)
: getProportionateScreenWidth(
11),
color: Color.fromARGB(255, 248, 124, 0)),
textAlign: TextAlign.left,
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomLeft,
widthFactor: 0.299,
heightFactor: 0.62,
child: Center(
child: Padding(
padding: EdgeInsets.only(
bottom:
getProportionateScreenHeight(
2),
left: 5),
child: Text(
'Jakarta, ${DateFormat('dd MMMM yyyy ').format(DateTime.fromMillisecondsSinceEpoch(certifProv.finishDate * 1000))}',
style: primaryTextStyle.copyWith(
fontWeight:
FontWeight.normal,
fontSize:
getProportionateScreenWidth(
4),
color: Color.fromARGB(255, 0, 0, 0)),
),
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomRight,
// widthFactor
heightFactor: 0.495,
child: Padding(
padding: EdgeInsets.only(
right: 19
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
QrImageView(
data: "https://vocasia.id/?no-certificate=${certifProv.certificateNo}",
version: QrVersions.auto,
size: getProportionateScreenHeight(48),
gapless: false,),
],
),
),
),
),
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomRight,
// widthFactor
heightFactor: 0.18,
child: Padding(
padding: EdgeInsets.only(
right: 25
),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
RichText(
text:
TextSpan(
text:
'Issued : ${DateFormat('dd MMMM yyyy ').format(DateTime.fromMillisecondsSinceEpoch(certifProv.finishDate * 1000))}',
style: primaryTextStyle
.copyWith(
fontWeight:
FontWeight.normal,
fontSize:
getProportionateScreenWidth(
3),
color:
Color(0xff575553),
),
),
)
],
),
),
),
),
],
);
},
),
),
),
),
],
);
} else if (state.state == certifProvider.ResultState.Error) {
return Center(
child: Column(
children: [
Text(
'Terjadi Kesalahan Coba Lagi',
style: thirdTextStyle,
),
],
),
);
} else {
return Center(
child: Text(
'Terjadi kesalahan',
style: thirdTextStyle,
),
);
}
},
),
),
),
),
);
}
Widget notFinish() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Sertifikat',
style: thirdTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Center(
child: Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Sertifikat',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(28),
),
),
Text(
'Belum Tersedia',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(28),
),
),
SizedBox(height: getProportionateScreenHeight(24)),
Stack(
children: [
Container(
width: double.infinity,
height: getProportionateScreenWidth(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
),
Container(
width: (SizeConfig.screenWidth -
getProportionateScreenWidth(32)) *
(totalProgress ?? 0) /
100,
height: getProportionateScreenWidth(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: primaryColor,
),
child: Text(
'${totalProgress ?? 0}%',
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: reguler,
color: baruTextutih,
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Anda baru menyelesaikan ${totalProgress ?? 0}% kursus',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(13),
),
),
SizedBox(height: getProportionateScreenHeight(16)),
Text(
'Anda belum memenuhi persyaratan untuk mendapatkan sertfikat. Selesaikan kursus anda untuk mendapatkan sertifikat penyelesaian kursus.',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(13),
),
),
],
),
),
),
),
);
}
Widget checkCertificateFinish() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Sertifikat',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
)),
body: Center(
child: Container(
margin: EdgeInsets.only(
left: getProportionateScreenWidth(16),
right: getProportionateScreenWidth(16),
),
child: Consumer<certifProvider.CertificateProvider>(
builder: (context, state, _) {
if (state.state == certifProvider.ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
);
} else if (state.state ==
certifProvider.ResultState.HasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(15),
width: double.infinity,
height: 280,
child: LayoutBuilder(
builder: (context, constraint) {
return Stack(
alignment: Alignment.center,
children: [
Image.asset(
'assets/images/certif_template_new.png'),
Positioned(
top: constraint.maxHeight / 2.55,
left: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 25),
child: Text(
certifProv.name!,
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Color(0xff575553)),
),
),
),
Positioned(
top: constraint.maxHeight / 1.9,
left: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 33),
child: Text('"${certifProv.title}"',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.bold,
fontSize:
(certifProv.title!.length >
20)
? 9
: 12,
color: Color(0xff575553)),
textAlign: TextAlign.center),
),
),
Positioned(
top: constraint.maxHeight / 1.6,
left: 0,
right: 0,
child: Center(
child: Text(
'${DateFormat('dd MMMM yyyy ').format(DateTime.fromMillisecondsSinceEpoch(certifProv.finishDate * 1000))}',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.normal,
fontSize: 8,
color: Color(0xff575553)),
),
),
),
Positioned(
bottom: constraint.maxHeight / 5.6,
left: constraint.maxWidth / 10,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'Certificate no : ${certifProv.certificateNo}',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.normal,
fontSize: 4,
color: Color(0xff575553),
),
),
Text(
'Certificate URL : https://vocasia-v4-develop.vercel.app/certificate/${certifProv.idPayment}-VOCASIA-${certifProv.certificateNo}',
style: primaryTextStyle.copyWith(
fontWeight: FontWeight.normal,
fontSize: 4,
color: Color(0xff575553),
),
),
],
),
)
],
);
},
),
),
],
);
} else if (state.state == certifProvider.ResultState.Error) {
return Center(
child: Column(
children: [
Text(
'Terjadi Kesalahan Coba Lagi',
style: thirdTextStyle,
),
],
),
);
} else {
return Center(
child: Text(
'Terjadi kesalahan',
style: thirdTextStyle,
),
);
}
},
),
),
),
),
);
}
Widget checkCertificateNotFinished() {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Sertifikat',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
),
body: Center(
child: Text(
'Sertifikat Belum Diterbitkan',
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(20),
),
),
),
),
);
}
Widget buildCertificate() {
return Container(
color: Colors.red,
margin: EdgeInsets.all(15),
width: double.infinity,
height: 300,
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('assets/certif_template_new.png'),
Positioned(
top: 120,
left: 0,
right: 0,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenHeight(25)),
child: Text(
'Safinatun Najah Unju',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: getProportionateScreenWidth(14)),
),
),
),
Positioned(
top: 155,
left: 0,
right: 0,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenHeight(33)),
child: Column(
children: [
Text(
'"Basic Excel Trainig For Professional Employees & Recruitment Selection Candidates"',
style: TextStyle(
fontWeight: FontWeight.w600, fontSize: 12),
textAlign: TextAlign.center),
SizedBox(height: getProportionateScreenHeight(10)),
Text(
'Jakarta, 24 October 2021',
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: getProportionateScreenWidth(8)),
)
],
),
),
),
Positioned(
bottom: getProportionateScreenHeight(50),
left: (65 / 640) * MediaQuery.of(context).size.width,
child: Column(
children: [
Text(
'Certificate no : 257911829183',
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: getProportionateScreenWidth(6)),
),
Text(
'Certificate no : 257911829183',
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: getProportionateScreenWidth(6)),
),
],
),
)
],
),
);
}
if (totalProgress == 100 && idCourse != null) {
return finish();
} else if (totalProgress != 100 && idCourse != null) {
return finish();
} else if (finishDate != false) {
return checkCertificateFinish();
} else {
return checkCertificateNotFinished();
}
}
}

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

View File

@ -0,0 +1,236 @@
import 'package:firebase_messaging/firebase_messaging.dart';
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/providers/user_info_provider.dart';
import 'package:initial_folder/screens/cart/cart_page.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:provider/provider.dart';
import '../../../../size_config.dart';
import '../notification.dart';
import 'icon_btn_with_counter.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
class HomeHeader extends StatefulWidget {
const HomeHeader({
Key? key,
}) : super(key: key);
@override
State<HomeHeader> createState() => _HomeHeaderState();
}
class _HomeHeaderState extends State<HomeHeader> {
@override
void initState() {
super.initState();
Future.delayed(Duration(seconds: 0), () async {
await Provider.of<NotificationProvider>(context, listen: false)
.getNotificationCount();
});
}
@override
Widget build(BuildContext context) {
UserInfoProvider userInfoProvider = Provider.of<UserInfoProvider>(context);
FirebaseMessaging.onMessage.listen((event) async {
if (event.notification!.body!.isNotEmpty) {
await Provider.of<NotificationProvider>(context, listen: false)
.getNotificationCount();
}
});
Future _showDialogNotLogin(String teks) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
elevation: 0.0,
contentPadding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(20),
vertical: getProportionateScreenHeight(20),
),
content: Text(
'Mohon login terlebih dahulu sebelum $teks',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11)),
),
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 Container(
height: getProportionateScreenHeight(60),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: EdgeInsets.only(left: getProportionateScreenWidth(23)),
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Welcome ${userInfoProvider.fullName}\n',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black),
),
TextSpan(
text: 'Let\'s\ Explore Course',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(16),
fontWeight: bold,
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black),
),
],
),
),
),
Row(
children: [
Transform.scale(
origin: Offset(-11, 0),
scale: getProportionateScreenHeight(0.9),
child: Container(
padding:
EdgeInsets.only(right: getProportionateScreenWidth(10)),
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.data.length,
icon: Theme.of(context).brightness ==
Brightness.dark
? SvgPicture.asset(
"assets/icons/cart_dark.svg")
: SvgPicture.asset("assets/icons/cart.svg"),
press: () => handleNotLoginCart(),
);
},
),
),
),
Padding(
padding:
EdgeInsets.only(left: SizeConfig.blockHorizontal! * 4),
),
],
),
],
),
),
);
}
}

View File

@ -0,0 +1,63 @@
// import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/theme.dart';
class IconBtnWithCounter extends StatelessWidget {
const IconBtnWithCounter({
Key? key,
required this.icon,
this.numOfitem = 0,
required this.press,
}) : super(key: key);
final Widget icon;
final int numOfitem;
final GestureTapCallback press;
@override
Widget build(BuildContext context) {
return IconButton(
highlightColor: Colors.transparent,
hoverColor: Colors.transparent,
onPressed: press,
visualDensity: VisualDensity(horizontal: -4.0, vertical: -4.0),
padding: EdgeInsets.zero,
icon: Stack(
clipBehavior: Clip.none,
children: [
Container(
height: 26,
width: 26,
child: icon,
),
if (numOfitem != 0)
Positioned(
top: 0,
right: -2,
child: Container(
height: 14,
width: 16,
decoration: BoxDecoration(
color: Color(0xffCD2228),
shape: BoxShape.circle,
// border: Border.all(width: 1.5, color: Colors.red),
),
child: Center(
child: Text(
"$numOfitem",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 8,
height: 1.3,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
)
],
),
);
}
}

View File

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import '../../../../theme.dart';
import '../../../../size_config.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:initial_folder/screens/splash/splash_screen_login.dart';
class Begin extends StatelessWidget {
const Begin({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//EmailProvider emailProvider = Provider.of<EmailProvider>(context);
final user = FirebaseAuth.instance.currentUser;
return Row(
children: <Widget>[
Column(
children: <Widget>[
Container(
height: getProportionateScreenWidth(60),
width: getProportionateScreenWidth(60),
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
//border: Border.all(width: 2.0, color: Colors.white),
image: (Condition.loginFirebase == true)
? DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(user!.photoURL!))
: DecorationImage(
image:
AssetImage('assets/images/Profile Image.png'))),
),
],
),
SizedBox(width: getProportionateScreenWidth(24)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//SizedBox(height: getProportionateScreenWidth(4)),
Row(
children: <Widget>[
Text(
"Hai,",
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: reguler,
color: tenthColor,
),
textAlign: TextAlign.left,
),
],
),
SizedBox(height: getProportionateScreenWidth(7)),
Row(
children: <Widget>[
Text(
'Mau Upgrade Skill Apa?',
style: secondaryTextStyle.copyWith(
color: tenthColor,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
textAlign: TextAlign.left,
),
],
),
],
),
],
);
}
}

View File

@ -0,0 +1,218 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/models/banners_model.dart';
import 'package:initial_folder/providers/banners_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:initial_folder/widgets/terms_and_privacy.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../size_config.dart';
class CarouselWithIndicatorDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _CarouselWithIndicatorState();
}
}
class _CarouselWithIndicatorState extends State<CarouselWithIndicatorDemo> {
int _current = 0;
@override
Widget build(BuildContext context) {
Widget listBannerPicture(BannersModel listBanner) {
return InkWell(
onTap: () {
String? idCourse;
if (listBanner.courseId.isNotEmpty) {
idCourse = listBanner.courseId;
} else {
if (listBanner.url!.isNotEmpty) {
if (listBanner.url!
.contains('https://vocasia-v4-develop.vercel.app/')) {
List<String> urlList = listBanner.url!.split('/');
try {
idCourse = urlList.last;
} on StateError {
idCourse = '0';
}
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: idCourse ?? '0',
),
),
);
} else {
Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
builder: (context) => TermsAndCondition(
// url: 'https://vocasia.id/home/contact',
url: listBanner.url!,
),
),
);
}
}
}
},
splashColor: Colors.white10,
child: Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: AspectRatio(
aspectRatio: 2,
child: CachedNetworkImage(
fadeInDuration: Duration(microseconds: 1),
imageUrl: listBanner.img.toString(),
fit: BoxFit.contain,
placeholder: (context, url) => Shimmer(
child: Container(
decoration: BoxDecoration(
color: ninthColor,
borderRadius: BorderRadius.circular(5),
),
),
gradient: LinearGradient(
stops: [0.2, 0.5, 0.6],
colors: [ninthColor, fourthColor, ninthColor])),
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
),
),
);
}
return Container(
child: Consumer<BannersProvider>(builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Padding(
padding: const EdgeInsets.all(18.0),
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
height: 210,
width: 50,
)),
);
} else if (state.state == ResultState.HasData) {
return Container(
child: Column(
children: [
CarouselSlider(
items: state.result
.map((banner) => listBannerPicture(banner))
.toList(),
options: CarouselOptions(
height: getProportionateScreenHeight(200),
disableCenter: true,
autoPlay: true,
autoPlayInterval: Duration(seconds: 10),
enlargeCenterPage: true,
viewportFraction: 1,
aspectRatio: 2,
onPageChanged: (index, reason) {
setState(() {
_current = index;
});
}),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: state.result.map((url) {
int index = state.result.indexOf(url);
return Container(
width: getProportionateScreenWidth(6.0),
height: getProportionateScreenWidth(6.0),
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3.0),
vertical: getProportionateScreenWidth(16)),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index ? thirdColor : fourthColor,
),
);
}).toList()),
],
),
);
} else if (state.state == ResultState.NoData) {
final defaultBanners = [
'assets/images/deffault_banner.png',
'assets/images/default_banner_2.png'
];
return Column(
children: [
CarouselSlider.builder(
itemCount: defaultBanners.length,
itemBuilder: (context, index, realIndex) {
return Image.asset(
defaultBanners[index],
width: double.infinity,
);
},
options: CarouselOptions(
height: getProportionateScreenHeight(200),
autoPlay: true,
autoPlayInterval: Duration(seconds: 10),
enlargeCenterPage: true,
viewportFraction: 1,
aspectRatio: 2,
onPageChanged: (index, reason) {
setState(() {
_current = index;
});
},
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(defaultBanners.length, (index) {
return Container(
width: getProportionateScreenWidth(6.0),
height: getProportionateScreenWidth(6.0),
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(3.0),
vertical: getProportionateScreenWidth(16),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index ? thirdColor : fourthColor,
),
);
}),
),
],
);
} else if (state.state == ResultState.Error) {
return Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(76),
top: getProportionateScreenHeight(45),
),
child: Container(
width: getProportionateScreenWidth(480),
height: getProportionateScreenHeight(100),
color: Colors.transparent,
child: Text('Internet lemah, mohon muat ulang'),
),
);
} else {
return Center(child: Text(''));
}
}),
);
}
}

View File

@ -0,0 +1,164 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/screens/certificate/certificate.dart';
import 'package:initial_folder/screens/coupon/coupon_page.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/custom_navigator_bottom.dart';
class CertificateVoucher extends StatelessWidget {
const CertificateVoucher({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Future _showDialogNotLogin() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
elevation: 0.0,
contentPadding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(20),
vertical: getProportionateScreenHeight(20),
),
content: Text(
'Mohon login terlebih dahulu sebelum menukarkan kupon',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11)),
),
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)),
),
],
),
);
}
return IntrinsicHeight(
child: Column(
children: [
SizedBox(height: getProportionateScreenHeight(20)),
Container(
height: getProportionateScreenHeight(44),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: -5,
blurRadius: 10,
offset: Offset(0, 3),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
Navigator.of(context, rootNavigator: true).push(
CustomNavigatorBottom(
child: Certificate(),
),
);
},
child: Row(
children: [
SvgPicture.asset(
"assets/icons/certificate.svg",
color: Theme.of(context).colorScheme.onPrimary,
width: getProportionateScreenWidth(13),
),
SizedBox(width: getProportionateScreenWidth(5)),
Text(
'Sertifikat',
textAlign: TextAlign.start,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: reguler,
),
),
],
),
),
SizedBox(width: getProportionateScreenWidth(40)),
Container(
height: getProportionateScreenHeight(18),
child: VerticalDivider(
color: Theme.of(context).colorScheme.onPrimary,
thickness: 1),
),
SizedBox(width: getProportionateScreenWidth(40)),
GestureDetector(
onTap: () {
if (Condition.loginEmail || Condition.loginFirebase) {
showModalBottomSheet(
elevation: 0,
backgroundColor:
Theme.of(context).colorScheme.background,
context: context,
builder: (context) => ClipRect(child: CouponPage()),
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
);
} else if (!Condition.loginEmail ||
!Condition.loginFirebase) {
_showDialogNotLogin();
}
},
child: Row(
children: [
SvgPicture.asset(
"assets/icons/voucher.svg",
color: Theme.of(context).colorScheme.onPrimary,
width: getProportionateScreenWidth(13),
),
SizedBox(width: getProportionateScreenWidth(5)),
Text(
'Voucher',
textAlign: TextAlign.start,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: reguler,
),
),
],
),
),
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,286 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/course_by_category_provider.dart';
import 'package:initial_folder/screens/detail_course/components/app_bar.dart';
import 'package:initial_folder/screens/detail_course/components/app_bar_filter.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/latest_course.dart';
import 'package:initial_folder/screens/home/components/body_comp/list_of_categories.dart';
import 'package:initial_folder/screens/home/components/body_comp/populer_course.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card.dart';
import 'package:initial_folder/services/course_by_category_service.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';
class CourseByCategory extends StatefulWidget {
CourseByCategory({
Key? key,
required this.name,
required this.categoryId,
required this.subId,
this.homeCategories,
}) : super(key: key);
final String name;
final String categoryId;
final String subId;
final bool? homeCategories;
@override
State<CourseByCategory> createState() => _CourseByCategoryState();
}
class _CourseByCategoryState extends State<CourseByCategory> {
bool _isExpanded = false;
bool _buttonPressed = false;
final ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
controller: _scrollController,
child: ChangeNotifierProvider<CourseByCategoryProvider>(
create: (context) => CourseByCategoryProvider(
courseByCategoryService: CourseByCategoryService(),
id: widget.categoryId,
subId: widget.subId,
fetchBySubcategory: false,
),
child: Container(
child: Consumer<CourseByCategoryProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(300)),
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
),
);
} else if (state.state == ResultState.HasData) {
return Stack(
children: [
GestureDetector(
child: Container(
color: Colors.transparent,
),
),
GestureDetector(
onTap: () {
setState(() {
_isExpanded = !_isExpanded;
_buttonPressed = !_buttonPressed;
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppBarHeader(),
SizedBox(height: getProportionateScreenHeight(23)),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(19)),
child: Text(
'${widget.name.replaceAll('&amp;', '&')}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(20),
letterSpacing: -0.5,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.start,
),
),
if (widget.homeCategories == null)
SizedBox(
height: getProportionateScreenHeight(65)),
if (widget.homeCategories == null)
PopulerCourse(text: 'Populer'),
if (widget.homeCategories == null)
LatestCourse(text: "New Release"),
if (widget.homeCategories == null)
SizedBox(
height: getProportionateScreenHeight(15)),
if (widget.homeCategories != null)
SizedBox(
height: getProportionateScreenHeight(25)),
if (widget.homeCategories == null)
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(16),
bottom: getProportionateScreenHeight(28),
),
child: Text(
"${widget.name}",
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
),
),
GridView.builder(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(21),
left: getProportionateScreenWidth(7),
bottom: getProportionateScreenHeight(18),
),
physics: ScrollPhysics(),
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.8 / 4,
crossAxisSpacing: 16,
mainAxisSpacing: 14,
),
itemCount: state.result.length,
itemBuilder: (context, index) {
var courses = state.result[index];
int price = int.tryParse(
courses.price.replaceAll('.', '')) ??
0;
int discountPrice = int.tryParse(courses
.discountPrice
.replaceAll('.', '')) ??
0;
int calculatedPrice =
(courses.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? courses.price
: calculatedPrice.toString();
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(13)),
child: ProductCard(
totalDiscount: courses.totalDiscount ?? 0,
students: courses.students ?? '0',
id: courses.idCourse,
thumbnail: courses.thumbnail ??
'https://vocasia.id/uploads/thumbnails/course_thumbnails/course_thumbnail_default_63.jpg',
title: courses.title,
instructorName: courses.instructorName,
specificRating: double.parse(courses
.rating[0]!.avgRating !=
null
? '${courses.rating[0]!.avgRating}'
: '5.0')
.toString(),
rating: courses.rating[0]!.avgRating != null
? '${courses.rating[0]!.avgRating}'
: '5.0',
numberOfRatings:
courses.rating[0]!.totalReview ?? '0',
isTopCourse: '0',
price: (courses.discountPrice == '0')
? 'Gratis'
: numberFormat(displayedPrice),
realPrice: (courses.price == '0')
? ''
: numberFormat(courses.price),
press: () async {
Navigator.of(context, rootNavigator: true)
.push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: courses.idCourse,
),
),
);
},
),
);
},
),
],
),
),
if (widget.homeCategories == null)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: 1,
heightFactor: 1,
child: Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(87)),
child: Categories(
selectedCategoryId: widget.categoryId,
key: UniqueKey(),
scrollController: _scrollController,
),
),
),
),
],
);
} else if (state.state == ResultState.NoData) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppBarHeader(),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Text(
'${widget.name.replaceAll('&amp;', '&')}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(25),
letterSpacing: -0.5,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.start,
),
),
Categories(
selectedCategoryId: widget.categoryId,
key: UniqueKey(),
scrollController: _scrollController,
),
SizedBox(height: getProportionateScreenHeight(200)),
Center(
child: Text(
"Oops! Tidak ada kursus yang tersedia dalam kategori ini.",
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
color: Colors.grey,
),
),
),
SizedBox(height: getProportionateScreenHeight(60)),
],
);
} else if (state.state == ResultState.Error) {
return Center(child: Text("No internet connections."));
} else {
return Center(child: Text(''));
}
}),
),
),
),
),
);
}
void _collapseSubcategories() {
_scrollController.animateTo(
0,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
}
}

View File

@ -0,0 +1,237 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/course_by_category_provider.dart';
import 'package:initial_folder/screens/detail_course/components/app_bar.dart';
import 'package:initial_folder/screens/detail_course/components/app_bar_filter.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card.dart';
import 'package:initial_folder/services/course_by_category_service.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';
class CourseBySubcategory extends StatefulWidget {
CourseBySubcategory({
Key? key,
required this.name,
required this.categoryId,
required this.subId,
}) : super(key: key);
final String name;
final String categoryId;
final String subId;
@override
State<CourseBySubcategory> createState() => _CourseBySubcategoryState();
}
class _CourseBySubcategoryState extends State<CourseBySubcategory> {
bool _isExpanded = false;
bool _buttonPressed = false;
final ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
controller: _scrollController,
child: ChangeNotifierProvider<CourseByCategoryProvider>(
create: (context) => CourseByCategoryProvider(
courseByCategoryService: CourseByCategoryService(),
id: widget.categoryId,
subId: widget.subId,
fetchBySubcategory: true,
),
child: Container(
child: Consumer<CourseByCategoryProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
return GestureDetector(
onTap: () {
setState(() {
_isExpanded = !_isExpanded;
_buttonPressed = !_buttonPressed;
});
},
child: Stack(
children: [
GestureDetector(
child: Container(
color: Colors.transparent,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppBarFilter(),
SizedBox(height: getProportionateScreenHeight(10)),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Text(
'${widget.name}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(20),
letterSpacing: -0.5,
fontWeight: bold,
),
textAlign: TextAlign.start,
),
),
SizedBox(height: getProportionateScreenHeight(20)),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Text(
"Semua Kursus ${widget.name}",
style:
thirdTextStyle.copyWith(fontWeight: bold),
),
),
SizedBox(height: getProportionateScreenHeight(20)),
GridView.builder(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(22),
left: getProportionateScreenWidth(7),
),
physics: ScrollPhysics(),
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.8 / 4,
crossAxisSpacing: 16,
mainAxisSpacing: 12,
),
itemCount: state.result.length,
itemBuilder: (context, index) {
var courses = state.result[index];
int price = int.tryParse(
courses.price.replaceAll('.', '')) ??
0;
int discountPrice = int.tryParse(courses
.discountPrice
.replaceAll('.', '')) ??
0;
int calculatedPrice =
(courses.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? courses.price
: calculatedPrice.toString();
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(17)),
child: ProductCard(
totalDiscount: courses.totalDiscount ?? 0,
students: courses.students ?? '0',
id: courses.idCourse,
thumbnail: courses.thumbnail ??
'https://vocasia.id/uploads/thumbnails/course_thumbnails/course_thumbnail_default_63.jpg',
title: courses.title,
instructorName: courses.instructorName,
specificRating: double.parse(courses
.rating[0]!.avgRating !=
null
? '${courses.rating[0]!.avgRating}'
: '5.0')
.toString(),
rating: courses.rating[0]!.avgRating != null
? '${courses.rating[0]!.avgRating}'
: '5.0',
numberOfRatings:
courses.rating[0]!.totalReview ?? '0',
isTopCourse: '0',
price: (courses.discountPrice == '0')
? 'Gratis'
: numberFormat(displayedPrice),
realPrice: (courses.price == '0')
? ''
: numberFormat(courses.price),
press: () async {
Navigator.of(context, rootNavigator: true)
.push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: courses.idCourse,
),
),
);
},
),
);
},
),
],
),
],
),
);
} else if (state.state == ResultState.NoData) {
return Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AppBarHeader(),
Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Text(
'${widget.name.replaceAll('&amp;', '&')}',
style: secondaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(25),
letterSpacing: -0.5,
),
textAlign: TextAlign.start,
),
),
],
),
Center(
child: Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(300)),
child: Text(
"Sub kategori yang dipilih tidak memiliki kursus",
style: TextStyle(
fontSize: getProportionateScreenWidth(10)),
),
),
),
],
);
} else if (state.state == ResultState.Error) {
return Center(child: Text("Terjadi kesalahan."));
} else {
return Center(child: Text(''));
}
}),
),
),
),
),
);
}
void _collapseSubcategories() {
_scrollController.animateTo(
0,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
}
}

View File

@ -0,0 +1,173 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/course_by_category_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card.dart';
import 'package:initial_folder/services/course_by_category_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
class CourseTerkait extends StatefulWidget {
CourseTerkait({
Key? key,
required this.name,
required this.categoryId,
required this.subId,
this.homeCategories,
}) : super(key: key);
final String name;
final String categoryId;
final String subId;
final bool? homeCategories;
@override
State<CourseTerkait> createState() => _CourseTerkaitState();
}
class _CourseTerkaitState extends State<CourseTerkait> {
final ScrollController _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
controller: _scrollController,
child: ChangeNotifierProvider<CourseByCategoryProvider>(
create: (context) => CourseByCategoryProvider(
courseByCategoryService: CourseByCategoryService(),
id: widget.categoryId,
subId: widget.subId,
fetchBySubcategory: false,
),
child: Container(
child: Consumer<CourseByCategoryProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
return Stack(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
height: getProportionateScreenHeight(13)),
Text(
' Kursus Terkait',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(15),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(20)),
GridView.builder(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(21),
left: getProportionateScreenWidth(7),
bottom: getProportionateScreenHeight(18),
),
physics: BouncingScrollPhysics(),
shrinkWrap: true,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.8 / 4,
crossAxisSpacing: 16,
mainAxisSpacing: 14,
),
itemCount: state.result.length,
itemBuilder: (context, index) {
var courses = state.result[index];
int price = int.tryParse(
courses.price.replaceAll('.', '')) ??
0;
int discountPrice = int.tryParse(courses
.discountPrice
.replaceAll('.', '')) ??
0;
int calculatedPrice =
(courses.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? courses.price
: calculatedPrice.toString();
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(13)),
child: ProductCard(
totalDiscount: courses.totalDiscount ?? 0,
students: courses.students ?? '0',
id: courses.idCourse,
thumbnail: courses.thumbnail ??
'https://vocasia.id/uploads/thumbnails/course_thumbnails/course_thumbnail_default_63.jpg',
title: courses.title,
instructorName: courses.instructorName,
specificRating: double.parse(courses
.rating[0]!.avgRating !=
null
? '${courses.rating[0]!.avgRating}'
: '5.0')
.toString(),
rating: courses.rating[0]!.avgRating != null
? '${courses.rating[0]!.avgRating}'
: '5.0',
numberOfRatings:
courses.rating[0]!.totalReview ?? '0',
isTopCourse: '0',
price: (courses.discountPrice == '0')
? 'Gratis'
: numberFormat(displayedPrice),
realPrice: (courses.price == '0')
? ''
: numberFormat(courses.price),
press: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DetailCourseScreen(
idcourse: courses.idCourse,
),
),
);
},
),
);
},
),
SizedBox(height: getProportionateScreenHeight(50)),
],
),
],
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text("Tidak ada kursus terkait"));
} else if (state.state == ResultState.Error) {
return Center(child: Text("No internet connections."));
} else {
return Center(child: Text(''));
}
},
),
),
),
),
);
}
}

View File

@ -0,0 +1,256 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/providers/categories_provider.dart';
import 'package:initial_folder/screens/home/components/body_comp/course_by_category.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
class HomeCategories extends StatelessWidget {
const HomeCategories({super.key});
@override
Widget build(BuildContext context) {
CategoriesProvider categoriesProvider =
Provider.of<CategoriesProvider>(context);
return Padding(
padding: EdgeInsets.only(left: getProportionateScreenWidth(17)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(15)),
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Kategori',
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
),
GestureDetector(
onTap: () =>
Navigator.pushNamed(context, '/lihatSemuaKategori'),
child: Text(
'Lihat Semua',
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(11),
),
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(18)),
Stack(
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(22),
right: getProportionateScreenWidth(14),
),
child: categoriesProvider.state == ResultState.Loading
? GridView.count(
crossAxisCount: 2,
childAspectRatio: 5 / 2,
mainAxisSpacing: 13,
crossAxisSpacing: 30,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: List.generate(4, (index) {
return Shimmer.fromColors(
baseColor: Colors.grey,
highlightColor: Colors.white,
child: SizedBox(
width: getProportionateScreenWidth(160),
child: Container(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(5),
horizontal: getProportionateScreenWidth(10),
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(18)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Container(
color: Colors.white,
height:
getProportionateScreenHeight(10),
),
SizedBox(
height:
getProportionateScreenHeight(7)),
Container(
color: Colors.white,
height:
getProportionateScreenHeight(10),
),
],
),
),
),
),
);
}),
)
: GridView.count(
crossAxisCount: 2,
childAspectRatio: 5 / 2,
mainAxisSpacing: 13,
crossAxisSpacing: 30,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: List.generate(4, (index) {
return GestureDetector(
onTap: () {
Navigator.of(context).push(
CustomNavigator(
child: CourseByCategory(
name: categoriesProvider
.result[index].nameCategory! ??
'',
categoryId:
categoriesProvider.result[index].id!,
subId: "",
homeCategories: true,
),
),
);
},
child: SizedBox(
width: getProportionateScreenWidth(160),
child: Container(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(5),
horizontal: getProportionateScreenWidth(10),
),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: Colors.grey,
),
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(18)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
categoriesProvider
.result[index].nameCategory!.replaceAll('&amp;', '&'),
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(10),
letterSpacing: 1,
fontWeight: bold,
),
),
],
),
),
),
),
);
}),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: 0.12,
heightFactor: 0.44,
child: SvgPicture.asset(
"assets/icons/category1.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: 0.12,
heightFactor: 1.53,
child: SvgPicture.asset(
"assets/icons/category3.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topCenter,
widthFactor: 0.6,
heightFactor: 0.4,
child: Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(37),
top: getProportionateScreenHeight(7),
),
child: SvgPicture.asset(
"assets/icons/category2.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomCenter,
widthFactor: 0.53,
heightFactor: 0.39,
child: Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(37),
bottom: getProportionateScreenHeight(7),
),
child: SvgPicture.asset(
"assets/icons/category4.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
],
),
);
}
}

View File

@ -0,0 +1,485 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/latest_course_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card_new.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../size_config.dart';
import '../../../../theme.dart';
class LatestCourse extends StatelessWidget {
const LatestCourse({Key? key, this.text}) : super(key: key);
final String? text;
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(height: getProportionateScreenHeight(20)),
Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
Text(
text.toString(),
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
),
]),
),
SizedBox(height: getProportionateScreenHeight(10)),
Consumer<LatestCourseProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
)
],
);
} else if (state.state == ResultState.HasData) {
return text != "New Release"
? Container(
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(
left: getProportionateScreenWidth(10)),
height: getProportionateScreenHeight(240),
child: ListView.builder(
scrollDirection: Axis.horizontal,
physics: const ScrollPhysics(),
shrinkWrap: true,
itemCount: state.result.length,
itemBuilder: (context, index) {
var latestCourse = state.result[index];
int price = int.tryParse(
latestCourse.price.replaceAll('.', '')) ??
0;
int discountPrice = int.tryParse(latestCourse
.discountPrice
.replaceAll('.', '')) ??
0;
int calculatedPrice =
(latestCourse.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? latestCourse.price
: calculatedPrice.toString();
// var finalRating = double.parse(
// (topCourse.specificRating![0] / 20).toStringAsFixed(2));
return Container(
margin: EdgeInsets.only(
top: getProportionateScreenHeight(10),
bottom: getProportionateScreenHeight(10),
),
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(18),
bottom: getProportionateScreenWidth(5),
),
child: ProductCardNew(
totalDiscount: latestCourse.totalDiscount ?? 0,
students: latestCourse.students ?? '0',
pad: 12,
// padRight: 12,
id: latestCourse.idCourse,
thumbnail: latestCourse.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: latestCourse.title,
instructorName: latestCourse.instructorName,
specificRating:
(latestCourse.rating.isNotEmpty &&
latestCourse.rating[0]?.avgRating !=
null)
? latestCourse.rating[0]!.avgRating
.toString()
: '0',
rating:
latestCourse.rating[0]!.avgRating != null
? '${latestCourse.rating[0]!.avgRating}'
: '5.0',
numberOfRatings: (latestCourse
.rating.isNotEmpty &&
latestCourse.rating[0]?.totalReview !=
null)
? latestCourse.rating[0]!.totalReview!
: '0',
isTopCourse: latestCourse.topCourse ?? '',
price: (latestCourse.price == '0')
? 'Gratis'
: (latestCourse.promoPrice != '0')
? numberFormat(latestCourse.promoPrice)
: numberFormat(displayedPrice),
realPrice: (latestCourse.price == '0')
? ''
: numberFormat(latestCourse.price),
press: () {
print(latestCourse.idCourse);
Navigator.of(context, rootNavigator: true)
.push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: latestCourse.idCourse,
isPromo: latestCourse.promoPrice != '0'
? true
: null,
),
),
);
},
),
),
);
},
),
)
: GridView.builder(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(22),
left: getProportionateScreenWidth(7),
top: getProportionateScreenHeight(10),
),
physics: ScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.55 / 4,
crossAxisSpacing: 16,
mainAxisSpacing: 12,
),
itemCount: state.result.length,
itemBuilder: (context, index) {
var latestCourse = state.result[index];
int price = int.tryParse(
latestCourse.price.replaceAll('.', '')) ??
0;
int discountPrice = int.tryParse(latestCourse
.discountPrice
.replaceAll('.', '')) ??
0;
int calculatedPrice =
(latestCourse.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? latestCourse.price
: calculatedPrice.toString();
return Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(17)),
child: ProductCardNew(
totalDiscount: latestCourse.totalDiscount ?? 0,
students: latestCourse.students ?? '0',
id: latestCourse.idCourse,
thumbnail: latestCourse.thumbnail ??
'https://vocasia.id/uploads/thumbnails/course_thumbnails/course_thumbnail_default_63.jpg',
title: latestCourse.title,
instructorName: latestCourse.instructorName,
specificRating: double.parse(
latestCourse.rating[0]!.avgRating != null
? '${latestCourse.rating[0]!.avgRating}'
: '5.0')
.toString(),
rating: latestCourse.rating[0]!.avgRating != null
? '${latestCourse.rating[0]!.avgRating}'
: '5.0',
numberOfRatings:
latestCourse.rating[0]!.totalReview ?? '0',
isTopCourse: '0',
price: (latestCourse.discountPrice == '0')
? 'Gratis'
: numberFormat(displayedPrice),
realPrice: (latestCourse.price == '0')
? ''
: numberFormat(latestCourse.price),
press: () async {
// await Hive.openBox<Wishlist>("wishlist");
// await Hive.openBox('carts');
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: latestCourse.idCourse,
isPromo: latestCourse.promoPrice != '0'
? true
: null,
),
),
);
},
),
);
},
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
)
],
);
} else {
return Center(child: Text(''));
}
},
)
],
);
}
// @override
// Widget build(BuildContext context) {
// return Column(
// children: [
// Padding(
// padding:
// EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
// child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
// Text('Kursus Terbaru',
// textAlign: TextAlign.left,
// style: secondaryTextStyle.copyWith(
// letterSpacing: 1,
// color: tenthColor,
// fontSize: getProportionateScreenWidth(14),
// fontWeight: semiBold)),
// ]),
// ),
// SizedBox(height: 20),
// Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Icon(Icons.construction_outlined),
// Text('Under Construction'),
// ],
// ),
// ],
// );
// }
}

View File

@ -0,0 +1,273 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:initial_folder/providers/categories_provider.dart'
as categoriesProv;
import 'package:initial_folder/providers/others_course_provider.dart';
import 'package:initial_folder/screens/home/components/body_comp/course_by_category.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:provider/provider.dart';
import '../../../../size_config.dart';
class LihatSemuaKategori extends StatefulWidget {
const LihatSemuaKategori({Key? key}) : super(key: key);
@override
State<LihatSemuaKategori> createState() => _LihatSemuaKategoriState();
}
class _LihatSemuaKategoriState extends State<LihatSemuaKategori> {
@override
Widget build(BuildContext context) {
categoriesProv.CategoriesProvider categoriesProvider =
Provider.of<categoriesProv.CategoriesProvider>(context);
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
"Kategori",
style: thirdTextStyle.copyWith(
fontWeight: bold, fontSize: getProportionateScreenWidth(16)),
),
),
body: Padding(
padding: EdgeInsets.only(left: getProportionateScreenWidth(15)),
child: Stack(
children: [
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(20),
right: getProportionateScreenWidth(14),
top: getProportionateScreenHeight(10),
),
child: categoriesProvider.state == ResultState.Loading
? Center(child: CircularProgressIndicator())
: GridView.count(
crossAxisCount: 2,
childAspectRatio: 4.3 / 2,
mainAxisSpacing: 13,
crossAxisSpacing: 30,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: List.generate(
categoriesProvider.result.length, (index) {
return GestureDetector(
onTap: () {
Navigator.of(context).push(
CustomNavigator(
child: CourseByCategory(
name: categoriesProvider
.result[index].nameCategory! ??
'',
categoryId:
categoriesProvider.result[index].id!,
subId: "",
homeCategories: true,
),
),
);
},
child: SizedBox(
width: getProportionateScreenWidth(160),
child: Container(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(5),
horizontal: getProportionateScreenWidth(10),
),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).brightness ==
Brightness.dark
? baruTextutih
: Colors.grey,
),
borderRadius: BorderRadius.circular(15),
),
child: Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(18)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
categoriesProvider
.result[index].nameCategory!.replaceAll('&amp;', '&'),
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(10),
fontWeight: bold,
),
),
],
),
),
),
),
);
}),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: 0.12,
heightFactor: 0.2,
child: Padding(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(9)),
child: SvgPicture.asset(
"assets/icons/category1.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: 0.12,
heightFactor: 0.59,
child: Padding(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(9)),
child: SvgPicture.asset(
"assets/icons/category3.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topRight,
widthFactor: 0.51,
heightFactor: 0.2,
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(133),
top: getProportionateScreenHeight(10),
),
child: SvgPicture.asset(
"assets/icons/category2.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.topRight,
widthFactor: 0.51,
heightFactor: 0.6,
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(133),
top: getProportionateScreenHeight(10),
),
child: SvgPicture.asset(
"assets/icons/category4.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.centerLeft,
widthFactor: 0.12,
heightFactor: 0.7,
child: Padding(
padding:
EdgeInsets.only(top: getProportionateScreenHeight(9)),
child: SvgPicture.asset(
"assets/icons/category5.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomLeft,
widthFactor: 0.12,
heightFactor: 0.57,
child: SvgPicture.asset(
"assets/icons/category7.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.centerRight,
widthFactor: 0.51,
heightFactor: 0.75,
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(133),
top: getProportionateScreenHeight(10),
),
child: SvgPicture.asset(
"assets/icons/category6.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomRight,
widthFactor: 0.51,
heightFactor: 0.57,
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(133)),
child: SvgPicture.asset(
"assets/icons/category8.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
),
if (categoriesProvider.state != ResultState.Loading)
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.bottomLeft,
widthFactor: 0.12,
heightFactor: 0.17,
child: SvgPicture.asset(
"assets/icons/category9.svg",
width: getProportionateScreenWidth(35),
height: getProportionateScreenHeight(35),
),
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,129 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/others_course_provider.dart';
import 'package:initial_folder/screens/detail_course/components/app_bar.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/theme.dart';
import 'package:provider/provider.dart';
import 'others_course.dart';
import 'product_card/product_card.dart';
import '../../../../size_config.dart';
import 'section_title.dart';
import 'package:intl/intl.dart';
class LihatSemuaKursus extends StatefulWidget {
static String routeName = "/lihatKursus";
const LihatSemuaKursus({Key? key}) : super(key: key);
@override
State<LihatSemuaKursus> createState() => _LihatSemuaKursusState();
}
class _LihatSemuaKursusState extends State<LihatSemuaKursus> {
ScrollController _controller = ScrollController();
@override
void initState() {
_controller.addListener(() {
onScroll();
});
}
void onScroll() async {
double maxScroll = _controller.position.maxScrollExtent;
double currentScroll = _controller.position.pixels;
if (maxScroll == currentScroll) {
await Provider.of<OthersCourseProvider>(context, listen: false)
.getOthersCourses();
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (_controller.hasClients) {
if (_controller.position.pixels != _controller.position.maxScrollExtent) {
_controller.animateTo(0,
duration: Duration(milliseconds: 900), curve: Curves.linear);
}
}
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
"Kursus Lainnya",
style: thirdTextStyle.copyWith(
fontWeight: bold, fontSize: getProportionateScreenWidth(16)),
),
),
body: Column(
children: [
Consumer<OthersCourseProvider>(builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
return Expanded(
child: ListView(controller: _controller, children: [
OthersCourse(
key: PageStorageKey<String>('lihatKursus'),
showTitle: true,
),
Provider.of<OthersCourseProvider>(context).loading
? Center(
child: SizedBox(
height: 30,
width: 30,
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
),
)
: SizedBox(height: 30),
SizedBox(height: 25),
]),
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Center(
child: Column(
children: [
Text(
'Terjadi Kesalahan Coba Lagi',
style: thirdTextStyle,
),
],
));
} else {
return Center(child: Text(''));
}
})
],
),
),
);
}
}
// courseProvider.course
// .map(
// (product) => ProductCard(
// product: product,
// ),
// )
// .toList(),

View File

@ -0,0 +1,239 @@
import 'dart:ui';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:initial_folder/models/subcategories_model.dart';
import 'package:initial_folder/providers/categories_provider.dart';
import 'package:initial_folder/screens/home/components/body_comp/course_by_subcategory.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';
class Categories extends StatefulWidget {
const Categories({
Key? key,
this.scrollable = false,
required this.selectedCategoryId,
required this.scrollController,
}) : super(key: key);
final bool scrollable;
final String selectedCategoryId;
final ScrollController scrollController;
@override
State<Categories> createState() => _CategoriesState();
}
class _CategoriesState extends State<Categories> {
bool _isExpanded = false;
bool _buttonPressed = false;
final GlobalKey<_CategoriesState> _categoriesKey =
GlobalKey<_CategoriesState>();
@override
void initState() {
super.initState();
widget.scrollController.addListener(_scrollListener);
}
@override
void dispose() {
widget.scrollController.removeListener(_scrollListener);
super.dispose();
}
void _scrollListener() {
if (_isExpanded) {
setState(() {
_isExpanded = false;
_buttonPressed = false;
});
}
}
void toggleExpansion(bool expanded) {
setState(() {
_isExpanded = expanded;
_buttonPressed = expanded;
});
if (!expanded) {
widget.scrollController.animateTo(
0,
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
}
}
@override
Widget build(BuildContext context) {
return Container(
child: Consumer<CategoriesProvider>(builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultState.HasData) {
final List<SubCategoryModel> filteredResult = state.result
.where((category) => category.id == widget.selectedCategoryId)
.map((category) => category.subCategories!)
.expand((element) => element)
.toList();
final bool showExpandIcon = filteredResult.length > 3;
return Container(
margin: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(10)),
child: Column(
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
boxShadow: [
BoxShadow(
color: Theme.of(context).brightness == Brightness.dark
? Colors.grey.withOpacity(0.6)
: Colors.black.withOpacity(0.2),
spreadRadius: -10,
blurRadius: 12,
offset: Offset(0, 9),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
...filteredResult
.take(_buttonPressed ? 2 : 2)
.map<Widget>((subcategory) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(17)),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
CustomNavigator(
child: CourseBySubcategory(
categoryId: widget.selectedCategoryId,
subId: subcategory.subId,
name: subcategory.nameSubCategory,
),
),
);
},
child: Text(
subcategory.nameSubCategory.isNotEmpty
? subcategory.nameSubCategory.replaceAll('&amp;', '&')
: 'No subcategories available',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11.5),
fontWeight: FontWeight.w600,
),
),
),
);
}).toList(),
if (showExpandIcon)
IconButton(
icon: Transform.rotate(
angle: _isExpanded ? pi / 2 : 0,
child: Icon(
Icons.arrow_forward_ios,
size: getProportionateScreenWidth(16),
),
),
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
_buttonPressed = !_buttonPressed;
});
},
),
],
),
if (_isExpanded)
Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(8)),
child: Container(
color: Theme.of(context).colorScheme.background,
height: 160,
child: ListView(
shrinkWrap: true,
physics: AlwaysScrollableScrollPhysics(),
children: filteredResult
.skip(2)
.map<Widget>((subcategory) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal:
getProportionateScreenWidth(17)),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
CustomNavigator(
child: CourseBySubcategory(
categoryId:
widget.selectedCategoryId,
subId: subcategory.subId,
name: subcategory.nameSubCategory,
),
),
);
},
child: Padding(
padding: EdgeInsets.only(
bottom:
getProportionateScreenHeight(10)),
child: Padding(
padding: EdgeInsets.only(
bottom:
getProportionateScreenHeight(
9)),
child: Text(
subcategory.nameSubCategory.isNotEmpty
? subcategory.nameSubCategory.replaceAll('&amp;', '&')
: 'No subcategories available',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
11.5),
fontWeight: FontWeight.w600,
),
),
),
),
),
);
}).toList(),
),
),
),
],
),
),
],
),
key: _categoriesKey,
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text("No subcategories available"));
} else if (state.state == ResultState.Error) {
return Center(child: Text("No internet connections."));
} else {
print(state.result.length);
return Center(child: Text(''));
}
}),
);
}
}

View File

@ -0,0 +1,368 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/others_course_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/lihat_semua_kursus_page.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import 'product_card/product_card.dart';
import '../../../../size_config.dart';
import 'section_title.dart';
class OthersCourse extends StatelessWidget {
final bool? showTitle;
const OthersCourse({Key? key, this.showTitle}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(16)),
child: (showTitle == null)
? SectionTitle(
title: "Kursus Lainnya",
press: () {
Navigator.push(
context,
CustomNavigator(
child: LihatSemuaKursus(),
),
);
},
)
: SizedBox()),
SizedBox(height: getProportionateScreenHeight(30)),
Consumer<OthersCourseProvider>(builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
)
],
);
} else if (state.state == ResultState.HasData) {
// state.result.shuffle();
return GridView.builder(
// controller: _controller,
padding: EdgeInsets.only(
right: getProportionateScreenWidth(23),
left: getProportionateScreenWidth(8),
),
physics: ScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2.6 / 4,
crossAxisSpacing: 15,
mainAxisSpacing: 10,
),
itemCount: state.result.length,
itemBuilder: (context, index) {
var othersCourse = state.result[index];
int price =
int.tryParse(othersCourse.price.replaceAll('.', '')) ?? 0;
int discountPrice = int.tryParse(
othersCourse.discountPrice.replaceAll('.', '')) ??
0;
int calculatedPrice = (othersCourse.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? othersCourse.price
: calculatedPrice.toString();
// var finalRating = double.parse(
// (othersCourse.specificRating![0] / 20).toStringAsFixed(2));
return Padding(
padding:
EdgeInsets.only(bottom: getProportionateScreenHeight(8)),
child: Container(
margin: EdgeInsets.only(
bottom: getProportionateScreenHeight(12)),
child: ProductCard(
totalDiscount: othersCourse.totalDiscount ?? 0,
students: othersCourse.students ?? '0',
id: othersCourse.idCourse,
thumbnail: othersCourse.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: othersCourse.title,
instructorName: othersCourse.instructorName,
specificRating: (othersCourse.rating.isNotEmpty &&
othersCourse.rating[0]?.avgRating != null)
? othersCourse.rating[0]!.avgRating.toString()
: '0',
rating: (othersCourse.rating.isNotEmpty &&
othersCourse.rating[0]?.avgRating != null)
? othersCourse.rating[0]!.avgRating.toString()
: '5.0',
numberOfRatings: (othersCourse.rating.isNotEmpty &&
othersCourse.rating[0]?.totalReview != null)
? othersCourse.rating[0]!.totalReview!
: '0',
isTopCourse: othersCourse.topCourse ?? '',
price: (othersCourse.price == '0')
? 'Gratis'
: (othersCourse.promoPrice != '0')
? numberFormat(othersCourse.promoPrice)
: numberFormat(displayedPrice),
realPrice: (othersCourse.price == '0')
? ''
: numberFormat(othersCourse.price),
press: () {
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: othersCourse.idCourse,
isPromo:
othersCourse.promoPrice != "0" ? true : null,
),
),
);
},
),
),
);
},
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
)
],
);
} else {
return Center(child: Text(''));
}
})
],
);
}
}
// courseProvider.course
// .map(
// (product) => ProductCard(
// product: product,
// ),
// )
// .toList(),

View File

@ -0,0 +1,361 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/top_course_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../size_config.dart';
import '../../../../theme.dart';
class PopulerCourse extends StatelessWidget {
const PopulerCourse({Key? key, this.text}) : super(key: key);
final String? text;
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
text.toString(),
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Consumer<TopCourseProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
)
],
);
} else if (state.state == ResultState.HasData) {
return Container(
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: getProportionateScreenWidth(10)),
height: getProportionateScreenHeight(220),
child: ListView.builder(
scrollDirection: Axis.horizontal,
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: state.result.length,
itemBuilder: (context, index) {
var topCourse = state.result[index];
// var finalRating = double.parse(
// (topCourse.specificRating![0] / 20).toStringAsFixed(2));
int price =
int.tryParse(topCourse.price.replaceAll('.', '')) ?? 0;
int discountPrice = int.tryParse(
topCourse.discountPrice.replaceAll('.', '')) ??
0;
int calculatedPrice = (topCourse.discountPrice != '0')
? price - discountPrice
: price;
String displayedPrice = (calculatedPrice == 0)
? topCourse.price
: calculatedPrice.toString();
return Container(
margin: EdgeInsets.only(
top: getProportionateScreenHeight(10),
),
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(18),
bottom: getProportionateScreenWidth(18),
),
child: ProductCard(
totalDiscount: topCourse.totalDiscount ?? 0,
students: topCourse.students ?? '0',
pad: 12,
id: topCourse.idCourse,
thumbnail: topCourse.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: topCourse.title,
instructorName: topCourse.instructorName,
specificRating: (topCourse.rating.isNotEmpty &&
topCourse.rating[0]?.avgRating != null)
? topCourse.rating[0]!.avgRating.toString()
: '0',
rating: (topCourse.rating.isNotEmpty &&
topCourse.rating[0]?.avgRating != null)
? topCourse.rating[0]!.avgRating.toString()
: '5.0',
numberOfRatings: (topCourse.rating.isNotEmpty &&
topCourse.rating[0]?.totalReview != null)
? topCourse.rating[0]!.totalReview!
: '0',
isTopCourse: topCourse.topCourse!,
price: (topCourse.price == '0')
? 'Gratis'
: (topCourse.promoPrice != '0')
? numberFormat(topCourse.promoPrice)
: numberFormat(displayedPrice),
realPrice: (topCourse.price == '0')
? ''
: numberFormat(topCourse.price),
press: () {
print(topCourse.idCourse);
Navigator.of(context, rootNavigator: true).push(
CustomNavigator(
child: DetailCourseScreen(
idcourse: topCourse.idCourse,
),
),
);
},
),
),
);
},
),
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
)
],
);
} else {
return Center(child: Text(''));
}
},
)
],
);
}
}

View File

@ -0,0 +1,243 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/providers/top_course_provider.dart';
import 'package:initial_folder/screens/detail_course/detail_course_screen.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card.dart';
import 'package:initial_folder/screens/home/components/body_comp/product_card/product_card_big.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../size_config.dart';
import '../../../../theme.dart';
class PopulerCourseBig extends StatelessWidget {
const PopulerCourseBig({Key? key, this.text}) : super(key: key);
final String? text;
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(16)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
text!,
textAlign: TextAlign.left,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(15),
fontWeight: semiBold,
),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(10)),
Consumer<TopCourseProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 105,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 190,
color: Colors.white,
)),
SizedBox(height: 10),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 120,
color: Colors.white,
)),
SizedBox(height: 8),
Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Container(
height: 15,
width: 85,
color: Colors.white,
),
),
],
),
)
],
);
} else if (state.state == ResultState.HasData) {
return Container(
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: getProportionateScreenWidth(4)),
height: getProportionateScreenHeight(270),
child: ListView.builder(
scrollDirection: Axis.horizontal,
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: state.result.length,
itemBuilder: (context, index) {
var topCourse = state.result[index];
// var finalRating = double.parse(
// (topCourse.specificRating![0] / 20).toStringAsFixed(2));
return Container(
margin: EdgeInsets.only(
top: getProportionateScreenHeight(10),
),
child: Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(13),
bottom: getProportionateScreenWidth(18),
),
child: ProductCardBig(
totalDiscount: topCourse.totalDiscount ?? 0,
students: topCourse.students ?? '0',
pad: 12,
id: topCourse.idCourse,
thumbnail: topCourse.thumbnail ??
'$baseUrl/uploads/courses_thumbnail/course_thumbnail_default_57.jpg',
title: topCourse.title,
instructorName: topCourse.instructorName,
specificRating: (topCourse.rating.isNotEmpty &&
topCourse.rating[0]?.avgRating != null)
? topCourse.rating[0]!.avgRating.toString()
: '0',
rating: (topCourse.rating.isNotEmpty &&
topCourse.rating[0]?.avgRating != null)
? topCourse.rating[0]!.avgRating.toString()
: '5.0',
numberOfRatings: (topCourse.rating.isNotEmpty &&
topCourse.rating[0]?.totalReview != null)
? topCourse.rating[0]!.totalReview!
: '0',
isTopCourse: topCourse.topCourse!,
price: (topCourse.discountPrice == '0')
? 'Gratis'
: numberFormat(topCourse.discountPrice),
realPrice: (topCourse.price == '0')
? ''
: numberFormat(topCourse.price),
press: () {
print(topCourse.idCourse);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailCourseScreen(
idcourse: topCourse.idCourse,
),
),
);
},
),
),
);
},
),
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Center(
child: Column(
children: [
Text('Terjadi Kesalahan Coba Lagi'),
],
),
);
} else {
return Center(child: Text(''));
}
},
)
],
);
}
}

View File

@ -0,0 +1,328 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../../theme.dart';
import '../../../../../size_config.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
class ProductCard extends StatelessWidget {
const ProductCard({
Key? key,
this.width = 120,
this.pad = 16,
this.padRight = 0,
this.isHome,
required this.thumbnail,
required this.id,
required this.isTopCourse,
required this.title,
required this.instructorName,
required this.rating,
required this.specificRating,
required this.numberOfRatings,
required this.price,
required this.realPrice,
required this.press,
required this.students,
required this.totalDiscount,
}) : super(key: key);
final double width;
final double pad, padRight;
final String thumbnail,
title,
instructorName,
price,
realPrice,
rating,
specificRating,
numberOfRatings,
id,
isTopCourse;
final String students;
final VoidCallback press;
final int totalDiscount;
final bool? isHome;
// final VoidCallback? whislistPress;
// final Widget? iconWishlist;
@override
Widget build(BuildContext context) {
//CourseProvider courseProvider = Provider.of<CourseProvider>(context);
// final formatCurrency =
// new NumberFormat.simpleCurrency(decimalDigits: 0, locale: 'id_ID');
bool isRatingValid = int.tryParse(rating) != null;
bool isStudentsValid = int.tryParse(students) != null;
final themeProvider = Provider.of<ThemeProvider>(context);
bool isPopular = false;
if (isRatingValid && isStudentsValid) {
int ratingValue = int.parse(rating);
int studentsValue = int.parse(students);
bool isSpecificRatingValid = int.tryParse(specificRating) != null;
bool isNumberOfRatingsValid = int.tryParse(numberOfRatings) != null;
if (isSpecificRatingValid && isNumberOfRatingsValid) {
int specificRatingValue = int.parse(specificRating);
int numberOfRatingsValue = int.parse(numberOfRatings);
isPopular = ratingValue > 4 &&
studentsValue > 19 &&
specificRatingValue > 4 &&
numberOfRatingsValue > 4;
}
}
return Stack(
children: [
Container(
width: getProportionateScreenWidth(155),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 1,
offset: Offset(7, 17),
),
],
),
padding: EdgeInsets.only(
left: getProportionateScreenWidth(pad),
right: getProportionateScreenWidth(padRight),
),
child: InkWell(
onTap: press,
child: Container(
width: getProportionateScreenWidth(40),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.primaryContainer,
spreadRadius: 11,
blurRadius: 0,
offset: Offset(0, 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AspectRatio(
aspectRatio: 1.7,
child: CachedNetworkImage(
imageUrl: thumbnail,
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.vertical(top: Radius.circular(5)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
placeholder: (context, url) => Shimmer(
child: Container(
decoration: BoxDecoration(
color: ninthColor,
borderRadius:
BorderRadius.vertical(top: Radius.circular(5)),
),
),
gradient: LinearGradient(
stops: [0.2, 0.5, 0.6],
colors: [ninthColor, fourthColor, ninthColor]),
),
errorWidget: (context, url, error) => Icon(Icons.error),
fadeInDuration: Duration(milliseconds: 1),
fadeOutDuration: Duration(milliseconds: 1),
),
),
SizedBox(height: getProportionateScreenWidth(4)),
Container(
padding: EdgeInsets.only(left: 2),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(12),
fontWeight: bold),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: getProportionateScreenWidth(6)),
// Row(
// children: [product.description],
// ),
RichText(
text: new TextSpan(
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
color: Theme.of(context).dividerColor,
),
children: <TextSpan>[
new TextSpan(
text: '',
style: TextStyle(
fontWeight: bold,
),
),
new TextSpan(
text: instructorName,
style: TextStyle(fontWeight: bold),
),
],
),
),
SizedBox(height: getProportionateScreenWidth(6)),
Row(
children: [
Text(
specificRating,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: bold,
),
),
SizedBox(
width: getProportionateScreenWidth(2),
),
RatingBarIndicator(
itemSize: getProportionateScreenWidth(11),
rating: double.parse(rating),
direction: Axis.horizontal,
itemCount: 5,
itemBuilder: (context, _) => FaIcon(
FontAwesomeIcons.solidStar,
color: thirteenColor,
),
),
SizedBox(width: getProportionateScreenWidth(3)),
Text(
'(' + numberOfRatings + ')',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: bold,
),
),
],
),
SizedBox(height: getProportionateScreenWidth(6)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
price,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontSize: SizeConfig.blockHorizontal! * 3,
fontWeight: bold,
),
),
],
),
SizedBox(height: getProportionateScreenWidth(6)),
if (realPrice.isNotEmpty && realPrice != price)
Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
realPrice,
style: primaryTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
// IconButton(onPressed: whislistPress, icon: iconWishlist)
],
),
)
else
SizedBox.shrink(),
if (isPopular)
Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10),
),
child: Container(
alignment: Alignment.center,
width: getProportionateScreenWidth(48),
height: getProportionateScreenHeight(17),
child: Text(
'Populer',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: Colors.white,
fontSize: SizeConfig.blockHorizontal! * 2.5,
fontWeight: bold,
),
),
decoration: BoxDecoration(
color:themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
borderRadius: BorderRadius.circular(5),
),
),
)
else
SizedBox.shrink(),
],
),
)
],
),
),
),
),
if (totalDiscount != 0)
Padding(
padding: EdgeInsets.only(top: getProportionateScreenHeight(7)),
child: Container(
height: 20,
alignment: Alignment.center,
width: getProportionateScreenWidth(35),
child: Text(
'${totalDiscount.toString()}%',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: baruTextutih,
fontSize: SizeConfig.blockHorizontal! * 2.5,
fontWeight: light,
),
),
decoration: BoxDecoration(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
borderRadius: BorderRadius.only(
topRight: Radius.circular(4),
bottomRight: Radius.circular(4),
),
),
),
)
else
SizedBox.shrink(),
],
);
}
}
// Shimmer(
// child: Container(
// color: Colors.black,
// ),
// gradient: LinearGradient(
// stops: [0.2, 0.5, 0.6],
// colors: [ninthColor, fourthColor, ninthColor])),

View File

@ -0,0 +1,329 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../../theme.dart';
import '../../../../../size_config.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
class ProductCardBig extends StatelessWidget {
const ProductCardBig({
Key? key,
this.width = 120,
this.pad = 16,
this.padRight = 0,
required this.thumbnail,
required this.id,
required this.isTopCourse,
required this.title,
required this.instructorName,
required this.rating,
required this.specificRating,
required this.numberOfRatings,
required this.price,
required this.realPrice,
required this.press,
required this.students,
required this.totalDiscount,
}) : super(key: key);
final double width;
final double pad, padRight;
final String thumbnail,
title,
instructorName,
price,
realPrice,
rating,
specificRating,
numberOfRatings,
id,
isTopCourse;
final String students;
final VoidCallback press;
final int totalDiscount;
// final VoidCallback? whislistPress;
// final Widget? iconWishlist;
@override
Widget build(BuildContext context) {
//CourseProvider courseProvider = Provider.of<CourseProvider>(context);
// final formatCurrency =
// new NumberFormat.simpleCurrency(decimalDigits: 0, locale: 'id_ID');
bool isRatingValid = int.tryParse(rating) != null;
bool isStudentsValid = int.tryParse(students) != null;
bool isPopular = false;
if (isRatingValid && isStudentsValid) {
int ratingValue = int.parse(rating);
int studentsValue = int.parse(students);
bool isSpecificRatingValid = int.tryParse(specificRating) != null;
bool isNumberOfRatingsValid = int.tryParse(numberOfRatings) != null;
if (isSpecificRatingValid && isNumberOfRatingsValid) {
int specificRatingValue = int.parse(specificRating);
int numberOfRatingsValue = int.parse(numberOfRatings);
isPopular = ratingValue > 4 &&
studentsValue > 19 &&
specificRatingValue > 4 &&
numberOfRatingsValue > 4;
}
}
return Stack(
children: [
Container(
height: getProportionateScreenHeight(500),
width: getProportionateScreenWidth(250),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 1,
offset: Offset(7, 17),
),
],
),
padding: EdgeInsets.only(
left: getProportionateScreenWidth(pad),
right: getProportionateScreenWidth(padRight),
),
child: InkWell(
onTap: press,
child: Container(
width: getProportionateScreenWidth(40),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.primaryContainer,
spreadRadius: 11,
blurRadius: 0,
offset: Offset(0, 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AspectRatio(
aspectRatio: 1.7,
child: CachedNetworkImage(
imageUrl: thumbnail,
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.vertical(top: Radius.circular(5)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.fill,
),
),
),
placeholder: (context, url) => Shimmer(
child: Container(
decoration: BoxDecoration(
color: ninthColor,
borderRadius:
BorderRadius.vertical(top: Radius.circular(5)),
),
),
gradient: LinearGradient(
stops: [0.2, 0.5, 0.6],
colors: [ninthColor, fourthColor, ninthColor]),
),
errorWidget: (context, url, error) => Icon(Icons.error),
fadeInDuration: Duration(milliseconds: 1),
fadeOutDuration: Duration(milliseconds: 1),
),
),
SizedBox(height: getProportionateScreenWidth(4)),
Container(
padding: EdgeInsets.only(left: 2),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(13),
fontWeight: bold),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: getProportionateScreenWidth(6)),
// Row(
// children: [product.description],
// ),
RichText(
text: new TextSpan(
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
color: Theme.of(context).dividerColor,
),
children: [
new TextSpan(
text: '',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
),
),
new TextSpan(
text: instructorName,
style: TextStyle(fontWeight: bold),
),
],
),
),
SizedBox(height: getProportionateScreenWidth(6)),
Row(
children: [
Text(
specificRating,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
fontWeight: bold,
),
),
SizedBox(
width: getProportionateScreenWidth(2),
),
RatingBarIndicator(
itemSize: getProportionateScreenWidth(12),
rating: double.parse(rating),
direction: Axis.horizontal,
itemCount: 1,
itemBuilder: (context, _) => FaIcon(
FontAwesomeIcons.solidStar,
color: thirteenColor,
),
),
SizedBox(
width: getProportionateScreenWidth(3),
),
Text(
'(' + numberOfRatings + ' Reviews)',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
fontWeight: light,
),
),
],
),
SizedBox(
height: getProportionateScreenWidth(6),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
price,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontSize: SizeConfig.blockHorizontal! * 3,
fontWeight: bold,
),
),
],
),
SizedBox(height: getProportionateScreenWidth(6)),
(realPrice != price)
? Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10)),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
realPrice,
style: thirdTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
// IconButton(
// onPressed: whislistPress,
// icon: iconWishlist)
],
),
)
: SizedBox(height: 13, width: 1),
if (isPopular)
Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10)),
child: Container(
alignment: Alignment.center,
width: getProportionateScreenWidth(48),
height: getProportionateScreenHeight(17),
child: Text(
'Populer',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: Colors.white,
fontSize: SizeConfig.blockHorizontal! * 2.5,
fontWeight: bold,
),
),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5),
),
),
)
else
SizedBox(height: 0, width: 0),
],
),
)
],
),
),
),
),
if (totalDiscount != 0)
Padding(
padding: EdgeInsets.only(top: getProportionateScreenHeight(7)),
child: Container(
height: 20,
alignment: Alignment.center,
width: getProportionateScreenWidth(35),
child: Text(
'${totalDiscount.toString()}%',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: baruTextutih,
fontSize: SizeConfig.blockHorizontal! * 2.5,
fontWeight: light,
),
),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(4),
bottomRight: Radius.circular(4),
),
),
),
)
else
SizedBox(height: 0, width: 0),
],
);
}
}
// Shimmer(
// child: Container(
// color: Colors.black,
// ),
// gradient: LinearGradient(
// stops: [0.2, 0.5, 0.6],
// colors: [ninthColor, fourthColor, ninthColor])),

View File

@ -0,0 +1,320 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:shimmer/shimmer.dart';
import '../../../../../theme.dart';
import '../../../../../size_config.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
class ProductCardCoupon extends StatelessWidget {
const ProductCardCoupon({
Key? key,
this.width = 120,
this.pad = 16,
this.padRight = 0,
required this.thumbnail,
required this.id,
required this.isTopCourse,
required this.title,
required this.instructorName,
required this.rating,
required this.specificRating,
required this.numberOfRatings,
required this.price,
required this.realPrice,
required this.press,
required this.students,
required this.totalDiscount,
}) : super(key: key);
final double width;
final double pad, padRight;
final String thumbnail,
title,
instructorName,
price,
realPrice,
rating,
specificRating,
numberOfRatings,
id,
isTopCourse;
final String students;
final VoidCallback press;
final int totalDiscount;
// final VoidCallback? whislistPress;
// final Widget? iconWishlist;
@override
Widget build(BuildContext context) {
//CourseProvider courseProvider = Provider.of<CourseProvider>(context);
// final formatCurrency =
// new NumberFormat.simpleCurrency(decimalDigits: 0, locale: 'id_ID');
bool isRatingValid = int.tryParse(rating) != null;
bool isStudentsValid = int.tryParse(students) != null;
bool isPopular = false;
if (isRatingValid && isStudentsValid) {
int ratingValue = int.parse(rating);
int studentsValue = int.parse(students);
bool isSpecificRatingValid = int.tryParse(specificRating) != null;
bool isNumberOfRatingsValid = int.tryParse(numberOfRatings) != null;
if (isSpecificRatingValid && isNumberOfRatingsValid) {
int specificRatingValue = int.parse(specificRating);
int numberOfRatingsValue = int.parse(numberOfRatings);
isPopular = ratingValue > 4 &&
studentsValue > 19 &&
specificRatingValue > 4 &&
numberOfRatingsValue > 4;
}
}
return Stack(
children: [
Container(
width: getProportionateScreenWidth(165),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 1,
offset: Offset(7, 17),
),
],
),
padding: EdgeInsets.only(
left: getProportionateScreenWidth(pad),
right: getProportionateScreenWidth(padRight),
),
child: InkWell(
onTap: press,
child: Container(
width: getProportionateScreenWidth(40),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.primaryContainer,
spreadRadius: 11,
blurRadius: 0,
offset: Offset(0, 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AspectRatio(
aspectRatio: 1.7,
child: CachedNetworkImage(
imageUrl: thumbnail,
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.vertical(top: Radius.circular(5)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
placeholder: (context, url) => Shimmer(
child: Container(
decoration: BoxDecoration(
color: ninthColor,
borderRadius:
BorderRadius.vertical(top: Radius.circular(5)),
),
),
gradient: LinearGradient(
stops: [0.2, 0.5, 0.6],
colors: [ninthColor, fourthColor, ninthColor]),
),
errorWidget: (context, url, error) => Icon(Icons.error),
fadeInDuration: Duration(milliseconds: 1),
fadeOutDuration: Duration(milliseconds: 1),
),
),
SizedBox(height: getProportionateScreenWidth(4)),
Container(
padding: EdgeInsets.only(left: 2),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: thirdTextStyle.copyWith(
letterSpacing: 1,
fontSize: getProportionateScreenWidth(12),
fontWeight: bold),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
SizedBox(height: getProportionateScreenWidth(6)),
// Row(
// children: [product.description],
// ),
RichText(
text: new TextSpan(
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
color: Theme.of(context).dividerColor,
),
children: <TextSpan>[
new TextSpan(
text: '',
style: TextStyle(
fontWeight: bold,
),
),
new TextSpan(
text: instructorName,
style: TextStyle(fontWeight: bold),
),
],
),
),
SizedBox(height: getProportionateScreenWidth(6)),
Row(
children: [
Text(
specificRating,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: bold,
),
),
SizedBox(
width: getProportionateScreenWidth(2),
),
RatingBarIndicator(
itemSize: getProportionateScreenWidth(11),
rating: double.parse(rating),
direction: Axis.horizontal,
itemCount: 5,
itemBuilder: (context, _) => FaIcon(
FontAwesomeIcons.solidStar,
color: thirteenColor,
),
),
SizedBox(width: getProportionateScreenWidth(3)),
Text(
'(' + numberOfRatings + ')',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(10),
fontWeight: bold,
),
),
],
),
SizedBox(height: getProportionateScreenWidth(6)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
price,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontSize: SizeConfig.blockHorizontal! * 3,
fontWeight: bold,
),
),
],
),
SizedBox(height: getProportionateScreenWidth(6)),
if (realPrice.isNotEmpty && realPrice != price)
Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
realPrice,
style: primaryTextStyle.copyWith(
decoration: TextDecoration.lineThrough,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
// IconButton(onPressed: whislistPress, icon: iconWishlist)
],
),
)
else
SizedBox.shrink(),
if (isPopular)
Padding(
padding: EdgeInsets.only(
right: getProportionateScreenWidth(10)),
child: Container(
alignment: Alignment.center,
width: getProportionateScreenWidth(48),
height: getProportionateScreenHeight(17),
child: Text(
'Populer',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: Colors.white,
fontSize: SizeConfig.blockHorizontal! * 2.5,
fontWeight: bold,
),
),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.circular(5),
),
),
)
else
SizedBox(height: 0, width: 0),
],
),
)
],
),
),
),
),
if (totalDiscount != 0)
Padding(
padding: EdgeInsets.only(top: getProportionateScreenHeight(7)),
child: Container(
height: 20,
alignment: Alignment.center,
width: getProportionateScreenWidth(35),
child: Text(
'${totalDiscount.toString()}%',
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
color: baruTextutih,
fontSize: SizeConfig.blockHorizontal! * 2.5,
fontWeight: light,
),
),
decoration: BoxDecoration(
color: primaryColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(4),
bottomRight: Radius.circular(4),
),
),
),
)
else
SizedBox(height: 0, width: 0),
],
);
}
}
// Shimmer(
// child: Container(
// color: Colors.black,
// ),
// gradient: LinearGradient(
// stops: [0.2, 0.5, 0.6],
// colors: [ninthColor, fourthColor, ninthColor])),

Some files were not shown because too many files have changed in this diff Show More