Initial commit: Penyerahan final Source code Tugas Akhir
This commit is contained in:
0
lib/screens/.gitkeep
Normal file
0
lib/screens/.gitkeep
Normal file
874
lib/screens/cart/cart_page.dart
Normal file
874
lib/screens/cart/cart_page.dart
Normal 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),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
325
lib/screens/cart/components/cart_list.dart
Normal file
325
lib/screens/cart/components/cart_list.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
69
lib/screens/certificate/all_certificate.dart
Normal file
69
lib/screens/certificate/all_certificate.dart
Normal 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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
155
lib/screens/certificate/certificate.dart
Normal file
155
lib/screens/certificate/certificate.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
195
lib/screens/certificate/certificatecheck/certificate_check.dart
Normal file
195
lib/screens/certificate/certificatecheck/certificate_check.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -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,
|
||||
// // ),
|
||||
// // ),
|
||||
// // ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
421
lib/screens/certificate/component/all_certificate_item.dart
Normal file
421
lib/screens/certificate/component/all_certificate_item.dart
Normal 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),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
380
lib/screens/certificate/component/just_certificate_count.dart
Normal file
380
lib/screens/certificate/component/just_certificate_count.dart
Normal 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),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
782
lib/screens/checkout/batas_bayar.dart
Normal file
782
lib/screens/checkout/batas_bayar.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
991
lib/screens/checkout/batas_bayar_bank.dart
Normal file
991
lib/screens/checkout/batas_bayar_bank.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
384
lib/screens/checkout/checkout_cart_coupon_page.dart
Normal file
384
lib/screens/checkout/checkout_cart_coupon_page.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
296
lib/screens/checkout/checkout_cart_page.dart
Normal file
296
lib/screens/checkout/checkout_cart_page.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
415
lib/screens/checkout/checkout_coupon_page.dart
Normal file
415
lib/screens/checkout/checkout_coupon_page.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
391
lib/screens/checkout/checkout_detail_coupon.dart
Normal file
391
lib/screens/checkout/checkout_detail_coupon.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
559
lib/screens/checkout/checkout_page.dart
Normal file
559
lib/screens/checkout/checkout_page.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
317
lib/screens/checkout/components/atm.dart
Normal file
317
lib/screens/checkout/components/atm.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
61
lib/screens/checkout/components/bar_batas_bayar.dart
Normal file
61
lib/screens/checkout/components/bar_batas_bayar.dart
Normal 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)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
263
lib/screens/checkout/components/bottom_sheet_detail.dart
Normal file
263
lib/screens/checkout/components/bottom_sheet_detail.dart
Normal 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')
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
262
lib/screens/checkout/components/bottom_sheet_history.dart
Normal file
262
lib/screens/checkout/components/bottom_sheet_history.dart
Normal 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')
|
||||
// ],
|
||||
// ),
|
||||
// )
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
29
lib/screens/checkout/components/cardmonth.dart
Normal file
29
lib/screens/checkout/components/cardmonth.dart
Normal 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));
|
||||
}
|
||||
}
|
||||
28
lib/screens/checkout/components/cardnumber.dart
Normal file
28
lib/screens/checkout/components/cardnumber.dart
Normal 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));
|
||||
}
|
||||
}
|
||||
159
lib/screens/checkout/components/course_list.dart
Normal file
159
lib/screens/checkout/components/course_list.dart
Normal 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)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
130
lib/screens/checkout/components/course_list_coupon.dart
Normal file
130
lib/screens/checkout/components/course_list_coupon.dart
Normal 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)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
105
lib/screens/checkout/components/field_kupon.dart
Normal file
105
lib/screens/checkout/components/field_kupon.dart
Normal 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)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
337
lib/screens/checkout/components/internet_banking.dart
Normal file
337
lib/screens/checkout/components/internet_banking.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
351
lib/screens/checkout/components/mobile_banking.dart
Normal file
351
lib/screens/checkout/components/mobile_banking.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
145
lib/screens/checkout/components/tab_bar_batas_bayar.dart
Normal file
145
lib/screens/checkout/components/tab_bar_batas_bayar.dart
Normal 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),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
435
lib/screens/checkout/detail_zero_payment.dart
Normal file
435
lib/screens/checkout/detail_zero_payment.dart
Normal 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
377
lib/screens/checkout/gopay/batas_bayar_gopay.dart
Normal file
377
lib/screens/checkout/gopay/batas_bayar_gopay.dart
Normal 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
249
lib/screens/checkout/gopay/bayargopay.dart
Normal file
249
lib/screens/checkout/gopay/bayargopay.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
395
lib/screens/checkout/gopay/gopay_payment_confirmation.dart
Normal file
395
lib/screens/checkout/gopay/gopay_payment_confirmation.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
102
lib/screens/checkout/gopay/payment_instruction_gopay.dart
Normal file
102
lib/screens/checkout/gopay/payment_instruction_gopay.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
345
lib/screens/checkout/gopay/qr_code_gopay.dart
Normal file
345
lib/screens/checkout/gopay/qr_code_gopay.dart
Normal 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));
|
||||
}
|
||||
151
lib/screens/checkout/not_success_paid_course.dart
Normal file
151
lib/screens/checkout/not_success_paid_course.dart
Normal 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")
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
361
lib/screens/checkout/snap_payment_page.dart
Normal file
361
lib/screens/checkout/snap_payment_page.dart
Normal 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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
130
lib/screens/checkout/success_paid_course.dart
Normal file
130
lib/screens/checkout/success_paid_course.dart
Normal 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,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
205
lib/screens/coupon/coupon_page.dart
Normal file
205
lib/screens/coupon/coupon_page.dart
Normal 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,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
369
lib/screens/coupon/success_radem_coupon_page.dart
Normal file
369
lib/screens/coupon/success_radem_coupon_page.dart
Normal 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(''));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
134
lib/screens/course/component/announcement.dart
Normal file
134
lib/screens/course/component/announcement.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
710
lib/screens/course/component/detail_play_course.dart
Normal file
710
lib/screens/course/component/detail_play_course.dart
Normal 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'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
400
lib/screens/course/component/detail_quest_and_answer.dart
Normal file
400
lib/screens/course/component/detail_quest_and_answer.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
32
lib/screens/course/component/download_certificate.dart
Normal file
32
lib/screens/course/component/download_certificate.dart
Normal 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'))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
487
lib/screens/course/component/expansion_tile_copy.dart
Normal file
487
lib/screens/course/component/expansion_tile_copy.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
308
lib/screens/course/component/inside_announcement.dart
Normal file
308
lib/screens/course/component/inside_announcement.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
53
lib/screens/course/component/pdfReader.dart
Normal file
53
lib/screens/course/component/pdfReader.dart
Normal 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,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
338
lib/screens/course/component/quest_and_answer.dart
Normal file
338
lib/screens/course/component/quest_and_answer.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
46
lib/screens/course/component/txtReader.dart
Normal file
46
lib/screens/course/component/txtReader.dart
Normal 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,
|
||||
)));
|
||||
}
|
||||
}
|
||||
79
lib/screens/course/html5_video_page.dart
Normal file
79
lib/screens/course/html5_video_page.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
198
lib/screens/course/my_course_page.dart
Normal file
198
lib/screens/course/my_course_page.dart
Normal 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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
1974
lib/screens/course/play_course_page.dart
Normal file
1974
lib/screens/course/play_course_page.dart
Normal file
File diff suppressed because it is too large
Load Diff
2022
lib/screens/course/play_course_page_old.dart
Normal file
2022
lib/screens/course/play_course_page_old.dart
Normal file
File diff suppressed because it is too large
Load Diff
2075
lib/screens/course/play_course_page_old_2.dart
Normal file
2075
lib/screens/course/play_course_page_old_2.dart
Normal file
File diff suppressed because it is too large
Load Diff
161
lib/screens/course/quiz_page.dart
Normal file
161
lib/screens/course/quiz_page.dart
Normal 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);
|
||||
},
|
||||
))
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
225
lib/screens/course/quiz_question_page.dart
Normal file
225
lib/screens/course/quiz_question_page.dart
Normal 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"<[^>]*>| ", 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);
|
||||
},
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
500
lib/screens/course/quiz_result_page.dart
Normal file
500
lib/screens/course/quiz_result_page.dart
Normal 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"<[^>]*>| ", 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);
|
||||
}
|
||||
}
|
||||
90
lib/screens/course/search_my_course_page.dart
Normal file
90
lib/screens/course/search_my_course_page.dart
Normal 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(''));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
784
lib/screens/course/sertif.dart
Normal file
784
lib/screens/course/sertif.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
676
lib/screens/course/sertif_view.dart
Normal file
676
lib/screens/course/sertif_view.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
482
lib/screens/detail_course/components/aktifitas.dart
Normal file
482
lib/screens/detail_course/components/aktifitas.dart
Normal 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"<[^>]*>| |&|"",
|
||||
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(''));
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
195
lib/screens/detail_course/components/app_bar.dart
Normal file
195
lib/screens/detail_course/components/app_bar.dart
Normal 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(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
124
lib/screens/detail_course/components/app_bar_filter.dart
Normal file
124
lib/screens/detail_course/components/app_bar_filter.dart
Normal 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),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
170
lib/screens/detail_course/components/custom_tab_bar.dart
Normal file
170
lib/screens/detail_course/components/custom_tab_bar.dart
Normal 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),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
557
lib/screens/detail_course/components/deskripsi.dart
Normal file
557
lib/screens/detail_course/components/deskripsi.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
75
lib/screens/detail_course/components/detail_list_ulasan.dart
Normal file
75
lib/screens/detail_course/components/detail_list_ulasan.dart
Normal 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
1535
lib/screens/detail_course/components/header.dart
Normal file
1535
lib/screens/detail_course/components/header.dart
Normal file
File diff suppressed because it is too large
Load Diff
604
lib/screens/detail_course/components/header_coupon.dart
Normal file
604
lib/screens/detail_course/components/header_coupon.dart
Normal 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
1
lib/screens/detail_course/components/image_course.dart
Normal file
1
lib/screens/detail_course/components/image_course.dart
Normal file
@ -0,0 +1 @@
|
||||
|
||||
@ -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),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
229
lib/screens/detail_course/components/instruktur.dart
Normal file
229
lib/screens/detail_course/components/instruktur.dart
Normal 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)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
262
lib/screens/detail_course/components/murid_and_rating.dart
Normal file
262
lib/screens/detail_course/components/murid_and_rating.dart
Normal 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(),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
283
lib/screens/detail_course/components/murid_and_whislist.dart
Normal file
283
lib/screens/detail_course/components/murid_and_whislist.dart
Normal 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),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
59
lib/screens/detail_course/components/tab_bar_items.dart
Normal file
59
lib/screens/detail_course/components/tab_bar_items.dart
Normal 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)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
36
lib/screens/detail_course/components/terkait.dart
Normal file
36
lib/screens/detail_course/components/terkait.dart
Normal 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: "",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
430
lib/screens/detail_course/components/ulasan.dart
Normal file
430
lib/screens/detail_course/components/ulasan.dart
Normal 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);
|
||||
}
|
||||
770
lib/screens/detail_course/detail_course_coupon_screen.dart
Normal file
770
lib/screens/detail_course/detail_course_coupon_screen.dart
Normal 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(''));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
2000
lib/screens/detail_course/detail_course_screen.dart
Normal file
2000
lib/screens/detail_course/detail_course_screen.dart
Normal file
File diff suppressed because it is too large
Load Diff
1592
lib/screens/detail_course/detail_course_voucher_screen.dart
Normal file
1592
lib/screens/detail_course/detail_course_voucher_screen.dart
Normal file
File diff suppressed because it is too large
Load Diff
236
lib/screens/home/components/appBar/home_header.dart
Normal file
236
lib/screens/home/components/appBar/home_header.dart
Normal 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
72
lib/screens/home/components/body_comp/beginning.dart
Normal file
72
lib/screens/home/components/body_comp/beginning.dart
Normal 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,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
218
lib/screens/home/components/body_comp/carousel.dart
Normal file
218
lib/screens/home/components/body_comp/carousel.dart
Normal 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(''));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
164
lib/screens/home/components/body_comp/certificate_voucher.dart
Normal file
164
lib/screens/home/components/body_comp/certificate_voucher.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
286
lib/screens/home/components/body_comp/course_by_category.dart
Normal file
286
lib/screens/home/components/body_comp/course_by_category.dart
Normal 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('&', '&')}',
|
||||
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('&', '&')}',
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
237
lib/screens/home/components/body_comp/course_by_subcategory.dart
Normal file
237
lib/screens/home/components/body_comp/course_by_subcategory.dart
Normal 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('&', '&')}',
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
173
lib/screens/home/components/body_comp/course_terkait.dart
Normal file
173
lib/screens/home/components/body_comp/course_terkait.dart
Normal 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(''));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
256
lib/screens/home/components/body_comp/home_categories.dart
Normal file
256
lib/screens/home/components/body_comp/home_categories.dart
Normal 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('&', '&'),
|
||||
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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
485
lib/screens/home/components/body_comp/latest_course.dart
Normal file
485
lib/screens/home/components/body_comp/latest_course.dart
Normal 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'),
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
}
|
||||
273
lib/screens/home/components/body_comp/lihat_semua_kategori.dart
Normal file
273
lib/screens/home/components/body_comp/lihat_semua_kategori.dart
Normal 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('&', '&'),
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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(),
|
||||
239
lib/screens/home/components/body_comp/list_of_categories.dart
Normal file
239
lib/screens/home/components/body_comp/list_of_categories.dart
Normal 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('&', '&')
|
||||
: '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('&', '&')
|
||||
: '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(''));
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
368
lib/screens/home/components/body_comp/others_course.dart
Normal file
368
lib/screens/home/components/body_comp/others_course.dart
Normal 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(),
|
||||
361
lib/screens/home/components/body_comp/populer_course.dart
Normal file
361
lib/screens/home/components/body_comp/populer_course.dart
Normal 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(''));
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
243
lib/screens/home/components/body_comp/populer_course_big.dart
Normal file
243
lib/screens/home/components/body_comp/populer_course_big.dart
Normal 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(''));
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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])),
|
||||
@ -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])),
|
||||
@ -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
Reference in New Issue
Block a user