Initial commit: Penyerahan final Source code Tugas Akhir

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

View File

@ -0,0 +1,874 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/providers/profile_image_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/providers/update_data_diri_provider.dart';
import 'package:initial_folder/providers/data_diri_provider.dart';
import 'package:initial_folder/services/user_info_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/widgets/login_regist/custom_profile_text_field.dart';
import 'package:initial_folder/providers/user_info_provider.dart' as userInfo;
import 'package:provider/provider.dart';
class DataDiri extends StatefulWidget {
@override
State<DataDiri> createState() => _DataDiriState();
}
class _DataDiriState extends State<DataDiri> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final List<String> gender = ['pria', 'wanita'];
void _handleGenderChange(String? value, DataDiriProvider state) {
setState(() {
newGender = value ?? '';
state.newGender = true;
isGenderEmpty = false;
});
}
late String newGender = '';
late String newName;
late String newBirthDate = '';
late String newHeadline;
late String newBiograpy;
late String newEmail;
late String newPhone;
late String newInstagram = '';
late String newTwitter = '';
late String newFacebook = '';
late String newLinkedin = '';
bool? isNameEmpty;
bool? isGenderEmpty;
bool? isBirthDateEmpty;
bool? isEmailEmpty;
bool? isPhoneEmpty;
DateTime birthDate = DateTime.now();
bool isLoading = false;
String? email = "";
void getUserEmail() async {
email = await UsersInfo().getEmail();
}
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
UpdateDataDiriProvider updateDataDiriProvider =
Provider.of<UpdateDataDiriProvider>(context);
ProfileImageProvider profileImageProvider =
Provider.of<ProfileImageProvider>(context, listen: false);
final ImagePicker _picker = ImagePicker();
Future _showMessage(String text) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
content: Text(
text,
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
color: baruTexthitam,
),
),
),
);
}
void takePhoto(ImageSource source) async {
try {
final XFile? pickedFile = await _picker.pickImage(source: source);
var imageFile = (pickedFile != null) ? File(pickedFile.path) : File('');
var email = await UsersInfo().getEmail();
if (await profileImageProvider.addProfileImage(pckFile: imageFile)) {
setState(() {
isLoading = true;
});
await Future.delayed(Duration(seconds: 2));
profileImageProvider.setImageFile(imageFile);
setState(() {
imageFile;
isLoading = false;
});
// await Provider.of<userInfo.UserInfoProvider>(context, listen: false)
// .getUserInfo(email);
_showMessage('Berhasil Upload Image');
}
} on PlatformException catch (e) {
print('Failed to pick image : $e');
}
}
Widget bottomSheet() {
return Container(
height: 100.0,
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
),
child: Column(
children: <Widget>[
Text(
"Choose Profile photo",
style: secondaryTextStyle.copyWith(fontSize: 20),
),
SizedBox(height: getProportionateScreenHeight(20)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton.icon(
icon: Icon(Icons.camera),
onPressed: () {
Navigator.pop(context);
takePhoto(ImageSource.camera);
},
label: Text(
"Camera",
style: primaryTextStyle,
),
),
TextButton.icon(
icon: Icon(Icons.image),
onPressed: () {
Navigator.pop(context);
takePhoto(ImageSource.gallery);
},
label: Text("Gallery", style: primaryTextStyle),
),
],
),
],
),
);
}
Widget imageProfile(String? urlImage) {
return Stack(
alignment: AlignmentDirectional.center,
children: [
CircleAvatar(
radius: getProportionateScreenWidth(40),
backgroundColor: Colors.amber,
backgroundImage: profileImageProvider.imageFile != null
? FileImage(profileImageProvider.imageFile!) as ImageProvider
: urlImage != null
? NetworkImage(urlImage) as ImageProvider
: AssetImage("assets/images/Profile Image.png")
as ImageProvider,
),
CircleAvatar(
radius: getProportionateScreenWidth(40),
backgroundColor: Color(0xff000000).withOpacity(0.5),
),
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) => GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.pop(context);
},
child: bottomSheet(),
),
);
},
icon: Icon(
Icons.camera_alt_outlined,
color: Colors.white,
),
)
],
);
}
return SafeArea(
child: ChangeNotifierProvider(
create: (context) =>
DataDiriProvider(userInfoService: UserInfoService()),
child: Consumer<DataDiriProvider>(
builder: (context, state, _) {
if (state.state == ResultStateData.Loading) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
),
);
} else if (state.state == ResultStateData.HasData) {
var result = state.result!.data[0];
newGender = state.newGender ? newGender : result.gender ?? '';
return Scaffold(
appBar: AppBar(
elevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Data Diri',
style: thirdTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: bold,
fontSize: getProportionateScreenWidth(14)),
),
actions: [
TextButton(
child: isLoading
? CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(
Colors.white,
),
)
: Text('Simpan',
style: thirdTextStyle.copyWith(
color:themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
fontWeight: reguler,
letterSpacing: 0.5,
fontSize: getProportionateScreenWidth(12))),
onPressed: () async {
setState(() {
isLoading = true;
});
if (this._formKey.currentState!.validate()) {
if (await updateDataDiriProvider.dataDiriUpdate(
fullname:
state.newName ? newName : result.fullname,
headline: state.newHeadline
? newHeadline
: result.headline,
biograph: state.newBiograpy
? newBiograpy
: result.biography,
twitter: state.newTwitter
? newTwitter
: result.socialLink?.twitter,
facebook: state.newFacebook
? newFacebook
: result.socialLink?.facebook,
linkedin: state.newLinkedin
? newLinkedin
: result.socialLink?.linkedin,
instagram: state.newInstagram
? newInstagram
: result.socialLink?.instagram,
phone: state.newPhone ? newPhone : result.phone,
// datebirth: state.isNewBirthDate
// ? newBirthDate
// : result.datebirth,
// gender:
// state.newGender ? newGender : result.gender,
email:
state.newEmail ? newEmail : result.email)) {
await Provider.of<DataDiriProvider>(context,
listen: false)
.getDataDiri();
_showMessage('Data diri berhasil diubah');
} else {
if (updateDataDiriProvider.updateDataDiriModel !=
null) {
dynamic updateDataDiriMessages =
updateDataDiriProvider
.updateDataDiriModel!.messages;
if (updateDataDiriMessages is! String) {
if (updateDataDiriMessages.fullname
is String) {
setState(() {
isNameEmpty = true;
});
}
if (updateDataDiriMessages.gender is String) {
setState(() {
isGenderEmpty = true;
});
}
if (updateDataDiriMessages.datebirth
is String) {
setState(() {
isBirthDateEmpty = true;
});
}
if (updateDataDiriMessages.phone is String) {
setState(() {
isPhoneEmpty = true;
});
}
if (updateDataDiriMessages.email is String) {
setState(() {
isEmailEmpty = true;
});
}
}
} else {
_showMessage('Silahkan Coba lagi');
}
if (state.newGender) {
if (newGender.isEmpty) {
setState(() {
isGenderEmpty = true;
});
}
} else {
if (result.gender == null) {
setState(() {
isGenderEmpty = true;
});
}
}
if (state.isNewBirthDate) {
if (newBirthDate.isEmpty) {
setState(() {
isBirthDateEmpty = true;
});
}
} else {
if (result.datebirth == null) {
setState(() {
isBirthDateEmpty = true;
});
}
}
}
}
setState(() {
isLoading = false;
});
})
],
),
body: ListView(
children: [
Container(
height: getProportionateScreenHeight(100),
// width: 360,
decoration: BoxDecoration(
color: Colors.grey[300],
image: DecorationImage(
image: AssetImage( isDarkMode
? 'assets/images/cover_dark.png'
: 'assets/images/cover_light.png'),
fit: BoxFit.cover,
),
),
// child: const Padding(
// padding: EdgeInsets.all(10),
// child: Align(
// alignment: Alignment.bottomRight,
// // child: Icon(
// // Icons.camera_alt,
// // color: Colors.white,
// // ),
// ),
// ),
),
Transform.translate(
offset: Offset(0, getProportionateScreenHeight(-45)),
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Consumer<userInfo.UserInfoProvider>(
builder: (context, state, _) {
if (state.state ==
userInfo.ResultState.Loading) {
return Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
);
} else if (state.state ==
userInfo.ResultState.HasData) {
return Center(
child: imageProfile(
state.result?.data[0].fotoProfile),
);
} else if (state.state ==
userInfo.ResultState.NoData) {
return Center(child: Text(state.message));
} else {
return Center(child: Text(''));
}
}),
),
SizedBox(height: getProportionateScreenHeight(16)),
Form(
key: _formKey,
child: Column(
children: [
CustomProfileTextField(
pad: getProportionateScreenWidth(2),
text: state.newName
? newName
: result.fullname ?? '',
hinttext: 'Tuliskan nama lengkap Anda',
title: 'Nama Lengkap*',
validate: validateName,
onChanged: (value) {
state.newName = true;
newName = value;
},
isErrorManual: isNameEmpty ?? false,
textErrorManual:
"Nama lengkap tidak boleh kosong",
),
CustomProfileTextField(
pad: getProportionateScreenWidth(2),
text: state.newHeadline
? newHeadline
: result.headline ?? '',
hinttext: 'Maksimal 60 kalimat',
title: 'Headline',
onChanged: (value) {
state.newHeadline = true;
newHeadline = value;
},
),
CustomProfileTextField(
pad: getProportionateScreenWidth(2),
text: state.newBiograpy
? newBiograpy
: result.biography ?? '',
hinttext: 'Tulis biografi singkat kamu',
title: 'Biografi',
minLines: 1,
maxLines: 5,
onChanged: (value) {
state.newBiograpy = true;
newBiograpy = value;
},
),
// Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// Text(
// 'Jenis Kelamin',
// style: thirdTextStyle.copyWith(
// fontWeight: semiBold,
// fontSize:
// getProportionateScreenWidth(
// 12),
// color: isDarkMode
// ? baruTextutih
// : baruTexthitam,
// letterSpacing: 0.5),
// ),
// Row(
// mainAxisAlignment:
// MainAxisAlignment.start,
// children: [
// Radio<String>(
// value: 'pria',
// groupValue: newGender,
// onChanged: (value) {
// _handleGenderChange(
// value, state);
// },
// ),
// Text(
// 'Laki-Laki',
// style: thirdTextStyle.copyWith(
// fontSize:
// getProportionateScreenWidth(
// 12),
// color: isDarkMode
// ? baruTextutih
// : baruTexthitam,
// letterSpacing: 0.5),
// ),
// Radio<String>(
// value: 'wanita',
// groupValue: newGender,
// onChanged: (value) {
// _handleGenderChange(
// value, state);
// },
// ),
// Text(
// 'Perempuan',
// style: thirdTextStyle.copyWith(
// fontSize:
// getProportionateScreenWidth(
// 12),
// color: isDarkMode
// ? baruTextutih
// : baruTexthitam,
// letterSpacing: 0.5),
// ),
// ],
// ),
// customTextValidator(isGenderEmpty,
// 'Jenis Kelamin tidak boleh kosong')
// ],
// ),
// SizedBox(height: 15),
// GestureDetector(
// child: Container(
// margin: EdgeInsets.only(
// bottom:
// getProportionateScreenWidth(20),
// ),
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// Text('Tanggal Lahir',
// style: secondaryTextStyle
// .copyWith(
// fontWeight: semiBold,
// fontSize:
// getProportionateScreenWidth(
// 12),
// color: isDarkMode
// ? baruTextutih
// : baruTexthitam,
// letterSpacing: 0.5)),
// SizedBox(
// height:
// getProportionateScreenWidth(
// 5),
// ),
// Container(
// width: double.infinity,
// height:
// getProportionateScreenWidth(
// 50),
// margin:
// EdgeInsets.only(bottom: 7),
// child: Row(
// mainAxisAlignment:
// MainAxisAlignment
// .spaceBetween,
// children: [
// Container(
// margin: EdgeInsets.only(
// left: 13),
// child: Text(
// state.isNewBirthDate
// ? newBirthDate
// : result.datebirth ??
// 'YYYY-MM-DD',
// style: primaryTextStyle
// .copyWith(
// fontSize:
// getProportionateScreenWidth(
// 12),
// color: state
// .isNewBirthDate
// ? baruTexthitam
// : secondaryColor,
// letterSpacing: 0.5,
// ),
// ),
// ),
// Padding(
// padding: EdgeInsets.only(
// right:
// getProportionateScreenWidth(
// 5)),
// child: Icon(Icons
// .keyboard_arrow_down_outlined),
// )
// ],
// ),
// decoration: BoxDecoration(
// color: isDarkMode
// ? Color(0xff212643)
// : Color(0xffF2F2F2),
// borderRadius:
// BorderRadius.circular(10),
// border: Border.all(
// color: isBirthDateEmpty ==
// null
// ? isDarkMode
// ? Color(0xff212643)
// : Color(0xffF2F2F2)
// : isBirthDateEmpty!
// ? Colors.red[700] ??
// Color(
// 0xffd32f2f)
// : isDarkMode
// ? Color(
// 0xff212643)
// : Color(
// 0xffF2F2F2),
// ),
// ),
// ),
// customTextValidator(
// isBirthDateEmpty,
// 'Tanggal lahir tidak boleh kosong'),
// ],
// ),
// ),
// onTap: () async {
// DateTime initialDate = state
// .isNewBirthDate
// ? DateTime(
// int.parse(newBirthDate
// .split('-')[0]),
// int.parse(newBirthDate
// .split('-')[1]),
// int.parse(newBirthDate
// .split('-')[2]))
// : result.datebirth == null
// ? DateTime.now()
// : DateTime(
// int.parse(result
// .datebirth!
// .split('-')[0]),
// int.parse(result
// .datebirth!
// .split('-')[1]),
// int.parse(
// result.datebirth!.split('-')[2]));
// final datePick = await showDatePicker(
// context: context,
// initialDate: initialDate,
// firstDate: DateTime(1900),
// lastDate: DateTime(2100),
// builder: (BuildContext context,
// Widget? child) {
// return Theme(
// data:
// Theme.of(context).copyWith(
// datePickerTheme:
// DatePickerThemeData(
// backgroundColor:
// Colors.white,
// headerBackgroundColor:
// primaryColor,
// headerForegroundColor:
// Colors.white,
// surfaceTintColor:
// Colors
// .transparent),
// colorScheme:
// ColorScheme.light(
// primary:
// primaryColor, // header background color
// onPrimary: Colors
// .white, // header text color
// onSurface:
// primaryColor, // body text color
// ),
// textButtonTheme:
// TextButtonThemeData(
// style: TextButton.styleFrom(
// foregroundColor:
// primaryColor, // button text color
// ),
// ),
// ),
// child: child!,
// );
// },
// );
// if (datePick != null &&
// datePick != birthDate) {
// birthDate = datePick;
// state.isNewBirthDate = true;
// setState(() {
// isBirthDateEmpty = false;
// });
// newBirthDate =
// "${birthDate.year}-${birthDate.month}-${birthDate.day}";
// }
// }),
// CustomProfileTextField(
// keyboardType: TextInputType.number,
// pad: getProportionateScreenWidth(2),
// text: state.newEmail
// ? newEmail
// : result.email ?? '',
// hinttext: 'Tuliskan email Anda',
// title: 'Email',
// validate: validateEmail,
// onChanged: (value) {
// state.newEmail = true;
// newEmail = value;
// },
// isErrorManual: isNameEmpty ?? false,
// textErrorManual:
// "Mohon masukkan email yang valid",
// ),
CustomProfileTextField(
keyboardType: TextInputType.number,
pad: getProportionateScreenWidth(2),
text: state.newPhone
? newPhone
: result.phone ?? '',
hinttext:
'Tuliskan nomor telepon Anda yang terdaftar',
title: 'Nomor Telepon / WA',
validate: validatePhone,
onChanged: (value) {
state.newPhone = true;
newPhone = value;
},
isErrorManual: isNameEmpty ?? false,
textErrorManual:
"Mohon masukkan nomor telepon yang valid",
),
// SizedBox(
// height: getProportionateScreenHeight(20),
// ),
// CustomProfileTextField(
// prefix: Padding(
// padding: EdgeInsets.only(
// top: getProportionateScreenHeight(10),
// left: getProportionateScreenWidth(20),
// right:
// getProportionateScreenHeight(10),
// ),
// child: FaIcon(
// FontAwesomeIcons.instagram,
// color: tenthColor),
// ),
// pad: getProportionateScreenWidth(2),
// text: state.newInstagram
// ? newInstagram
// : result.socialLink?.instagram ?? '',
// hinttext: 'http://instagram.com/',
// noTitle: true,
// onChanged: (value) {
// state.newInstagram = true;
// newInstagram = value;
// },
// ),
// CustomProfileTextField(
// prefix: Padding(
// padding: EdgeInsets.only(
// top: getProportionateScreenHeight(10),
// left: getProportionateScreenWidth(20),
// right:
// getProportionateScreenHeight(10),
// ),
// child: FaIcon(FontAwesomeIcons.twitter,
// color: tenthColor),
// ),
// pad: getProportionateScreenWidth(2),
// text: state.newTwitter
// ? newTwitter
// : result.socialLink?.twitter ?? '',
// hinttext: 'http://twitter.com/',
// noTitle: true,
// onChanged: (value) {
// state.newTwitter = true;
// newTwitter = value;
// },
// ),
// CustomProfileTextField(
// prefix: Padding(
// padding: EdgeInsets.only(
// top: getProportionateScreenHeight(10),
// left: getProportionateScreenWidth(20),
// right:
// getProportionateScreenHeight(10),
// ),
// child: FaIcon(
// FontAwesomeIcons.facebookF,
// color: tenthColor),
// ),
// pad: getProportionateScreenWidth(2),
// text: state.newFacebook
// ? newFacebook
// : result.socialLink?.facebook ?? '',
// hinttext: 'http://facebook.com/',
// noTitle: true,
// onChanged: (value) {
// state.newFacebook = true;
// newFacebook = value;
// },
// ),
// CustomProfileTextField(
// prefix: Padding(
// padding: EdgeInsets.only(
// top: getProportionateScreenHeight(10),
// left: getProportionateScreenWidth(20),
// right:
// getProportionateScreenHeight(10),
// ),
// child: FaIcon(
// FontAwesomeIcons.linkedinIn,
// color: tenthColor),
// ),
// pad: getProportionateScreenWidth(2),
// text: state.newLinkedin
// ? newLinkedin
// : result.socialLink?.linkedin ?? '',
// hinttext: 'http://linkedin.com/',
// noTitle: true,
// onChanged: (value) {
// state.newLinkedin = true;
// newLinkedin = value;
// },
// ),
],
)),
],
),
),
)
],
),
);
} else if (state.state == ResultStateData.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultStateData.Error) {
return Center(
child: TextButton(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('Server internal Error ${state.message}'),
Icon(Icons.refresh)
],
),
onPressed: () {}),
);
} else {
return Center(child: Text(''));
}
},
),
),
);
}
}

View File

@ -0,0 +1,513 @@
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/screens/profile/account_sign_in/invoice.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/default_button_payment.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/detail_invoice_provider.dart'
as detailProvs;
class DetailPembelianSukses extends StatefulWidget {
DetailPembelianSukses({
Key? key,
this.orderId,
this.dataHistoryTransactionModel,
}) : super(key: key);
final String? orderId;
final HistoryTransactionModel? dataHistoryTransactionModel;
final Map<String, String> status = {
'null': "Dibatalkan",
'1': 'Berhasil',
'0': 'Transaksi Kursus Gratis',
'2': 'Menunggu Pembayaran',
'-1': 'Pembayaran Ditolak',
'-2': 'Melebihi Batas Waktu',
};
final Map<String, String> paymentType = {
'null': "Dibatalkan",
'bank transfer': 'Bank Transfer',
'echannel': 'Bank Transfer',
'credit card': 'Kartu Kredit',
'permata': 'Bank Transfer',
'gopay': 'GoPay',
'cstore': 'Gerai',
'free': 'Kursus Gratis',
'Coupon Free Course': 'Kursus Gratis'
};
@override
State<DetailPembelianSukses> createState() => _DetailPembelianSuksesState();
}
class _DetailPembelianSuksesState extends State<DetailPembelianSukses> {
bool isButtonPressed = false;
final TextStyle baris = primaryTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.orderId!.isNotEmpty) {
try {
Provider.of<detailProvs.DetailInvoiceProvider>(context, listen: false)
.fetchDetailInvoice(widget.orderId);
} catch (e) {
print('Gagal detail invoice $e');
}
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
"Cara Pembayaran",
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(15),
),
),
),
body: SingleChildScrollView(
child: Consumer<detailProvs.DetailInvoiceProvider>(
builder: (context, provider, child) {
if (provider.state == detailProvs.ResultState.loading) {
return Center(
child: Column(
children: [
Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(100)),
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
),
],
),
);
} else if (provider.state == detailProvs.ResultState.hasData) {
Widget buildTextWidget() {
String text = "";
if (provider.detailInvoice?[0].permataVaNumber != null) {
text = "Permata Virtual Account";
} else if (provider.detailInvoice?[0].billerCode != null) {
text = "Mandiri Virtual Account";
} else if (provider.detailInvoice?[0].vaNumbers != null &&
provider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bni')) {
text = "BNI Virtual Account";
} else if (provider.detailInvoice?[0].vaNumbers != null &&
provider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bca')) {
text = "BCA Virtual Account";
} else if (provider.detailInvoice?[0].billerCode != null) {
text = "Mandiri Virtual Account";
} else if (provider.detailInvoice?[0].store == "alfamart") {
text = "Alfamart";
} else if (provider.detailInvoice?[0].store == "indomaret") {
text = "Indomart";
} else if (provider.detailInvoice?[0].paymentType ==
"credit_card") {
text = "Credit Card";
} else if (provider.detailInvoice?[0].paymentType == "gopay") {
text = "QRIS";
} else {
"Transaksi Gratis";
}
return Text(
text ?? "Transaksi Gratis",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11)),
);
}
return Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4),
),
color: Theme.of(context).colorScheme.primaryContainer,
),
padding: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(10),
top: getProportionateScreenHeight(15),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Transaksi Selesai',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
),
),
if (widget
.dataHistoryTransactionModel?.statusPayment ==
'1' ||
widget.dataHistoryTransactionModel
?.statusPayment ==
'0')
_statusLabel(
widget.status[widget.dataHistoryTransactionModel?.statusPayment] ??
'',
eightColor)
else if (widget.dataHistoryTransactionModel!.statusPayment == '2' ||
widget.dataHistoryTransactionModel!.statusPayment ==
'0')
_statusLabel(
widget.status[widget.dataHistoryTransactionModel?.statusPayment] ??
'',
fiveColor)
else if (widget.dataHistoryTransactionModel!
.statusPayment !=
null &&
widget.status.containsKey(
widget.dataHistoryTransactionModel!.statusPayment))
_statusLabel(widget.status[widget.dataHistoryTransactionModel?.statusPayment] ?? '', sevenColor)
else
_statusLabel(widget.status['null']! ?? "null", sevenColor)
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Order ID',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
),
),
Text(
widget.orderId!,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Tanggal Pembelian',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
),
),
Text(
DateFormat('E, d MMM y').format(DateTime.parse(
widget.dataHistoryTransactionModel!.date
.toString())),
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11),
),
),
],
),
],
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(4),
bottomRight: Radius.circular(4),
),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color:
Theme.of(context).brightness == Brightness.dark
? Colors.transparent
: secondaryColor.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 2,
offset: Offset(0, getProportionateScreenHeight(4)),
),
],
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(10)),
Text(
"Kursus",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11)),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
listCourse(
imageUrl: provider.thumbnail,
title: widget.dataHistoryTransactionModel!
.courses?[0].title,
instructor: widget.dataHistoryTransactionModel!
.courses?[0].instructor,
price: widget.dataHistoryTransactionModel!
.courses?[0].price,
discountPrice: widget
.dataHistoryTransactionModel!
.courses?[0]
.price,
totalPrices: 0,
),
],
),
Text(
'Rincian Pembayaran',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
),
),
SizedBox(height: getProportionateScreenHeight(11)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
buildTextWidget(),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Harga',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(provider.detailInvoice![0].grossAmount! ?? "0"))}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11)),
),
],
),
SizedBox(height: getProportionateScreenHeight(2)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Potongan Kupon',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse("0"))}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11)),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Bayar',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(provider.detailInvoice![0].grossAmount! ?? "0"))}',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(13),
fontWeight: semiBold,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
DefaultButtonPayment(
width: double.infinity,
height: 37,
text: "Lihat Invoice",
weight: semiBold,
press: () {
if (!isButtonPressed) {
isButtonPressed = true;
if (provider.detailInvoice?[0]
.transactionStatus ==
'settlement' ||
provider.detailInvoice![0]
.transactionStatus ==
'capture') {
Navigator.push(
context,
CustomNavigator(
child: Invoice(
dataHistoryTransactionModel:
widget.dataHistoryTransactionModel,
),
),
);
} else {
CherryToast.error(
animationDuration: Durations.long1,
toastDuration: Duration(seconds: 2),
title: Text(
"Pembayaran ini belum berhasil",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
),
animationType: AnimationType.fromTop,
).show(context);
}
Future.delayed(Duration(seconds: 2), () {
isButtonPressed = false;
});
}
},
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
),
],
),
);
} else if (provider.state == detailProvs.ResultState.noData) {
return Center(child: Text(provider.message ?? ''));
} else if (provider.state == detailProvs.ResultState.error) {
return Center(child: Text(provider.message ?? ''));
} else {
return Container();
}
},
),
),
);
}
Widget listCourse({
String? imageUrl,
String? title,
String? instructor,
String? price,
String? discountPrice,
int? totalPrices,
}) {
return Container(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(6),
bottom: getProportionateScreenHeight(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(60),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: NetworkImage(imageUrl == null || imageUrl.isEmpty
? '$baseUrl/images/default-thumbnail.png'
: imageUrl.startsWith("http")
? imageUrl
: '$baseUrl/uploads/thumbnail/course_thumbnails/$imageUrl'),
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),
),
),
],
),
),
],
),
);
}
Widget _statusLabel(String text, Color color) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(2),
horizontal: getProportionateScreenWidth(5)),
child: Text(
text,
style: thirdTextStyle.copyWith(
color: baruTextutih,
fontSize: getProportionateScreenWidth(9),
fontWeight: semiBold,
),
),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(5),
),
);
}
}

View File

@ -0,0 +1,924 @@
import 'dart:async';
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/models/history_transaction_model.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/screens/checkout/components/bar_batas_bayar.dart';
import 'package:initial_folder/screens/checkout/components/tab_bar_batas_bayar.dart';
import 'package:initial_folder/screens/checkout/gopay/payment_instruction_gopay.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/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:initial_folder/providers/detail_invoice_provider.dart'
as detailProv;
import 'package:shared_preferences/shared_preferences.dart';
class DetailInvoice extends StatefulWidget {
const DetailInvoice({
Key? key,
this.orderId,
this.dataHistoryTransactionModel,
}) : super(key: key);
final String? orderId;
final HistoryTransactionModel? dataHistoryTransactionModel;
@override
State<DetailInvoice> createState() => _DetailInvoiceState();
}
class _DetailInvoiceState extends State<DetailInvoice> {
Duration? remainingTime;
final TextStyle baris = primaryTextStyle.copyWith(
fontWeight: reguler,
color: secondaryColor,
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5,
);
Future<void> saveRemainingTime(Duration remainingTime) async {
final prefs = await SharedPreferences.getInstance();
prefs.setInt('remainingTime', remainingTime.inSeconds);
}
Future<void> loadRemainingTime() async {
final prefs = await SharedPreferences.getInstance();
final remainingTimeInSeconds = prefs.getInt('remainingTime');
if (remainingTimeInSeconds != null) {
remainingTime = Duration(seconds: remainingTimeInSeconds);
}
}
Timer? countdownTimer;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.dataHistoryTransactionModel?.dateExpired != null) {
final now = DateTime.now();
final expiryTime = widget.dataHistoryTransactionModel!.dateExpired!;
setState(() {
remainingTime = expiryTime.isAfter(now)
? expiryTime.difference(now)
: Duration.zero;
});
// Mulai timer hanya jika ada waktu tersisa
if (remainingTime != Duration.zero) {
startCountdownTimer();
}
}
if (widget.orderId?.isNotEmpty ?? false) {
Provider.of<detailProv.DetailInvoiceProvider>(context, listen: false)
.fetchDetailInvoice(widget.orderId);
}
});
}
void startCountdownTimer() {
countdownTimer = Timer.periodic(Duration(seconds: 1), (_) {
if (remainingTime == null || remainingTime!.inSeconds <= 0) {
countdownTimer?.cancel();
setState(() {
remainingTime = Duration.zero;
});
} else {
setState(() {
remainingTime = remainingTime! - Duration(seconds: 1);
});
print('Remaining time: $remainingTime');
}
});
}
@override
void dispose() {
countdownTimer?.cancel();
if (remainingTime != null) {
saveRemainingTime(remainingTime!);
}
super.dispose();
}
Widget buildCountdownTimer() {
if (remainingTime == null || remainingTime!.inSeconds <= 0) {
return Text(
'00:00:00',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(10),
color: baruTextutih,
),
);
}
final hours = remainingTime!.inHours.toString().padLeft(2, '0');
final minutes = (remainingTime!.inMinutes % 60).toString().padLeft(2, '0');
final seconds = (remainingTime!.inSeconds % 60).toString().padLeft(2, '0');
return Text(
'$hours:$minutes:$seconds',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize: getProportionateScreenWidth(10),
color: baruTextutih,
),
);
}
@override
Widget build(BuildContext context) {
PageProvider pageProvider = Provider.of<PageProvider>(context);
final themeProvider = Provider.of<ThemeProvider>(context);
return Scaffold(
appBar: AppBar(
centerTitle: true,
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
"Cara Pembayaran",
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(15),
),
),
),
body: SingleChildScrollView(
child: Consumer<detailProv.DetailInvoiceProvider>(
builder: (context, provider, child) {
if (provider.state == detailProv.ResultState.loading) {
return Center(
child: Column(
children: [
Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(100)),
child: CircularProgressIndicator(
strokeWidth: 2,
color: primaryColor,
),
),
],
),
);
} else if (provider.state == detailProv.ResultState.hasData) {
Widget buildTextWidget() {
String text = "";
if (provider.detailInvoice![0].permataVaNumber != null) {
text = "Permata Virtual Account";
} else if (provider.detailInvoice![0].billerCode != null) {
text = "Mandiri Virtual Account";
} else if (provider.detailInvoice![0].vaNumbers != null &&
provider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bni')) {
text = "BNI Virtual Account";
} else if (provider.detailInvoice![0].vaNumbers != null &&
provider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bca')) {
text = "BCA Virtual Account";
} else if (provider.detailInvoice![0].billerCode != null) {
text = "Mandiri Virtual Account";
} else if (provider.detailInvoice![0].store == "alfamart") {
text = "Alfamart";
} else if (provider.detailInvoice![0].store == "indomaret") {
text = "Indomart";
} else if (provider.detailInvoice![0].paymentType ==
"credit_card") {
text = "Credit Card";
} else {
text = "QRIS";
}
return Text(
text,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
);
}
String getVAText() {
String text = provider.detailInvoice![0].orderId!;
if (provider.detailInvoice != null &&
provider.detailInvoice!.isNotEmpty) {
var invoice = provider.detailInvoice![0];
if (invoice.permataVaNumber != null) {
text = invoice.permataVaNumber!;
} else if (invoice.billerCode != null) {
text = invoice.billKey!;
} else if (invoice.vaNumbers != null &&
invoice.vaNumbers!.any((va) => va.bank == 'bni')) {
text = invoice.vaNumbers![0].vaNumber!;
} else if (invoice.vaNumbers != null &&
invoice.vaNumbers!.any((va) => va.bank == 'bca')) {
text = invoice.vaNumbers![0].vaNumber!;
} else if (invoice.billerCode != null) {
text = invoice.billKey!;
} else if (invoice.store == "alfamart") {
text = provider.detailInvoice![0].paymentCode!;
} else if (invoice.store == "indomaret") {
text = provider.detailInvoice![0].paymentCode!;
} else if (provider.detailInvoice![0].paymentType ==
"credit_card") {
text = provider.detailInvoice![0].maskedCard!
.replaceAll('-', '');
} else {
text = provider.detailInvoice![0].orderId!;
}
}
return text;
}
Widget buildVAaWidget() {
String text = getVAText();
return Text(
text,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
);
}
Widget buildImageWidget() {
String imageName = "qris";
if (provider.detailInvoice![0].permataVaNumber != null) {
imageName = "permata";
} else if (provider.detailInvoice![0].billerCode != null) {
imageName = "mandiri";
} else if (provider.detailInvoice![0].vaNumbers != null &&
provider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bni')) {
imageName = "bni";
} else if (provider.detailInvoice![0].vaNumbers != null &&
provider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bca')) {
imageName = "bca";
} else if (provider.detailInvoice![0].store == "alfamart") {
imageName = "alfamart";
} else if (provider.detailInvoice![0].store == "indomaret") {
imageName = "indomaret";
} else if (provider.detailInvoice![0].paymentType ==
"credit_card") {
imageName = "qris";
}
return Container(
width: getProportionateScreenWidth(50),
height: getProportionateScreenWidth(17),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.brightness ==
Brightness.dark
? Colors.transparent
: (provider.detailInvoice![0].paymentType ==
"gopay")
? baruTexthitam.withOpacity(0.3)
: Colors.transparent,
spreadRadius: 1,
blurRadius: 3,
offset: Offset(0, 1),
),
],
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: AssetImage('assets/images/$imageName.png'),
),
),
);
}
return Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10),
vertical: getProportionateScreenHeight(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4),
),
color: Theme.of(context).colorScheme.primaryContainer,
),
padding: EdgeInsets.only(
left: getProportionateScreenWidth(10),
right: getProportionateScreenWidth(10),
top: getProportionateScreenHeight(15),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Batas Waktu Pembayaran',
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
SizedBox(height: getProportionateScreenHeight(2)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
DateFormat('E, d MMM y HH:mm WIB').format(
DateTime.parse(provider
.detailInvoice![0].expiryTime!)),
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)),
buildCountdownTimer(),
],
),
),
],
),
if (provider.detailInvoice![0].paymentType == "gopay")
SizedBox(height: getProportionateScreenHeight(5)),
if (provider.detailInvoice![0].paymentType == "gopay")
Divider(
color: secondaryColor,
thickness: 1,
),
],
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(4),
bottomRight: Radius.circular(4),
),
color: Theme.of(context).colorScheme.primaryContainer,
boxShadow: [
BoxShadow(
color:
Theme.of(context).brightness == Brightness.dark
? Colors.transparent
: secondaryColor.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 2,
offset: Offset(0, getProportionateScreenHeight(4)),
),
],
),
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: getProportionateScreenHeight(10)),
Text(
"Kursus",
style: thirdTextStyle.copyWith(
fontFamily: "Poppins",
fontSize: getProportionateScreenWidth(11),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
listCourse(
imageUrl: provider.thumbnail,
title: widget.dataHistoryTransactionModel!
.courses?[0].title,
instructor: widget.dataHistoryTransactionModel!
.courses?[0].instructor,
price: widget.dataHistoryTransactionModel!
.courses?[0].price,
discountPrice: widget
.dataHistoryTransactionModel!
.courses?[0]
.price,
totalPrices: 0,
),
],
),
if (provider.detailInvoice![0].paymentType == "gopay")
Divider(
color: secondaryColor,
thickness: 1,
),
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildTextWidget(),
buildImageWidget(),
],
),
SizedBox(height: getProportionateScreenHeight(12)),
provider.detailInvoice![0].store == null &&
provider.detailInvoice![0].paymentType !=
"credit_card"
? (provider.detailInvoice![0].paymentType !=
"gopay")
? Text(
"Nomor Virtual Akun",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
)
: provider.detailInvoice![0].paymentType !=
"credit_card"
? (provider.detailInvoice![0]
.paymentType !=
"gopay")
? Text(
"Nomor Pesananan",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
10),
),
)
: Text(
"Order ID",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
10),
),
)
: SizedBox.shrink()
: Text(
"Kode Pembayaran",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
if (provider.detailInvoice![0].paymentType ==
"credit_card")
Text(
"Nomor Kartu Kredit",
style: primaryTextStyle.copyWith(
color: Colors.white,
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(5)),
Row(
children: [
buildVAaWidget(),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: getVAText().toString()))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Ke Clipboard'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
if (provider.detailInvoice?[0].billKey != null ||
provider.detailInvoice?[0].store == "indomaret")
Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(5)),
child: Text(
"Merchant id",
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
),
if (provider.detailInvoice?[0].billKey != null)
Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(16)),
child: Row(
children: [
Text(
provider.detailInvoice![0].billerCode!,
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: provider
.detailInvoice![0].billerCode
.toString()))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Kode Pembayaran'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
),
if (provider.detailInvoice?[0].store == "indomaret")
Padding(
padding: EdgeInsets.only(
bottom: getProportionateScreenHeight(10)),
child: Row(
children: [
Text(
provider.detailInvoice![0].merchantId!,
style: primaryTextStyle.copyWith(
color: Colors.black,
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: provider
.detailInvoice![0].merchantId
.toString()))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Kode Merchant'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
color: primaryColor,
fontSize:
getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
),
Text(
'Total Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize: getProportionateScreenWidth(10),
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
children: [
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(provider.detailInvoice![0].grossAmount!))}',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(13),
),
),
Spacer(),
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(
text: double.parse(provider
.detailInvoice![0]
.grossAmount!)
.toString()))
.then(
(_) {
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Berhasil Menyalin Ke Clipboard'),
),
);
},
);
},
child: Text(
"Salin",
style: thirdTextStyle.copyWith(
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
fontSize: getProportionateScreenWidth(10),
fontWeight: reguler,
),
),
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
],
),
),
SizedBox(height: getProportionateScreenHeight(24)),
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: [
provider.detailInvoice![0].paymentType != "gopay"
? Container(
width: double.infinity,
padding: EdgeInsets.only(
top: getProportionateScreenHeight(15),
bottom: getProportionateScreenHeight(7),
left: getProportionateScreenWidth(18),
),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4),
topRight: Radius.circular(4),
),
boxShadow: [
BoxShadow(
color: secondaryColor.withOpacity(0.2),
spreadRadius: 0,
blurRadius: 2,
offset: Offset(
0, getProportionateScreenHeight(4)),
),
],
),
child: Text(
'Cara Pembayaran',
style: secondaryTextStyle.copyWith(
letterSpacing: 1,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14),
),
),
)
: SizedBox.shrink(),
Container(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(5),
),
child: provider.detailInvoice![0].store ==
'indomaret' ||
provider.detailInvoice![0].store ==
'alfamart'
? BarBatasBayar(
provider.detailInvoice![0].store!)
: (provider.detailInvoice![0].paymentType !=
"gopay")
? TabBarBatasBayar(
bank: provider.detailInvoice![0]
.vaNumbers !=
null
? provider.detailInvoice![0]
.vaNumbers![0].bank
: (provider.detailInvoice?[0]
.permataVaNumber !=
null
? "permata"
: provider.detailInvoice![0]
.paymentType),
)
: PaymentInstructionGopay(),
),
],
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DefaultButton(
text: 'Belanja kursus lainnya',
weight: semiBold,
press: () {
pageProvider.currentIndex == 0;
Navigator.pushAndRemoveUntil(
context,
CustomNavigatorPop(
child: HomeScreen(),
),
(route) => false);
},
),
],
),
SizedBox(height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: getProportionateScreenWidth(300),
height: getProportionateScreenHeight(38),
child: TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Cek Status Transaksi",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: semiBold,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode,
letterSpacing: 0.5,
),
),
style: TextButton.styleFrom(
foregroundColor:
Theme.of(context).colorScheme.background,
shape: RoundedRectangleBorder(
side: BorderSide( color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode),
borderRadius: BorderRadius.circular(
getProportionateScreenWidth(10)),
),
backgroundColor: Colors.transparent,
),
),
),
],
),
],
),
);
} else if (provider.state == detailProv.ResultState.noData) {
return Center(child: Text(provider.message ?? ''));
} else if (provider.state == detailProv.ResultState.error) {
return Center(child: Text(provider.message ?? ''));
} else {
return Container();
}
},
),
),
);
}
Widget listCourse({
String? imageUrl,
String? title,
String? instructor,
String? price,
String? discountPrice,
int? totalPrices,
}) {
return Container(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(6),
bottom: getProportionateScreenHeight(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(60),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: NetworkImage(imageUrl == null || imageUrl.isEmpty
? '$baseUrl/images/default-thumbnail.png'
: imageUrl.startsWith("http")
? imageUrl
: '$baseUrl/uploads/thumbnail/course_thumbnails/$imageUrl'),
fit: BoxFit.cover,
),
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,377 @@
// this screen is only when the profile (name, email, phone number, password) is not complete
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:initial_folder/models/data_diri_model.dart';
import 'package:initial_folder/providers/data_diri_provider.dart';
import 'package:initial_folder/providers/firebase_authentication_provider.dart';
import 'package:initial_folder/providers/incomplete_profile_provider.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/helper/validator.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/registrasi/registrasi_screen.dart';
import 'package:initial_folder/services/user_info_service.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/custom_profile_text_field.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:initial_folder/widgets/login_regist/footer.dart';
import 'package:initial_folder/widgets/login_regist/header.dart';
import 'package:initial_folder/widgets/login_regist/loading_button.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/helper/user_info.dart';
class IncompleteProfile extends StatefulWidget {
static String routeName = "/uncomplete_profile";
IncompleteProfile({Key? key}) : super(key: key);
@override
_IncompleteProfileState createState() => _IncompleteProfileState();
}
class _IncompleteProfileState extends State<IncompleteProfile> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController reEmailController =
TextEditingController(text: '');
final TextEditingController passwordController =
TextEditingController(text: '');
final TextEditingController rePasswordController =
TextEditingController(text: '');
bool isLoading = false;
bool _isObscure = true;
bool _isObscure1 = true;
bool? isEmailEmpty = false;
bool? isPhoneEmpty = false;
bool? isNameEmpty = false;
late String newName = '';
late String newEmail = '';
late String newPhone = '';
late String password = '';
late String rePassword = '';
@override
Widget build(BuildContext context) {
SizeConfig().init(context);
IncompleteProfileProvider incompleteProfileProvider =
Provider.of<IncompleteProfileProvider>(context);
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),
),
),
);
}
handleProfile(DataDiriProvider state, DataOfDataDiriModel result) async {
setState(() {
isLoading = true;
});
if (await incompleteProfileProvider.updateIncompleteProfile(
fullname: state.newName ? newName : result.fullname ?? '',
email: state.newEmail ? newEmail : result.email ?? '',
phone: state.newPhone ? newPhone : result.phone ?? '',
newPassword: password,
newConfirmPassword: rePassword)) {
Navigator.of(context).pushNamedAndRemoveUntil(
HomeScreen.routeName, (Route<dynamic> route) => false);
} else {
if (incompleteProfileProvider.updateIncompleteProfileModel != null) {
dynamic updateIncompleteProfileMessages =
incompleteProfileProvider.updateIncompleteProfileModel!.messages;
if (updateIncompleteProfileMessages is! String) {
// validate name from backend
if (updateIncompleteProfileMessages.fullname is String) {
setState(() {
isNameEmpty = true;
});
}
// validate datebirth from backend
if (updateIncompleteProfileMessages.phone is String) {
setState(() {
isPhoneEmpty = true;
});
}
// validate datebirth from backend
if (updateIncompleteProfileMessages.email is String) {
setState(() {
isEmailEmpty = true;
});
}
} else {
if (incompleteProfileProvider
.updateIncompleteProfileModel!.status ==
404) {
Navigator.of(context).pushNamedAndRemoveUntil(
LoginEmail.routeName, (Route<dynamic> route) => false);
_showMessage("Sesi habis silahkan login ulang");
} else {
_showMessage(updateIncompleteProfileMessages);
}
}
}
}
setState(() {
isLoading = false;
});
}
void _validateInputs(DataDiriProvider state, DataOfDataDiriModel result) {
if (this._formKey.currentState!.validate()) {
handleProfile(state, result);
}
}
Widget form(DataDiriProvider state, DataOfDataDiriModel result) {
Widget nameInput() {
return CustomProfileTextField(
pad: getProportionateScreenWidth(16),
text: state.newName ? newName : result.fullname ?? '',
hinttext: 'Masukan nama lengkap',
title: 'Nama Lengkap',
validate: validateName,
onChanged: (value) {
isNameEmpty = false;
state.newName = true;
newName = value;
},
isErrorManual: isNameEmpty ?? false,
textErrorManual: "Nama lengkap tidak boleh kosong",
);
}
Widget emailInput() {
return CustomProfileTextField(
pad: getProportionateScreenWidth(16),
text: state.newEmail ? newEmail : result.email ?? '',
hinttext: 'Masukan email',
title: 'Email',
validate: validateEmail,
onChanged: (value) {
isEmailEmpty = false;
state.newEmail = true;
newEmail = value;
},
isErrorManual: isEmailEmpty ?? false,
textErrorManual: "Mohon masukkan email yang valid",
);
}
Widget reEmailInput() {
return CustomProfileTextField(
pad: getProportionateScreenWidth(16),
text: '',
hinttext: 'Masukan konfirmasi email',
title: 'Konfirmasi Email',
validate: (String? value) {
return validateReEmail(
value, state.newEmail ? newEmail : result.email ?? '');
},
);
}
Widget phoneNumberInput() {
return CustomProfileTextField(
pad: getProportionateScreenWidth(16),
text: state.newPhone ? newPhone : result.phone ?? '',
hinttext: 'Masukan no hp',
title: 'No Telepon',
validate: validatePhone,
onChanged: (value) {
isPhoneEmpty = false;
state.newPhone = true;
newPhone = value;
},
isErrorManual: isPhoneEmpty ?? false,
textErrorManual: "Mohon masukkan nomor telepon yang valid",
);
}
Widget passwordInput() {
return CustomProfileTextField(
pad: getProportionateScreenWidth(16),
text: '',
hinttext: 'Masukan password',
title: 'Password',
validate: validatePassword,
onChanged: (value) {
password = value;
},
obscuretext: _isObscure,
suffix: GestureDetector(
onTap: () => setState(() {
_isObscure = !_isObscure;
}),
child: _isObscure
? Icon(
FeatherIcons.eyeOff,
color: secondaryColor,
size: 18,
)
: Icon(
FeatherIcons.eye,
color: secondaryColor,
size: 18,
)),
);
}
Widget rePasswordInput() {
return CustomProfileTextField(
pad: getProportionateScreenWidth(16),
text: '',
hinttext: 'Masukan password',
title: 'Konfirmasi Password',
validate: (String? value) {
return validateRePassword(value, password);
},
onChanged: (value) {
rePassword = value;
},
obscuretext: _isObscure1,
suffix: GestureDetector(
onTap: () => setState(() {
_isObscure1 = !_isObscure1;
}),
child: _isObscure1
? Icon(
FeatherIcons.eyeOff,
color: secondaryColor,
size: 18,
)
: Icon(
FeatherIcons.eye,
color: secondaryColor,
size: 18,
)),
);
}
Widget button() {
return Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(15),
right: getProportionateScreenWidth(15),
top: getProportionateScreenHeight(3)),
child: isLoading
? LoadingButton(
backgroundButtonColor: primaryColor,
textButtonColor: Color(0xff050505))
: DefaultButton(
text: 'Simpan',
press: () {
_validateInputs(state, result);
},
),
);
}
return Form(
key: _formKey,
child: Column(
children: [
phoneNumberInput(),
passwordInput(),
rePasswordInput(),
SizedBox(
height: getProportionateScreenHeight(8),
),
button(),
],
),
);
}
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IconButton(
onPressed: () async {
final provider = Provider.of<FirebaseAuthenticationProvider>(
context,
listen: false);
await UsersInfo().logout();
await provider.logout();
Navigator.of(context).pushNamedAndRemoveUntil(
RegistrationScreen.routeName,
(Route<dynamic> route) => false);
},
icon: Icon(Icons.arrow_back),
iconSize: getProportionateScreenWidth(18),
padding: EdgeInsets.all(getProportionateScreenWidth(8)),
),
Container(
child: Align(
alignment: Alignment.center,
child: Header(
text: 'Yuk Lengkapi Profile kamu sebelum memulai',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(14),
letterSpacing: 0.5)),
),
),
SizedBox(
height: getProportionateScreenHeight(32),
),
ChangeNotifierProvider(
create: (context) =>
DataDiriProvider(userInfoService: UserInfoService()),
child:
Consumer<DataDiriProvider>(builder: (context, state, _) {
if (state.state == ResultStateData.Loading) {
return Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
);
} else if (state.state == ResultStateData.HasData) {
var result = state.result!.data[0];
return form(state, result);
} else if (state.state == ResultStateData.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultStateData.Error) {
return Center(
child: TextButton(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('Server internal Error ${state.message}'),
Icon(Icons.refresh)
],
),
onPressed: () {}),
);
} else {
return Center(child: Text('Gagal mengambil data'));
}
})),
SizedBox(height: getProportionateScreenHeight(32)),
],
),
),
),
);
}
}

View File

@ -0,0 +1,491 @@
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:initial_folder/base_service.dart';
import 'package:initial_folder/models/history_transaction_model.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:initial_folder/widgets/login_regist/default_button_payment.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:initial_folder/providers/detail_invoice_provider.dart'
as invProv;
class Invoice extends StatefulWidget {
Invoice({
super.key,
this.dataHistoryTransactionModel,
});
final HistoryTransactionModel? dataHistoryTransactionModel;
@override
State<Invoice> createState() => _InvoiceState();
}
class _InvoiceState extends State<Invoice> {
final GlobalKey _globalKey = GlobalKey();
bool _isDownloading = false;
Future<void> _captureAndSave() async {
setState(() {
_isDownloading = true;
});
RenderRepaintBoundary boundary =
_globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
ui.Image image = await boundary.toImage();
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List();
if (!(await Permission.storage.status.isGranted)) {
await Permission.storage.request();
}
final result = await ImageGallerySaver.saveImage(
pngBytes,
quality: 100,
name: "invoice_${widget.dataHistoryTransactionModel!.orderId}",
);
setState(() {
_isDownloading = false;
});
print(result);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Invoice sudah terdownload!')),
);
}
@override
Widget build(BuildContext context) {
var dataUser = Provider.of<UserInfoProvider>(context, listen: false).result;
return Scaffold(
appBar: AppBar(
centerTitle: true,
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
"Invoice",
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(15),
),
),
),
body: SingleChildScrollView(
child: Consumer<invProv.DetailInvoiceProvider>(
builder: (context, invoiceProvider, child) {
if (invoiceProvider.state == invProv.ResultState.loading) {
return Center(child: CircularProgressIndicator());
} else if (invoiceProvider.state == invProv.ResultState.hasData) {
Widget buildTextWidget() {
String text = "";
if (invoiceProvider.detailInvoice![0].permataVaNumber != null) {
text = "Permata Virtual Account";
} else if (invoiceProvider.detailInvoice![0].billerCode !=
null) {
text = "Mandiri Virtual Account";
} else if (invoiceProvider.detailInvoice![0].vaNumbers !=
null &&
invoiceProvider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bni')) {
text = "BNI Virtual Account";
} else if (invoiceProvider.detailInvoice![0].vaNumbers !=
null &&
invoiceProvider.detailInvoice![0].vaNumbers!
.any((va) => va.bank == 'bca')) {
text = "BCA Virtual Account";
} else if (invoiceProvider.detailInvoice![0].billerCode !=
null) {
text = "Mandiri Virtual Account";
} else if (invoiceProvider.detailInvoice![0].store ==
"alfamart") {
text = "Alfamart";
} else if (invoiceProvider.detailInvoice![0].store ==
"indomaret") {
text = "Indomart";
} else if (invoiceProvider.detailInvoice![0].paymentType ==
"credit_card") {
text = "Credit Card";
} else {
text = "Transaski Gratis";
}
return Text(
text,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(11)),
);
}
return Center(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(25)),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
RepaintBoundary(
key: _globalKey,
child: Stack(
children: [
Image.asset(
Theme.of(context).colorScheme.brightness ==
Brightness.dark
? "assets/images/invoices_dark.png"
: "assets/images/invoices.png",
width: getProportionateScreenWidth(370),
height: getProportionateScreenHeight(470),
fit: BoxFit.fill,
),
Padding(
padding: EdgeInsets.only(
left: getProportionateScreenWidth(25),
right: getProportionateScreenWidth(25),
top: getProportionateScreenHeight(70),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Order ID',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11),
),
),
Text(
widget.dataHistoryTransactionModel!
.orderId!,
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11),
),
),
],
),
SizedBox(
height: getProportionateScreenHeight(5)),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Tanggal Pembelian',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11),
),
),
Text(
DateFormat('E, d MMM y').format(
DateTime.parse(widget
.dataHistoryTransactionModel!
.date
.toString())),
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
11)),
),
],
),
SizedBox(
height: getProportionateScreenHeight(10)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Informasi Pembeli',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11),
),
),
],
),
Divider(
color: secondaryColor,
thickness: 0.5,
height: 20,
),
Text(
'Nama',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(9),
),
),
SizedBox(
height: getProportionateScreenHeight(5)),
Text(
dataUser!.data[0].fullname!,
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11)),
),
SizedBox(
height: getProportionateScreenHeight(6)),
Text(
'Email',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(9),
),
),
SizedBox(
height: getProportionateScreenHeight(5)),
Text(
dataUser.data[0].email!,
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11)),
),
SizedBox(
height: getProportionateScreenHeight(10)),
Text(
"Kursus",
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11)),
),
Divider(
color: secondaryColor,
thickness: 0.5,
height: 20,
),
Column(
children: widget
.dataHistoryTransactionModel!.courses!
.map((e) => listCourse(
imageUrl: e.thumbnail,
title: e.title,
instructor: e.instructor,
price: e.price,
))
.toList(),
),
SizedBox(
height: getProportionateScreenHeight(15)),
Text(
"Informasi Pembayaran",
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(11)),
),
Divider(
color: secondaryColor,
thickness: 0.5,
height: 20,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Metode Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
buildTextWidget(),
],
),
Divider(
color: secondaryColor,
thickness: 0.5,
height: 20,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Harga',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(invoiceProvider.detailInvoice![0].grossAmount! ?? "0"))}',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
11)),
),
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Potongan Kupon',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse("0"))}',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
11)),
),
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Biaya Layanan',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse("0"))}',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(
11)),
),
],
),
Divider(
color: secondaryColor,
thickness: 0.5,
height: 20,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'Total Bayar',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(10),
),
),
Text(
'Rp. ${NumberFormat.currency(locale: 'id', symbol: '', decimalDigits: 0).format(double.parse(invoiceProvider.detailInvoice![0].grossAmount! ?? "0"))}',
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(13),
fontWeight: semiBold,
),
),
],
),
],
),
),
SizedBox(height: getProportionateScreenHeight(20)),
],
),
),
SizedBox(height: getProportionateScreenHeight(15)),
_isDownloading
? CircularProgressIndicator()
: DefaultButtonPayment(
text: "Download",
press: () {
_captureAndSave();
},
width: double.infinity,
height: 37,
isInvoice: true,
),
],
),
),
);
} else if (invoiceProvider.state == invProv.ResultState.noData) {
return Center(child: Text('No Data'));
} else if (invoiceProvider.state == invProv.ResultState.error) {
return Center(child: Text('Error'));
} else {
return Center(child: Text('Unexpected state'));
}
},
),
),
);
}
Widget listCourse({
String? imageUrl,
String? title,
String? instructor,
String? price,
String? discountPrice,
int? totalPrices,
}) {
return Container(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(6),
bottom: getProportionateScreenHeight(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(60),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
image: DecorationImage(
image: NetworkImage(imageUrl != null && imageUrl.isNotEmpty
? "$baseUrl/uploads/thumbnail/course_thumbnails/$imageUrl"
: "https://api.vokasia.id/images/default-thumbnail.png"),
fit: BoxFit.cover,
),
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Flexible(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: thirdTextStyle.copyWith(
letterSpacing: 0.5,
fontWeight: reguler,
fontSize: getProportionateScreenWidth(11),
),
),
],
),
),
],
),
);
}
}

View File

@ -0,0 +1,368 @@
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
import 'package:flutter/material.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/detail_invoice_provider.dart';
import 'package:initial_folder/providers/history_transactions_provider.dart'
as historyProv;
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/providers/total_price_provider.dart';
import 'package:initial_folder/screens/home/home_screen.dart';
import 'package:initial_folder/screens/profile/account_sign_in/detail_pembelian_sukses.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:initial_folder/widgets/custom_navigator_pop.dart';
import 'package:initial_folder/widgets/riwayat_list.dart';
import 'package:provider/provider.dart';
import 'package:shimmer/shimmer.dart';
class RiwayatTransaksi extends StatefulWidget {
RiwayatTransaksi({Key? key}) : super(key: key);
static const String routeName = "/riwayat-transaksi";
@override
State<RiwayatTransaksi> createState() => _RiwayatTransaksiState();
}
class _RiwayatTransaksiState extends State<RiwayatTransaksi> {
bool isButtonPressed = false;
Future<bool> _onWillPop() async {
Provider.of<PageProvider>(context, listen: false).currentIndex = 4;
Navigator.pushAndRemoveUntil(
context,
CustomNavigatorPop(
child: HomeScreen(),
),
(route) => false,
);
return Future.value(false);
}
@override
void initState() {
super.initState();
// Memanggil fungsi getHistoryTransaction untuk refresh data ketika halaman pertama kali dibuka
WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<historyProv.HistoryTranscationsProvider>(context, listen: false)
.getHistoryTransaction();
});
}
@override
Widget build(BuildContext context) {
var selected = Provider.of<DetailInvoiceProvider>(context);
var historyProvider =
Provider.of<historyProv.HistoryTranscationsProvider>(context);
final selectedTotalPrices = Provider.of<TotalPriceProvider>(context);
PageProvider pageProvider = Provider.of<PageProvider>(context);
return WillPopScope(
onWillPop: _onWillPop,
child: SafeArea(
child: Scaffold(
appBar: AppBar(
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Riwayat Pembelian',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(15),
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: Theme.of(context).colorScheme.onBackground,
size: getProportionateScreenWidth(17),
),
onPressed: () {
_onWillPop();
},
),
),
body: Column(
children: [
InkWell(
onTap: () {
Navigator.push(
context,
CustomNavigator(
child: RiwayatTransaksiPending(),
),
);
},
child: Container(
padding: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(12)),
margin: EdgeInsets.symmetric(
vertical: getProportionateScreenHeight(10),
horizontal: getProportionateScreenWidth(16)),
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? seventeenColor.withOpacity(0.3)
: baruTextutih,
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
children: [
Icon(
Icons.pending_actions,
color: Theme.of(context).brightness == Brightness.dark
? secondaryColor
: baruTexthitam,
size: getProportionateScreenWidth(17),
),
SizedBox(width: getProportionateScreenWidth(15)),
Text(
'Menunggu Pembayaran (${historyProvider.paymentPending?.length ?? 0})',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(15),
color:
Theme.of(context).brightness == Brightness.dark
? secondaryColor
: baruTexthitam,
),
)
],
),
Icon(Icons.chevron_right)
],
),
),
),
Consumer<historyProv.HistoryTranscationsProvider>(
builder: (context, state, _) {
if (state.state == historyProv.ResultState.loading) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(15)),
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(70),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(70),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
),
);
} else if (state.state == historyProv.ResultState.noData) {
return Center(
child: Text(state.message),
);
} else if (state.state == historyProv.ResultState.hasData) {
List<HistoryTransactionModel> history = state.historyPayment!;
return Expanded(
child: RefreshIndicator(
onRefresh: () async {
await Provider.of<
historyProv.HistoryTranscationsProvider>(
context,
listen: false)
.getHistoryTransaction();
},
color: primaryColor,
strokeWidth: 2,
child: ListView.builder(
physics: ScrollPhysics(),
itemCount: history.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
selectedTotalPrices.selectedTotalPrices = history[index].totalPrice ?? 0;
selected.selectedThumbnail = history[index].courses?.isNotEmpty == true
? history[index].courses![0].thumbnail ?? 'default_thumbnail.png'
: 'default_thumbnail.png';
if (!isButtonPressed) {
setState(() {
isButtonPressed = true;
});
if (history[index].statusPayment != "0") {
Navigator.push(
context,
CustomNavigator(
child: DetailPembelianSukses(
orderId: history[index].orderId!,
dataHistoryTransactionModel:
history[index],
),
),
);
} else {
CherryToast.error(
animationDuration: Durations.medium1,
toastDuration: Duration(seconds: 2),
title: Text(
"Pembayaran gratis tidak memiliki invoice",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
),
animationType: AnimationType.fromTop,
).show(context);
}
Future.delayed(Duration(seconds: 2), () {
isButtonPressed = false;
});
}
},
child: RiwayatList(
dataHistoryTransactionModel: history[index],
),
);
},
),
),
);
} else if (state.state == historyProv.ResultState.error) {
return RefreshIndicator(
onRefresh: () async {
await Provider.of<
historyProv.HistoryTranscationsProvider>(
context,
listen: false)
.getHistoryTransaction();
},
child: Center(
child: Text(state.message),
),
);
} else {
return Center(
child: CircularProgressIndicator(
color: primaryColor,
strokeWidth: 2,
),
);
}
},
),
],
),
),),
);
}
}

View File

@ -0,0 +1,238 @@
import 'package:flutter/material.dart';
import 'package:initial_folder/models/history_transaction_model.dart';
import 'package:initial_folder/providers/history_transactions_provider.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/riwayat_list_delete.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/order_provider.dart' as orderProvider;
import 'package:shimmer/shimmer.dart';
class RiwayatTransaksiPending extends StatelessWidget {
const RiwayatTransaksiPending({Key? key}) : super(key: key);
static const String routeName = "/riwayat-transaksi-pending";
@override
Widget build(BuildContext context) {
Provider.of<orderProvider.OrderProvider>(context, listen: false).clear();
return WillPopScope(
onWillPop: () async {
Navigator.pushReplacementNamed(context, RiwayatTransaksi.routeName);
return false;
},
child: SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
scrolledUnderElevation: 0.0,
backgroundColor: Theme.of(context).colorScheme.background,
title: Text(
'Menunggu Pembayaran',
style: thirdTextStyle.copyWith(
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(15),
),
),
),
body: StreamBuilder<List<HistoryTransactionModel>>(
stream:
Provider.of<HistoryTranscationsProvider>(context, listen: false)
.getHistoryTransactionStream(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(15)),
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(70),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(15)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(100),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(70),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
SizedBox(width: getProportionateScreenWidth(10)),
Container(
width: getProportionateScreenWidth(130),
height: getProportionateScreenHeight(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
SizedBox(height: getProportionateScreenHeight(8)),
Container(
width: double.infinity,
height: getProportionateScreenHeight(90),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
),
],
),
),
);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
List<HistoryTransactionModel>? history = snapshot.data;
return history?.length == 0
? Center(
child: Text('Belum ada pembayaran dalam status menunggu'),
)
: RefreshIndicator(
onRefresh: () async {
await Provider.of<HistoryTranscationsProvider>(context,
listen: false)
.getHistoryTransaction();
},
color: primaryColor,
strokeWidth: 2,
child: Container(
margin: EdgeInsets.only(
top: getProportionateScreenHeight(15)),
child: ListView.builder(
itemCount: history?.length,
itemBuilder: (context, index) {
return RiwayatListDelete(
dataHistoryTransactionModel: history![index],
onPaymentCancelled: (message) async {
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,
message,
style: thirdTextStyle.copyWith(
fontSize:
getProportionateScreenWidth(12),
),
),
),
),
);
await Provider.of<HistoryTranscationsProvider>(
context,
listen: false)
.getHistoryTransaction();
},
);
},
),
),
);
}
},
),
),),
);
}
}

View File

@ -0,0 +1,315 @@
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:initial_folder/providers/update_password_provider.dart';
import 'package:initial_folder/size_config.dart';
import 'package:initial_folder/theme.dart';
import 'package:initial_folder/widgets/login_regist/custom_text_form_field.dart';
import 'package:initial_folder/helper/validator.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:initial_folder/providers/user_info_provider.dart';
import 'package:initial_folder/widgets/login_regist/loading_button.dart';
import 'package:provider/provider.dart';
import 'package:tap_debouncer/tap_debouncer.dart';
class SettingAkun extends StatefulWidget {
@override
State<SettingAkun> createState() => _SettingAkunState();
}
class _SettingAkunState extends State<SettingAkun> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _currentPasswordController =
TextEditingController(text: '');
final TextEditingController _newPasswordController =
TextEditingController(text: '');
final TextEditingController _confirmPasswordController =
TextEditingController(text: '');
bool _isObscure = true;
bool _isObscure1 = true;
bool _isObscure2 = true;
bool _isloading = true;
@override
Widget build(BuildContext context) {
final Brightness brightnessValue =
MediaQuery.of(context).platformBrightness;
bool isDarkMode = brightnessValue == Brightness.dark;
UserInfoProvider userInfoProvider = Provider.of<UserInfoProvider>(context);
UpdatePasswordProvider updatePasswordProvider =
Provider.of<UpdatePasswordProvider>(context);
// EmailProvider emailProvider = Provider.of<EmailProvider>(context);
// ShowHidePassword showHidePassword = Provider.of<ShowHidePassword>(context);
// ShowHidePassword1 showHidePassword1 =
// Provider.of<ShowHidePassword1>(context);
// ShowHidePassword2 showHidePassword2 =
// Provider.of<ShowHidePassword2>(context);
Future _showMessage(String text) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
contentPadding: EdgeInsets.fromLTRB(22, 30, 22, 30),
content: Text(
text,
textAlign: TextAlign.center,
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
),
);
}
updatePassword(
{required idUser,
String? email,
String? oldPassword,
String? password,
String? newPasswordConfirm}) async {
await Provider.of<UpdatePasswordProvider>(context, listen: false)
.passwordUpdate(
idUser: idUser,
email: email,
oldPassword: oldPassword,
password: password,
newPasswordConfirm: newPasswordConfirm)
.then((value) => {
setState(() {
if (value == true) {
_showMessage('Password Berhasil Diubah');
_isloading = true;
} else {
setState(() {
_isloading = true;
print('masuk sini');
});
_showMessage('Password Gagal Diubah');
_isloading = true;
}
})
});
}
void _validateInputs() async {
setState(() {
_isloading = false;
});
if (this._formKey.currentState!.validate()) {
await updatePassword(
idUser: userInfoProvider.result!.data[0].idUser,
email: userInfoProvider.result!.data[0].email,
oldPassword: _currentPasswordController.text,
password: _newPasswordController.text,
newPasswordConfirm: _confirmPasswordController.text,
);
} else {
setState(() {
_isloading = true;
print('masuk sini');
});
CherryToast.error(
toastPosition: Position.top,
animationDuration: Durations.long1,
title: Text(
"Formulir tidak valid, periksa kembali",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
),
animationType: AnimationType.fromTop,
).show(context);
}
}
Widget form() {
Widget currentPasswordInput() {
return CustomTextField(
pad: getProportionateScreenWidth(2),
controler: _currentPasswordController,
hinttext: 'Masukkan password saat ini',
title: 'Password Lama',
obscuretext: _isObscure,
validate: (String? value) {
if (value!.length == 0)
return 'Password tidak boleh kosong';
else if (value.length < 8)
return 'Password minimal harus berjumlah 8 karakter';
return null;
},
suffix: GestureDetector(
onTap: () => setState(() {
_isObscure = !_isObscure;
}),
child: _isObscure
? Icon(
Icons.visibility_off,
color: secondaryColor,
size: 18,
)
: Icon(
Icons.visibility,
color: secondaryColor,
size: 18,
)),
);
}
Widget newPasswordInput() {
return CustomTextField(
pad: getProportionateScreenWidth(2),
controler: _newPasswordController,
hinttext: 'Masukkan password baru',
title: 'Password Baru',
obscuretext: _isObscure1,
validate: (String? value) {
if (value!.length == 0)
return 'Password tidak boleh kosong';
else if (value.length < 8)
return 'Password minimal harus berjumlah 8 karakter';
else if (value == _currentPasswordController.text) {
return 'Password tidak boleh sama';
}
return null;
},
suffix: GestureDetector(
onTap: () {
setState(() {
_isObscure1 = !_isObscure1;
});
},
child: _isObscure1
? Icon(
Icons.visibility_off,
color: secondaryColor,
size: 18,
)
: Icon(
Icons.visibility,
color: secondaryColor,
size: 18,
)),
);
}
Widget confirmPasswordInput() {
return CustomTextField(
pad: getProportionateScreenWidth(2),
controler: _confirmPasswordController,
hinttext: 'Konfirmasi password baru',
title: 'Konfirmasi Password',
obscuretext: _isObscure2,
suffix: GestureDetector(
onTap: () => setState(() {
_isObscure2 = !_isObscure2;
}),
child: _isObscure2
? Icon(
Icons.visibility_off,
color: secondaryColor,
size: 18,
)
: Icon(
Icons.visibility,
color: secondaryColor,
size: 18,
)),
validate: (String? value) {
if (value!.length == 0)
return 'Password tidak boleh kosong';
else if (value.length < 8)
return 'Password minimal harus berjumlah 8 karakter';
else if (value != _newPasswordController.text) {
return 'Password baru dengan konfirmasi tidak sama';
}
return null;
},
);
}
Widget bottomNav() {
return _isloading != true
? Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(45),
vertical: getProportionateScreenHeight(10)),
child: LoadingButton(
backgroundButtonColor: primaryColor,
textButtonColor: Color(0xff050505)))
: Container(
margin: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(45),
vertical: getProportionateScreenHeight(10)),
child: TapDebouncer(
cooldown: const Duration(milliseconds: 3000),
onTap: () async =>
await {_validateInputs()}, // your tap handler moved here
builder: (BuildContext context, TapDebouncerFunc? onTap) {
return DefaultButton(
text: 'Simpan perubahan',
press: onTap,
);
},
),
);
}
return Form(
key: _formKey,
child: Column(
children: [
currentPasswordInput(),
SizedBox(height: getProportionateScreenHeight(15)),
newPasswordInput(),
SizedBox(height: getProportionateScreenHeight(15)),
confirmPasswordInput(),
SizedBox(height: getProportionateScreenHeight(70)),
bottomNav(),
],
),
);
}
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
title: Text(
'Pengaturan Akun',
style: secondaryTextStyle.copyWith(
letterSpacing: 0.23,
fontWeight: semiBold,
fontSize: getProportionateScreenWidth(14)),
)),
body: ListView(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
form(),
SizedBox(
height: getProportionateScreenHeight(13),
),
],
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,605 @@
import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:image_picker/image_picker.dart';
import 'package:initial_folder/helper/user_info.dart';
import 'package:initial_folder/providers/firebase_authentication_provider.dart';
import 'package:initial_folder/providers/page_provider.dart';
import 'package:initial_folder/providers/profile_image_provider.dart';
import 'package:initial_folder/providers/theme_provider.dart';
import 'package:initial_folder/providers/user_info_provider.dart';
import 'package:initial_folder/screens/certificate/certificate.dart';
import 'package:initial_folder/screens/login/login_with_email/login_email_screen.dart';
import 'package:initial_folder/screens/profile/account_sign_in/data_diri.dart';
import 'package:initial_folder/screens/profile/account_sign_in/riwayat_transaksi.dart';
import 'package:initial_folder/screens/profile/account_sign_in/setting_akun.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/screens/profile/components/about_profile_list.dart';
import 'package:initial_folder/widgets/custom_navigator.dart';
import 'package:initial_folder/widgets/login_regist/default_button.dart';
import 'package:initial_folder/widgets/terms_and_privacy.dart';
import 'package:provider/provider.dart';
import 'package:initial_folder/providers/history_transactions_provider.dart'
as historyProvider;
class SignInScreen extends StatefulWidget {
const SignInScreen({
Key? key,
}) : super(key: key);
@override
State<SignInScreen> createState() => _SignInScreenState();
}
class _SignInScreenState extends State<SignInScreen> {
final String frontEndUrl = "https://vocasia.id";
bool isLoading = false;
final double maximumRadius = 1000;
bool showCircle = true;
@override
Widget build(BuildContext context) {
ProfileImageProvider profileImageProvider =
Provider.of<ProfileImageProvider>(context, listen: false);
final ImagePicker _picker = ImagePicker();
final themeProvider = Provider.of<ThemeProvider>(context);
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
Future _showMessage(String text) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
contentPadding: const EdgeInsets.fromLTRB(22, 30, 22, 30),
content: Text(
text,
textAlign: TextAlign.center,
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12), letterSpacing: 1),
),
),
);
}
void takePhoto(ImageSource source) async {
try {
final XFile? pickedFile = await _picker.pickImage(source: source);
var imageFile = (pickedFile != null) ? File(pickedFile.path) : File('');
if (await profileImageProvider.addProfileImage(pckFile: imageFile)) {
setState(() {
isLoading = true;
});
await Future.delayed(const Duration(seconds: 2));
profileImageProvider.setImageFile(imageFile);
setState(() {
imageFile;
isLoading = false;
});
_showMessage('Berhasil Upload Image');
}
} on PlatformException catch (e) {
print('Failed to pick image : $e');
}
}
Widget bottomSheet() {
return Container(
height: 100.0,
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 20,
),
child: Column(
children: <Widget>[
Text(
"Choose Profile photo",
style: secondaryTextStyle.copyWith(fontSize: 20),
),
SizedBox(height: getProportionateScreenHeight(20)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton.icon(
icon: const Icon(Icons.camera),
onPressed: () {
Navigator.pop(context);
takePhoto(ImageSource.camera);
},
label: Text(
"Camera",
style: primaryTextStyle,
),
),
TextButton.icon(
icon: const Icon(Icons.image),
onPressed: () {
Navigator.pop(context);
takePhoto(ImageSource.gallery);
},
label: Text("Gallery", style: primaryTextStyle),
),
],
),
],
),
);
}
Widget imageProfile(String? urlImage) {
return Stack(
children: [
CircleAvatar(
radius: getProportionateScreenWidth(40),
backgroundImage: profileImageProvider.imageFile != null
? FileImage(profileImageProvider.imageFile!) as ImageProvider
: urlImage != null
? NetworkImage(urlImage) as ImageProvider
: const AssetImage("assets/images/Profile Image.png")
as ImageProvider,
),
Positioned(
bottom: 0,
right: 0,
child: Container(
width: getProportionateScreenWidth(30),
height: getProportionateScreenHeight(30),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[200],
border: Border.all(
width: getProportionateScreenWidth(2),
color: Colors.white)),
child: IconButton(
icon: Icon(
size: getProportionateScreenHeight(10),
FeatherIcons.edit,
color: Colors.black,
),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) => GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.pop(context);
},
child: bottomSheet(),
),
);
},
),
),
),
],
);
}
getProfile() async {
var email = await UsersInfo().getEmail();
Provider.of<UserInfoProvider>(context, listen: false).getUserInfo(email);
}
PageProvider pageProvider =
Provider.of<PageProvider>(context, listen: false);
Future _showDialogLogout() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
backgroundColor: Theme.of(context).colorScheme.background,
surfaceTintColor: Colors.transparent,
contentPadding: const EdgeInsets.fromLTRB(12, 26, 22, 15),
content: Padding(
padding: const EdgeInsets.only(bottom: 15.0),
child: Text(
textAlign: TextAlign.center,
'Apakah anda yakin ingin keluar?',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
),
),
),
actions: [
GestureDetector(
onTap: () async {
final provider = Provider.of<FirebaseAuthenticationProvider>(
context,
listen: false);
await UsersInfo().logout();
await provider.logout();
Condition.loginEmail = false;
Condition.loginFirebase = false;
UsersInfo().getIdUser().then((value) {
FirebaseMessaging.instance
.unsubscribeFromTopic("payment-before-paid-$value");
FirebaseMessaging.instance
.unsubscribeFromTopic("payment-after-paid-$value");
FirebaseMessaging.instance
.unsubscribeFromTopic("qna-new-qna-$value");
FirebaseMessaging.instance
.unsubscribeFromTopic("qna-reply-qna-$value");
FirebaseMessaging.instance
.unsubscribeFromTopic("alert-carts-$value");
});
pageProvider.remove();
final themeProvider =
Provider.of<ThemeProvider>(context, listen: false);
await themeProvider.saveCurrentTheme();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (_) => LoginEmail(),
),
(_) => false,
);
},
child: Text('Ya',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode ,)),
),
SizedBox(width: getProportionateScreenWidth(5)),
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Text('Tidak',
style: primaryTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
letterSpacing: 1,
color: themeProvider.themeData == ThemeClass.darkmode
?primaryColor : primaryColorligtmode ,)),
),
const SizedBox(width: 12),
],
),
);
}
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.background,
centerTitle: true,
scrolledUnderElevation: 0.0,
title: Text(
"Profile",
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenHeight(12),
fontWeight: semiBold,
letterSpacing: 2.3,
),
),
actions: [
IconButton(
icon: SvgPicture.asset(
themeProvider.themeData == ThemeClass.darkmode
? 'assets/icons/moon.svg'
: 'assets/icons/sun.svg',
),
onPressed: () {
setState(() {
themeProvider.toggleTheme();
});
},
),
SizedBox(width: getProportionateScreenWidth(7)),
],
),
body: Stack(
children: [
ListView(
children: [
Container(
height: getProportionateScreenHeight(100),
// width: 360,
decoration: BoxDecoration(
color: Colors.grey[300],
image: DecorationImage(
image: AssetImage( isDarkMode
? 'assets/images/cover_dark.png'
: 'assets/images/cover_light.png'),
fit: BoxFit.cover,
),
),
// child: const Padding(
// padding: EdgeInsets.all(10),
// child: Align(
// alignment: Alignment.bottomRight,
// // child: Icon(
// // Icons.camera_alt,
// // color: Colors.white,
// // ),
// ),
// ),
),
Transform.translate(
offset: Offset(0, getProportionateScreenHeight(-40)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Consumer<UserInfoProvider>(
builder: (context, state, _) {
if (state.state == ResultState.Loading) {
return const CircleAvatar(
backgroundColor: Colors.white,
child: Center(
child: CircularProgressIndicator(
color: secondaryColor,
strokeWidth: 2,
),
),
);
} else if (state.state == ResultState.HasData) {
//var idus = state.result!.data[0].idUser;
return Column(
children: [
imageProfile(
state.result?.data[0].fotoProfile),
SizedBox(
height: getProportionateScreenHeight(16)),
Text(
state.result!.data[0].fullname ?? ' ',
style: secondaryTextStyle.copyWith(
fontWeight: semiBold,
letterSpacing: 1,
fontSize:
getProportionateScreenWidth(14)),
textAlign: TextAlign.center,
),
SizedBox(
height: getProportionateScreenHeight(3)),
Text(
state.result!.data[0].email ?? '',
style: primaryTextStyle.copyWith(
color: secondaryColor,
letterSpacing: 0.5,
fontSize: getProportionateScreenWidth(12),
),
textAlign: TextAlign.center,
),
SizedBox(
height: getProportionateScreenHeight(15)),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const Certificate(),
),
);
},
child: Container(
height: getProportionateScreenHeight(40),
padding:
const EdgeInsets.only(left: 10, right: 10),
// width: 10,
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.primaryContainer,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color:
Theme.of(context).brightness ==
Brightness.dark
? Colors.transparent
: Colors.grey,
spreadRadius: 0.01,
blurRadius: 4,
offset:
const Offset(4, 5), // Shadow position
),
],
),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Image.asset(
"assets/images/certificate_icon_profile.png",
width: 18,
color: Theme.of(context)
.colorScheme
.onBackground,
),
SizedBox(
width:
getProportionateScreenWidth(15),
),
Flexible(
child: Text(
'Ayo cek status sertifikat mu sekarang. Download dan bagikan ke media sosial!',
style: thirdTextStyle.copyWith(
fontWeight: reguler,
fontSize:
getProportionateScreenWidth(
12),
),
)),
Icon(
Icons.arrow_forward_ios,
size:
getProportionateScreenWidth(20),
)
],
),
),
)
],
);
} else if (state.state == ResultState.NoData) {
return Center(child: Text(state.message));
} else if (state.state == ResultState.Error) {
return Center(
child: TextButton(
child: const Column(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [Icon(Icons.refresh)],
),
onPressed: () => getProfile()),
);
} else {
return const Center(child: Text(''));
}
},
),
),
SizedBox(height: getProportionateScreenHeight(15)),
SizedBox(height: getProportionateScreenHeight(10)),
Text(
'Preferensi Akun',
style: thirdTextStyle.copyWith(
fontSize: getProportionateScreenWidth(12),
fontWeight: bold,
),
),
SizedBox(height: getProportionateScreenHeight(13)),
AboutAccountList(
onPress: () {
Route route = MaterialPageRoute(
builder: (context) => DataDiri(),
);
Navigator.push(
context,
route,
).then((value) async {
var email = await UsersInfo().getEmail();
setState(() {
Provider.of<UserInfoProvider>(context,
listen: false)
.getUserInfo(email);
});
});
},
title: 'Data Diri'),
AboutAccountList(
onPress: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SettingAkun(),
),
);
},
title: 'Pengaturan Akun'),
AboutAccountList(
onPress: () {
pageProvider.remove();
Provider.of<
historyProvider
.HistoryTranscationsProvider>(context,
listen: false)
.getHistoryTransaction();
Navigator.push(context,
CustomNavigator(child: RiwayatTransaksi()));
},
title: 'Riwayat Transaksi'),
SizedBox(height: getProportionateScreenWidth(30)),
// Text(
// 'Bantuan Dan Dukungan',
// style: thirdTextStyle.copyWith(
// fontSize: getProportionateScreenWidth(12),
// fontWeight: bold,
// ),
// ),
// SizedBox(height: getProportionateScreenHeight(13)),
// AboutAccountList(
// onPress: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => TermsAndCondition(
// url: '$frontEndUrl/about-us', id: 'about'),
// ),
// );
// },
// title: 'Tentang Vocasia'),
// AboutAccountList(
// onPress: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => TermsAndCondition(
// url: '$frontEndUrl/syarat-ketentuan',
// id: 'sk'),
// ),
// );
// },
// title: 'Syarat dan Ketentuan'),
// AboutAccountList(
// onPress: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => TermsAndCondition(
// url: '$frontEndUrl/privacy-policy',
// id: 'prv'),
// ),
// );
// },
// title: 'Kebijakan Privasi'),
// AboutAccountList(
// onPress: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => TermsAndCondition(
// url: '$frontEndUrl/contact', id: 'ctc'),
// ),
// );
// },
// title: 'Kontak Kami'),
// AboutAccountList(
// onPress: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => TermsAndCondition(
// url: '$frontEndUrl/help', id: 'help'),
// ),
// );
// },
// title: 'Bantuan'),
Center(
child: DefaultButton(
text: 'Keluar',
press: () {
_showDialogLogout();
},
),
)
],
),
),
)
],
),
],
),
);
}
}