import 'package:absensi_sas_flutter/app/constant.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:google_sign_in/google_sign_in.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:permission_handler/permission_handler.dart'; import '../../app/route.dart'; import '../../provider/current_check_distance_provider.dart'; import '../../provider/current_check_jam_presensi_provider.dart'; import '../../provider/current_menu_provider.dart'; import '../../provider/current_user_provider.dart'; import '../../provider/google_login_provider.dart'; import '../../widget/custom_drawer.dart'; import '../../widget/real_date.dart'; import '../../widget/real_time.dart'; import '../../widget/sankbar_widget.dart'; import '../presensi/check_distance_provider.dart'; import '../presensi/check_presensi_jam_provider.dart'; class HomeScreen extends HookConsumerWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final selectedUser = ref.read(currentUserProvider); final isLoadingProsesCheckDistance = useState(false); final varCurrentDistanceProvider = ref.watch(currentCheckDistanceProvider); final varCurrentCheckJamProvider = ref.watch(currentCheckJamPresensiProvider); final positionLatitude = useState(""); final positionLongitude = useState(""); GoogleSignInAccount? currentUserGoogle = ref.watch(currentUserGoogleProvider); 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; } }); return () {}; }, []); useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0"; if (staffID != "0") { // panggil check jam presensi provider Map inpVariablesCheckPresensiJam = { "M_StaffID": selectedUser?.model.staffId ?? "", "M_CompanyID": selectedUser?.model.companyId ?? "", "token": selectedUser?.token ?? "", }; ref.read(checkPresensiJamProvider.notifier).checkPresensiJam( selectedUser?.model.staffId ?? "", selectedUser?.model.companyId ?? "", selectedUser?.token ?? "", inpVariablesCheckPresensiJam, ); } }); return () {}; }, []); Future getAddressFromLocation() async { try { isLoadingProsesCheckDistance.value = true; // Mendapatkan posisi pengguna LocationPermission permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { isLoadingProsesCheckDistance.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 (placemarks.isNotEmpty) { isLoadingProsesCheckDistance.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(); // panggil check distance provider ref.read(checkDistanceProvider.notifier).checkDistance( selectedUser?.model.staffId ?? "", selectedUser?.model.companyId ?? "", positionLatitude.value, positionLongitude.value, ); } else { isLoadingProsesCheckDistance.value = false; SanckbarWidget( context, 'Tidak dapat menemukan alamat.', snackbarType.error); print("Tidak dapat menemukan alamat."); } } catch (e) { print("Error: $e"); isLoadingProsesCheckDistance.value = false; SanckbarWidget(context, 'Error : $e', snackbarType.error); } } Future requestLocationPermission() async { var status = await Permission.location.request(); isLoadingProsesCheckDistance.value = true; if (status.isGranted) { // Izin diberikan, lanjutkan dengan mendapatkan lokasi getAddressFromLocation(); } else { isLoadingProsesCheckDistance.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) { 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; if (varCurrentDistanceProvider?.selfie == "TRUE") { ref.read(currentPageProvider.notifier).update((state) => -1); Navigator.pushNamed(context, presensiSelfieRoute); } else { if (varCurrentDistanceProvider?.selfie == "FALSE") { ref.read(currentPageProvider.notifier).update((state) => -1); Navigator.pushNamed(context, presensiRoute); } } } }); // check jam presensi ref.listen(checkPresensiJamProvider, (prev, next) { if (next is CheckPresensiJamStateLoading) { isLoadingProsesCheckDistance.value = true; } else if (next is CheckPresensiJamStateError) { isLoadingProsesCheckDistance.value = false; print("Error : " + next.toString()); SanckbarWidget( context, "Error : " + next.toString(), snackbarType.warning); } else if (next is CheckPresensiJamStateDone) { isLoadingProsesCheckDistance.value = false; } }); return Scaffold( floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButton: Container( width: Constant.getActualXPhone(context: context, x: 100), height: Constant.getActualYPhone(context: context, y: 100), child: FittedBox( child: (isLoadingProsesCheckDistance.value) ? SizedBox( width: Constant.getActualXPhone(context: context, x: 50), height: Constant.getActualYPhone(context: context, y: 50), child: Center( child: CircularProgressIndicator( color: Constant.textOrange, ), ), ) : FloatingActionButton( onPressed: () async { requestLocationPermission(); }, backgroundColor: Color(0xFFFFFFFF), shape: CircleBorder(), child: Container( width: Constant.getActualXPhone(context: context, x: 50), height: Constant.getActualYPhone(context: context, y: 50), decoration: BoxDecoration( image: DecorationImage( image: AssetImage( 'images/finger_tap_orange_botnav.png'), // Ganti dengan path gambar Anda ), ), ), ), ), ), 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( mainAxisAlignment: MainAxisAlignment.center, children: [ Image( image: AssetImage('images/home_orange.png'), ), Text( 'Beranda', style: Constant.subtitle_500_12(context: context).copyWith( color: Constant.textOrange, ), ) ], ), )), Expanded( child: Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image( image: AssetImage('images/person_grey.png'), ), Text( 'Profile', style: Constant.subtitle_500_12(context: context).copyWith( color: Constant.textLightGrey, ), ) ], ), )), ], ), ), body: SafeArea( child: SingleChildScrollView( child: Container( width: Constant.getActualXPhone(context: context, x: 390), // height: Constant.getActualYPhone(context: context, y: 844), child: RefreshIndicator( onRefresh: () async {}, child: Column( children: [ 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( child: (currentUserGoogle == null) ? Center( child: CircularProgressIndicator(), ) : ListTile( // leading: Container( // width: Constant.getActualXPhone( // context: context, x: 36), // height: Constant.getActualYPhone( // context: context, y: 36), // child: Image( // image: AssetImage('images/avatar_c.png'), // ), // ), leading: GoogleUserCircleAvatar( identity: currentUserGoogle, ), title: Text( // "Stephen Kusumo", // selectedUser?.model.name ?? "", currentUserGoogle.displayName ?? "", overflow: TextOverflow.ellipsis, style: Constant.titleH1_700(context: context) ..copyWith( color: Constant.textBlack, ), ), subtitle: Text( // "Step@example.com", // currentUserGoogle?.email ?? "", selectedUser?.model.email ?? "", style: Constant.subtitle_500_12(context: context) .copyWith( color: Constant.textLightGrey, ), ), trailing: Container( width: Constant.getActualXPhone( context: context, x: 36), height: Constant.getActualYPhone( context: context, y: 36), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12.0), color: Colors.white, shape: BoxShape.rectangle, boxShadow: [ BoxShadow( offset: Offset(0, 12), blurRadius: 24, color: Color.fromRGBO(145, 158, 171, 0.12), ), ], ), child: IconButton( onPressed: () {}, icon: Container( width: Constant.getActualXPhone( context: context, x: 20), height: Constant.getActualYPhone( context: context, y: 20), child: Image( image: AssetImage('images/alert_badge.png'), ), ), ), ), ), ), ), SizedBox( height: Constant.getActualYPhone(context: context, y: 44), ), //Card Time Padding( padding: EdgeInsets.only( left: Constant.getActualXPhone(context: context, x: 33), right: Constant.getActualXPhone(context: context, x: 27), ), child: Container( width: Constant.getActualXPhone(context: context, x: 330), height: Constant.getActualYPhone(context: context, y: 200), decoration: BoxDecoration( borderRadius: BorderRadius.circular(40), image: DecorationImage( image: AssetImage( 'images/card_bg_1.png'), // Ganti dengan path gambar Anda fit: BoxFit.fill, // Sesuaikan cara gambar ditampilkan ), ), child: Padding( padding: EdgeInsets.only( top: Constant.getActualYPhone(context: context, y: 16), left: Constant.getActualXPhone(context: context, x: 25), right: Constant.getActualXPhone(context: context, x: 25), ), child: Container( width: Constant.getActualXPhone( context: context, x: 280), height: Constant.getActualYPhone( context: context, y: 150), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Date RealTimeFormattedDate(), SizedBox( height: Constant.getActualYPhone( context: context, y: 8), ), //Time RealTimeClock(), // Menampilkan waktu real-time menggunakan RealTimeClock SizedBox( height: Constant.getActualYPhone( context: context, y: 20), ), Row( mainAxisAlignment: MainAxisAlignment .center, // Menengahkan secara horizontal children: [ Spacer(), // Spasi di sebelah kiri "Check In" Column( children: [ Image.asset( 'images/finger_tap.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), ), (varCurrentCheckJamProvider ?.isAbsenClockIn == "TRUE") ? Text( // '--:--', varCurrentCheckJamProvider ?.jamClockIn ?? "NULL", ) : Text( '--:--', style: TextStyle( // Atur gaya teks '--:--' sesuai kebutuhan ), ), Text( 'Clock In', style: Constant.titleH2_700( context: context) .copyWith( color: Constant.textLightGrey, ), ), ], ), SizedBox( width: Constant.getActualXPhone( context: context, x: 96), ), // Jarak antara "Check In" dan "Check Out" Column( children: [ Image.asset( 'images/finger_tap.png', // Path gambar untuk "Check Out" width: Constant.getActualXPhone( context: context, x: 22), height: Constant.getActualYPhone( context: context, y: 22), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 8), ), (varCurrentCheckJamProvider ?.isAbsenClockOut == "TRUE") ? Text( // '--:--', varCurrentCheckJamProvider ?.jamClockOut ?? "NULL", ) : Text( '--:--', style: TextStyle( // Atur gaya teks '--:--' sesuai kebutuhan ), ), Text( 'Clock Out', style: Constant.titleH2_700( context: context) .copyWith( color: Constant.textLightGrey, ), ), ], ), Spacer(), // Spasi di sebelah kanan "Check Out" ], ), SizedBox( height: Constant.getActualYPhone( context: context, y: 16), ), ], ), ), ), ), ), SizedBox( height: Constant.getActualYPhone(context: context, y: 56), ), //Menu Cuti Lembur Padding( padding: EdgeInsets.only( left: Constant.getActualXPhone(context: context, x: 33), right: Constant.getActualXPhone(context: context, x: 27), ), child: Container( width: Constant.getActualXPhone(context: context, x: 330), child: Row( children: [ //Menu Cuti Container( width: Constant.getActualXPhone( context: context, x: 98), // color: Colors.amber, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Color.fromRGBO(145, 158, 171, 0.20), ), ], ), 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: 8), bottom: Constant.getActualYPhone( context: context, y: 8), ), child: InkWell( onTap: () {}, child: Column( children: [ Container( child: Image( width: Constant.getActualXPhone( context: context, x: 50), height: Constant.getActualYPhone( context: context, y: 50), image: AssetImage('images/person.png'), ), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 8), ), Text( 'Cuti', style: Constant.titleH2_600_14( context: context) .copyWith( color: Constant.textDarkGrey, ), ), ], ), ), ), ), SizedBox( width: Constant.getActualXPhone( context: context, x: 18), ), //Menu Lembur Container( width: Constant.getActualXPhone( context: context, x: 98), // color: Colors.amber, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Color.fromRGBO(145, 158, 171, 0.20), ), ], ), 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: 8), bottom: Constant.getActualYPhone( context: context, y: 8), ), child: InkWell( onTap: () {}, child: Column( children: [ Container( child: Image( width: Constant.getActualXPhone( context: context, x: 50), height: Constant.getActualYPhone( context: context, y: 50), image: AssetImage('images/task.png'), ), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 8), ), Text( 'Lembur', style: Constant.titleH2_600_14( context: context) .copyWith( color: Constant.textDarkGrey, ), ), ], ), ), ), ), ], ), ), ), SizedBox( height: Constant.getActualYPhone(context: context, y: 56), ), //Menu Rekap Presensi Padding( padding: EdgeInsets.only( right: Constant.getActualXPhone(context: context, x: 27), left: Constant.getActualXPhone(context: context, x: 33), bottom: Constant.getActualYPhone(context: context, y: 40)), child: Container( width: Constant.getActualXPhone(context: context, x: 330), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Rekap Presensi Bulan Ini', style: Constant.titleH1_500_18(context: context) .copyWith( color: Constant.textTrueBlack, ), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 20), ), Container( decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(16), color: Colors.white, // Set background color to #FFF boxShadow: [ BoxShadow( color: Color.fromRGBO(145, 158, 171, 0.20), blurRadius: 2, ), ], ), child: Padding( padding: EdgeInsets.only( top: Constant.getActualYPhone( context: context, y: 12), bottom: Constant.getActualYPhone( context: context, y: 12), left: Constant.getActualXPhone( context: context, x: 24), right: Constant.getActualXPhone( context: context, x: 24), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '24 hari', style: Constant.subtitle_600_14( context: context) .copyWith( color: Constant.textOrange, ), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 4), ), SizedBox( child: Row( children: [ Image( image: AssetImage( 'images/person_available_grey.png'), ), SizedBox( width: Constant.getActualXPhone( context: context, x: 4), ), Text( 'Kehadiran', style: Constant.subtitle_500_12( context: context) .copyWith( color: Constant.textDarkGrey, ), ), ], ), ) ], ), ), Image( image: AssetImage('images/divider.png'), ), //Tidak Hadir Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '2 hari', style: Constant.subtitle_600_14( context: context) .copyWith( color: Constant.textOrange, ), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 4), ), SizedBox( child: Row( children: [ Image( image: AssetImage( 'images/person_delete_grey.png'), ), SizedBox( width: Constant.getActualXPhone( context: context, x: 4), ), Text( 'Tidak Hadir', style: Constant.subtitle_500_12( context: context) .copyWith( color: Constant.textDarkGrey, ), ), ], ), ) ], ), ), Image( image: AssetImage('images/divider.png'), ), //Tidak Hadir Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '5 hari', style: Constant.subtitle_600_14( context: context) .copyWith( color: Constant.textOrange, ), ), SizedBox( height: Constant.getActualYPhone( context: context, y: 4), ), SizedBox( child: Row( children: [ Image( image: AssetImage( 'images/task_pending_grey.png'), ), SizedBox( width: Constant.getActualXPhone( context: context, x: 4), ), Text( 'Lembur', style: Constant.subtitle_500_12( context: context) .copyWith( color: Constant.textDarkGrey, ), ), ], ), ), ], ), ), ], ), ), ), ], ), ), ), ], ), ), ), ), ), ); } }