import 'package:absensi_sas_flutter/screen/presensi/check_distance_provider.dart'; import 'package:absensi_sas_flutter/widget/real_date.dart'; import 'package:absensi_sas_flutter/widget/sankbar_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:geocoding/geocoding.dart'; import 'package:geolocator/geolocator.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:permission_handler/permission_handler.dart'; import '../../app/constant.dart'; import '../../app/route.dart'; import '../../provider/current_check_distance_provider.dart'; import '../../provider/current_user_provider.dart'; import '../../widget/real_time.dart'; class PresensiScreen extends HookConsumerWidget { const PresensiScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final currentAddressUserLocation = useState(""); final isLoadingAddressUserLocation = useState(false); final isLoadingProsesCheckDistance = useState(false); final varCurrentDistanceProvider = ref.watch(currentCheckDistanceProvider); final selectedUser = ref.read(currentUserProvider); final positionLatitude = useState(""); final positionLongitude = useState(""); // final tTransactionCurrentDistance = useState("NULL"); Future getAddressFromLocation() async { try { isLoadingAddressUserLocation.value = true; // Mendapatkan posisi pengguna LocationPermission permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { isLoadingAddressUserLocation.value = false; SanckbarWidget(context, 'Izin lokasi ditolak', snackbarType.error); // Handle jika pengguna menolak izin lokasi print("Izin lokasi ditolak"); return; } Position position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high); // Mendapatkan alamat dari posisi List placemarks = await placemarkFromCoordinates( position.latitude, position.longitude); if (positionLongitude.value.isEmpty && positionLatitude.value.isEmpty) { if (placemarks.isNotEmpty) { isLoadingAddressUserLocation.value = false; Placemark placemark = placemarks.first; // String address = // "${placemark.thoroughfare}, ${placemark.locality}, ${placemark.administrativeArea}, ${placemark.country},"; String address = "${placemark.street}, ${placemark.subLocality}, ${placemark.subAdministrativeArea}, ${placemark.postalCode}"; print("Alamat: $address"); positionLatitude.value = position.latitude.toString(); positionLongitude.value = position.longitude.toString(); if (address != "") { currentAddressUserLocation.value = address; } } else { isLoadingAddressUserLocation.value = false; SanckbarWidget( context, 'Tidak dapat menemukan alamat.', snackbarType.error); print("Tidak dapat menemukan alamat."); } } else { // jika sudah dapat latitude dan logitude baru panggil check distance provider if (positionLatitude.value.isNotEmpty && positionLongitude.value.isNotEmpty) { print('check distance provider'); // panggil check distance provider ref.read(checkDistanceProvider.notifier).checkDistance( selectedUser?.model.staffId ?? "", selectedUser?.model.companyId ?? "", positionLatitude.value, positionLongitude.value, ); } } } catch (e) { print("Error: $e"); isLoadingAddressUserLocation.value = false; SanckbarWidget(context, 'Error : $e', snackbarType.error); } } Future requestLocationPermission() async { var status = await Permission.location.request(); isLoadingAddressUserLocation.value = true; if (status.isGranted) { // Izin diberikan, lanjutkan dengan mendapatkan lokasi getAddressFromLocation(); } else { isLoadingAddressUserLocation.value = false; // Izin ditolak, berikan pemberitahuan atau instruksi // print('Izin lokasi ditolak'); SanckbarWidget(context, 'Izin Ditolak', snackbarType.error); } } // check distance provider ref.listen(checkDistanceProvider, (prev, next) { print('status check distance ' + next.toString()); if (next is CheckDistanceStateLoading) { isLoadingProsesCheckDistance.value = true; } else if (next is CheckDistanceStateError) { isLoadingProsesCheckDistance.value = false; SanckbarWidget(context, next.message, snackbarType.warning); } else if (next is CheckDistanceStateDone) { isLoadingProsesCheckDistance.value = false; // tTransactionCurrentDistance.value = // varCurrentDistanceProvider?.currentDistance ?? ""; // print("distance XXX : "+tTransactionCurrentDistance.value); if (varCurrentDistanceProvider?.selfie == "TRUE") { Navigator.pushNamed(context, presensiSelfieRoute); } } }); useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0"; if (staffID == "0") { //not login Navigator.of(context) .pushNamedAndRemoveUntil(loginRoute, (route) => true); // Navigator.popAndPushNamed(context, loginRoute); return; } // requestLocationPermission(); }); return () {}; }, []); useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { requestLocationPermission(); // // jika sudah dapat latitude dan logitude baru panggil check distance provider // if (positionLatitude.value.isNotEmpty && // positionLongitude.value.isNotEmpty) { // // panggil check distance provider // ref.read(checkDistanceProvider.notifier).checkDistance( // selectedUser?.model.staffId ?? "", // selectedUser?.model.companyId ?? "", // positionLatitude.value, // positionLongitude.value, // ); // } }); return () {}; }, []); // show konfirmasi dialog Future showConfirmationDialog( BuildContext context, String T_TransactionM_StaffID, String T_TransactionM_CompanyID, String T_TransactionCurrentLatitude, String T_TransactionCurrentLongitude, String T_TransactionCurrentDistance, String T_TransactionSelfiePhoto, String token, ) async { return showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('Konfirmasi'), content: Text('Apakah anda yakin untuk melakukan Clock In?'), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), actions: [ ElevatedButton( onPressed: () { T_TransactionSelfiePhoto = ""; var param = { "T_TransactionM_StaffID": T_TransactionM_StaffID, "T_TransactionM_CompanyID": T_TransactionM_CompanyID, "T_TransactionCurrentLatitude": T_TransactionCurrentLatitude, "T_TransactionCurrentLongitude": T_TransactionCurrentLongitude, "T_TransactionCurrentDistance": T_TransactionCurrentDistance, "T_TransactionSelfiePhoto": T_TransactionSelfiePhoto, "token":token, }; print(param); Navigator.of(context).pop(); }, child: Text( 'Yakin', style: Constant.logintitle_700(context: context).copyWith( fontWeight: FontWeight.w600, color: Constant.textWhite, ), ), style: ButtonStyle( backgroundColor: MaterialStateColor.resolveWith( (st) => Constant.textOrange), shape: MaterialStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( color: Constant.textOrange, ), ), ), shadowColor: MaterialStateProperty.all(Color(0xffff48423d)), elevation: MaterialStateProperty.all(4.0), ), ), TextButton( onPressed: () { Navigator.of(context).pop(); // Tutup dialog }, style: ButtonStyle( backgroundColor: MaterialStateColor.resolveWith( (st) => Constant.textWhite), shape: MaterialStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( color: Constant.textBlack, ), ), ), shadowColor: MaterialStateProperty.all(Color(0xffff48423d)), elevation: MaterialStateProperty.all(4.0), ), child: Text( 'Batal', style: TextStyle( color: Constant.textTrueBlack, ), ), ), ], ); }, ); } return Padding( padding: EdgeInsets.only( top: Constant.getActualYPhone(context: context, y: 30), ), child: Scaffold( appBar: AppBar( title: Text( // 'Home Screen', 'Presensi', overflow: TextOverflow.ellipsis, style: TextStyle( color: Constant.textBlack, ), ), backgroundColor: Constant.textWhite, iconTheme: IconThemeData( color: Constant.textBlack, ), // elevation: 1.0, elevation: 0.5, ), body: SafeArea( child: Padding( padding: EdgeInsets.only( top: Constant.getActualYPhone(context: context, y: 58), left: Constant.getActualXPhone(context: context, x: 33), right: Constant.getActualXPhone(context: context, x: 27), ), child: Container( width: Constant.getActualXPhone(context: context, x: 390), // height: Constant.getActualYPhone(context: context, y: 844), height: MediaQuery.of(context).size.height, child: Column( children: [ // Text(ref.watch(currentCheckDistanceProvider)?.currentDistance ?? "NULL"), // Spacer(), // tanggal sekarang RealTimeFormattedDate(), SizedBox( height: Constant.getActualYPhone(context: context, y: 8), ), // jam sekarang RealTimeClock(), SizedBox( height: Constant.getActualYPhone(context: context, y: 24), ), // address dan refresh Container( width: Constant.getActualXPhone(context: context, x: 350), decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), color: Constant.bgAddressPresensi, ), child: Padding( padding: EdgeInsets.only( left: Constant.getActualXPhone(context: context, x: 12), right: Constant.getActualXPhone(context: context, x: 12), top: Constant.getActualYPhone(context: context, y: 12), bottom: Constant.getActualYPhone(context: context, y: 12), ), child: Row( children: [ // Bagian kiri Padding( padding: EdgeInsets.only(left: 12, right: 8), child: Column( children: [ Icon( Icons.location_on_outlined, color: Constant.textDarkGrey, ), ], ), ), // Bagian tengah Expanded( child: Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: Column( children: [ (isLoadingAddressUserLocation.value) ? Center( child: CircularProgressIndicator(), ) : Text( // 'Perumahan Grand House of Klodran No. 5, Klodran, Kec. Colomadu, Kabupaten Karanganyar, Jawa Tengah 57172', currentAddressUserLocation.value, overflow: TextOverflow.ellipsis, maxLines: 10, style: Constant.titleH2_400_12( context: context) .copyWith( color: Constant.textDarkGrey, ), ), ], ), ), ), // Bagian kanan Padding( padding: EdgeInsets.only(right: 12), child: Column( children: [ InkWell( onTap: () async { getAddressFromLocation(); // jika sudah dapat latitude dan logitude baru panggil check distance provider if (positionLatitude.value.isNotEmpty && positionLongitude.value.isNotEmpty) { // panggil check distance provider ref .read(checkDistanceProvider.notifier) .checkDistance( selectedUser?.model.staffId ?? "", selectedUser?.model.companyId ?? "", positionLatitude.value, positionLongitude.value, ); } }, child: Container( width: Constant.getActualXPhone( context: context, x: 36), height: Constant.getActualYPhone( context: context, y: 36), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: Constant.textOrange, ), child: Image.asset( 'images/sync_white.png', // Path gambar untuk "Refresh" width: Constant.getActualXPhone( context: context, x: 20), height: Constant.getActualYPhone( context: context, y: 20), ), ), ), ], ), ), ], ), ), ), SizedBox( height: Constant.getActualYPhone(context: context, y: 50), ), // gambar icon presensi Container( width: Constant.getActualXPhone(context: context, x: 130), height: Constant.getActualYPhone(context: context, y: 130), child: FittedBox( child: FloatingActionButton( onPressed: () async { final T_TransactionM_StaffID = selectedUser?.model.staffId ?? ""; final T_TransactionM_CompanyID = selectedUser?.model.companyId ?? ""; final T_TransactionCurrentLatitude = positionLatitude.value; final T_TransactionCurrentLongitude = positionLongitude.value; final T_TransactionCurrentDistance = varCurrentDistanceProvider?.currentDistance ?? ""; final T_TransactionSelfiePhoto = ""; final token = selectedUser?.token ?? ""; showConfirmationDialog( context, T_TransactionM_StaffID, T_TransactionM_CompanyID, T_TransactionCurrentLatitude, T_TransactionCurrentLongitude, T_TransactionCurrentDistance, T_TransactionSelfiePhoto, token, ); }, backgroundColor: Color(0xFFFFFFFF), shape: CircleBorder(), child: Container( width: Constant.getActualXPhone( context: context, x: 130), height: Constant.getActualYPhone( context: context, y: 130), decoration: BoxDecoration( image: DecorationImage( // fit: BoxFit.cover, image: AssetImage( 'images/presensi_finger2.png'), // Ganti dengan path gambar Anda ), ), ), ), ), ), // Container( // width: Constant.getActualXPhone(context: context, x: 100), // height: Constant.getActualYPhone(context: context, y: 200), // decoration: BoxDecoration( // image: DecorationImage( // fit: BoxFit.cover, // image: AssetImage( // 'images/presensi_finger1.png'), // Ganti dengan path gambar Anda // ), // ), // ), Spacer(), // Expanded( // child: SizedBox(), // ), // clock in & clock out Padding( padding: EdgeInsets.only( left: Constant.getActualXPhone(context: context, x: 70), right: Constant.getActualXPhone(context: context, x: 70), // top: // Constant.getActualYPhone(context: context, y: 12), bottom: Constant.getActualYPhone(context: context, y: 55), ), child: Container( width: Constant.getActualXPhone(context: context, x: 390), // color: Colors.amber, child: Row( children: [ Column( children: [ Image.asset( 'images/clockin_presensi.png', // Path gambar untuk "Clock In" width: Constant.getActualXPhone( context: context, x: 22), height: Constant.getActualYPhone( context: context, y: 22), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 8), ), Text( '--:--', style: Constant.titlePresensiH2_700( context: context) .copyWith( color: Constant.textTrueBlack, ), ), Text( 'Clock In', style: Constant.titleH2_700(context: context) .copyWith( color: Constant.textTrueBlack, ), ), ], ), Spacer(), Column( children: [ Image.asset( 'images/clockout_presensi.png', // Path gambar untuk "Check In" width: Constant.getActualXPhone( context: context, x: 22), height: Constant.getActualYPhone( context: context, y: 22), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 8), ), Text( '--:--', style: Constant.titlePresensiH2_700( context: context) .copyWith( color: Constant.textTrueBlack, ), ), Text( 'Clock Out', style: Constant.titleH2_700(context: context) .copyWith( color: Constant.textTrueBlack, ), ), ], ), ], ), ), ), ], ), ), ), ), // bottomNavigationBar: Container( // width: Constant.getActualXPhone(context: context, x: 390), // height: Constant.getActualYPhone(context: context, y: 84), // decoration: BoxDecoration( // color: Color(0xFFFFFFFF), // boxShadow: [ // BoxShadow( // offset: Offset(0, -1), // blurRadius: 8, // spreadRadius: -8, // color: Color.fromRGBO(0, 0, 0, 0.10), // ), // ], // ), // child: Row( // children: [ // Expanded( // child: Container( // child: Column( // children: [ // Image.asset( // 'images/clockin_presensi.png', // Path gambar untuk "Clock In" // width: Constant.getActualXPhone(context: context, x: 22), // height: Constant.getActualYPhone(context: context, y: 22), // ), // SizedBox( // height: Constant.getActualYPhone(context: context, y: 8), // ), // Text( // '--:--', // style: Constant.titlePresensiH2_700(context: context) // .copyWith( // color: Constant.textTrueBlack, // ), // ), // Text( // 'Clock In', // style: Constant.titleH2_700(context: context).copyWith( // color: Constant.textTrueBlack, // ), // ), // ], // ), // )), // Expanded( // child: Container( // child: Column( // children: [ // Image.asset( // 'images/clockout_presensi.png', // Path gambar untuk "Check In" // width: Constant.getActualXPhone(context: context, x: 22), // height: Constant.getActualYPhone(context: context, y: 22), // ), // SizedBox( // height: Constant.getActualYPhone(context: context, y: 8), // ), // Text( // '--:--', // style: Constant.titlePresensiH2_700(context: context) // .copyWith( // color: Constant.textTrueBlack, // ), // ), // Text( // 'Clock Out', // style: Constant.titleH2_700(context: context).copyWith( // color: Constant.textTrueBlack, // ), // ), // ], // ), // )), // ], // ), // ), ), ); } }