Commit 77a3594d authored by Dio Maulana's avatar Dio Maulana

jagain absen masuk keluar di frontend

parent 6ae1e7c8
...@@ -5,6 +5,7 @@ import 'package:excelso_attendance/helper/pref.dart'; ...@@ -5,6 +5,7 @@ import 'package:excelso_attendance/helper/pref.dart';
import 'package:excelso_attendance/main.dart'; import 'package:excelso_attendance/main.dart';
import 'package:excelso_attendance/models/absent.dart'; import 'package:excelso_attendance/models/absent.dart';
import 'package:excelso_attendance/models/branch.dart'; import 'package:excelso_attendance/models/branch.dart';
import 'package:excelso_attendance/models/profile.dart';
import 'package:excelso_attendance/models/shift.dart'; import 'package:excelso_attendance/models/shift.dart';
import 'package:excelso_attendance/resource/strings.dart'; import 'package:excelso_attendance/resource/strings.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
...@@ -113,9 +114,11 @@ class Api { ...@@ -113,9 +114,11 @@ class Api {
return ApiResponse(error: true, msg: Strings.cantConnectToServer); return ApiResponse(error: true, msg: Strings.cantConnectToServer);
} else { } else {
if (jsonObject['status'] == "ok") { if (jsonObject['status'] == "ok") {
Map<String, dynamic> user = jsonObject['data']['user'];
return ApiResponse( return ApiResponse(
error: false, error: false,
msg: Strings.succesGetData, msg: Strings.succesGetData,
data: ProfileModel.json(user),
); );
} else { } else {
return ApiResponse( return ApiResponse(
......
import 'package:excelso_attendance/helper/component/button.dart';
import 'package:excelso_attendance/resource/font.dart';
import 'package:excelso_attendance/resource/style.dart';
import 'package:flutter/material.dart';
Future<dynamic> modalDialogGlobal({
required BuildContext context,
required Size size,
required String title,
required String contentBody,
required String buttonText,
required void Function() tapButton,
bool isActiveCancelButton = false,
bool isCustomSecondButton = false,
String customSecondButtonText = '',
Widget? navigateToCustomButton,
}) async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext ctxDialog) => AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: getBoldStyle(
color: Colors.black,
fontFamily: FontConstants.montserrat,
fontSize: FontSize.s24,
),
),
const SizedBox(
height: 16,
),
Text(
contentBody,
style: getMediumStyle(
color: Colors.black,
fontFamily: FontConstants.openSans,
fontSize: FontSize.s16,
),
),
const SizedBox(
height: 42,
),
InkWell(
onTap: () {
tapButton();
},
child: CustomButton(
text: buttonText,
),
),
(isActiveCancelButton)
? InkWell(
onTap: () {
Navigator.pop(context);
},
child: const CustomButton(
text: "Cancel",
colorButton: Colors.transparent,
colorText: Colors.black,
),
)
: const SizedBox(),
(isCustomSecondButton)
? Column(
children: [
const SizedBox(
height: 10,
),
InkWell(
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => navigateToCustomButton!),
);
},
child: CustomButton(
text: customSecondButtonText,
),
),
],
)
: const SizedBox()
],
),
),
);
}
class ProfileModel {
String id;
String brand;
String name;
bool attendanceIn;
bool attendanceOut;
ProfileModel({
required this.id,
required this.brand,
required this.name,
required this.attendanceIn,
required this.attendanceOut,
});
factory ProfileModel.json(Map<String, dynamic> json) {
return ProfileModel(
id: json['id'],
brand: json['brand'],
name: json['name'],
attendanceIn: json['today_attendance_in'],
attendanceOut: json['today_attendance_out'],
);
}
}
...@@ -6,6 +6,7 @@ import 'dart:io'; ...@@ -6,6 +6,7 @@ import 'dart:io';
import 'package:excelso_attendance/api/api.dart'; import 'package:excelso_attendance/api/api.dart';
import 'package:excelso_attendance/helper/arguments/error_args.dart'; import 'package:excelso_attendance/helper/arguments/error_args.dart';
import 'package:excelso_attendance/helper/arguments/route_args.dart'; import 'package:excelso_attendance/helper/arguments/route_args.dart';
import 'package:excelso_attendance/helper/modal_dialog.dart';
import 'package:excelso_attendance/helper/widget_responsive.dart'; import 'package:excelso_attendance/helper/widget_responsive.dart';
import 'package:excelso_attendance/main.dart'; import 'package:excelso_attendance/main.dart';
import 'package:excelso_attendance/models/absent.dart'; import 'package:excelso_attendance/models/absent.dart';
...@@ -26,6 +27,7 @@ import 'package:excelso_attendance/resource/size.dart'; ...@@ -26,6 +27,7 @@ import 'package:excelso_attendance/resource/size.dart';
import 'package:excelso_attendance/resource/style.dart'; import 'package:excelso_attendance/resource/style.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
// import 'package:quiver/async.dart';
class AbsentCameraView extends StatefulWidget { class AbsentCameraView extends StatefulWidget {
const AbsentCameraView({ const AbsentCameraView({
...@@ -62,6 +64,8 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -62,6 +64,8 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
// bool isPermissionAccept = true; // bool isPermissionAccept = true;
// String? errorCamera; // String? errorCamera;
bool isCameraLoading = true;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
...@@ -82,6 +86,10 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -82,6 +86,10 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
void initStateFunc() { void initStateFunc() {
getCameraDescrption().then((value) { getCameraDescrption().then((value) {
cameras = value; cameras = value;
if (debug) {
// ignore: avoid_print
print("JUMLAH CAMERA TEDETEKSI: ${cameras!.length}");
}
if (cameras!.length > 1) { if (cameras!.length > 1) {
_cameraDescription = cameras![1]; _cameraDescription = cameras![1];
} else { } else {
...@@ -100,12 +108,76 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -100,12 +108,76 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
// Define the resolution to use. // Define the resolution to use.
ResolutionPreset.medium, ResolutionPreset.medium,
imageFormatGroup: ImageFormatGroup.jpeg, imageFormatGroup: ImageFormatGroup.jpeg,
enableAudio: false,
);
initCamera(_controller!);
}
}).catchError((e) {
if (e is CameraException) {
switch (e.code) {
case 'CameraAccessDenied':
// setState(() {
// isPermissionAccept = false;
// });
Navigator.pushNamedAndRemoveUntil(
context,
Routes.errorWidget,
(route) => false,
arguments: ErrorWidgetArguments(
errorMessage: Strings.cameraNotActive,
),
);
default:
// setState(() {
// errorCamera = "$e";
// });
// Navigator.pushNamedAndRemoveUntil(
// context,
// Routes.errorWidget,
// (route) => false,
// arguments: ErrorWidgetArguments(
// errorMessage: "ERROR: $e",
// ),
// );
modalDialogGlobal(
context: context,
size: MediaQuery.of(context).size,
title: "Error",
contentBody: "$e",
buttonText: "OK",
tapButton: () {
Navigator.pop(context);
},
);
if (debug) {
// ignore: avoid_print
print("CAMERA PERMISSION PROB ERROR: $e");
}
}
}
});
}
Future<void> initCamera(CameraController c) async {
c.initialize().then((_) {
if (!mounted) {
Navigator.pushNamedAndRemoveUntil(
context,
Routes.errorWidget,
(route) => false,
arguments: ErrorWidgetArguments(
errorMessage: Strings.cameraNotMounted,
),
); );
setState(() { return;
_initializeControllerFuture = _controller!.initialize();
});
} }
setState(() {
isCameraLoading = false;
});
}).catchError((e) { }).catchError((e) {
setState(() {
isCameraLoading = false;
});
if (e is CameraException) { if (e is CameraException) {
switch (e.code) { switch (e.code) {
case 'CameraAccessDenied': case 'CameraAccessDenied':
...@@ -124,6 +196,25 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -124,6 +196,25 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
// setState(() { // setState(() {
// errorCamera = "$e"; // errorCamera = "$e";
// }); // });
// Navigator.pushNamedAndRemoveUntil(
// context,
// Routes.errorWidget,
// (route) => false,
// arguments: ErrorWidgetArguments(
// errorMessage: "ERROR: $e",
// ),
// );
modalDialogGlobal(
context: context,
size: MediaQuery.of(context).size,
title: "Error",
contentBody: "$e",
buttonText: "OK",
tapButton: () {
Navigator.pop(context);
},
);
if (debug) { if (debug) {
// ignore: avoid_print // ignore: avoid_print
print("CAMERA PERMISSION PROB ERROR: $e"); print("CAMERA PERMISSION PROB ERROR: $e");
...@@ -137,6 +228,32 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -137,6 +228,32 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
return await availableCameras(); return await availableCameras();
} }
// untuk mengetahui lama proses taking foto sampai response sukses
// final int _start = 10000;
// int _longTime = 0;
// CountdownTimer? countDownTimer;
// void startTimer() {
// print("START TIMER");
// countDownTimer = CountdownTimer(
// Duration(milliseconds: _start),
// const Duration(milliseconds: 1),
// );
// var sub = countDownTimer!.listen(null);
// sub.onData((duration) {
// setState(() {
// _longTime = duration.elapsed.inMilliseconds;
// });
// });
// }
// void stopTimer() {
// print("TIMER STOP");
// print("LAMA PROSES $_longTime miliseconds");
// countDownTimer!.cancel();
// }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
...@@ -153,343 +270,674 @@ class _AbsentCameraViewState extends State<AbsentCameraView> { ...@@ -153,343 +270,674 @@ class _AbsentCameraViewState extends State<AbsentCameraView> {
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// (isPermissionAccept) ? isCameraLoading
(_initializeControllerFuture != null) ? const Center(child: CircularProgressIndicator())
? FutureBuilder( : Stack(
future: _initializeControllerFuture, children: [
builder: ((context, snapshot) { Container(
if (snapshot.connectionState == ConnectionState.done) { width: size.width,
return Stack( height: size.height,
padding: EdgeInsets.only(
top: AppPadding.safeAreaTop(context) + 40),
child: (pictureIsTaken)
? (isPhone)
? Image.file(
File(imagePathPhone!),
fit: BoxFit.fill,
)
: Image.memory(
imagePath!,
// fit: BoxFit.fill,
)
: CameraPreview(
_controller!,
),
),
Container(
width: size.width,
height: size.height,
padding: EdgeInsets.only(
top: AppPadding.safeAreaTop(context) + 40),
child: Image(
fit: BoxFit.fill,
image: AssetImage(Assets.frameOverlay),
),
),
Container(
width: size.width,
height: size.height,
child: Column(
children: [ children: [
Container( Container(
width: size.width, height: AppPadding.safeAreaTop(context) + 60,
height: size.height, width: double.infinity,
padding: EdgeInsets.only( decoration: BoxDecoration(
top: AppPadding.safeAreaTop(context) + 40), borderRadius: const BorderRadius.only(
child: (pictureIsTaken) bottomRight: Radius.circular(20),
? (isPhone) bottomLeft: Radius.circular(20),
? Image.file( ),
File(imagePathPhone!), color: ColorManager.primary,
fit: BoxFit.fill,
)
: Image.memory(
imagePath!,
// fit: BoxFit.fill,
)
: CameraPreview(
_controller!,
),
),
Container(
width: size.width,
height: size.height,
padding: EdgeInsets.only(
top: AppPadding.safeAreaTop(context) + 40),
child: Image(
fit: BoxFit.fill,
image: AssetImage(Assets.frameOverlay),
), ),
), child: Container(
Container( padding: EdgeInsets.symmetric(
width: size.width, horizontal: AppPadding.p20),
height: size.height, margin: EdgeInsets.only(
child: Column( top: AppPadding.safeAreaTop(context),
children: [ ),
Container( child: Row(
height: AppPadding.safeAreaTop(context) + 60, crossAxisAlignment: CrossAxisAlignment.center,
width: double.infinity, children: [
decoration: BoxDecoration( GestureDetector(
borderRadius: const BorderRadius.only( onTap: () {
bottomRight: Radius.circular(20), Navigator.pop(context);
bottomLeft: Radius.circular(20), },
child: const Icon(
Icons.arrow_back,
color: Colors.white,
size: 24,
), ),
color: ColorManager.primary,
), ),
child: Container( Container(
padding: EdgeInsets.symmetric(
horizontal: AppPadding.p20),
margin: EdgeInsets.only( margin: EdgeInsets.only(
top: AppPadding.safeAreaTop(context), left: AppMargin.m16,
), ),
child: Row( child: Text(
crossAxisAlignment: "Verifikasi Wajah (${cameras!.length})",
CrossAxisAlignment.center, style: getBoldStyle(
color: Colors.white,
fontSize: 17,
),
),
)
],
),
),
),
const SizedBox(
height: 15,
),
WidgetAbsentAndTime(
isIn: widget.isIn,
outletName: widget.branchModel.code,
),
const Spacer(),
(pictureIsTaken)
? Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 100,
child: CustomButton(
text: "Submit",
onTap: () async {
// startTimer();
await EasyLoading.show(
status: Strings.pleaseWait,
maskType: EasyLoadingMaskType.none,
);
if (widget.isIn) {
Api.shiftIn(
widget.branchModel.id,
widget.nik,
widget.shiftModel!.id,
imageBase64!,
).then((apiResponse) {
// stopTimer();
EasyLoading.dismiss();
if (apiResponse.error) {
EasyLoading.showToast(
apiResponse.msg);
return;
}
AbsentSuccessModel absentSuccess =
apiResponse.data
as AbsentSuccessModel;
Navigator.pushNamedAndRemoveUntil(
context,
Routes.absentSuccess,
(route) => false,
arguments: AbsentSuccessArguments(
absentSuccess: absentSuccess,
isIn: true,
),
);
});
} else {
Api.shiftOut(
widget.branchModel.id,
widget.nik,
imageBase64!,
).then((apiResponse) {
// stopTimer();
EasyLoading.dismiss();
if (apiResponse.error) {
EasyLoading.showToast(
apiResponse.msg,
);
return;
}
AbsentSuccessModel absentSuccess =
apiResponse.data
as AbsentSuccessModel;
Navigator.pushNamedAndRemoveUntil(
context,
Routes.absentSuccess,
(route) => false,
arguments: AbsentSuccessArguments(
absentSuccess: absentSuccess,
isIn: false,
),
);
});
}
},
),
),
Container(
width: 100,
margin: const EdgeInsets.only(
top: 10,
),
child: GestureDetector(
onTap: () {
setState(() {
pictureIsTaken = false;
_controller = CameraController(
// Get a specific camera from the list of available cameras.
_cameraDescription!,
// Define the resolution to use.
ResolutionPreset.medium,
imageFormatGroup:
ImageFormatGroup.jpeg,
enableAudio: false,
);
initCamera(_controller!);
});
},
child: CustomButton(
text: "Foto Ulang",
colorButton: ColorManager.grey,
),
),
),
],
)
: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
GestureDetector( // GestureDetector(
onTap: () { // onTap: () {
Navigator.pop(context); // if (flashMode ==
// FlashMode.always) {
// flashMode = FlashMode.off;
// } else {
// flashMode = FlashMode.always;
// }
// setState(() {
// _controller!
// .setFlashMode(flashMode);
// });
// },
// child: Icon(
// Icons.flash_auto,
// size: 35,
// color: ColorManager.primary,
// ),
// ),
const SizedBox(
width: 100,
),
InkWell(
onTap: () async {
try {
await _initializeControllerFuture;
// ambil imagenya
XFile image = await _controller!
.takePicture();
String? imageResultPhone;
Uint8List? imageResultWeb;
if (isPhone) {
imageResultPhone = image.path;
imageResultWeb =
await image.readAsBytes();
} else {
imageResultWeb =
await image.readAsBytes();
}
// kalau gak ke ambil gak ngelakuin aksi apa2
if (!mounted) return;
setState(() {
pictureIsTaken = true;
imagePath = imageResultWeb;
imagePathPhone = imageResultPhone;
imageBase64 =
base64Encode(imageResultWeb!);
});
} catch (e) {
if (debug) {
// ignore: avoid_print
print(
"TERJADI KESALAHAAN SAAT AMBIL GAMBER, ERROR: $e");
}
}
}, },
child: const Icon( child: Container(
Icons.arrow_back, width: 80,
color: Colors.white, height: 80,
size: 24, decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(100),
border: Border.all(
width: 1.5,
color: Colors.black,
),
color: Colors.red,
),
), ),
), ),
Container( const SizedBox(
margin: EdgeInsets.only( width: 60,
left: AppMargin.m16, ),
), GestureDetector(
child: Text( onTap: () {
"Verifikasi Wajah", if (cameras!.length > 1) {
style: getBoldStyle( setState(() {
color: Colors.white, isCameraLoading = true;
fontSize: 17, if (_cameraDescription ==
), cameras![0]) {
_cameraDescription =
cameras![1];
} else {
_cameraDescription =
cameras![0];
}
_controller = CameraController(
// Get a specific camera from the list of available cameras.
_cameraDescription!,
// Define the resolution to use.
ResolutionPreset.medium,
imageFormatGroup:
ImageFormatGroup.jpeg,
enableAudio: false,
);
initCamera(_controller!);
});
} else {
EasyLoading.showToast(
"Kamera lain tidak terdeteksi");
}
},
child: Icon(
Icons.switch_camera_outlined,
size: 35,
color: ColorManager.primary,
), ),
) )
], ],
), ),
), ],
), ),
const SizedBox( const SizedBox(
height: 15, height: 30,
), )
WidgetAbsentAndTime(
isIn: widget.isIn,
outletName: widget.branchModel.code,
),
const Spacer(),
(pictureIsTaken)
? Column(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Container(
width: 100,
child: CustomButton(
text: "Submit",
onTap: () async {
await EasyLoading.show(
status: Strings.pleaseWait,
maskType:
EasyLoadingMaskType.none,
);
if (widget.isIn) {
Api.shiftIn(
widget.branchModel.id,
widget.nik,
widget.shiftModel!.id,
imageBase64!,
).then((apiResponse) {
EasyLoading.dismiss();
if (apiResponse.error) {
EasyLoading.showToast(
apiResponse.msg);
return;
}
AbsentSuccessModel
absentSuccess =
apiResponse.data
as AbsentSuccessModel;
Navigator.pushNamed(
context,
Routes.absentSuccess,
arguments:
AbsentSuccessArguments(
absentSuccess:
absentSuccess,
isIn: true,
),
);
});
} else {
Api.shiftOut(
widget.branchModel.id,
widget.nik,
imageBase64!,
).then((apiResponse) {
EasyLoading.dismiss();
if (apiResponse.error) {
EasyLoading.showToast(
apiResponse.msg,
);
return;
}
AbsentSuccessModel
absentSuccess =
apiResponse.data
as AbsentSuccessModel;
Navigator.pushNamed(
context,
Routes.absentSuccess,
arguments:
AbsentSuccessArguments(
absentSuccess:
absentSuccess,
isIn: false,
),
);
});
}
},
),
),
Container(
width: 100,
margin: const EdgeInsets.only(
top: 10,
),
child: GestureDetector(
onTap: () {
setState(() {
pictureIsTaken = false;
_controller = CameraController(
// Get a specific camera from the list of available cameras.
_cameraDescription!,
// Define the resolution to use.
ResolutionPreset.medium,
imageFormatGroup:
ImageFormatGroup.jpeg,
);
_initializeControllerFuture =
_controller!.initialize();
});
},
child: CustomButton(
text: "Foto Ulang",
colorButton: ColorManager.grey,
),
),
),
],
)
: Stack(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
// GestureDetector(
// onTap: () {
// if (flashMode ==
// FlashMode.always) {
// flashMode = FlashMode.off;
// } else {
// flashMode = FlashMode.always;
// }
// setState(() {
// _controller!
// .setFlashMode(flashMode);
// });
// },
// child: Icon(
// Icons.flash_auto,
// size: 35,
// color: ColorManager.primary,
// ),
// ),
const SizedBox(
width: 100,
),
InkWell(
onTap: () async {
try {
await _initializeControllerFuture;
// ambil imagenya
XFile image =
await _controller!
.takePicture();
String? imageResultPhone;
Uint8List? imageResultWeb;
if (isPhone) {
imageResultPhone =
image.path;
imageResultWeb = await image
.readAsBytes();
} else {
imageResultWeb = await image
.readAsBytes();
}
// kalau gak ke ambil gak ngelakuin aksi apa2
if (!mounted) return;
setState(() {
pictureIsTaken = true;
imagePath = imageResultWeb;
imagePathPhone =
imageResultPhone;
imageBase64 = base64Encode(
imageResultWeb!);
});
} catch (e) {
if (debug) {
// ignore: avoid_print
print(
"TERJADI KESALAHAAN SAAT AMBIL GAMBER, ERROR: $e");
}
}
},
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
100),
border: Border.all(
width: 1.5,
color: Colors.black,
),
color: Colors.red,
),
),
),
const SizedBox(
width: 60,
),
GestureDetector(
onTap: () {
if (cameras!.length > 1) {
setState(() {
if (_cameraDescription ==
cameras![0]) {
_cameraDescription =
cameras![1];
} else {
_cameraDescription =
cameras![0];
}
_controller =
CameraController(
// Get a specific camera from the list of available cameras.
_cameraDescription!,
// Define the resolution to use.
ResolutionPreset.medium,
imageFormatGroup:
ImageFormatGroup.jpeg,
);
_initializeControllerFuture =
_controller!
.initialize();
});
}
},
child: Icon(
Icons.switch_camera_outlined,
size: 35,
color: ColorManager.primary,
),
)
],
),
],
),
const SizedBox(
height: 30,
)
],
),
),
], ],
); ),
} else { ),
return const Center(child: CircularProgressIndicator()); ],
}
}),
) )
: const Center(child: CircularProgressIndicator()) // (isPermissionAccept) ?
// (_initializeControllerFuture != null)
// ? FutureBuilder(
// future: _initializeControllerFuture,
// builder: ((context, snapshot) {
// if (snapshot.connectionState == ConnectionState.done) {
// return Stack(
// children: [
// Container(
// width: size.width,
// height: size.height,
// padding: EdgeInsets.only(
// top: AppPadding.safeAreaTop(context) + 40),
// child: (pictureIsTaken)
// ? (isPhone)
// ? Image.file(
// File(imagePathPhone!),
// fit: BoxFit.fill,
// )
// : Image.memory(
// imagePath!,
// // fit: BoxFit.fill,
// )
// : CameraPreview(
// _controller!,
// ),
// ),
// Container(
// width: size.width,
// height: size.height,
// padding: EdgeInsets.only(
// top: AppPadding.safeAreaTop(context) + 40),
// child: Image(
// fit: BoxFit.fill,
// image: AssetImage(Assets.frameOverlay),
// ),
// ),
// Container(
// width: size.width,
// height: size.height,
// child: Column(
// children: [
// Container(
// height: AppPadding.safeAreaTop(context) + 60,
// width: double.infinity,
// decoration: BoxDecoration(
// borderRadius: const BorderRadius.only(
// bottomRight: Radius.circular(20),
// bottomLeft: Radius.circular(20),
// ),
// color: ColorManager.primary,
// ),
// child: Container(
// padding: EdgeInsets.symmetric(
// horizontal: AppPadding.p20),
// margin: EdgeInsets.only(
// top: AppPadding.safeAreaTop(context),
// ),
// child: Row(
// crossAxisAlignment:
// CrossAxisAlignment.center,
// children: [
// GestureDetector(
// onTap: () {
// Navigator.pop(context);
// },
// child: const Icon(
// Icons.arrow_back,
// color: Colors.white,
// size: 24,
// ),
// ),
// Container(
// margin: EdgeInsets.only(
// left: AppMargin.m16,
// ),
// child: Text(
// "Verifikasi Wajah (${cameras!.length})",
// style: getBoldStyle(
// color: Colors.white,
// fontSize: 17,
// ),
// ),
// )
// ],
// ),
// ),
// ),
// const SizedBox(
// height: 15,
// ),
// WidgetAbsentAndTime(
// isIn: widget.isIn,
// outletName: widget.branchModel.code,
// ),
// const Spacer(),
// (pictureIsTaken)
// ? Column(
// crossAxisAlignment:
// CrossAxisAlignment.center,
// children: [
// Container(
// width: 100,
// child: CustomButton(
// text: "Submit",
// onTap: () async {
// // startTimer();
// await EasyLoading.show(
// status: Strings.pleaseWait,
// maskType:
// EasyLoadingMaskType.none,
// );
// if (widget.isIn) {
// Api.shiftIn(
// widget.branchModel.id,
// widget.nik,
// widget.shiftModel!.id,
// imageBase64!,
// ).then((apiResponse) {
// // stopTimer();
// EasyLoading.dismiss();
// if (apiResponse.error) {
// EasyLoading.showToast(
// apiResponse.msg);
// return;
// }
// AbsentSuccessModel
// absentSuccess =
// apiResponse.data
// as AbsentSuccessModel;
// Navigator
// .pushNamedAndRemoveUntil(
// context,
// Routes.absentSuccess,
// (route) => false,
// arguments:
// AbsentSuccessArguments(
// absentSuccess:
// absentSuccess,
// isIn: true,
// ),
// );
// });
// } else {
// Api.shiftOut(
// widget.branchModel.id,
// widget.nik,
// imageBase64!,
// ).then((apiResponse) {
// // stopTimer();
// EasyLoading.dismiss();
// if (apiResponse.error) {
// EasyLoading.showToast(
// apiResponse.msg,
// );
// return;
// }
// AbsentSuccessModel
// absentSuccess =
// apiResponse.data
// as AbsentSuccessModel;
// Navigator
// .pushNamedAndRemoveUntil(
// context,
// Routes.absentSuccess,
// (route) => false,
// arguments:
// AbsentSuccessArguments(
// absentSuccess:
// absentSuccess,
// isIn: false,
// ),
// );
// });
// }
// },
// ),
// ),
// Container(
// width: 100,
// margin: const EdgeInsets.only(
// top: 10,
// ),
// child: GestureDetector(
// onTap: () {
// setState(() {
// pictureIsTaken = false;
// _controller = CameraController(
// // Get a specific camera from the list of available cameras.
// _cameraDescription!,
// // Define the resolution to use.
// ResolutionPreset.medium,
// imageFormatGroup:
// ImageFormatGroup.jpeg,
// );
// _initializeControllerFuture =
// _controller!.initialize();
// });
// },
// child: CustomButton(
// text: "Foto Ulang",
// colorButton: ColorManager.grey,
// ),
// ),
// ),
// ],
// )
// : Stack(
// children: [
// Row(
// mainAxisAlignment:
// MainAxisAlignment.center,
// children: [
// // GestureDetector(
// // onTap: () {
// // if (flashMode ==
// // FlashMode.always) {
// // flashMode = FlashMode.off;
// // } else {
// // flashMode = FlashMode.always;
// // }
// // setState(() {
// // _controller!
// // .setFlashMode(flashMode);
// // });
// // },
// // child: Icon(
// // Icons.flash_auto,
// // size: 35,
// // color: ColorManager.primary,
// // ),
// // ),
// const SizedBox(
// width: 100,
// ),
// InkWell(
// onTap: () async {
// try {
// await _initializeControllerFuture;
// // ambil imagenya
// XFile image =
// await _controller!
// .takePicture();
// String? imageResultPhone;
// Uint8List? imageResultWeb;
// if (isPhone) {
// imageResultPhone =
// image.path;
// imageResultWeb = await image
// .readAsBytes();
// } else {
// imageResultWeb = await image
// .readAsBytes();
// }
// // kalau gak ke ambil gak ngelakuin aksi apa2
// if (!mounted) return;
// setState(() {
// pictureIsTaken = true;
// imagePath = imageResultWeb;
// imagePathPhone =
// imageResultPhone;
// imageBase64 = base64Encode(
// imageResultWeb!);
// });
// } catch (e) {
// if (debug) {
// // ignore: avoid_print
// print(
// "TERJADI KESALAHAAN SAAT AMBIL GAMBER, ERROR: $e");
// }
// }
// },
// child: Container(
// width: 80,
// height: 80,
// decoration: BoxDecoration(
// borderRadius:
// BorderRadius.circular(
// 100),
// border: Border.all(
// width: 1.5,
// color: Colors.black,
// ),
// color: Colors.red,
// ),
// ),
// ),
// const SizedBox(
// width: 60,
// ),
// GestureDetector(
// onTap: () {
// if (cameras!.length > 1) {
// setState(() {
// if (_cameraDescription ==
// cameras![0]) {
// _cameraDescription =
// cameras![1];
// } else {
// _cameraDescription =
// cameras![0];
// }
// _controller =
// CameraController(
// // Get a specific camera from the list of available cameras.
// _cameraDescription!,
// // Define the resolution to use.
// ResolutionPreset.medium,
// imageFormatGroup:
// ImageFormatGroup.jpeg,
// );
// _initializeControllerFuture =
// _controller!
// .initialize();
// });
// } else {
// EasyLoading.showToast(
// "Kamera lain tidak terdeteksi");
// }
// },
// child: Icon(
// Icons.switch_camera_outlined,
// size: 35,
// color: ColorManager.primary,
// ),
// )
// ],
// ),
// ],
// ),
// const SizedBox(
// height: 30,
// )
// ],
// ),
// ),
// ],
// );
// } else {
// return const Center(child: CircularProgressIndicator());
// }
// }),
// )
// : const Center(child: CircularProgressIndicator())
// : Center( // : Center(
// child: Padding( // child: Padding(
// padding: EdgeInsets.symmetric( // padding: EdgeInsets.symmetric(
......
...@@ -6,9 +6,11 @@ import 'package:excelso_attendance/helper/arguments/route_args.dart'; ...@@ -6,9 +6,11 @@ import 'package:excelso_attendance/helper/arguments/route_args.dart';
import 'package:excelso_attendance/helper/component/button.dart'; import 'package:excelso_attendance/helper/component/button.dart';
// import 'package:excelso_attendance/helper/component/text_field.dart'; // import 'package:excelso_attendance/helper/component/text_field.dart';
import 'package:excelso_attendance/helper/global_function/date_time.dart'; import 'package:excelso_attendance/helper/global_function/date_time.dart';
import 'package:excelso_attendance/helper/modal_dialog.dart';
import 'package:excelso_attendance/helper/pref.dart'; import 'package:excelso_attendance/helper/pref.dart';
import 'package:excelso_attendance/helper/widget_responsive.dart'; import 'package:excelso_attendance/helper/widget_responsive.dart';
import 'package:excelso_attendance/models/branch.dart'; import 'package:excelso_attendance/models/branch.dart';
import 'package:excelso_attendance/models/profile.dart';
import 'package:excelso_attendance/models/shift.dart'; import 'package:excelso_attendance/models/shift.dart';
import 'package:excelso_attendance/resource/assets.dart'; import 'package:excelso_attendance/resource/assets.dart';
import 'package:excelso_attendance/resource/colors.dart'; import 'package:excelso_attendance/resource/colors.dart';
...@@ -349,8 +351,42 @@ class _BodyWidgetState extends State<BodyWidget> { ...@@ -349,8 +351,42 @@ class _BodyWidgetState extends State<BodyWidget> {
).then((apiResponse) { ).then((apiResponse) {
EasyLoading.dismiss(); EasyLoading.dismiss();
if (apiResponse.error) { if (apiResponse.error) {
EasyLoading.showToast(apiResponse.msg); modalDialogGlobal(
context: context,
size: MediaQuery.of(context).size,
title: "Gagal",
contentBody: apiResponse.msg,
buttonText: "Ok",
tapButton: () {
Navigator.pop(context);
});
} else { } else {
ProfileModel profileUser =
apiResponse.data as ProfileModel;
if (profileUser.attendanceOut) {
modalDialogGlobal(
context: context,
size: MediaQuery.of(context).size,
title: "Gagal",
contentBody: Strings.alreadyOut,
buttonText: "Ok",
tapButton: () {
Navigator.pop(context);
});
return;
}
if (profileUser.attendanceIn == false) {
modalDialogGlobal(
context: context,
size: MediaQuery.of(context).size,
title: "Gagal",
contentBody: Strings.outButNotIn,
buttonText: "Ok",
tapButton: () {
Navigator.pop(context);
});
return;
}
Navigator.pushNamed( Navigator.pushNamed(
context, context,
Routes.absentCamera, Routes.absentCamera,
...@@ -966,8 +1002,30 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> { ...@@ -966,8 +1002,30 @@ class _WidgetSelectShiftState extends State<WidgetSelectShift> {
EasyLoading.dismiss(); EasyLoading.dismiss();
if (apiResponse.error) { if (apiResponse.error) {
Navigator.pop(context); Navigator.pop(context);
EasyLoading.showToast(apiResponse.msg); modalDialogGlobal(
context: context,
size: MediaQuery.of(context).size,
title: "Gagal",
contentBody: apiResponse.msg,
buttonText: "Ok",
tapButton: () {
Navigator.pop(context);
});
} else { } else {
ProfileModel profileUser = apiResponse.data as ProfileModel;
if (profileUser.attendanceIn) {
modalDialogGlobal(
context: context,
size: MediaQuery.of(context).size,
title: "Gagal",
contentBody: Strings.alreadyIn,
buttonText: "Ok",
tapButton: () {
Navigator.pop(context);
Navigator.pop(context);
});
return;
}
Navigator.popAndPushNamed( Navigator.popAndPushNamed(
context, context,
Routes.absentCamera, Routes.absentCamera,
......
...@@ -157,184 +157,187 @@ class BodyWidget extends StatelessWidget { ...@@ -157,184 +157,187 @@ class BodyWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SingleChildScrollView( Size size = MediaQuery.of(context).size;
child: Column( return Column(
children: [ children: [
Container( Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: ColorManager.primary, color: ColorManager.primary,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(50), bottomLeft: Radius.circular(50),
bottomRight: Radius.circular(50), bottomRight: Radius.circular(50),
),
), ),
child: Column( ),
mainAxisSize: MainAxisSize.min, child: Column(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min,
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Container( children: [
padding: EdgeInsets.only( Container(
top: AppPadding.safeAreaTop(context) + 38, padding: EdgeInsets.only(
left: AppPadding.p20, top: AppPadding.safeAreaTop(context) + 38,
right: AppPadding.p20, left: AppPadding.p20,
), right: AppPadding.p20,
child: Center(
child: Image(
width: 119,
height: 46,
image: AssetImage(Assets.excelso),
),
),
), ),
Container( child: Center(
padding: EdgeInsets.symmetric(
horizontal: AppPadding.p20,
),
margin: EdgeInsets.only(
top: AppMargin.m16,
),
width: double.infinity,
height: 332,
child: Image( child: Image(
fit: BoxFit.fill, width: 119,
image: AssetImage( height: 46,
Assets.onboarding, image: AssetImage(Assets.excelso),
),
), ),
), ),
Container( ),
padding: const EdgeInsets.symmetric( Container(
horizontal: 40, padding: EdgeInsets.symmetric(
), horizontal: AppPadding.p20,
margin: const EdgeInsets.only( ),
top: 32, margin: EdgeInsets.only(
bottom: 59, top: AppMargin.m16,
),
width: double.infinity,
height: size.height * 0.37,
child: Image(
fit: BoxFit.fill,
image: AssetImage(
Assets.onboarding,
), ),
child: Column( ),
crossAxisAlignment: CrossAxisAlignment.start, ),
children: [ Container(
Text( padding: const EdgeInsets.symmetric(
"Attendance", horizontal: 40,
style: getSemiBoldStyle( ),
color: Colors.white, margin: const EdgeInsets.only(
fontSize: 24, top: 32,
fontFamily: FontConstants.montserrat, bottom: 59,
), ),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Attendance",
style: getSemiBoldStyle(
color: Colors.white,
fontSize: 24,
fontFamily: FontConstants.montserrat,
), ),
Text( ),
'''Memudahkan anda melakukan absen Text(
'''Memudahkan anda melakukan absen
dengan sekali klik''', dengan sekali klik''',
style: getRegularStyle( style: getRegularStyle(
color: Colors.white, color: Colors.white,
fontSize: 12, fontSize: 12,
), ),
) )
], ],
), ),
) )
], ],
),
), ),
GestureDetector( ),
onTap: () { GestureDetector(
if (getAllApi) { onTap: () {
Navigator.pushNamed( if (getAllApi) {
context, Navigator.pushNamed(
Routes.home, context,
arguments: HomeArguments( Routes.home,
branchModel: nearestBranch, arguments: HomeArguments(
shiftModel: shiftList, branchModel: nearestBranch,
), shiftModel: shiftList,
); ),
} );
}, }
child: Container( },
margin: const EdgeInsets.only( child: Container(
top: 60, margin: EdgeInsets.only(
), top: size.height * 0.05,
padding: EdgeInsets.symmetric( ),
horizontal: AppPadding.p20, padding: EdgeInsets.symmetric(
), horizontal: AppPadding.p20,
child: Center( ),
child: (getAllApi) child: Center(
? (errorMessage == null) child: (getAllApi)
? Container( ? (errorMessage == null)
width: 60, ? Container(
height: 60, width: 60,
decoration: BoxDecoration( height: 60,
borderRadius: BorderRadius.circular(100), decoration: BoxDecoration(
color: ColorManager.primary, borderRadius: BorderRadius.circular(100),
color: ColorManager.primary,
),
child: const Center(
child: Icon(
Icons.arrow_forward_ios_rounded,
color: Colors.white,
size: 23,
), ),
child: const Center( ),
child: Icon( )
Icons.arrow_forward_ios_rounded, : Column(
color: Colors.white, children: [
size: 23, Text(
errorMessage!,
style: getSemiBoldStyle(
color: Colors.black,
fontSize: 16,
), ),
textAlign: TextAlign.center,
), ),
) (errorMessage == Strings.cantConnectToServer)
: Column( ? GestureDetector(
children: [ onTap: () {
Text( Navigator.pushNamedAndRemoveUntil(
errorMessage!, context,
style: getSemiBoldStyle( Routes.onBoarding,
color: Colors.black, (route) => false,
fontSize: 16, );
), },
textAlign: TextAlign.center, child: Container(
), width: 60,
(errorMessage == Strings.cantConnectToServer) height: 60,
? GestureDetector( margin: EdgeInsets.only(
onTap: () { top: AppMargin.m10,
Navigator.pushNamedAndRemoveUntil( ),
context, decoration: BoxDecoration(
Routes.onBoarding, borderRadius:
(route) => false, BorderRadius.circular(100),
); color: ColorManager.primary,
}, ),
child: Container( child: const Center(
width: 60, child: Icon(
height: 60, Icons.refresh_rounded,
margin: EdgeInsets.only( color: Colors.white,
top: AppMargin.m10, size: 23,
),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(100),
color: ColorManager.primary,
),
child: const Center(
child: Icon(
Icons.refresh_rounded,
color: Colors.white,
size: 23,
),
), ),
), ),
) ),
: const SizedBox(), )
], : const SizedBox(),
) ],
: CircularProgressIndicator( )
color: ColorManager.primary, : CircularProgressIndicator(
), color: ColorManager.primary,
), ),
), ),
), ),
Container( ),
margin: const EdgeInsets.only( const Spacer(),
top: 30, Container(
), margin: const EdgeInsets.only(
child: Text( top: 30,
"Since © 2023", ),
style: getMediumStyle( child: Text(
color: Colors.black, "Since © 2023",
), style: getMediumStyle(
color: Colors.black,
), ),
) ),
], ),
), SizedBox(
height: AppMargin.m10,
)
],
); );
} }
} }
...@@ -13,4 +13,9 @@ class Strings { ...@@ -13,4 +13,9 @@ class Strings {
static String serverError = "Something wrong with our server, refresh page"; static String serverError = "Something wrong with our server, refresh page";
static String succesGetData = "Success get data"; static String succesGetData = "Success get data";
static String pleaseWait = "Please wait..."; static String pleaseWait = "Please wait...";
static String cameraNotMounted = "Kamera tidak berhasil di load";
static String alreadyIn = "Anda sudah melakukan absen masuk hari ini";
static String alreadyOut = "Anda sudah melakukan absen keluar hari ini";
static String outButNotIn = "Anda belum melaukan absen masuk";
} }
...@@ -74,7 +74,7 @@ packages: ...@@ -74,7 +74,7 @@ packages:
source: hosted source: hosted
version: "2.5.1" version: "2.5.1"
camera_web: camera_web:
dependency: transitive dependency: "direct main"
description: description:
name: camera_web name: camera_web
sha256: bcbd775fb3a9d51cc3ece899d54ad66f6306410556bac5759f78e13f9228841f sha256: bcbd775fb3a9d51cc3ece899d54ad66f6306410556bac5759f78e13f9228841f
...@@ -425,7 +425,7 @@ packages: ...@@ -425,7 +425,7 @@ packages:
source: hosted source: hosted
version: "4.2.4" version: "4.2.4"
quiver: quiver:
dependency: transitive dependency: "direct main"
description: description:
name: quiver name: quiver
sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
......
...@@ -31,6 +31,7 @@ environment: ...@@ -31,6 +31,7 @@ environment:
dependencies: dependencies:
autocomplete_textfield: ^2.0.1 autocomplete_textfield: ^2.0.1
camera: ^0.10.5+2 camera: ^0.10.5+2
camera_web: ^0.3.1+4
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
dropdown_button2: ^2.1.3 dropdown_button2: ^2.1.3
flutter: flutter:
...@@ -39,6 +40,7 @@ dependencies: ...@@ -39,6 +40,7 @@ dependencies:
flutter_native_splash: ^2.3.0 flutter_native_splash: ^2.3.0
geolocator: ^9.0.2 geolocator: ^9.0.2
http: ^0.13.5 http: ^0.13.5
quiver: ^3.2.1
shared_preferences: ^2.1.1 shared_preferences: ^2.1.1
url_strategy: ^0.2.0 url_strategy: ^0.2.0
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
This is a placeholder for base href that will be replaced by the value of This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`. the `--base-href` argument provided to `flutter build`.
--> -->
<base href="$FLUTTER_BASE_HREF" /> <base href="/attendance/" />
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta content="IE=Edge" http-equiv="X-UA-Compatible" /> <meta content="IE=Edge" http-equiv="X-UA-Compatible" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment