From b772e74e17af0a87689518e8b4dcbfa7a889f8db Mon Sep 17 00:00:00 2001 From: sindhu Date: Thu, 25 Jan 2024 14:17:50 +0700 Subject: [PATCH] step 7 : login, logout (bug disconnect), home screen top info user login --- lib/app/constant.dart | 3 + lib/app/route.dart | 13 ++ lib/main.dart | 11 +- lib/model/auth_model.dart | 62 +++++++ lib/model/logout_response_model.dart | 18 ++ lib/provider/current_user_provider.dart | 4 + lib/provider/google_login_provider.dart | 4 +- lib/repository/auth_repository.dart | 55 ++++++ lib/repository/base_repository.dart | 1 + lib/screen/home/home_screen.dart | 181 +++++++++++++++++++ lib/screen/login/login_provider.dart | 98 +++++++++++ lib/screen/login/login_screen.dart | 225 ++++++++++++++++-------- lib/screen/login/logout_provider.dart | 70 ++++++++ lib/widget/sankbar_widget.dart | 50 ++++++ pubspec.lock | 8 + pubspec.yaml | 1 + 16 files changed, 731 insertions(+), 73 deletions(-) create mode 100644 lib/model/auth_model.dart create mode 100644 lib/model/logout_response_model.dart create mode 100644 lib/provider/current_user_provider.dart create mode 100644 lib/repository/auth_repository.dart create mode 100644 lib/screen/home/home_screen.dart create mode 100644 lib/screen/login/login_provider.dart create mode 100644 lib/screen/login/logout_provider.dart create mode 100644 lib/widget/sankbar_widget.dart diff --git a/lib/app/constant.dart b/lib/app/constant.dart index de62f16..8b4afe9 100644 --- a/lib/app/constant.dart +++ b/lib/app/constant.dart @@ -7,6 +7,9 @@ class Constant { // base url graphql static String baseURLGraphQl = "http://devone.aplikasi.web.id:3300/query"; + static String bearerName = "absensi-sas"; + static String accountGoogle = "absensi-google-account"; + static double designHeightPhone = 844; static double designWidthPhone = 390; diff --git a/lib/app/route.dart b/lib/app/route.dart index 29c5784..7f363a3 100644 --- a/lib/app/route.dart +++ b/lib/app/route.dart @@ -1,3 +1,4 @@ +import 'package:absensi_sas_flutter/screen/home/home_screen.dart'; import 'package:flutter/material.dart'; import '../test_flutter_map.dart'; import '../screen/login/login_screen.dart'; @@ -6,6 +7,7 @@ import '../screen/splash/splash_screen.dart'; const loginRoute = "/loginRoute"; const splashRoute = "/splashRoute"; const testFlutterMapRoute = "/testFlutterMapRoute"; +const homeRoute = "/homeRoute"; class AppRoute { static Route generateRoute(RouteSettings settings) { @@ -21,6 +23,17 @@ class AppRoute { }); } + // home route + if (settings.name == homeRoute) { + return MaterialPageRoute(builder: (context) { + return MediaQuery( + data: MediaQuery.of(context) + .copyWith(textScaleFactor: 1.0, padding: EdgeInsets.all(0)), + child: HomeScreen(), + ); + }); + } + // splash screen if (settings.name == splashRoute) { return MaterialPageRoute(builder: (context) { diff --git a/lib/main.dart b/lib/main.dart index af6e7ac..297cadf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,9 +3,18 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../app/route.dart'; // import '../test_map.dart'; +// final routerProvider = Provider((_) => GlobalKey()); + void main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(const ProviderScope(child: MyApp())); + runApp( + ProviderScope( + // overrides: [ + // routerProvider.overrideWithValue(GlobalKey()), + // ], + child: MyApp(), + ), + ); } class MyApp extends StatelessWidget { diff --git a/lib/model/auth_model.dart b/lib/model/auth_model.dart new file mode 100644 index 0000000..d8ac98f --- /dev/null +++ b/lib/model/auth_model.dart @@ -0,0 +1,62 @@ +class AuthModel { + final String token; + final StaffModel model; + final String? idTokenGoogle; + final String? accessTokenGoogle; + + AuthModel({ + required this.token, + required this.model, + this.idTokenGoogle, + this.accessTokenGoogle, + }); +} + +class StaffModel { + String? staffId; + String? nip; + String? name; + String? email; + String? phoneNumber; + String? token; + String? idGoogleSignIn; + String? companyId; + String? companyName; + + StaffModel( + {this.staffId, + this.nip, + this.name, + this.email, + this.phoneNumber, + this.token, + this.idGoogleSignIn, + this.companyId, + this.companyName}); + + StaffModel.fromJson(Map json) { + staffId = json['staff_id']; + nip = json['nip']; + name = json['name']; + email = json['email']; + phoneNumber = json['phone_number']; + token = json['token']; + idGoogleSignIn = json['id_google_sign_in']; + companyId = json['company_id']; + companyName = json['company_name']; + } + + Map toJson() { + final Map data = new Map(); + data['staff_id'] = this.staffId; + data['nip'] = this.nip; + data['name'] = this.name; + data['email'] = this.email; + data['phone_number'] = this.phoneNumber; + data['token'] = this.token; + data['id_google_sign_in'] = this.idGoogleSignIn; + data['company_id'] = this.companyId; + data['company_name'] = this.companyName; + return data; + } +} diff --git a/lib/model/logout_response_model.dart b/lib/model/logout_response_model.dart new file mode 100644 index 0000000..85c5ff5 --- /dev/null +++ b/lib/model/logout_response_model.dart @@ -0,0 +1,18 @@ +class LogoutResponseModel { + String? status; + String? message; + + LogoutResponseModel({this.status, this.message}); + + LogoutResponseModel.fromJson(Map json) { + status = json['status']; + message = json['message']; + } + + Map toJson() { + final Map data = new Map(); + data['status'] = this.status; + data['message'] = this.message; + return data; + } +} \ No newline at end of file diff --git a/lib/provider/current_user_provider.dart b/lib/provider/current_user_provider.dart new file mode 100644 index 0000000..e358c65 --- /dev/null +++ b/lib/provider/current_user_provider.dart @@ -0,0 +1,4 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../model/auth_model.dart'; + +final currentUserProvider = StateProvider((ref) => null); \ No newline at end of file diff --git a/lib/provider/google_login_provider.dart b/lib/provider/google_login_provider.dart index 5c1a728..ab2a95a 100644 --- a/lib/provider/google_login_provider.dart +++ b/lib/provider/google_login_provider.dart @@ -10,4 +10,6 @@ final googleSignInProvider = StateProvider((ref) { ); }); -final currentUserProvider = StateProvider((ref) => null); \ No newline at end of file +final currentUserGoogleProvider = StateProvider((ref) => null); + +final isNotifyFromLogout = StateProvider((ref) => false); \ No newline at end of file diff --git a/lib/repository/auth_repository.dart b/lib/repository/auth_repository.dart new file mode 100644 index 0000000..3344693 --- /dev/null +++ b/lib/repository/auth_repository.dart @@ -0,0 +1,55 @@ +import 'package:absensi_sas_flutter/model/logout_response_model.dart'; +import 'package:google_sign_in/google_sign_in.dart'; + +import '../model/auth_model.dart'; +import 'base_repository.dart'; + +class AuthRepository extends BaseRepository { + AuthRepository({required super.graphql, required super.dio}); + + // login + Future login( + String email, + String idGoogleSignIn, + ) async { + const String query = + r'''mutation($emailParam:String!, $id_google_sign_in_Param:String!){ loginAttendance(email:$emailParam, id_google_sign_in:$id_google_sign_in_Param){ staff_id nip name email phone_number token id_google_sign_in company_id company_name } }'''; + + Map inpVariables = { + "emailParam": email, + "id_google_sign_in_Param": idGoogleSignIn + }; + final resp = await postGraphQlMutation(query, inpVariables); + // final loginData = AuthModel.fromJson(resp['userLogin']); + + print('obj loginAttendance : ${resp["loginAttendance"]}'); + print('token : ${resp["loginAttendance"]["token"]}'); + + final result = AuthModel( + token: resp["loginAttendance"]["token"], + model: StaffModel.fromJson(resp["loginAttendance"]), + ); + return result; + } + + // logout + Future logout( + String email, String idGoogleSignIn) async { + const String query = + r'''mutation($emailParam:String!, $id_google_sign_in_Param:String!){ logoutAttendance(email:$emailParam, id_google_sign_in:$id_google_sign_in_Param){ staff_id nip name email phone_number token id_google_sign_in company_id company_name } }'''; + + Map inpVariables = { + "emailParam": email, + "id_google_sign_in_Param": idGoogleSignIn + }; + final resp = await postGraphQlMutation(query, inpVariables); + // final loginData = AuthModel.fromJson(resp['userLogin']); + + // final result = resp['logoutAttendance']['status']; + + final result = LogoutResponseModel( + message: resp['logoutAttendance']['message'], + status: resp['logoutAttendance']['status']); + return result; + } +} diff --git a/lib/repository/base_repository.dart b/lib/repository/base_repository.dart index 652893b..8ea39be 100644 --- a/lib/repository/base_repository.dart +++ b/lib/repository/base_repository.dart @@ -21,6 +21,7 @@ abstract class BaseRepository { throw BaseRepositoryException(message: result.exception.toString()); } + // return result.data!; return result.data!; } catch (e) { throw BaseRepositoryException(message: e.toString()); diff --git a/lib/screen/home/home_screen.dart b/lib/screen/home/home_screen.dart new file mode 100644 index 0000000..bc867b9 --- /dev/null +++ b/lib/screen/home/home_screen.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 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(), + ) + : 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/screen/login/login_provider.dart b/lib/screen/login/login_provider.dart new file mode 100644 index 0000000..e65f0a6 --- /dev/null +++ b/lib/screen/login/login_provider.dart @@ -0,0 +1,98 @@ +import 'dart:convert'; + +import 'package:absensi_sas_flutter/provider/google_login_provider.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../app/constant.dart'; +import '../../model/auth_model.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../provider/current_user_provider.dart'; +import '../../provider/dio_provider.dart'; +import '../../provider/graphql_provider.dart'; +import '../../repository/auth_repository.dart'; +import '../../repository/base_repository.dart'; + +abstract class LoginState extends Equatable { + final DateTime date; + const LoginState(this.date); + @override + List get props => [date]; +} + +class LoginStateInit extends LoginState { + LoginStateInit() : super(DateTime.now()); +} + +class LoginStateLoading extends LoginState { + LoginStateLoading() : super(DateTime.now()); +} + +class LoginStateError extends LoginState { + final String message; + LoginStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class LoginStateDone extends LoginState { + final AuthModel model; + LoginStateDone({ + required this.model, + }) : super(DateTime.now()); +} + +//notifier +class LoginNotifier extends StateNotifier { + final Ref ref; + LoginNotifier({ + required this.ref, + }) : super(LoginStateInit()); + + void login( + String email, + String idGoogleSignIn, + ) async { + try { + state = LoginStateLoading(); + final graphql = ref.read(graphqlProvider('')); + final dio = ref.read(dioProvider); + final resp = await AuthRepository(graphql: graphql, dio: dio).login( + email, + idGoogleSignIn, + ); + + //Simpan ke token + final shared = await SharedPreferences.getInstance(); + final token = jsonEncode({ + "date": DateTime.now().toString(), + "model": resp.model, + "token": resp.token + }); + await shared.setString(Constant.bearerName, token); + ref.read(currentUserProvider.notifier).state = resp; + + // // set google sign in account + // final accountEncode = jsonEncode({ + // "account": account, + // }); + // await shared.setString(Constant.accountGoogle, accountEncode); + // ref.read(currentUserGoogleProvider.notifier).state = acc + + + state = LoginStateDone(model: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = LoginStateError(message: e.message ?? ""); + } else { + state = LoginStateError(message: e.toString()); + } + } + } +} + +// provider +final loginProvider = StateNotifierProvider( + (ref) => LoginNotifier(ref: ref), +); diff --git a/lib/screen/login/login_screen.dart b/lib/screen/login/login_screen.dart index f79b038..988b19d 100644 --- a/lib/screen/login/login_screen.dart +++ b/lib/screen/login/login_screen.dart @@ -1,18 +1,20 @@ -import 'dart:io'; +import 'dart:convert'; -import 'package:dio/dio.dart'; +import 'package:absensi_sas_flutter/screen/login/login_provider.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.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:path_provider/path_provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import '../../app/constant.dart'; +import '../../app/route.dart'; +import '../../model/auth_model.dart'; +import '../../provider/current_user_provider.dart'; import '../../provider/google_login_provider.dart'; -import 'package:crypton/crypton.dart' as crypton; +import '../../widget/sankbar_widget.dart'; class LoginScreen extends HookConsumerWidget { const LoginScreen({super.key}); @@ -22,60 +24,130 @@ class LoginScreen extends HookConsumerWidget { // inisialisasi // ref.watch itu sama spt memantau state terus menerus // ref.read itu memantau namun hny 1x saja - GoogleSignInAccount? currentUser = ref.watch(currentUserProvider); + GoogleSignInAccount? currentUserGoogle = + ref.watch(currentUserGoogleProvider); final googleSignIn = ref.watch(googleSignInProvider); - Future postPublicKey() async { - Dio dio = Dio(); - String url = "https://example.com/api/post_endpoint"; - try { - final publicPem = await rootBundle.loadString('assets/public_key.pem'); - final publicKey = crypton.RSAPublicKey.fromPEM(publicPem); - - // GoogleSignInAccount? currentUser = ref.watch(currentUserProvider); - // final googleSignIn = ref.watch(googleSignInProvider); - // return filePath; - - publicKey.encrypt("testing satu dua tiga"); - Map data = { - "publickey": publicKey, - "id_google_sign_in": "102110797605607117832", - "email": "sindhu@sismedia.com" - }; - - Response response = await dio.post( - url, - data: data, - ); - - // Menampilkan respons dari server - print("Response data: ${response.data}"); - - // googleSignIn.onCurrentUserChanged.listen((account) { - // // untuk update value ke provider google_login_provider yaitu currentUserProvider - // ref.read(currentUserProvider.notifier).update((state) => account); - // }); - // googleSignIn.signInSilently(); - } catch (e) { - print("Error reading file: $e"); - } - } + final isLoading = useState(false); + final errorMessage = useState(""); + final isSuccess = useState(false); useEffect(() { - // googleSignIn.onCurrentUserChanged.listen((account) { - // // untuk update value ke provider google_login_provider yaitu currentUserProvider - // ref.read(currentUserProvider.notifier).update((state) => account); - // }); - // googleSignIn.signInSilently(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0"; - postPublicKey(); + googleSignIn.onCurrentUserChanged.listen((account) { + ref + .read(currentUserGoogleProvider.notifier) + .update((state) => account); + }); + googleSignIn.signInSilently(); + // if (currentUserGoogle != null && staffID == "0") { + // ref.read(loginProvider.notifier).login( + // currentUserGoogle.email, + // currentUserGoogle.id, + // ); + // } + + if (currentUserGoogle != null) { + if (staffID == "0") { + ref.read(loginProvider.notifier).login( + currentUserGoogle.email, + currentUserGoogle.id, + ); + } + } + }); return () {}; - }, const []); + }, [currentUserGoogle]); + + useEffect(() { + return () {}; + }, [currentUserGoogle]); + + WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { + final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0"; + final shared = await SharedPreferences.getInstance(); + final bearerString = shared.get(Constant.bearerName).toString(); + final xmodel = jsonDecode(bearerString); + if (xmodel == null) return; + final authModel = AuthModel( + token: xmodel["token"], + model: StaffModel( + companyId: xmodel["model"]["companyId"], + companyName: xmodel["model"]["companyName"], + email: xmodel["model"]["email"], + staffId: xmodel["model"]["staffId"], + idGoogleSignIn: xmodel['model']['idGoogleSignIn'], + name: xmodel['model']['name'], + nip: xmodel['model']['nip'], + phoneNumber: xmodel["model"]["phoneNumber"], + token: xmodel["model"]["token"], + ), + ); + + googleSignIn.onCurrentUserChanged.listen((account) { + if (account != null && staffID == "0") { + ref + .read(currentUserGoogleProvider.notifier) + .update((state) => account); + ref.read(currentUserProvider.notifier).state = authModel; + Navigator.of(context).pushNamedAndRemoveUntil( + homeRoute, + (route) => false, + ); + } + }); + + // ref.read(currentUserProvider.notifier).state = authModel; + + // Navigator.of(context).pushNamedAndRemoveUntil( + // homeRoute, + // (route) => false, + // ); + }); + + // LISTEN PROVIDER + ref.listen(loginProvider, (prev, next) { + if (next is LoginStateLoading) { + isLoading.value = true; + } else if (next is LoginStateError) { + isLoading.value = false; + // errorMessage.value = next.message; + // Timer(const Duration(seconds: 3), () { + // errorMessage.value = ""; + // }); + SanckbarWidget(context, next.message, snackbarType.warning); + } else if (next is LoginStateDone) { + isLoading.value = false; + isSuccess.value = true; + // ref.read(currentPageProvider.state).update((state) => 0); + Navigator.of(context) + .pushNamedAndRemoveUntil(homeRoute, (route) => false); + } + }); // fungsi untuk sync ke google mail - Future handleSignIn() async { + Future handleSignInGmail() async { try { + // auth ke email await googleSignIn.signIn(); + googleSignIn.onCurrentUserChanged.listen((account) async { + ref + .read(currentUserGoogleProvider.notifier) + .update((state) => account); + + // Check jika account tidak null dan belum login + if (account != null && + ref.read(currentUserProvider)?.model.staffId == "0") { + // Lakukan login + ref.read(loginProvider.notifier).login( + account.email, + account.id, + ); + } + }); + googleSignIn.signInSilently(); } catch (error) { if (kDebugMode) { print(error); @@ -91,27 +163,27 @@ class LoginScreen extends HookConsumerWidget { SizedBox( height: Constant.getActualYPhone(context: context, y: 100), ), - (currentUser != null) - ? Container( - child: ListTile( - leading: GoogleUserCircleAvatar( - identity: currentUser, - ), - title: Text( - currentUser.displayName ?? "", - ), - subtitle: Text( - currentUser.email, - ), - trailing: IconButton( - icon: Icon(Icons.logout_outlined), - onPressed: () async { - await googleSignIn.disconnect(); - }, - ), - ), - ) - : + // (currentUserGoogle != null) + // ? Container( + // child: ListTile( + // leading: GoogleUserCircleAvatar( + // identity: currentUserGoogle, + // ), + // title: Text( + // currentUserGoogle.displayName ?? "", + // ), + // subtitle: Text( + // currentUserGoogle.email, + // ), + // trailing: IconButton( + // icon: Icon(Icons.logout_outlined), + // onPressed: () async { + // await googleSignIn.disconnect(); + // }, + // ), + // ), + // ) + // : // Logo Landscape Padding( padding: EdgeInsets.only( @@ -182,6 +254,17 @@ class LoginScreen extends HookConsumerWidget { ], ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + + // ElevatedButton( + // onPressed: () async { + // await googleSignIn.disconnect(); + // }, + // child: Text('logout'), + // ), + SizedBox( height: Constant.getActualYPhone(context: context, y: 64), ), @@ -197,7 +280,7 @@ class LoginScreen extends HookConsumerWidget { height: Constant.getActualYPhone(context: context, y: 48), child: ElevatedButton( onPressed: () async { - await handleSignIn(); + await handleSignInGmail(); }, child: Row( mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/screen/login/logout_provider.dart b/lib/screen/login/logout_provider.dart new file mode 100644 index 0000000..e165641 --- /dev/null +++ b/lib/screen/login/logout_provider.dart @@ -0,0 +1,70 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../../model/logout_response_model.dart'; +import '../../provider/dio_provider.dart'; +import '../../provider/graphql_provider.dart'; +import '../../repository/auth_repository.dart'; +import '../../repository/base_repository.dart'; + +// 3. state provider +final logoutProvider = StateNotifierProvider( + (ref) => LogoutNotifier(ref: ref)); + +// 2. notifier +class LogoutNotifier extends StateNotifier { + final Ref ref; + LogoutNotifier({required this.ref}) : super(LogoutStateInit()); + void logout({ + required String email, + required String idGoogleSignIn, + }) async { + try { + state = LogoutStateLoading(); + final graphql = ref.read(graphqlProvider('')); + final dio = ref.read(dioProvider); + final resp = await AuthRepository(graphql: graphql, dio: dio).logout( + email, + idGoogleSignIn, + ); + + // print(resp); + state = LogoutStateDone(model: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = LogoutStateError(message: e.message ?? ""); + } else { + state = LogoutStateError(message: e.toString()); + } + } + } +} + +// 1. state +abstract class LogoutState extends Equatable { + final DateTime date; + const LogoutState(this.date); + @override + List get props => [date]; +} + +class LogoutStateInit extends LogoutState { + LogoutStateInit() : super(DateTime.now()); +} + +class LogoutStateLoading extends LogoutState { + LogoutStateLoading() : super(DateTime.now()); +} + +class LogoutStateError extends LogoutState { + final String message; + LogoutStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class LogoutStateDone extends LogoutState { + final LogoutResponseModel model; + LogoutStateDone({ + required this.model, + }) : super(DateTime.now()); +} diff --git a/lib/widget/sankbar_widget.dart b/lib/widget/sankbar_widget.dart new file mode 100644 index 0000000..2da9336 --- /dev/null +++ b/lib/widget/sankbar_widget.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:top_snackbar_flutter/custom_snack_bar.dart'; +import 'package:top_snackbar_flutter/top_snack_bar.dart'; + +enum snackbarType { error, info, success, warning } + +SanckbarWidget(BuildContext context, String msg, snackbarType tipe) { + switch (tipe) { + case snackbarType.error: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.error( + message: msg, + ), + ); + break; + case snackbarType.success: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.success( + message: msg, + ), + ); + break; + case snackbarType.info: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.info( + message: msg, + ), + ); + break; + case snackbarType.warning: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.info( + backgroundColor: Colors.orangeAccent, + message: msg, + ), + ); + break; + default: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.info( + message: msg, + ), + ); + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index a97942e..6780abe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -773,6 +773,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.1" + top_snackbar_flutter: + dependency: "direct main" + description: + name: top_snackbar_flutter + sha256: "22d14664a13db6ac714934c3382bd8d4daa57fb888a672f922df71981c5a5cb2" + url: "https://pub.dev" + source: hosted + version: "3.1.0" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 45c7f77..2237c6c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,7 @@ dependencies: path_provider: ^2.0.2 intl: ^0.17.0 graphql: ^5.1.3 + top_snackbar_flutter: ^3.1.0 dev_dependencies: flutter_test: