diff --git a/images/alert_badge.png b/images/alert_badge.png new file mode 100644 index 0000000..8acbeaa Binary files /dev/null and b/images/alert_badge.png differ diff --git a/images/avatar_c.png b/images/avatar_c.png new file mode 100644 index 0000000..59b86b7 Binary files /dev/null and b/images/avatar_c.png differ diff --git a/images/card_bg_1.png b/images/card_bg_1.png new file mode 100644 index 0000000..ba60fbe Binary files /dev/null and b/images/card_bg_1.png differ diff --git a/images/divider.png b/images/divider.png new file mode 100644 index 0000000..466a045 Binary files /dev/null and b/images/divider.png differ diff --git a/images/finger_tap.png b/images/finger_tap.png new file mode 100644 index 0000000..4a49821 Binary files /dev/null and b/images/finger_tap.png differ diff --git a/images/finger_tap_botnav.png b/images/finger_tap_botnav.png new file mode 100644 index 0000000..5fd1eed Binary files /dev/null and b/images/finger_tap_botnav.png differ diff --git a/images/finger_tap_orange_botnav.png b/images/finger_tap_orange_botnav.png new file mode 100644 index 0000000..a0e8095 Binary files /dev/null and b/images/finger_tap_orange_botnav.png differ diff --git a/images/home_orange.png b/images/home_orange.png new file mode 100644 index 0000000..60cd166 Binary files /dev/null and b/images/home_orange.png differ diff --git a/images/person.png b/images/person.png new file mode 100644 index 0000000..b37f627 Binary files /dev/null and b/images/person.png differ diff --git a/images/person_available_grey.png b/images/person_available_grey.png new file mode 100644 index 0000000..5c8d175 Binary files /dev/null and b/images/person_available_grey.png differ diff --git a/images/person_delete_grey.png b/images/person_delete_grey.png new file mode 100644 index 0000000..efd948a Binary files /dev/null and b/images/person_delete_grey.png differ diff --git a/images/person_grey.png b/images/person_grey.png new file mode 100644 index 0000000..e41ba5d Binary files /dev/null and b/images/person_grey.png differ diff --git a/images/task.png b/images/task.png new file mode 100644 index 0000000..b685e50 Binary files /dev/null and b/images/task.png differ diff --git a/images/task_pending_grey.png b/images/task_pending_grey.png new file mode 100644 index 0000000..c893fb2 Binary files /dev/null and b/images/task_pending_grey.png differ diff --git a/lib/app/constant.dart b/lib/app/constant.dart index 8b4afe9..0efe329 100644 --- a/lib/app/constant.dart +++ b/lib/app/constant.dart @@ -14,8 +14,11 @@ class Constant { static double designWidthPhone = 390; // color theme + static Color textTrueBlack = const Color(0xff000000); static Color textBlack = const Color(0xff212B36); static Color textLightGrey = const Color(0xff919EAB); + static Color textOrange = const Color(0xffF15A29); + static Color textDarkGrey = const Color(0xff637381); // size convertion static double getActualXPhone({ @@ -53,4 +56,58 @@ class Constant { fontWeight: FontWeight.w700, ); } + + static TextStyle titleH2_600_14({required BuildContext context}) { + return TextStyle( + fontSize: Constant.getActualYPhone(context: context, y: 14), + fontWeight: FontWeight.w600, + fontFamily: 'Public Sans'); + } + + static TextStyle titleH1_500_18({required BuildContext context}) { + return TextStyle( + fontSize: Constant.getActualYPhone(context: context, y: 18), + fontWeight: FontWeight.w500, + fontFamily: 'Public Sans'); + } + + static TextStyle titleH2_700({required BuildContext context}) { + return TextStyle( + fontFamily: 'Quicksand', + fontSize: Constant.getActualYPhone(context: context, y: 14), + fontWeight: FontWeight.w700, + ); + } + + static TextStyle time_700({required BuildContext context}) { + return TextStyle( + fontSize: Constant.getActualYPhone(context: context, y: 28), + fontWeight: FontWeight.w700, + fontFamily: 'Quicksand', + ); + } + + static TextStyle subtitle_600_14({required BuildContext context}) { + return TextStyle( + fontSize: Constant.getActualYPhone(context: context, y: 14), + fontWeight: FontWeight.w700, + fontFamily: 'Public Sans', + ); + } + + static TextStyle subtitle_500_12({required BuildContext context}) { + return TextStyle( + fontSize: Constant.getActualYPhone(context: context, y: 12), + fontWeight: FontWeight.w500, + fontFamily: 'Public Sans', + ); + } + + static TextStyle date_600({required BuildContext context}) { + return TextStyle( + fontSize: Constant.getActualYPhone(context: context, y: 16), + fontWeight: FontWeight.w600, + fontFamily: 'Quicksand', + ); + } } diff --git a/lib/app/route.dart b/lib/app/route.dart index 7f363a3..c7d1069 100644 --- a/lib/app/route.dart +++ b/lib/app/route.dart @@ -1,5 +1,6 @@ -import 'package:absensi_sas_flutter/screen/home/home_screen.dart'; +import 'package:absensi_sas_flutter/screen/home/home_screen_v1.dart'; import 'package:flutter/material.dart'; +import '../screen/home/home_screen.dart'; import '../test_flutter_map.dart'; import '../screen/login/login_screen.dart'; import '../screen/splash/splash_screen.dart'; diff --git a/lib/main.dart b/lib/main.dart index 297cadf..52e66e5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,23 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../app/route.dart'; +import 'package:intl/date_symbol_data_local.dart'; // import '../test_map.dart'; // final routerProvider = Provider((_) => GlobalKey()); void main() async { WidgetsFlutterBinding.ensureInitialized(); + initializeDateFormatting(); + await SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + ]); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarIconBrightness: + Brightness.dark, // this will change the brightness of the icons + statusBarColor: Colors.white, // or any color you want + )); runApp( ProviderScope( // overrides: [ @@ -34,7 +45,8 @@ class MyApp extends StatelessWidget { primarySwatch: Colors.orange, ), // home: TestMap(), - initialRoute: loginRoute, + // initialRoute: loginRoute, + initialRoute: homeRoute, // initialRoute: testFlutterMapRoute, onGenerateRoute: AppRoute.generateRoute, ); diff --git a/lib/screen/home/home_screen.dart b/lib/screen/home/home_screen.dart index bc867b9..6e1521b 100644 --- a/lib/screen/home/home_screen.dart +++ b/lib/screen/home/home_screen.dart @@ -1,179 +1,634 @@ -import 'dart:async'; - -import 'package:absensi_sas_flutter/screen/login/logout_provider.dart'; +import 'package:absensi_sas_flutter/app/constant.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:google_sign_in/google_sign_in.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import '../../app/constant.dart'; -import '../../app/route.dart'; -import '../../provider/current_user_provider.dart'; -import '../../provider/google_login_provider.dart'; -import '../../widget/sankbar_widget.dart'; +import '../../widget/real_date.dart'; +import '../../widget/real_time.dart'; class HomeScreen extends HookConsumerWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final isLoading = useState(false); - // final errorMessage = useState(""); - final successMessage = useState(""); - final googleSignIn = ref.watch(googleSignInProvider); - - // final currentUserGoogleAccount = ref.watch(currentUserGoogleProvider); - - GoogleSignInAccount? currentUserGoogle = - ref.watch(currentUserGoogleProvider); - - final selectedUser = ref.read(currentUserProvider); - - // GoogleSignInAccount? accountX; - // final accountX = useState(null); - - // useEffect(() { - // WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { - // final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0"; - // if (staffID == "0" && currentUserGoogle == null) { - // //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"; - // final accountGoogle = ref.read(currentUserGoogleProvider)?.id ?? "0"; - - // if (staffID == "0" && accountGoogle == "0") { - // //not login - // Navigator.of(context) - // .pushNamedAndRemoveUntil(loginRoute, (route) => true); - - // // Navigator.popAndPushNamed(context, loginRoute); - // return; - // } - // }); - // return () {}; - // }, []); - - // LISTEN PROVIDER - ref.listen(logoutProvider, (prev, next) async { - if (next is LogoutStateLoading) { - isLoading.value = true; - } else if (next is LogoutStateError) { - isLoading.value = false; - // errorMessage.value = next.message; - // Timer(const Duration(seconds: 3), () { - // errorMessage.value = ""; - // }); - SanckbarWidget(context, next.message, snackbarType.warning); - } else if (next is LogoutStateDone) { - isLoading.value = false; - - if (next.model.status == "OK") { - final shared = await SharedPreferences.getInstance(); - final bearerString = shared.get(Constant.bearerName).toString(); - // print(bearerString); - if (bearerString.isNotEmpty) { - shared.remove(bearerString); - shared.clear(); - // Navigator.popAndPushNamed(context, loginRoute); - Navigator.of(context).pushNamedAndRemoveUntil( - loginRoute, - (route) => false, - ); - } - Timer(const Duration(seconds: 3), () async { - successMessage.value = ""; - }); - } else { - SanckbarWidget( - context, - next.model.message.toString(), - snackbarType.warning, - ); - } - } - }); - - Future handleLogout() async { - final googleSignIn = GoogleSignIn(); - - // googleSignIn.signOut(); - await googleSignIn.disconnect(); - await googleSignIn.signOut(); - - // ref.read(currentUserGoogleProvider.notifier).update((state) => null); - // final shared = await SharedPreferences.getInstance(); - // final bearerString = shared.get(Constant.bearerName).toString(); - // if (bearerString.isNotEmpty) { - // shared.remove(bearerString); - // shared.clear(); - // } - - // if (googleSignIn.currentUser != null) { - // GoogleSignIn().signOut(); - // } - - // await GoogleSignIn().disconnect(); - - // Clear state dan kembali ke halaman login - // ref.read(currentUserGoogleProvider.notifier).update((state) => null); - // final shared = await SharedPreferences.getInstance(); - // final bearerString = shared.get(Constant.bearerName).toString(); - // if (bearerString.isNotEmpty) { - // shared.remove(bearerString); - // shared.clear(); - // } - Navigator.of(context) - .pushNamedAndRemoveUntil(loginRoute, (route) => false); - } + return Scaffold( - body: Padding( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - (currentUserGoogle == null) - ? Center( - child: CircularProgressIndicator(), + floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, + floatingActionButton: Container( + width: Constant.getActualXPhone(context: context, x: 100), + height: Constant.getActualYPhone(context: context, y: 100), + child: FittedBox( + child: FloatingActionButton( + onPressed: () {}, + 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, + ), ) - : Container( + ], + ), + )), + 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: 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: ListTile( - leading: GoogleUserCircleAvatar( - // identity: accountX.value!, - // identity: selectedUser?.googleSignInAccount, - identity: currentUserGoogle, - ), + leading: Container( + width: + Constant.getActualXPhone(context: context, x: 36), + height: + Constant.getActualYPhone(context: context, y: 36), + child: Image( + image: AssetImage('images/avatar_c.png'), + )), title: Text( - // accountX.value!.displayName ?? "" - // selectedUser?.model.name ?? "", - currentUserGoogle.displayName ?? "", + "Stephen Kusumo", + overflow: TextOverflow.ellipsis, + style: Constant.titleH1_700(context: context) + ..copyWith( + color: Constant.textBlack, + ), ), - // currentUserGoogle?.displayName ?? ""), subtitle: Text( - // currentUserGoogle?.email ?? "", - selectedUser?.model.email ?? "", - // accountX.value!.email + "Step@example.com", + style: + Constant.subtitle_500_12(context: context).copyWith( + color: Constant.textLightGrey, + ), ), - trailing: IconButton( - icon: Icon(Icons.logout_outlined), - onPressed: () async { - handleLogout(); - }, + 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), + ), + 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), + ), + 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, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), ), ), ); diff --git a/lib/screen/home/home_screen_v1.dart b/lib/screen/home/home_screen_v1.dart new file mode 100644 index 0000000..142ebe0 --- /dev/null +++ b/lib/screen/home/home_screen_v1.dart @@ -0,0 +1,181 @@ +import 'dart:async'; + +import 'package:absensi_sas_flutter/screen/login/logout_provider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../app/constant.dart'; +import '../../app/route.dart'; +import '../../provider/current_user_provider.dart'; +import '../../provider/google_login_provider.dart'; +import '../../widget/sankbar_widget.dart'; + +class HomeScreenV1 extends HookConsumerWidget { + const HomeScreenV1({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isLoading = useState(false); + // final errorMessage = useState(""); + final successMessage = useState(""); + final googleSignIn = ref.watch(googleSignInProvider); + + // final currentUserGoogleAccount = ref.watch(currentUserGoogleProvider); + + GoogleSignInAccount? currentUserGoogle = + ref.watch(currentUserGoogleProvider); + + final selectedUser = ref.read(currentUserProvider); + + // GoogleSignInAccount? accountX; + // final accountX = useState(null); + + // useEffect(() { + // WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + // final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0"; + // if (staffID == "0" && currentUserGoogle == null) { + // //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"; + // final accountGoogle = ref.read(currentUserGoogleProvider)?.id ?? "0"; + + // if (staffID == "0" && accountGoogle == "0") { + // //not login + // Navigator.of(context) + // .pushNamedAndRemoveUntil(loginRoute, (route) => true); + + // // Navigator.popAndPushNamed(context, loginRoute); + // return; + // } + // }); + // return () {}; + // }, []); + + // LISTEN PROVIDER + ref.listen(logoutProvider, (prev, next) async { + if (next is LogoutStateLoading) { + isLoading.value = true; + } else if (next is LogoutStateError) { + isLoading.value = false; + // errorMessage.value = next.message; + // Timer(const Duration(seconds: 3), () { + // errorMessage.value = ""; + // }); + SanckbarWidget(context, next.message, snackbarType.warning); + } else if (next is LogoutStateDone) { + isLoading.value = false; + + if (next.model.status == "OK") { + final shared = await SharedPreferences.getInstance(); + final bearerString = shared.get(Constant.bearerName).toString(); + // print(bearerString); + if (bearerString.isNotEmpty) { + shared.remove(bearerString); + shared.clear(); + // Navigator.popAndPushNamed(context, loginRoute); + Navigator.of(context).pushNamedAndRemoveUntil( + loginRoute, + (route) => false, + ); + } + Timer(const Duration(seconds: 3), () async { + successMessage.value = ""; + }); + } else { + SanckbarWidget( + context, + next.model.message.toString(), + snackbarType.warning, + ); + } + } + }); + + Future handleLogout() async { + final googleSignIn = GoogleSignIn(); + + // googleSignIn.signOut(); + await googleSignIn.disconnect(); + await googleSignIn.signOut(); + + // ref.read(currentUserGoogleProvider.notifier).update((state) => null); + // final shared = await SharedPreferences.getInstance(); + // final bearerString = shared.get(Constant.bearerName).toString(); + // if (bearerString.isNotEmpty) { + // shared.remove(bearerString); + // shared.clear(); + // } + + // if (googleSignIn.currentUser != null) { + // GoogleSignIn().signOut(); + // } + + // await GoogleSignIn().disconnect(); + + // Clear state dan kembali ke halaman login + // ref.read(currentUserGoogleProvider.notifier).update((state) => null); + // final shared = await SharedPreferences.getInstance(); + // final bearerString = shared.get(Constant.bearerName).toString(); + // if (bearerString.isNotEmpty) { + // shared.remove(bearerString); + // shared.clear(); + // } + Navigator.of(context) + .pushNamedAndRemoveUntil(loginRoute, (route) => false); + } + + return Scaffold( + body: Padding( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + (currentUserGoogle == null) + ? Center( + child: CircularProgressIndicator(), + ) + : Container( + child: ListTile( + leading: GoogleUserCircleAvatar( + // identity: accountX.value!, + // identity: selectedUser?.googleSignInAccount, + identity: currentUserGoogle, + ), + title: Text( + // accountX.value!.displayName ?? "" + // selectedUser?.model.name ?? "", + currentUserGoogle.displayName ?? "", + ), + // currentUserGoogle?.displayName ?? ""), + subtitle: Text( + // currentUserGoogle?.email ?? "", + selectedUser?.model.email ?? "", + // accountX.value!.email + ), + trailing: IconButton( + icon: Icon(Icons.logout_outlined), + onPressed: () async { + handleLogout(); + }, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widget/real_date.dart b/lib/widget/real_date.dart new file mode 100644 index 0000000..dea3be5 --- /dev/null +++ b/lib/widget/real_date.dart @@ -0,0 +1,25 @@ +import 'dart:async'; + +import 'package:absensi_sas_flutter/app/constant.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:intl/intl.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +class RealTimeFormattedDate extends HookConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + final currentTime = useState(DateTime.now()); + + // Format waktu menjadi tanggal yang diinginkan + String formattedDate = + DateFormat('EEEE, d MMMM y', 'id_ID').format(currentTime.value); + + // Tampilkan widget Text dengan tanggal yang diformat + return Text( + formattedDate, + style: Constant.date_600(context: context) + .copyWith(color: Constant.textBlack), + ); + } +} diff --git a/lib/widget/real_time.dart b/lib/widget/real_time.dart new file mode 100644 index 0000000..0397300 --- /dev/null +++ b/lib/widget/real_time.dart @@ -0,0 +1,39 @@ +import 'dart:async'; + +import 'package:absensi_sas_flutter/app/constant.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:intl/intl.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +class RealTimeClock extends HookConsumerWidget { + @override + Widget build(BuildContext context, WidgetRef ref) { + // Menggunakan useState untuk menyimpan waktu saat ini + final currentTime = useState(DateTime.now()); + StreamSubscription? subscription; + + useEffect(() { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + final clockStream = Stream.periodic( + Duration(seconds: 1), (i) => DateTime.now()); + subscription = clockStream.listen((time) { + currentTime.value = time; + }); + }); + return () async { + subscription?.cancel(); + }; + }, []); + + // Format waktu menjadi tanggal yang diinginkan + String formattedTime = DateFormat('HH:mm:ss').format(currentTime.value); + + // Tampilkan widget Text dengan waktu yang diformat + return Text( + formattedTime, + style: Constant.time_700(context: context) + .copyWith(color: Constant.textBlack), + ); + } +}