From 6a0795180b3c5f367b0e78620f6a528b2af33222 Mon Sep 17 00:00:00 2001 From: Sergey Dmitriev <51058739+0niel@users.noreply.github.com> Date: Wed, 15 Feb 2023 22:41:30 +0300 Subject: [PATCH] feature: Create NFC-Pass Device Connect (#279) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add deferredLoading * feature: Create NFC-Pass Device Connect * feat: Create Nfc Fetcher and refactor auth bloc * Удалён AuthBloc. Его функции перенесены в Profile Bloc * Теперь в события не передаются токены доступа к апи. Управление токенами делегируется на репозиторий/remote data-source или отдельные пакеты для управления сетевыми запросами * Создан `fetchNfcCode` event для получения кода пропуск * feat: Add NFC fetching and errors feedback * Update AndroidManifest.xml --- android/app/src/main/AndroidManifest.xml | 1 + android/build.gradle | 4 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- lib/common/errors/exceptions.dart | 4 + lib/common/errors/failures.dart | 4 + lib/data/datasources/user_local.dart | 40 +- lib/data/datasources/user_remote.dart | 182 +- lib/data/models/nfc_pass_model.dart | 33 + lib/data/models/user_model.dart | 15 +- .../repositories/user_repository_impl.dart | 113 +- lib/domain/entities/nfc_pass.dart | 20 + lib/domain/entities/user.dart | 6 + lib/domain/repositories/user_repository.dart | 31 +- lib/domain/usecases/connect_nfc_pass.dart | 30 + lib/domain/usecases/fetch_nfc_code.dart | 34 + lib/domain/usecases/get_announces.dart | 16 +- lib/domain/usecases/get_attendance.dart | 7 +- lib/domain/usecases/get_employees.dart | 7 +- lib/domain/usecases/get_nfc_passes.dart | 29 + lib/domain/usecases/get_scores.dart | 16 +- lib/domain/usecases/get_user_data.dart | 15 +- lib/domain/usecases/log_in.dart | 17 +- .../usecases/send_nfc_not_exist_feedback.dart | 31 + lib/main.dart | 33 +- .../bloc/announces_bloc/announces_bloc.dart | 2 +- .../bloc/announces_bloc/announces_event.dart | 8 +- .../bloc/attendance_bloc/attendance_bloc.dart | 2 +- .../attendance_bloc/attendance_event.dart | 4 +- .../bloc/auth_bloc/auth_bloc.dart | 65 - .../bloc/auth_bloc/auth_event.dart | 22 - .../bloc/auth_bloc/auth_state.dart | 30 - .../bloc/employee_bloc/employee_bloc.dart | 3 +- .../bloc/employee_bloc/employee_event.dart | 5 +- .../nfc_feedback_bloc/nfc_feedback_bloc.dart | 35 + .../nfc_feedback_bloc.freezed.dart | 922 ++++++++ .../nfc_feedback_bloc/nfc_feedback_event.dart | 12 + .../nfc_feedback_bloc/nfc_feedback_state.dart | 9 + .../bloc/nfc_pass_bloc/nfc_pass_bloc.dart | 169 ++ .../nfc_pass_bloc/nfc_pass_bloc.freezed.dart | 1865 +++++++++++++++++ .../bloc/nfc_pass_bloc/nfc_pass_event.dart | 19 + .../bloc/nfc_pass_bloc/nfc_pass_state.dart | 15 + .../bloc/profile_bloc/profile_bloc.dart | 28 - .../bloc/profile_bloc/profile_event.dart | 14 - .../bloc/profile_bloc/profile_state.dart | 21 - .../bloc/scores_bloc/scores_bloc.dart | 2 +- .../bloc/scores_bloc/scores_event.dart | 8 +- .../bloc/user_bloc/user_bloc.dart | 100 + .../bloc/user_bloc/user_bloc.freezed.dart | 1125 ++++++++++ .../bloc/user_bloc/user_event.dart | 9 + .../bloc/user_bloc/user_state.dart | 9 + lib/presentation/core/routes/routes.dart | 5 + lib/presentation/core/routes/routes.gr.dart | 203 +- lib/presentation/pages/login/login_page.dart | 42 +- lib/presentation/pages/map/map_page.dart | 1 - .../profile/profile_attendance_page.dart | 19 +- .../pages/profile/profile_lectors_page.dart | 21 +- .../pages/profile/profile_nfc_pass_page.dart | 695 ++++++ .../pages/profile/profile_page.dart | 299 ++- .../pages/profile/profile_scores_page.dart | 20 +- lib/service_locator.dart | 52 +- pubspec.yaml | 24 +- 61 files changed, 5921 insertions(+), 653 deletions(-) create mode 100644 lib/data/models/nfc_pass_model.dart create mode 100644 lib/domain/entities/nfc_pass.dart create mode 100644 lib/domain/usecases/connect_nfc_pass.dart create mode 100644 lib/domain/usecases/fetch_nfc_code.dart create mode 100644 lib/domain/usecases/get_nfc_passes.dart create mode 100644 lib/domain/usecases/send_nfc_not_exist_feedback.dart delete mode 100644 lib/presentation/bloc/auth_bloc/auth_bloc.dart delete mode 100644 lib/presentation/bloc/auth_bloc/auth_event.dart delete mode 100644 lib/presentation/bloc/auth_bloc/auth_state.dart create mode 100644 lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.dart create mode 100644 lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.freezed.dart create mode 100644 lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_event.dart create mode 100644 lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_state.dart create mode 100644 lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.dart create mode 100644 lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.freezed.dart create mode 100644 lib/presentation/bloc/nfc_pass_bloc/nfc_pass_event.dart create mode 100644 lib/presentation/bloc/nfc_pass_bloc/nfc_pass_state.dart delete mode 100644 lib/presentation/bloc/profile_bloc/profile_bloc.dart delete mode 100644 lib/presentation/bloc/profile_bloc/profile_event.dart delete mode 100644 lib/presentation/bloc/profile_bloc/profile_state.dart create mode 100644 lib/presentation/bloc/user_bloc/user_bloc.dart create mode 100644 lib/presentation/bloc/user_bloc/user_bloc.freezed.dart create mode 100644 lib/presentation/bloc/user_bloc/user_event.dart create mode 100644 lib/presentation/bloc/user_bloc/user_state.dart create mode 100644 lib/presentation/pages/profile/profile_nfc_pass_page.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 3aaa4d79..e0f4381a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="ninja.mirea.mireaapp"> + setTokenToCache(String token); Future getTokenFromCache(); Future removeTokenFromCache(); + + Future getNfcCodeFromCache(); + Future setNfcCodeToCache(int code); + Future removeNfcCodeFromCache(); } class UserLocalDataImpl implements UserLocalData { final SharedPreferences sharedPreferences; + final FlutterSecureStorage secureStorage; - UserLocalDataImpl({required this.sharedPreferences}); + UserLocalDataImpl({ + required this.sharedPreferences, + required this.secureStorage, + }); @override Future setTokenToCache(String token) { - return sharedPreferences.setString('auth_token', token); + return secureStorage.write(key: 'lks_access_token', value: token); } @override - Future getTokenFromCache() { - String? token = sharedPreferences.getString('auth_token'); + Future getTokenFromCache() async { + String? token = await secureStorage.read(key: 'lks_access_token'); if (token == null) throw CacheException('Auth token are not set'); return Future.value(token); } @override Future removeTokenFromCache() { - return sharedPreferences.remove('auth_token'); + return secureStorage.delete(key: 'lks_access_token'); + } + + @override + Future getNfcCodeFromCache() async { + String? value = await secureStorage.read(key: 'nfc_code'); + + if (value == null) throw CacheException('NFC code are not set'); + + return Future.value(int.parse(value)); + } + + @override + Future setNfcCodeToCache(int code) async { + await secureStorage.write(key: 'nfc_code', value: code.toString()); + } + + @override + Future removeNfcCodeFromCache() async { + await secureStorage.delete(key: 'nfc_code'); } } diff --git a/lib/data/datasources/user_remote.dart b/lib/data/datasources/user_remote.dart index 0539bcb9..0c984f19 100644 --- a/lib/data/datasources/user_remote.dart +++ b/lib/data/datasources/user_remote.dart @@ -6,22 +6,29 @@ import 'package:rtu_mirea_app/common/oauth.dart'; import 'package:rtu_mirea_app/data/models/announce_model.dart'; import 'package:rtu_mirea_app/data/models/attendance_model.dart'; import 'package:rtu_mirea_app/data/models/employee_model.dart'; +import 'package:rtu_mirea_app/data/models/nfc_pass_model.dart'; import 'package:rtu_mirea_app/data/models/score_model.dart'; import 'package:rtu_mirea_app/data/models/user_model.dart'; abstract class UserRemoteData { Future auth(); Future logOut(); - Future getProfileData(String token); - Future> getAnnounces(String token); - Future> getEmployees(String token, String name); - Future> getAttendance( - String token, String dateStart, String dateEnd); - Future>> getScores(String token); + Future getProfileData(); + Future> getAnnounces(); + Future> getEmployees(String name); + Future> getAttendance(String dateStart, String dateEnd); + Future>> getScores(); + Future> getNfcPasses( + String code, String studentId, String deviceId); + Future getNfcCode(String code, String studentId, String deviceId); + Future connectNfcPass( + String code, String studentId, String deviceId, String deviceName); + Future sendNfcNotExistFeedback( + String fullName, String group, String personalNumber, String studentId); } class UserRemoteDataImpl implements UserRemoteData { - static const _apiUrl = 'https://lks.mirea.ninja/api/'; + static const _apiUrl = 'https://lks.mirea.ninja/api'; final Dio httpClient; final LksOauth2 lksOauth2; @@ -45,13 +52,14 @@ class UserRemoteDataImpl implements UserRemoteData { } @override - Future getProfileData(String token) async { + Future getProfileData() async { final response = await lksOauth2.oauth2Helper.get( - '$_apiUrl?action=getData&url=https://lk.mirea.ru/profile/', + '$_apiUrl/?action=getData&url=https://lk.mirea.ru/profile/', ); var jsonResponse = json.decode(response.body); - log('Status code: ${response.statusCode}, Response: ${response.body}'); + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'getProfileData'); if (jsonResponse.containsKey('errors')) { throw ServerException(jsonResponse['errors'][0]); @@ -59,17 +67,18 @@ class UserRemoteDataImpl implements UserRemoteData { if (response.statusCode == 200) { return UserModel.fromRawJson(response.body); } else { - throw ServerException('Response status code is $response.statusCode'); + throw ServerException('Response status code is ${response.statusCode}'); } } @override - Future> getAnnounces(String token) async { + Future> getAnnounces() async { final response = await lksOauth2.oauth2Helper.get( - '$_apiUrl?action=getData&url=https://lk.mirea.ru/livestream/', + '$_apiUrl/?action=getData&url=https://lk.mirea.ru/livestream/', ); - log('Status code: ${response.statusCode}, Response: ${response.body}'); + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'getAnnounces'); var jsonResponse = json.decode(response.body); if (jsonResponse.containsKey('errors')) { @@ -83,17 +92,18 @@ class UserRemoteDataImpl implements UserRemoteData { } return announces; } else { - throw ServerException('Response status code is $response.statusCode'); + throw ServerException('Response status code is ${response.statusCode}'); } } @override - Future> getEmployees(String token, String name) async { + Future> getEmployees(String name) async { final response = await lksOauth2.oauth2Helper.get( - '$_apiUrl?action=getData&url=https://lk.mirea.ru/lectors/&page=undefined&findname=$name', + '$_apiUrl/?action=getData&url=https://lk.mirea.ru/lectors/&page=undefined&findname=$name', ); - log('Status code: ${response.statusCode}, Response: ${response.body}'); + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'getEmployees'); var jsonResponse = json.decode(response.body); if (jsonResponse.containsKey('errors')) { @@ -109,17 +119,18 @@ class UserRemoteDataImpl implements UserRemoteData { } return employees; } else { - throw ServerException('Response status code is $response.statusCode'); + throw ServerException('Response status code is ${response.statusCode}'); } } @override - Future>> getScores(String token) async { + Future>> getScores() async { final response = await lksOauth2.oauth2Helper.get( - '$_apiUrl?action=getData&url=https://lk.mirea.ru/learning/scores/', + '$_apiUrl/?action=getData&url=https://lk.mirea.ru/learning/scores/', ); - log('Status code: ${response.statusCode}, Response: ${response.body}'); + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'getScores'); var jsonResponse = json.decode(response.body); if (jsonResponse.containsKey('errors')) { @@ -140,18 +151,74 @@ class UserRemoteDataImpl implements UserRemoteData { return scores; } else { - throw ServerException('Response status code is $response.statusCode'); + throw ServerException('Response status code is ${response.statusCode}'); + } + } + + @override + Future> getNfcPasses( + String code, String studentId, String deviceId) async { + final response = await lksOauth2.oauth2Helper + .get('$_apiUrl/cms/nfc-passes/$code/$studentId/$deviceId'); + + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'getScores'); + + if (response.statusCode != 200) { + try { + var jsonResponse = json.decode(response.body); + if (jsonResponse.containsKey('message')) { + throw ServerException(jsonResponse['message']); + } + } catch (e) { + throw ServerException('Response status code is ${response.statusCode}'); + } + } + + var jsonResponse = json.decode(response.body); + + List userNfcPasses = []; + userNfcPasses = List.from(jsonResponse['data'] + .map((x) => NfcPassModel.fromJson(x['attributes']))); + return userNfcPasses; + } + + @override + Future connectNfcPass( + String code, String studentId, String deviceId, String deviceName) async { + final data = { + 'code': code, + 'studentId': studentId, + 'deviceId': deviceId, + 'deviceName': deviceName, + }; + + final response = await lksOauth2.oauth2Helper.post( + '$_apiUrl/cms/nfc-passes', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: json.encode(data), + ); + + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'connectNfcPass'); + + if (response.statusCode != 200) { + throw ServerException('Response status code is ${response.statusCode}'); } } @override Future> getAttendance( - String token, String dateStart, String dateEnd) async { + String dateStart, String dateEnd) async { final response = await lksOauth2.oauth2Helper.get( - '$_apiUrl?action=getData&url=https://lk.mirea.ru/schedule/attendance/&startDate=$dateStart&endDate=$dateEnd', + '$_apiUrl/?action=getData&url=https://lk.mirea.ru/schedule/attendance/&startDate=$dateStart&endDate=$dateEnd', ); - log('Status code: ${response.statusCode}, Response: ${response.body}'); + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'getAttendance'); var jsonResponse = json.decode(response.body); if (jsonResponse.containsKey('errors')) { @@ -174,7 +241,68 @@ class UserRemoteDataImpl implements UserRemoteData { } return attendance; } else { - throw ServerException('Response status code is $response.statusCode'); + throw ServerException('Response status code is ${response.statusCode}'); + } + } + + @override + Future getNfcCode(String code, String studentId, String deviceId) async { + final response = await lksOauth2.oauth2Helper + .get('$_apiUrl/get-nfc-code/$code/$studentId/$deviceId'); + + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'getNfcCode'); + + var jsonResponse = json.decode(response.body); + + if (jsonResponse.containsKey('code')) { + return jsonResponse['code']; + } else { + // Local api error + if (jsonResponse.containsKey('message')) { + throw ServerException(jsonResponse['message']); + } + // LKS api error + else if (jsonResponse.containsKey('error') && + jsonResponse['error'] == 'StaffnodeNotExist') { + throw NfcStaffnodeNotExistException(); + } else { + throw ServerException('${jsonResponse['error']}'); + } + } + } + + @override + Future sendNfcNotExistFeedback(String fullName, String group, + String personalNumber, String studentId) async { + final data = { + 'fullName': fullName, + 'group': group, + 'personalNumber': personalNumber, + 'studentId': studentId, + }; + + final response = await lksOauth2.oauth2Helper.post( + '$_apiUrl/cms/nfc-pass-not-exist-feedback', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: json.encode(data), + ); + + log('Status code: ${response.statusCode}, Response: ${response.body}', + name: 'sendNfcNotExistFeedback'); + + if (response.statusCode != 200) { + if (response.statusCode == 400) { + if (response.body.contains("This attribute must be unique")) { + throw ServerException('Уже отправлено. Пожалуйста, подождите. ' + 'Время обработки заявки - до 7 рабочих дней.'); + } + } else { + throw ServerException('Response status code is ${response.statusCode}'); + } } } } diff --git a/lib/data/models/nfc_pass_model.dart b/lib/data/models/nfc_pass_model.dart new file mode 100644 index 00000000..f4c2e9a0 --- /dev/null +++ b/lib/data/models/nfc_pass_model.dart @@ -0,0 +1,33 @@ +import 'package:rtu_mirea_app/domain/entities/nfc_pass.dart'; + +class NfcPassModel extends NfcPass { + const NfcPassModel({ + required code, + required studentId, + required deviceName, + required deviceId, + required connected, + }) : super( + code: code, + studentId: studentId, + deviceName: deviceName, + connected: connected, + deviceId: deviceId, + ); + + factory NfcPassModel.fromJson(Map json) => NfcPassModel( + code: json["code"], + studentId: json["studentId"], + deviceName: json["deviceName"], + connected: json["connected"], + deviceId: json["deviceId"], + ); + + Map toJson() => { + "code": code, + "studentId": studentId, + "deviceName": deviceName, + "connected": connected, + "deviceId": deviceId, + }; +} diff --git a/lib/data/models/user_model.dart b/lib/data/models/user_model.dart index 8a880504..9a83920f 100644 --- a/lib/data/models/user_model.dart +++ b/lib/data/models/user_model.dart @@ -26,6 +26,8 @@ class UserModel extends User { required department, required prodDepartment, required type, + required code, + required studentId, }) : super( id: id, login: login, @@ -49,14 +51,21 @@ class UserModel extends User { department: department, prodDepartment: prodDepartment, type: type, + code: code, + studentId: studentId, ); factory UserModel.fromRawJson(String str) => UserModel.fromJson(json.decode(str)); factory UserModel.fromJson(Map json) { - final student = json["STUDENTS"].values.first; - final eduProgram = json["EDU_PROGRAM"].values.first; + final student = json["STUDENTS"].values.firstWhere((element) => + !element["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"].contains("Д") && + !element["PROPERTIES"]["PERSONAL_NUMBER"]["VALUE"].contains("Ж")); + + final eduProgram = json["EDU_PROGRAM"] + .values + .firstWhere((element) => element["ACTIVE"] == "Y"); return UserModel( id: json["ID"], @@ -81,6 +90,8 @@ class UserModel extends User { department: eduProgram["PROPERTIES"]["DEPARTMENT"]["VALUE_TEXT"], prodDepartment: eduProgram["PROPERTIES"]["PROD_DEPARTMENT"]["VALUE_TEXT"], type: eduProgram["TYPE"], + code: student["CODE"], + studentId: student["ID"], ); } } diff --git a/lib/data/repositories/user_repository_impl.dart b/lib/data/repositories/user_repository_impl.dart index a9613625..04be8294 100644 --- a/lib/data/repositories/user_repository_impl.dart +++ b/lib/data/repositories/user_repository_impl.dart @@ -7,6 +7,7 @@ import 'package:rtu_mirea_app/data/datasources/user_remote.dart'; import 'package:rtu_mirea_app/domain/entities/announce.dart'; import 'package:rtu_mirea_app/domain/entities/attendance.dart'; import 'package:rtu_mirea_app/domain/entities/employee.dart'; +import 'package:rtu_mirea_app/domain/entities/nfc_pass.dart'; import 'package:rtu_mirea_app/domain/entities/score.dart'; import 'package:rtu_mirea_app/domain/entities/user.dart'; import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; @@ -16,12 +17,13 @@ class UserRepositoryImpl implements UserRepository { final UserLocalData localDataSource; final InternetConnectionCheckerPlus connectionChecker; - UserRepositoryImpl( - {required this.remoteDataSource, - required this.localDataSource, - required this.connectionChecker}); + UserRepositoryImpl({ + required this.remoteDataSource, + required this.localDataSource, + required this.connectionChecker, + }); @override - Future> logIn(String login, String password) async { + Future> logIn() async { if (await connectionChecker.hasConnection) { try { final authToken = await remoteDataSource.auth(); @@ -40,18 +42,18 @@ class UserRepositoryImpl implements UserRepository { @override Future> logOut() async { - // try { - // return Right(await localDataSource.removeTokenFromCache()); - // } on CacheException { - // return Future.value(const Left(CacheFailure())); - // } - return Right(await remoteDataSource.logOut()); + try { + await remoteDataSource.logOut(); + return Right(await localDataSource.removeTokenFromCache()); + } on CacheException { + return Future.value(const Left(CacheFailure())); + } } @override - Future> getUserData(String token) async { + Future> getUserData() async { try { - final user = await remoteDataSource.getProfileData(token); + final user = await remoteDataSource.getProfileData(); return Future.value(Right(user)); } on ServerException { return Future.value(const Left(ServerFailure())); @@ -62,19 +64,16 @@ class UserRepositoryImpl implements UserRepository { Future> getAuthToken() async { try { final token = await localDataSource.getTokenFromCache(); - final _ = await remoteDataSource.getProfileData(token); return Future.value(Right(token)); } on CacheException { return Future.value(const Left(CacheFailure())); - } on ServerException { - return Future.value(const Left(ServerFailure())); } } @override - Future>> getAnnounces(String token) async { + Future>> getAnnounces() async { try { - final announces = await remoteDataSource.getAnnounces(token); + final announces = await remoteDataSource.getAnnounces(); return Right(announces); } on ServerException { return Future.value(const Left(ServerFailure())); @@ -82,10 +81,9 @@ class UserRepositoryImpl implements UserRepository { } @override - Future>> getEmployees( - String token, String name) async { + Future>> getEmployees(String name) async { try { - final employees = await remoteDataSource.getEmployees(token, name); + final employees = await remoteDataSource.getEmployees(name); return Right(employees); } on ServerException { return Future.value(const Left(ServerFailure())); @@ -93,10 +91,9 @@ class UserRepositoryImpl implements UserRepository { } @override - Future>>> getScores( - String token) async { + Future>>> getScores() async { try { - final scores = await remoteDataSource.getScores(token); + final scores = await remoteDataSource.getScores(); return Right(scores); } on ServerException { return Future.value(const Left(ServerFailure())); @@ -105,13 +102,77 @@ class UserRepositoryImpl implements UserRepository { @override Future>> getAattendance( - String token, String dateStart, String dateEnd) async { + String dateStart, String dateEnd) async { try { final attendance = - await remoteDataSource.getAttendance(token, dateStart, dateEnd); + await remoteDataSource.getAttendance(dateStart, dateEnd); return Right(attendance); } on ServerException { return Future.value(const Left(ServerFailure())); } } + + @override + Future>> getNfcPasses( + String code, String studentId, String deviceId) async { + try { + final nfcPasses = + await remoteDataSource.getNfcPasses(code, studentId, deviceId); + return Right(nfcPasses); + } on ServerException { + return Future.value(const Left(ServerFailure())); + } + } + + @override + Future> connectNfcPass( + String code, String studentId, String deviceId, String deviceName) { + try { + remoteDataSource.connectNfcPass(code, studentId, deviceId, deviceName); + return Future.value(const Right(null)); + } on ServerException { + return Future.value(const Left(ServerFailure())); + } + } + + @override + Future> fetchNfcCode( + String code, String studentId, String deviceId, String deviceName) async { + final isLoggedIn = await getAuthToken().then((value) => value.isRight()); + + if (!isLoggedIn) { + return const Left(ServerFailure("Пользователь не авторизован")); + } + + if (await connectionChecker.hasConnection) { + try { + final nfcCode = + await remoteDataSource.getNfcCode(code, studentId, deviceId); + await localDataSource.setNfcCodeToCache(nfcCode); + return const Right(null); + } on ServerException catch (e) { + if (e is NfcStaffnodeNotExistException) { + return const Left(NfcStaffnodeNotExistFailure()); + } + + await localDataSource.removeNfcCodeFromCache(); + + return Left(ServerFailure(e.cause)); + } + } else { + return const Left(ServerFailure("Отсутсвует соединение с интернетом")); + } + } + + @override + Future> sendNfcNotExistFeedback( + String fullName, String group, String personalNumber, String studentId) { + try { + remoteDataSource.sendNfcNotExistFeedback( + fullName, group, personalNumber, studentId); + return Future.value(const Right(null)); + } on ServerException catch (e) { + return Future.value(Left(ServerFailure(e.cause))); + } + } } diff --git a/lib/domain/entities/nfc_pass.dart b/lib/domain/entities/nfc_pass.dart new file mode 100644 index 00000000..c9b7a2e8 --- /dev/null +++ b/lib/domain/entities/nfc_pass.dart @@ -0,0 +1,20 @@ +import 'package:equatable/equatable.dart'; + +class NfcPass extends Equatable { + const NfcPass({ + required this.code, + required this.studentId, + required this.deviceName, + required this.deviceId, + required this.connected, + }); + + final String code; + final String studentId; + final String deviceName; + final String deviceId; + final bool connected; + + @override + List get props => [code, studentId, deviceName, deviceId, connected]; +} diff --git a/lib/domain/entities/user.dart b/lib/domain/entities/user.dart index 8d47b5af..4462051f 100644 --- a/lib/domain/entities/user.dart +++ b/lib/domain/entities/user.dart @@ -23,6 +23,8 @@ class User extends Equatable { final String department; final String prodDepartment; final String type; + final String code; + final String studentId; const User({ required this.id, @@ -47,6 +49,8 @@ class User extends Equatable { required this.department, required this.prodDepartment, required this.type, + required this.code, + required this.studentId, }); @override @@ -73,5 +77,7 @@ class User extends Equatable { department, prodDepartment, type, + code, + studentId, ]; } diff --git a/lib/domain/repositories/user_repository.dart b/lib/domain/repositories/user_repository.dart index 5fc38c72..486c55cf 100644 --- a/lib/domain/repositories/user_repository.dart +++ b/lib/domain/repositories/user_repository.dart @@ -3,18 +3,35 @@ import 'package:rtu_mirea_app/common/errors/failures.dart'; import 'package:rtu_mirea_app/domain/entities/announce.dart'; import 'package:rtu_mirea_app/domain/entities/attendance.dart'; import 'package:rtu_mirea_app/domain/entities/employee.dart'; +import 'package:rtu_mirea_app/domain/entities/nfc_pass.dart'; import 'package:rtu_mirea_app/domain/entities/score.dart'; import 'package:rtu_mirea_app/domain/entities/user.dart'; abstract class UserRepository { - Future> logIn(String login, String password); + Future> logIn(); Future> logOut(); - Future> getUserData(String token); - Future>> getAnnounces(String token); - Future>> getEmployees( - String token, String name); - Future>>> getScores(String token); + Future> getUserData(); + Future>> getAnnounces(); + Future>> getEmployees(String name); + Future>>> getScores(); Future>> getAattendance( - String token, String dateStart, String dateEnd); + String dateStart, String dateEnd); Future> getAuthToken(); + + Future>> getNfcPasses( + String code, String studentId, String deviceId); + Future> connectNfcPass( + String code, String studentId, String deviceId, String deviceName); + + /// Fetch NFC code from server. If device is not connected, then clear all + /// local NFC codes from [FlutterSecureStorage]. If device is connected, then + /// update local data with new NFC code. + /// + /// Returns [Failure] if device is not connected or if there is no internet + /// connection. Returns [void] if device is connected. + Future> fetchNfcCode( + String code, String studentId, String deviceId, String deviceName); + + Future> sendNfcNotExistFeedback( + String fullName, String group, String personalNumber, String studentId); } diff --git a/lib/domain/usecases/connect_nfc_pass.dart b/lib/domain/usecases/connect_nfc_pass.dart new file mode 100644 index 00000000..c09f187c --- /dev/null +++ b/lib/domain/usecases/connect_nfc_pass.dart @@ -0,0 +1,30 @@ +import 'package:dartz/dartz.dart'; +import 'package:equatable/equatable.dart'; +import 'package:rtu_mirea_app/common/errors/failures.dart'; +import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; +import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; + +class ConnectNfcPass extends UseCase { + final UserRepository userRepository; + + ConnectNfcPass(this.userRepository); + + @override + Future> call(ConnectNfcPassParams params) { + return userRepository.connectNfcPass( + params.code, params.studentId, params.deviceId, params.deviceName); + } +} + +class ConnectNfcPassParams extends Equatable { + const ConnectNfcPassParams( + this.code, this.studentId, this.deviceId, this.deviceName); + + final String code; + final String studentId; + final String deviceId; + final String deviceName; + + @override + List get props => [code, studentId, deviceId, deviceName]; +} diff --git a/lib/domain/usecases/fetch_nfc_code.dart b/lib/domain/usecases/fetch_nfc_code.dart new file mode 100644 index 00000000..8b70435c --- /dev/null +++ b/lib/domain/usecases/fetch_nfc_code.dart @@ -0,0 +1,34 @@ +import 'package:dartz/dartz.dart'; +import 'package:equatable/equatable.dart'; +import 'package:rtu_mirea_app/common/errors/failures.dart'; +import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; +import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; + +/// Get NFC code from server if device is connected. If device is not connected, +/// then clear all local NFC codes. +/// +/// If device is connected, then update local data with new NFC code. +class FetchNfcCode extends UseCase { + final UserRepository userRepository; + + FetchNfcCode(this.userRepository); + + @override + Future> call(FetchNfcCodeParams params) { + return userRepository.fetchNfcCode( + params.code, params.studentId, params.deviceId, params.deviceName); + } +} + +class FetchNfcCodeParams extends Equatable { + const FetchNfcCodeParams( + this.code, this.studentId, this.deviceId, this.deviceName); + + final String code; + final String studentId; + final String deviceId; + final String deviceName; + + @override + List get props => [code, studentId, deviceId, deviceName]; +} diff --git a/lib/domain/usecases/get_announces.dart b/lib/domain/usecases/get_announces.dart index c8075473..6833a212 100644 --- a/lib/domain/usecases/get_announces.dart +++ b/lib/domain/usecases/get_announces.dart @@ -1,26 +1,16 @@ import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; import 'package:rtu_mirea_app/common/errors/failures.dart'; import 'package:rtu_mirea_app/domain/entities/announce.dart'; import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; -class GetAnnounces extends UseCase, GetAnnouncesParams> { +class GetAnnounces extends UseCase, void> { final UserRepository userRepository; GetAnnounces(this.userRepository); @override - Future>> call( - GetAnnouncesParams params) async { - return await userRepository.getAnnounces(params.token); + Future>> call([params]) async { + return await userRepository.getAnnounces(); } } - -class GetAnnouncesParams extends Equatable { - final String token; - const GetAnnouncesParams(this.token); - - @override - List get props => [token]; -} diff --git a/lib/domain/usecases/get_attendance.dart b/lib/domain/usecases/get_attendance.dart index 389b9c30..e5f464d6 100644 --- a/lib/domain/usecases/get_attendance.dart +++ b/lib/domain/usecases/get_attendance.dart @@ -14,16 +14,15 @@ class GetAttendance extends UseCase, GetAttendanceParams> { Future>> call( GetAttendanceParams params) async { return await userRepository.getAattendance( - params.token, params.startDate, params.endDate); + params.startDate, params.endDate); } } class GetAttendanceParams extends Equatable { - final String token; final String startDate; final String endDate; - const GetAttendanceParams(this.token, this.startDate, this.endDate); + const GetAttendanceParams(this.startDate, this.endDate); @override - List get props => [token, startDate, endDate]; + List get props => [startDate, endDate]; } diff --git a/lib/domain/usecases/get_employees.dart b/lib/domain/usecases/get_employees.dart index 4ec58a39..0c3f813c 100644 --- a/lib/domain/usecases/get_employees.dart +++ b/lib/domain/usecases/get_employees.dart @@ -12,15 +12,14 @@ class GetEmployees extends UseCase, GetEmployeesParams> { @override Future>> call(GetEmployeesParams params) { - return userRepository.getEmployees(params.token, params.name); + return userRepository.getEmployees(params.name); } } class GetEmployeesParams extends Equatable { - final String token; final String name; - const GetEmployeesParams(this.token, this.name); + const GetEmployeesParams(this.name); @override - List get props => [token, name]; + List get props => [name]; } diff --git a/lib/domain/usecases/get_nfc_passes.dart b/lib/domain/usecases/get_nfc_passes.dart new file mode 100644 index 00000000..a5a05794 --- /dev/null +++ b/lib/domain/usecases/get_nfc_passes.dart @@ -0,0 +1,29 @@ +import 'package:dartz/dartz.dart'; +import 'package:equatable/equatable.dart'; +import 'package:rtu_mirea_app/common/errors/failures.dart'; +import 'package:rtu_mirea_app/domain/entities/nfc_pass.dart'; +import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; +import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; + +class GetNfcPasses extends UseCase, GetNfcPassesParams> { + final UserRepository userRepository; + + GetNfcPasses(this.userRepository); + + @override + Future>> call(GetNfcPassesParams params) { + return userRepository.getNfcPasses( + params.code, params.studentId, params.deviceId); + } +} + +class GetNfcPassesParams extends Equatable { + const GetNfcPassesParams(this.code, this.studentId, this.deviceId); + + final String code; + final String studentId; + final String deviceId; + + @override + List get props => [code, studentId, deviceId]; +} diff --git a/lib/domain/usecases/get_scores.dart b/lib/domain/usecases/get_scores.dart index b397f850..9030171d 100644 --- a/lib/domain/usecases/get_scores.dart +++ b/lib/domain/usecases/get_scores.dart @@ -1,26 +1,16 @@ import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; import 'package:rtu_mirea_app/common/errors/failures.dart'; import 'package:rtu_mirea_app/domain/entities/score.dart'; import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; -class GetScores extends UseCase>, GetScoresParams> { +class GetScores extends UseCase>, void> { final UserRepository userRepository; GetScores(this.userRepository); @override - Future>>> call( - GetScoresParams params) { - return userRepository.getScores(params.token); + Future>>> call([params]) async { + return userRepository.getScores(); } } - -class GetScoresParams extends Equatable { - final String token; - const GetScoresParams(this.token); - - @override - List get props => [token]; -} diff --git a/lib/domain/usecases/get_user_data.dart b/lib/domain/usecases/get_user_data.dart index 8b601b72..813111ef 100644 --- a/lib/domain/usecases/get_user_data.dart +++ b/lib/domain/usecases/get_user_data.dart @@ -1,25 +1,16 @@ import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; import 'package:rtu_mirea_app/common/errors/failures.dart'; import 'package:rtu_mirea_app/domain/entities/user.dart'; import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; -class GetUserData extends UseCase { +class GetUserData extends UseCase { final UserRepository userRepository; GetUserData(this.userRepository); @override - Future> call(GetUserDataParams params) { - return userRepository.getUserData(params.token); + Future> call([params]) async { + return userRepository.getUserData(); } } - -class GetUserDataParams extends Equatable { - final String token; - const GetUserDataParams(this.token); - - @override - List get props => [token]; -} diff --git a/lib/domain/usecases/log_in.dart b/lib/domain/usecases/log_in.dart index b340af0d..30640c94 100644 --- a/lib/domain/usecases/log_in.dart +++ b/lib/domain/usecases/log_in.dart @@ -1,26 +1,15 @@ import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; import 'package:rtu_mirea_app/common/errors/failures.dart'; import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; -class LogIn extends UseCase { +class LogIn extends UseCase { final UserRepository userRepository; LogIn(this.userRepository); @override - Future> call(LogInParams params) async { - return userRepository.logIn(params.login, params.password); + Future> call([params]) async { + return await userRepository.logIn(); } } - -class LogInParams extends Equatable { - final String login; - final String password; - - const LogInParams(this.login, this.password); - - @override - List get props => [login, password]; -} diff --git a/lib/domain/usecases/send_nfc_not_exist_feedback.dart b/lib/domain/usecases/send_nfc_not_exist_feedback.dart new file mode 100644 index 00000000..6ca7028c --- /dev/null +++ b/lib/domain/usecases/send_nfc_not_exist_feedback.dart @@ -0,0 +1,31 @@ +import 'package:dartz/dartz.dart'; +import 'package:equatable/equatable.dart'; +import 'package:rtu_mirea_app/common/errors/failures.dart'; +import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; +import 'package:rtu_mirea_app/domain/usecases/usecase.dart'; + +class SendNfcNotExistFeedback + extends UseCase { + final UserRepository userRepository; + + SendNfcNotExistFeedback(this.userRepository); + + @override + Future> call(SendNfcNotExistFeedbackParams params) { + return userRepository.sendNfcNotExistFeedback( + params.fullName, params.group, params.personalNumber, params.studentId); + } +} + +class SendNfcNotExistFeedbackParams extends Equatable { + const SendNfcNotExistFeedbackParams( + this.fullName, this.group, this.personalNumber, this.studentId); + + final String fullName; + final String group; + final String personalNumber; + final String studentId; + + @override + List get props => [fullName, group, personalNumber, studentId]; +} diff --git a/lib/main.dart b/lib/main.dart index 7c7e4759..60715015 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:intl/intl.dart'; import 'package:rtu_mirea_app/common/oauth.dart'; import 'package:rtu_mirea_app/common/widget_data_init.dart'; @@ -13,15 +14,18 @@ import 'package:rtu_mirea_app/presentation/bloc/about_app_bloc/about_app_bloc.da import 'package:rtu_mirea_app/presentation/bloc/announces_bloc/announces_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/app_cubit/app_cubit.dart'; import 'package:rtu_mirea_app/presentation/bloc/attendance_bloc/attendance_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/auth_bloc/auth_bloc.dart'; + import 'package:rtu_mirea_app/presentation/bloc/employee_bloc/employee_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/map_cubit/map_cubit.dart'; import 'package:rtu_mirea_app/presentation/bloc/news_bloc/news_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/profile_bloc/profile_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.dart'; + import 'package:rtu_mirea_app/presentation/bloc/schedule_bloc/schedule_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/scores_bloc/scores_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/stories_bloc/stories_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/update_info_bloc/update_info_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; import 'package:rtu_mirea_app/presentation/core/routes/routes.gr.dart'; import 'package:rtu_mirea_app/presentation/theme.dart'; import 'package:intl/intl_standalone.dart'; @@ -60,6 +64,13 @@ Future main() async { await FirebaseAnalytics.instance.logAppOpen(); if (kDebugMode) { + // Force disable Crashlytics collection while doing every day development + await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(false); + + // Clear Secure Storage + var secureStorage = getIt(); + await secureStorage.deleteAll(); + // Clear local dota var prefs = getIt(); await prefs.clear(); @@ -111,9 +122,11 @@ class App extends StatelessWidget { BlocProvider( create: (context) => getIt()..add(AboutAppGetMembers())), - BlocProvider( - create: (context) => getIt()..add(AuthLogInFromCache())), - BlocProvider(create: (context) => getIt()), + BlocProvider( + create: (context) => + getIt()..add(const UserEvent.started()), + lazy: false, + ), BlocProvider( create: (context) => getIt()), BlocProvider(create: (context) => getIt()), @@ -126,6 +139,16 @@ class App extends StatelessWidget { create: (_) => getIt(), lazy: false, // We need to init it as soon as possible ), + BlocProvider( + create: (_) => getIt() + ..add( + const NfcPassEvent.fetchNfcCode(), + ), + lazy: false, + ), + BlocProvider( + create: (_) => getIt(), + ), ], child: Consumer( builder: (BuildContext context, AppNotifier value, Widget? child) { diff --git a/lib/presentation/bloc/announces_bloc/announces_bloc.dart b/lib/presentation/bloc/announces_bloc/announces_bloc.dart index fcfaee28..f45d08fb 100644 --- a/lib/presentation/bloc/announces_bloc/announces_bloc.dart +++ b/lib/presentation/bloc/announces_bloc/announces_bloc.dart @@ -19,7 +19,7 @@ class AnnouncesBloc extends Bloc { ) async { emit(AnnouncesLoading()); - final announces = await getAnnounces(GetAnnouncesParams(event.token)); + final announces = await getAnnounces(); announces.fold((failure) => emit(AnnouncesLoadError()), (r) => emit(AnnouncesLoaded(announces: r))); diff --git a/lib/presentation/bloc/announces_bloc/announces_event.dart b/lib/presentation/bloc/announces_bloc/announces_event.dart index 0ae481c6..25697cff 100644 --- a/lib/presentation/bloc/announces_bloc/announces_event.dart +++ b/lib/presentation/bloc/announces_bloc/announces_event.dart @@ -8,12 +8,8 @@ abstract class AnnouncesEvent extends Equatable { } class LoadAnnounces extends AnnouncesEvent { - final String token; - - const LoadAnnounces({ - required this.token, - }); + const LoadAnnounces(); @override - List get props => [token]; + List get props => []; } diff --git a/lib/presentation/bloc/attendance_bloc/attendance_bloc.dart b/lib/presentation/bloc/attendance_bloc/attendance_bloc.dart index e3c0d080..d9fcaaed 100644 --- a/lib/presentation/bloc/attendance_bloc/attendance_bloc.dart +++ b/lib/presentation/bloc/attendance_bloc/attendance_bloc.dart @@ -40,7 +40,7 @@ class AttendanceBloc extends Bloc { emit(AttendanceLoading()); final announces = await getAttendance( - GetAttendanceParams(event.token, event.startDate, event.endDate)); + GetAttendanceParams(event.startDate, event.endDate)); announces.fold((failure) => emit(AttendanceLoadError()), (result) { emit(AttendanceLoaded( diff --git a/lib/presentation/bloc/attendance_bloc/attendance_event.dart b/lib/presentation/bloc/attendance_bloc/attendance_event.dart index fdbd1783..f9d39e9b 100644 --- a/lib/presentation/bloc/attendance_bloc/attendance_event.dart +++ b/lib/presentation/bloc/attendance_bloc/attendance_event.dart @@ -8,16 +8,14 @@ abstract class AttendanceEvent extends Equatable { } class LoadAttendance extends AttendanceEvent { - final String token; final String startDate; final String endDate; const LoadAttendance({ - required this.token, required this.startDate, required this.endDate, }); @override - List get props => [token, startDate, endDate]; + List get props => [startDate, endDate]; } diff --git a/lib/presentation/bloc/auth_bloc/auth_bloc.dart b/lib/presentation/bloc/auth_bloc/auth_bloc.dart deleted file mode 100644 index e620d90c..00000000 --- a/lib/presentation/bloc/auth_bloc/auth_bloc.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:rtu_mirea_app/domain/usecases/get_auth_token.dart'; -import 'package:rtu_mirea_app/domain/usecases/get_user_data.dart'; -import 'package:rtu_mirea_app/domain/usecases/log_in.dart'; -import 'package:rtu_mirea_app/domain/usecases/log_out.dart'; - -part 'auth_event.dart'; -part 'auth_state.dart'; - -class AuthBloc extends Bloc { - final LogIn logIn; - final LogOut logOut; - final GetUserData getUserData; - final GetAuthToken getAuthToken; - - AuthBloc({ - required this.getAuthToken, - required this.logIn, - required this.logOut, - required this.getUserData, - }) : super(AuthUnknown()) { - on(_onAuthLogIn); - on(_onAuthLogInFromCache); - on(_onAuthLogOut); - } - - void _onAuthLogInFromCache( - AuthLogInFromCache event, - Emitter emit, - ) async { - final res = await getAuthToken(); - res.fold((failure) => emit(const LogInError(cause: '')), - (token) => emit(LogInSuccess(token: token))); - } - - void _onAuthLogOut( - AuthLogOut event, - Emitter emit, - ) async { - final res = await logOut(); - res.fold((failure) => null, (r) => emit(AuthUnauthorized())); - } - - void _onAuthLogIn( - AuthLogInEvent event, - Emitter emit, - ) async { - if (event.login.length < 4 || event.password.length < 4) { - return emit(const LogInError(cause: "Введёт неверный логин или пароль")); - } - - final res = await logIn(LogInParams(event.login, event.password)); - res.fold( - (failure) => emit(LogInError( - cause: failure.cause ?? - "Ошибка при авторизации. Повторите попытку позже")), - (res) { - emit(LogInSuccess(token: res)); - FirebaseAnalytics.instance.logLogin(); - }, - ); - } -} diff --git a/lib/presentation/bloc/auth_bloc/auth_event.dart b/lib/presentation/bloc/auth_bloc/auth_event.dart deleted file mode 100644 index 026bd62d..00000000 --- a/lib/presentation/bloc/auth_bloc/auth_event.dart +++ /dev/null @@ -1,22 +0,0 @@ -part of 'auth_bloc.dart'; - -abstract class AuthEvent extends Equatable { - const AuthEvent(); - - @override - List get props => []; -} - -class AuthLogInEvent extends AuthEvent { - final String login; - final String password; - - const AuthLogInEvent({required this.login, required this.password}); - - @override - List get props => [login, password]; -} - -class AuthLogInFromCache extends AuthEvent {} - -class AuthLogOut extends AuthEvent {} diff --git a/lib/presentation/bloc/auth_bloc/auth_state.dart b/lib/presentation/bloc/auth_bloc/auth_state.dart deleted file mode 100644 index c921bcdf..00000000 --- a/lib/presentation/bloc/auth_bloc/auth_state.dart +++ /dev/null @@ -1,30 +0,0 @@ -part of 'auth_bloc.dart'; - -abstract class AuthState extends Equatable { - const AuthState(); - - @override - List get props => []; -} - -class AuthUnknown extends AuthState {} - -class AuthUnauthorized extends AuthState {} - -class LogInError extends AuthState { - final String cause; - - const LogInError({required this.cause}); - - @override - List get props => [cause]; -} - -class LogInSuccess extends AuthState { - final String token; - - const LogInSuccess({required this.token}); - - @override - List get props => [token]; -} diff --git a/lib/presentation/bloc/employee_bloc/employee_bloc.dart b/lib/presentation/bloc/employee_bloc/employee_bloc.dart index b6a978ae..1fb5ca01 100644 --- a/lib/presentation/bloc/employee_bloc/employee_bloc.dart +++ b/lib/presentation/bloc/employee_bloc/employee_bloc.dart @@ -20,8 +20,7 @@ class EmployeeBloc extends Bloc { if (event.name.length > 2) { emit(EmployeeLoading()); - final employees = - await getEmployees(GetEmployeesParams(event.token, event.name)); + final employees = await getEmployees(GetEmployeesParams(event.name)); employees.fold((failure) => emit(EmployeeLoadError()), (result) { if (result.isEmpty) { diff --git a/lib/presentation/bloc/employee_bloc/employee_event.dart b/lib/presentation/bloc/employee_bloc/employee_event.dart index a58bb823..fb64a74e 100644 --- a/lib/presentation/bloc/employee_bloc/employee_event.dart +++ b/lib/presentation/bloc/employee_bloc/employee_event.dart @@ -9,10 +9,9 @@ abstract class EmployeeEvent extends Equatable { class LoadEmployees extends EmployeeEvent { final String name; - final String token; - const LoadEmployees({required this.token, required this.name}); + const LoadEmployees({required this.name}); @override - List get props => [name, token]; + List get props => [name]; } diff --git a/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.dart b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.dart new file mode 100644 index 00000000..02fea498 --- /dev/null +++ b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.dart @@ -0,0 +1,35 @@ +import 'package:bloc/bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:rtu_mirea_app/domain/usecases/send_nfc_not_exist_feedback.dart'; + +part 'nfc_feedback_event.dart'; +part 'nfc_feedback_state.dart'; +part 'nfc_feedback_bloc.freezed.dart'; + +class NfcFeedbackBloc extends Bloc { + SendNfcNotExistFeedback sendNfcNotExistFeedback; + + NfcFeedbackBloc({required this.sendNfcNotExistFeedback}) + : super(const _Initial()) { + on((event, emit) { + event.map( + started: (e) => emit(const _Initial()), + sendFeedback: (e) async { + emit(const _Loading()); + final result = await sendNfcNotExistFeedback( + SendNfcNotExistFeedbackParams( + e.fullName, + e.group, + e.personalNumber, + e.studentId, + ), + ); + result.fold( + (failure) => emit(_Failure(failure.cause ?? 'Неизвестная ошибка')), + (success) => emit(const _Success()), + ); + }, + ); + }); + } +} diff --git a/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.freezed.dart b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.freezed.dart new file mode 100644 index 00000000..45e0d059 --- /dev/null +++ b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.freezed.dart @@ -0,0 +1,922 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'nfc_feedback_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$NfcFeedbackEvent { + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function(String fullName, String group, + String personalNumber, String studentId) + sendFeedback, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function(String fullName, String group, String personalNumber, + String studentId)? + sendFeedback, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function(String fullName, String group, String personalNumber, + String studentId)? + sendFeedback, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_SendFeedback value) sendFeedback, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_SendFeedback value)? sendFeedback, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_SendFeedback value)? sendFeedback, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NfcFeedbackEventCopyWith<$Res> { + factory $NfcFeedbackEventCopyWith( + NfcFeedbackEvent value, $Res Function(NfcFeedbackEvent) then) = + _$NfcFeedbackEventCopyWithImpl<$Res, NfcFeedbackEvent>; +} + +/// @nodoc +class _$NfcFeedbackEventCopyWithImpl<$Res, $Val extends NfcFeedbackEvent> + implements $NfcFeedbackEventCopyWith<$Res> { + _$NfcFeedbackEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_StartedCopyWith<$Res> { + factory _$$_StartedCopyWith( + _$_Started value, $Res Function(_$_Started) then) = + __$$_StartedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_StartedCopyWithImpl<$Res> + extends _$NfcFeedbackEventCopyWithImpl<$Res, _$_Started> + implements _$$_StartedCopyWith<$Res> { + __$$_StartedCopyWithImpl(_$_Started _value, $Res Function(_$_Started) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Started implements _Started { + const _$_Started(); + + @override + String toString() { + return 'NfcFeedbackEvent.started()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Started); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function(String fullName, String group, + String personalNumber, String studentId) + sendFeedback, + }) { + return started(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function(String fullName, String group, String personalNumber, + String studentId)? + sendFeedback, + }) { + return started?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function(String fullName, String group, String personalNumber, + String studentId)? + sendFeedback, + required TResult orElse(), + }) { + if (started != null) { + return started(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_SendFeedback value) sendFeedback, + }) { + return started(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_SendFeedback value)? sendFeedback, + }) { + return started?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_SendFeedback value)? sendFeedback, + required TResult orElse(), + }) { + if (started != null) { + return started(this); + } + return orElse(); + } +} + +abstract class _Started implements NfcFeedbackEvent { + const factory _Started() = _$_Started; +} + +/// @nodoc +abstract class _$$_SendFeedbackCopyWith<$Res> { + factory _$$_SendFeedbackCopyWith( + _$_SendFeedback value, $Res Function(_$_SendFeedback) then) = + __$$_SendFeedbackCopyWithImpl<$Res>; + @useResult + $Res call( + {String fullName, String group, String personalNumber, String studentId}); +} + +/// @nodoc +class __$$_SendFeedbackCopyWithImpl<$Res> + extends _$NfcFeedbackEventCopyWithImpl<$Res, _$_SendFeedback> + implements _$$_SendFeedbackCopyWith<$Res> { + __$$_SendFeedbackCopyWithImpl( + _$_SendFeedback _value, $Res Function(_$_SendFeedback) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fullName = null, + Object? group = null, + Object? personalNumber = null, + Object? studentId = null, + }) { + return _then(_$_SendFeedback( + fullName: null == fullName + ? _value.fullName + : fullName // ignore: cast_nullable_to_non_nullable + as String, + group: null == group + ? _value.group + : group // ignore: cast_nullable_to_non_nullable + as String, + personalNumber: null == personalNumber + ? _value.personalNumber + : personalNumber // ignore: cast_nullable_to_non_nullable + as String, + studentId: null == studentId + ? _value.studentId + : studentId // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_SendFeedback implements _SendFeedback { + const _$_SendFeedback( + {required this.fullName, + required this.group, + required this.personalNumber, + required this.studentId}); + + @override + final String fullName; + @override + final String group; + @override + final String personalNumber; + @override + final String studentId; + + @override + String toString() { + return 'NfcFeedbackEvent.sendFeedback(fullName: $fullName, group: $group, personalNumber: $personalNumber, studentId: $studentId)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_SendFeedback && + (identical(other.fullName, fullName) || + other.fullName == fullName) && + (identical(other.group, group) || other.group == group) && + (identical(other.personalNumber, personalNumber) || + other.personalNumber == personalNumber) && + (identical(other.studentId, studentId) || + other.studentId == studentId)); + } + + @override + int get hashCode => + Object.hash(runtimeType, fullName, group, personalNumber, studentId); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_SendFeedbackCopyWith<_$_SendFeedback> get copyWith => + __$$_SendFeedbackCopyWithImpl<_$_SendFeedback>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function(String fullName, String group, + String personalNumber, String studentId) + sendFeedback, + }) { + return sendFeedback(fullName, group, personalNumber, studentId); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function(String fullName, String group, String personalNumber, + String studentId)? + sendFeedback, + }) { + return sendFeedback?.call(fullName, group, personalNumber, studentId); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function(String fullName, String group, String personalNumber, + String studentId)? + sendFeedback, + required TResult orElse(), + }) { + if (sendFeedback != null) { + return sendFeedback(fullName, group, personalNumber, studentId); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_SendFeedback value) sendFeedback, + }) { + return sendFeedback(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_SendFeedback value)? sendFeedback, + }) { + return sendFeedback?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_SendFeedback value)? sendFeedback, + required TResult orElse(), + }) { + if (sendFeedback != null) { + return sendFeedback(this); + } + return orElse(); + } +} + +abstract class _SendFeedback implements NfcFeedbackEvent { + const factory _SendFeedback( + {required final String fullName, + required final String group, + required final String personalNumber, + required final String studentId}) = _$_SendFeedback; + + String get fullName; + String get group; + String get personalNumber; + String get studentId; + @JsonKey(ignore: true) + _$$_SendFeedbackCopyWith<_$_SendFeedback> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$NfcFeedbackState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(String message) failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(String message)? failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? success, + TResult Function(String message)? failure, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Success value) success, + required TResult Function(_Failure value) failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Success value)? success, + TResult? Function(_Failure value)? failure, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Success value)? success, + TResult Function(_Failure value)? failure, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NfcFeedbackStateCopyWith<$Res> { + factory $NfcFeedbackStateCopyWith( + NfcFeedbackState value, $Res Function(NfcFeedbackState) then) = + _$NfcFeedbackStateCopyWithImpl<$Res, NfcFeedbackState>; +} + +/// @nodoc +class _$NfcFeedbackStateCopyWithImpl<$Res, $Val extends NfcFeedbackState> + implements $NfcFeedbackStateCopyWith<$Res> { + _$NfcFeedbackStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_InitialCopyWith<$Res> { + factory _$$_InitialCopyWith( + _$_Initial value, $Res Function(_$_Initial) then) = + __$$_InitialCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_InitialCopyWithImpl<$Res> + extends _$NfcFeedbackStateCopyWithImpl<$Res, _$_Initial> + implements _$$_InitialCopyWith<$Res> { + __$$_InitialCopyWithImpl(_$_Initial _value, $Res Function(_$_Initial) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Initial implements _Initial { + const _$_Initial(); + + @override + String toString() { + return 'NfcFeedbackState.initial()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Initial); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(String message) failure, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(String message)? failure, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? success, + TResult Function(String message)? failure, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Success value) success, + required TResult Function(_Failure value) failure, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Success value)? success, + TResult? Function(_Failure value)? failure, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Success value)? success, + TResult Function(_Failure value)? failure, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class _Initial implements NfcFeedbackState { + const factory _Initial() = _$_Initial; +} + +/// @nodoc +abstract class _$$_LoadingCopyWith<$Res> { + factory _$$_LoadingCopyWith( + _$_Loading value, $Res Function(_$_Loading) then) = + __$$_LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_LoadingCopyWithImpl<$Res> + extends _$NfcFeedbackStateCopyWithImpl<$Res, _$_Loading> + implements _$$_LoadingCopyWith<$Res> { + __$$_LoadingCopyWithImpl(_$_Loading _value, $Res Function(_$_Loading) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Loading implements _Loading { + const _$_Loading(); + + @override + String toString() { + return 'NfcFeedbackState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(String message) failure, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(String message)? failure, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? success, + TResult Function(String message)? failure, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Success value) success, + required TResult Function(_Failure value) failure, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Success value)? success, + TResult? Function(_Failure value)? failure, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Success value)? success, + TResult Function(_Failure value)? failure, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class _Loading implements NfcFeedbackState { + const factory _Loading() = _$_Loading; +} + +/// @nodoc +abstract class _$$_SuccessCopyWith<$Res> { + factory _$$_SuccessCopyWith( + _$_Success value, $Res Function(_$_Success) then) = + __$$_SuccessCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_SuccessCopyWithImpl<$Res> + extends _$NfcFeedbackStateCopyWithImpl<$Res, _$_Success> + implements _$$_SuccessCopyWith<$Res> { + __$$_SuccessCopyWithImpl(_$_Success _value, $Res Function(_$_Success) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Success implements _Success { + const _$_Success(); + + @override + String toString() { + return 'NfcFeedbackState.success()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Success); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(String message) failure, + }) { + return success(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(String message)? failure, + }) { + return success?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? success, + TResult Function(String message)? failure, + required TResult orElse(), + }) { + if (success != null) { + return success(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Success value) success, + required TResult Function(_Failure value) failure, + }) { + return success(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Success value)? success, + TResult? Function(_Failure value)? failure, + }) { + return success?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Success value)? success, + TResult Function(_Failure value)? failure, + required TResult orElse(), + }) { + if (success != null) { + return success(this); + } + return orElse(); + } +} + +abstract class _Success implements NfcFeedbackState { + const factory _Success() = _$_Success; +} + +/// @nodoc +abstract class _$$_FailureCopyWith<$Res> { + factory _$$_FailureCopyWith( + _$_Failure value, $Res Function(_$_Failure) then) = + __$$_FailureCopyWithImpl<$Res>; + @useResult + $Res call({String message}); +} + +/// @nodoc +class __$$_FailureCopyWithImpl<$Res> + extends _$NfcFeedbackStateCopyWithImpl<$Res, _$_Failure> + implements _$$_FailureCopyWith<$Res> { + __$$_FailureCopyWithImpl(_$_Failure _value, $Res Function(_$_Failure) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = null, + }) { + return _then(_$_Failure( + null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_Failure implements _Failure { + const _$_Failure(this.message); + + @override + final String message; + + @override + String toString() { + return 'NfcFeedbackState.failure(message: $message)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Failure && + (identical(other.message, message) || other.message == message)); + } + + @override + int get hashCode => Object.hash(runtimeType, message); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_FailureCopyWith<_$_Failure> get copyWith => + __$$_FailureCopyWithImpl<_$_Failure>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(String message) failure, + }) { + return failure(message); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(String message)? failure, + }) { + return failure?.call(message); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function()? success, + TResult Function(String message)? failure, + required TResult orElse(), + }) { + if (failure != null) { + return failure(message); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Success value) success, + required TResult Function(_Failure value) failure, + }) { + return failure(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Success value)? success, + TResult? Function(_Failure value)? failure, + }) { + return failure?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Success value)? success, + TResult Function(_Failure value)? failure, + required TResult orElse(), + }) { + if (failure != null) { + return failure(this); + } + return orElse(); + } +} + +abstract class _Failure implements NfcFeedbackState { + const factory _Failure(final String message) = _$_Failure; + + String get message; + @JsonKey(ignore: true) + _$$_FailureCopyWith<_$_Failure> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_event.dart b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_event.dart new file mode 100644 index 00000000..7c2d2536 --- /dev/null +++ b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_event.dart @@ -0,0 +1,12 @@ +part of 'nfc_feedback_bloc.dart'; + +@freezed +class NfcFeedbackEvent with _$NfcFeedbackEvent { + const factory NfcFeedbackEvent.started() = _Started; + const factory NfcFeedbackEvent.sendFeedback({ + required String fullName, + required String group, + required String personalNumber, + required String studentId, + }) = _SendFeedback; +} diff --git a/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_state.dart b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_state.dart new file mode 100644 index 00000000..afac69a4 --- /dev/null +++ b/lib/presentation/bloc/nfc_feedback_bloc/nfc_feedback_state.dart @@ -0,0 +1,9 @@ +part of 'nfc_feedback_bloc.dart'; + +@freezed +class NfcFeedbackState with _$NfcFeedbackState { + const factory NfcFeedbackState.initial() = _Initial; + const factory NfcFeedbackState.loading() = _Loading; + const factory NfcFeedbackState.success() = _Success; + const factory NfcFeedbackState.failure(String message) = _Failure; +} diff --git a/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.dart b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.dart new file mode 100644 index 00000000..da0745c0 --- /dev/null +++ b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.dart @@ -0,0 +1,169 @@ +import 'package:bloc/bloc.dart'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_nfc_kit/flutter_nfc_kit.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:rtu_mirea_app/common/errors/failures.dart'; +import 'package:rtu_mirea_app/domain/entities/nfc_pass.dart'; +import 'package:rtu_mirea_app/domain/usecases/connect_nfc_pass.dart'; +import 'package:rtu_mirea_app/domain/usecases/fetch_nfc_code.dart'; +import 'package:rtu_mirea_app/domain/usecases/get_auth_token.dart'; +import 'package:rtu_mirea_app/domain/usecases/get_nfc_passes.dart'; +import 'package:rtu_mirea_app/domain/usecases/get_user_data.dart'; + +part 'nfc_pass_event.dart'; +part 'nfc_pass_state.dart'; +part 'nfc_pass_bloc.freezed.dart'; + +class NfcPassBloc extends Bloc { + /// This variable is used to prevent multiple fetches of NFC code. + static bool isNfcFetched = false; + + final GetNfcPasses getNfcPasses; + final ConnectNfcPass connectNfcPass; + final GetAuthToken getAuthToken; + final DeviceInfoPlugin deviceInfo; + final FetchNfcCode fetchNfcCode; + final GetUserData getUserData; + + NfcPassBloc({ + required this.getNfcPasses, + required this.connectNfcPass, + required this.deviceInfo, + required this.getAuthToken, + required this.getUserData, + required this.fetchNfcCode, + }) : super(const _Initial()) { + on<_Started>(_onStarted); + on<_GetNfcPasses>(_onGetNfcPasses); + on<_ConnectNfcPass>(_onConnectNfcPass); + on<_FetchNfcCode>(_onFetchNfcCode); + } + + void _onGetNfcPasses( + _GetNfcPasses event, + Emitter emit, + ) async { + final failureOrNfcPasses = await getNfcPasses( + GetNfcPassesParams( + event.code, + event.studentId, + event.deviceId, + ), + ); + failureOrNfcPasses.fold( + (failure) => emit(NfcPassState.error(failure.cause ?? "Ошибка")), + (nfcPasses) => emit(NfcPassState.loaded(nfcPasses)), + ); + } + + void _onConnectNfcPass( + _ConnectNfcPass event, + Emitter emit, + ) async { + emit(const NfcPassState.loading()); + + final failureOrNfcPasses = await connectNfcPass( + ConnectNfcPassParams( + event.code, + event.studentId, + event.deviceId, + event.deviceName, + ), + ); + + failureOrNfcPasses.fold( + (failure) => emit(NfcPassState.error(failure.cause ?? + "Не удалось подключить устройство. Попробуйте еще раз.")), + (nfcPasses) { + isNfcFetched = false; + add(_GetNfcPasses( + event.code, + event.studentId, + event.deviceId, + )); + }, + ); + } + + void _onStarted( + _Started event, + Emitter emit, + ) async { + emit(const NfcPassState.loading()); + if (kDebugMode) { + emit(const NfcPassState.initial()); + return; + } + final availability = await FlutterNfcKit.nfcAvailability; + + if (availability == NFCAvailability.not_supported) { + emit(const NfcPassState.nfcNotSupported()); + } else if (availability == NFCAvailability.disabled) { + emit(const NfcPassState.nfcDisabled()); + } else { + emit(const NfcPassState.initial()); + } + } + + void _onFetchNfcCode( + _FetchNfcCode event, + Emitter emit, + ) async { + // Token is not empty if user is logged in + bool isAunthenticated = false; + final tokenRes = await getAuthToken(); + tokenRes.fold( + (failure) => isAunthenticated = false, + (token) => isAunthenticated = true, + ); + + if (!isAunthenticated) { + return; + } + + final userDataRes = await getUserData(); + String? studentId; + String? code; + userDataRes.fold( + (failure) => studentId = null, + (userData) { + studentId = userData.studentId; + code = userData.code; + }, + ); + + if (studentId == null || code == null) { + return; + } + + final deviceInfoRes = await deviceInfo.androidInfo; + final deviceId = deviceInfoRes.id; + final deviceName = deviceInfoRes.model; + + final failureOrNfcCode = await fetchNfcCode( + FetchNfcCodeParams( + code!, + studentId!, + deviceId, + deviceName, + ), + ); + + failureOrNfcCode.fold((failure) { + if (failure is NfcStaffnodeNotExistFailure) { + emit(const NfcPassState.nfcNotExist()); + } else { + emit(NfcPassState.error(failure.cause ?? "Неизвестная ошибка")); + } + }, (nfcCode) { + add(_GetNfcPasses( + code!, + studentId!, + deviceId, + )); + + isNfcFetched = true; + }); + } +} diff --git a/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.freezed.dart b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.freezed.dart new file mode 100644 index 00000000..67c9b94b --- /dev/null +++ b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.freezed.dart @@ -0,0 +1,1865 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'nfc_pass_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$NfcPassEvent { + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function( + String code, String studentId, String deviceId, String deviceName) + connectNfcPass, + required TResult Function(String code, String studentId, String deviceId) + getNfcPasses, + required TResult Function() fetchNfcCode, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult? Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult? Function()? fetchNfcCode, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult Function()? fetchNfcCode, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_ConnectNfcPass value) connectNfcPass, + required TResult Function(_GetNfcPasses value) getNfcPasses, + required TResult Function(_FetchNfcCode value) fetchNfcCode, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_ConnectNfcPass value)? connectNfcPass, + TResult? Function(_GetNfcPasses value)? getNfcPasses, + TResult? Function(_FetchNfcCode value)? fetchNfcCode, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_ConnectNfcPass value)? connectNfcPass, + TResult Function(_GetNfcPasses value)? getNfcPasses, + TResult Function(_FetchNfcCode value)? fetchNfcCode, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NfcPassEventCopyWith<$Res> { + factory $NfcPassEventCopyWith( + NfcPassEvent value, $Res Function(NfcPassEvent) then) = + _$NfcPassEventCopyWithImpl<$Res, NfcPassEvent>; +} + +/// @nodoc +class _$NfcPassEventCopyWithImpl<$Res, $Val extends NfcPassEvent> + implements $NfcPassEventCopyWith<$Res> { + _$NfcPassEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_StartedCopyWith<$Res> { + factory _$$_StartedCopyWith( + _$_Started value, $Res Function(_$_Started) then) = + __$$_StartedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_StartedCopyWithImpl<$Res> + extends _$NfcPassEventCopyWithImpl<$Res, _$_Started> + implements _$$_StartedCopyWith<$Res> { + __$$_StartedCopyWithImpl(_$_Started _value, $Res Function(_$_Started) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Started with DiagnosticableTreeMixin implements _Started { + const _$_Started(); + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassEvent.started()'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('type', 'NfcPassEvent.started')); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Started); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function( + String code, String studentId, String deviceId, String deviceName) + connectNfcPass, + required TResult Function(String code, String studentId, String deviceId) + getNfcPasses, + required TResult Function() fetchNfcCode, + }) { + return started(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult? Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult? Function()? fetchNfcCode, + }) { + return started?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult Function()? fetchNfcCode, + required TResult orElse(), + }) { + if (started != null) { + return started(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_ConnectNfcPass value) connectNfcPass, + required TResult Function(_GetNfcPasses value) getNfcPasses, + required TResult Function(_FetchNfcCode value) fetchNfcCode, + }) { + return started(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_ConnectNfcPass value)? connectNfcPass, + TResult? Function(_GetNfcPasses value)? getNfcPasses, + TResult? Function(_FetchNfcCode value)? fetchNfcCode, + }) { + return started?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_ConnectNfcPass value)? connectNfcPass, + TResult Function(_GetNfcPasses value)? getNfcPasses, + TResult Function(_FetchNfcCode value)? fetchNfcCode, + required TResult orElse(), + }) { + if (started != null) { + return started(this); + } + return orElse(); + } +} + +abstract class _Started implements NfcPassEvent { + const factory _Started() = _$_Started; +} + +/// @nodoc +abstract class _$$_ConnectNfcPassCopyWith<$Res> { + factory _$$_ConnectNfcPassCopyWith( + _$_ConnectNfcPass value, $Res Function(_$_ConnectNfcPass) then) = + __$$_ConnectNfcPassCopyWithImpl<$Res>; + @useResult + $Res call( + {String code, String studentId, String deviceId, String deviceName}); +} + +/// @nodoc +class __$$_ConnectNfcPassCopyWithImpl<$Res> + extends _$NfcPassEventCopyWithImpl<$Res, _$_ConnectNfcPass> + implements _$$_ConnectNfcPassCopyWith<$Res> { + __$$_ConnectNfcPassCopyWithImpl( + _$_ConnectNfcPass _value, $Res Function(_$_ConnectNfcPass) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? code = null, + Object? studentId = null, + Object? deviceId = null, + Object? deviceName = null, + }) { + return _then(_$_ConnectNfcPass( + null == code + ? _value.code + : code // ignore: cast_nullable_to_non_nullable + as String, + null == studentId + ? _value.studentId + : studentId // ignore: cast_nullable_to_non_nullable + as String, + null == deviceId + ? _value.deviceId + : deviceId // ignore: cast_nullable_to_non_nullable + as String, + null == deviceName + ? _value.deviceName + : deviceName // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_ConnectNfcPass + with DiagnosticableTreeMixin + implements _ConnectNfcPass { + const _$_ConnectNfcPass( + this.code, this.studentId, this.deviceId, this.deviceName); + + @override + final String code; + @override + final String studentId; + @override + final String deviceId; + @override + final String deviceName; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassEvent.connectNfcPass(code: $code, studentId: $studentId, deviceId: $deviceId, deviceName: $deviceName)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'NfcPassEvent.connectNfcPass')) + ..add(DiagnosticsProperty('code', code)) + ..add(DiagnosticsProperty('studentId', studentId)) + ..add(DiagnosticsProperty('deviceId', deviceId)) + ..add(DiagnosticsProperty('deviceName', deviceName)); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_ConnectNfcPass && + (identical(other.code, code) || other.code == code) && + (identical(other.studentId, studentId) || + other.studentId == studentId) && + (identical(other.deviceId, deviceId) || + other.deviceId == deviceId) && + (identical(other.deviceName, deviceName) || + other.deviceName == deviceName)); + } + + @override + int get hashCode => + Object.hash(runtimeType, code, studentId, deviceId, deviceName); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_ConnectNfcPassCopyWith<_$_ConnectNfcPass> get copyWith => + __$$_ConnectNfcPassCopyWithImpl<_$_ConnectNfcPass>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function( + String code, String studentId, String deviceId, String deviceName) + connectNfcPass, + required TResult Function(String code, String studentId, String deviceId) + getNfcPasses, + required TResult Function() fetchNfcCode, + }) { + return connectNfcPass(code, studentId, deviceId, deviceName); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult? Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult? Function()? fetchNfcCode, + }) { + return connectNfcPass?.call(code, studentId, deviceId, deviceName); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult Function()? fetchNfcCode, + required TResult orElse(), + }) { + if (connectNfcPass != null) { + return connectNfcPass(code, studentId, deviceId, deviceName); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_ConnectNfcPass value) connectNfcPass, + required TResult Function(_GetNfcPasses value) getNfcPasses, + required TResult Function(_FetchNfcCode value) fetchNfcCode, + }) { + return connectNfcPass(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_ConnectNfcPass value)? connectNfcPass, + TResult? Function(_GetNfcPasses value)? getNfcPasses, + TResult? Function(_FetchNfcCode value)? fetchNfcCode, + }) { + return connectNfcPass?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_ConnectNfcPass value)? connectNfcPass, + TResult Function(_GetNfcPasses value)? getNfcPasses, + TResult Function(_FetchNfcCode value)? fetchNfcCode, + required TResult orElse(), + }) { + if (connectNfcPass != null) { + return connectNfcPass(this); + } + return orElse(); + } +} + +abstract class _ConnectNfcPass implements NfcPassEvent { + const factory _ConnectNfcPass(final String code, final String studentId, + final String deviceId, final String deviceName) = _$_ConnectNfcPass; + + String get code; + String get studentId; + String get deviceId; + String get deviceName; + @JsonKey(ignore: true) + _$$_ConnectNfcPassCopyWith<_$_ConnectNfcPass> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_GetNfcPassesCopyWith<$Res> { + factory _$$_GetNfcPassesCopyWith( + _$_GetNfcPasses value, $Res Function(_$_GetNfcPasses) then) = + __$$_GetNfcPassesCopyWithImpl<$Res>; + @useResult + $Res call({String code, String studentId, String deviceId}); +} + +/// @nodoc +class __$$_GetNfcPassesCopyWithImpl<$Res> + extends _$NfcPassEventCopyWithImpl<$Res, _$_GetNfcPasses> + implements _$$_GetNfcPassesCopyWith<$Res> { + __$$_GetNfcPassesCopyWithImpl( + _$_GetNfcPasses _value, $Res Function(_$_GetNfcPasses) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? code = null, + Object? studentId = null, + Object? deviceId = null, + }) { + return _then(_$_GetNfcPasses( + null == code + ? _value.code + : code // ignore: cast_nullable_to_non_nullable + as String, + null == studentId + ? _value.studentId + : studentId // ignore: cast_nullable_to_non_nullable + as String, + null == deviceId + ? _value.deviceId + : deviceId // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_GetNfcPasses with DiagnosticableTreeMixin implements _GetNfcPasses { + const _$_GetNfcPasses(this.code, this.studentId, this.deviceId); + + @override + final String code; + @override + final String studentId; + @override + final String deviceId; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassEvent.getNfcPasses(code: $code, studentId: $studentId, deviceId: $deviceId)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'NfcPassEvent.getNfcPasses')) + ..add(DiagnosticsProperty('code', code)) + ..add(DiagnosticsProperty('studentId', studentId)) + ..add(DiagnosticsProperty('deviceId', deviceId)); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_GetNfcPasses && + (identical(other.code, code) || other.code == code) && + (identical(other.studentId, studentId) || + other.studentId == studentId) && + (identical(other.deviceId, deviceId) || + other.deviceId == deviceId)); + } + + @override + int get hashCode => Object.hash(runtimeType, code, studentId, deviceId); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_GetNfcPassesCopyWith<_$_GetNfcPasses> get copyWith => + __$$_GetNfcPassesCopyWithImpl<_$_GetNfcPasses>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function( + String code, String studentId, String deviceId, String deviceName) + connectNfcPass, + required TResult Function(String code, String studentId, String deviceId) + getNfcPasses, + required TResult Function() fetchNfcCode, + }) { + return getNfcPasses(code, studentId, deviceId); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult? Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult? Function()? fetchNfcCode, + }) { + return getNfcPasses?.call(code, studentId, deviceId); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult Function()? fetchNfcCode, + required TResult orElse(), + }) { + if (getNfcPasses != null) { + return getNfcPasses(code, studentId, deviceId); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_ConnectNfcPass value) connectNfcPass, + required TResult Function(_GetNfcPasses value) getNfcPasses, + required TResult Function(_FetchNfcCode value) fetchNfcCode, + }) { + return getNfcPasses(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_ConnectNfcPass value)? connectNfcPass, + TResult? Function(_GetNfcPasses value)? getNfcPasses, + TResult? Function(_FetchNfcCode value)? fetchNfcCode, + }) { + return getNfcPasses?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_ConnectNfcPass value)? connectNfcPass, + TResult Function(_GetNfcPasses value)? getNfcPasses, + TResult Function(_FetchNfcCode value)? fetchNfcCode, + required TResult orElse(), + }) { + if (getNfcPasses != null) { + return getNfcPasses(this); + } + return orElse(); + } +} + +abstract class _GetNfcPasses implements NfcPassEvent { + const factory _GetNfcPasses( + final String code, final String studentId, final String deviceId) = + _$_GetNfcPasses; + + String get code; + String get studentId; + String get deviceId; + @JsonKey(ignore: true) + _$$_GetNfcPassesCopyWith<_$_GetNfcPasses> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_FetchNfcCodeCopyWith<$Res> { + factory _$$_FetchNfcCodeCopyWith( + _$_FetchNfcCode value, $Res Function(_$_FetchNfcCode) then) = + __$$_FetchNfcCodeCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_FetchNfcCodeCopyWithImpl<$Res> + extends _$NfcPassEventCopyWithImpl<$Res, _$_FetchNfcCode> + implements _$$_FetchNfcCodeCopyWith<$Res> { + __$$_FetchNfcCodeCopyWithImpl( + _$_FetchNfcCode _value, $Res Function(_$_FetchNfcCode) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_FetchNfcCode with DiagnosticableTreeMixin implements _FetchNfcCode { + const _$_FetchNfcCode(); + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassEvent.fetchNfcCode()'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('type', 'NfcPassEvent.fetchNfcCode')); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_FetchNfcCode); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function( + String code, String studentId, String deviceId, String deviceName) + connectNfcPass, + required TResult Function(String code, String studentId, String deviceId) + getNfcPasses, + required TResult Function() fetchNfcCode, + }) { + return fetchNfcCode(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult? Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult? Function()? fetchNfcCode, + }) { + return fetchNfcCode?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function( + String code, String studentId, String deviceId, String deviceName)? + connectNfcPass, + TResult Function(String code, String studentId, String deviceId)? + getNfcPasses, + TResult Function()? fetchNfcCode, + required TResult orElse(), + }) { + if (fetchNfcCode != null) { + return fetchNfcCode(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_ConnectNfcPass value) connectNfcPass, + required TResult Function(_GetNfcPasses value) getNfcPasses, + required TResult Function(_FetchNfcCode value) fetchNfcCode, + }) { + return fetchNfcCode(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_ConnectNfcPass value)? connectNfcPass, + TResult? Function(_GetNfcPasses value)? getNfcPasses, + TResult? Function(_FetchNfcCode value)? fetchNfcCode, + }) { + return fetchNfcCode?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_ConnectNfcPass value)? connectNfcPass, + TResult Function(_GetNfcPasses value)? getNfcPasses, + TResult Function(_FetchNfcCode value)? fetchNfcCode, + required TResult orElse(), + }) { + if (fetchNfcCode != null) { + return fetchNfcCode(this); + } + return orElse(); + } +} + +abstract class _FetchNfcCode implements NfcPassEvent { + const factory _FetchNfcCode() = _$_FetchNfcCode; +} + +/// @nodoc +mixin _$NfcPassState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NfcPassStateCopyWith<$Res> { + factory $NfcPassStateCopyWith( + NfcPassState value, $Res Function(NfcPassState) then) = + _$NfcPassStateCopyWithImpl<$Res, NfcPassState>; +} + +/// @nodoc +class _$NfcPassStateCopyWithImpl<$Res, $Val extends NfcPassState> + implements $NfcPassStateCopyWith<$Res> { + _$NfcPassStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_InitialCopyWith<$Res> { + factory _$$_InitialCopyWith( + _$_Initial value, $Res Function(_$_Initial) then) = + __$$_InitialCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_InitialCopyWithImpl<$Res> + extends _$NfcPassStateCopyWithImpl<$Res, _$_Initial> + implements _$$_InitialCopyWith<$Res> { + __$$_InitialCopyWithImpl(_$_Initial _value, $Res Function(_$_Initial) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Initial with DiagnosticableTreeMixin implements _Initial { + const _$_Initial(); + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassState.initial()'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('type', 'NfcPassState.initial')); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Initial); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } +} + +abstract class _Initial implements NfcPassState { + const factory _Initial() = _$_Initial; +} + +/// @nodoc +abstract class _$$_LoadingCopyWith<$Res> { + factory _$$_LoadingCopyWith( + _$_Loading value, $Res Function(_$_Loading) then) = + __$$_LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_LoadingCopyWithImpl<$Res> + extends _$NfcPassStateCopyWithImpl<$Res, _$_Loading> + implements _$$_LoadingCopyWith<$Res> { + __$$_LoadingCopyWithImpl(_$_Loading _value, $Res Function(_$_Loading) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Loading with DiagnosticableTreeMixin implements _Loading { + const _$_Loading(); + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassState.loading()'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('type', 'NfcPassState.loading')); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class _Loading implements NfcPassState { + const factory _Loading() = _$_Loading; +} + +/// @nodoc +abstract class _$$_LoadedCopyWith<$Res> { + factory _$$_LoadedCopyWith(_$_Loaded value, $Res Function(_$_Loaded) then) = + __$$_LoadedCopyWithImpl<$Res>; + @useResult + $Res call({List nfcPasses}); +} + +/// @nodoc +class __$$_LoadedCopyWithImpl<$Res> + extends _$NfcPassStateCopyWithImpl<$Res, _$_Loaded> + implements _$$_LoadedCopyWith<$Res> { + __$$_LoadedCopyWithImpl(_$_Loaded _value, $Res Function(_$_Loaded) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? nfcPasses = null, + }) { + return _then(_$_Loaded( + null == nfcPasses + ? _value._nfcPasses + : nfcPasses // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$_Loaded with DiagnosticableTreeMixin implements _Loaded { + const _$_Loaded(final List nfcPasses) : _nfcPasses = nfcPasses; + + final List _nfcPasses; + @override + List get nfcPasses { + if (_nfcPasses is EqualUnmodifiableListView) return _nfcPasses; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_nfcPasses); + } + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassState.loaded(nfcPasses: $nfcPasses)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'NfcPassState.loaded')) + ..add(DiagnosticsProperty('nfcPasses', nfcPasses)); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Loaded && + const DeepCollectionEquality() + .equals(other._nfcPasses, _nfcPasses)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_nfcPasses)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_LoadedCopyWith<_$_Loaded> get copyWith => + __$$_LoadedCopyWithImpl<_$_Loaded>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) { + return loaded(nfcPasses); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) { + return loaded?.call(nfcPasses); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(nfcPasses); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) { + return loaded(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) { + return loaded?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) { + if (loaded != null) { + return loaded(this); + } + return orElse(); + } +} + +abstract class _Loaded implements NfcPassState { + const factory _Loaded(final List nfcPasses) = _$_Loaded; + + List get nfcPasses; + @JsonKey(ignore: true) + _$$_LoadedCopyWith<_$_Loaded> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_NfcNotExistCopyWith<$Res> { + factory _$$_NfcNotExistCopyWith( + _$_NfcNotExist value, $Res Function(_$_NfcNotExist) then) = + __$$_NfcNotExistCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_NfcNotExistCopyWithImpl<$Res> + extends _$NfcPassStateCopyWithImpl<$Res, _$_NfcNotExist> + implements _$$_NfcNotExistCopyWith<$Res> { + __$$_NfcNotExistCopyWithImpl( + _$_NfcNotExist _value, $Res Function(_$_NfcNotExist) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_NfcNotExist with DiagnosticableTreeMixin implements _NfcNotExist { + const _$_NfcNotExist(); + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassState.nfcNotExist()'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('type', 'NfcPassState.nfcNotExist')); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_NfcNotExist); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) { + return nfcNotExist(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) { + return nfcNotExist?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) { + if (nfcNotExist != null) { + return nfcNotExist(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) { + return nfcNotExist(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) { + return nfcNotExist?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) { + if (nfcNotExist != null) { + return nfcNotExist(this); + } + return orElse(); + } +} + +abstract class _NfcNotExist implements NfcPassState { + const factory _NfcNotExist() = _$_NfcNotExist; +} + +/// @nodoc +abstract class _$$_ErrorCopyWith<$Res> { + factory _$$_ErrorCopyWith(_$_Error value, $Res Function(_$_Error) then) = + __$$_ErrorCopyWithImpl<$Res>; + @useResult + $Res call({String cause}); +} + +/// @nodoc +class __$$_ErrorCopyWithImpl<$Res> + extends _$NfcPassStateCopyWithImpl<$Res, _$_Error> + implements _$$_ErrorCopyWith<$Res> { + __$$_ErrorCopyWithImpl(_$_Error _value, $Res Function(_$_Error) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? cause = null, + }) { + return _then(_$_Error( + null == cause + ? _value.cause + : cause // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_Error with DiagnosticableTreeMixin implements _Error { + const _$_Error(this.cause); + + @override + final String cause; + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassState.error(cause: $cause)'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('type', 'NfcPassState.error')) + ..add(DiagnosticsProperty('cause', cause)); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_Error && + (identical(other.cause, cause) || other.cause == cause)); + } + + @override + int get hashCode => Object.hash(runtimeType, cause); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_ErrorCopyWith<_$_Error> get copyWith => + __$$_ErrorCopyWithImpl<_$_Error>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) { + return error(cause); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) { + return error?.call(cause); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) { + if (error != null) { + return error(cause); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class _Error implements NfcPassState { + const factory _Error(final String cause) = _$_Error; + + String get cause; + @JsonKey(ignore: true) + _$$_ErrorCopyWith<_$_Error> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_NfcDisabledCopyWith<$Res> { + factory _$$_NfcDisabledCopyWith( + _$_NfcDisabled value, $Res Function(_$_NfcDisabled) then) = + __$$_NfcDisabledCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_NfcDisabledCopyWithImpl<$Res> + extends _$NfcPassStateCopyWithImpl<$Res, _$_NfcDisabled> + implements _$$_NfcDisabledCopyWith<$Res> { + __$$_NfcDisabledCopyWithImpl( + _$_NfcDisabled _value, $Res Function(_$_NfcDisabled) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_NfcDisabled with DiagnosticableTreeMixin implements _NfcDisabled { + const _$_NfcDisabled(); + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassState.nfcDisabled()'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('type', 'NfcPassState.nfcDisabled')); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_NfcDisabled); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) { + return nfcDisabled(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) { + return nfcDisabled?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) { + if (nfcDisabled != null) { + return nfcDisabled(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) { + return nfcDisabled(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) { + return nfcDisabled?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) { + if (nfcDisabled != null) { + return nfcDisabled(this); + } + return orElse(); + } +} + +abstract class _NfcDisabled implements NfcPassState { + const factory _NfcDisabled() = _$_NfcDisabled; +} + +/// @nodoc +abstract class _$$_NfcNotSupportedCopyWith<$Res> { + factory _$$_NfcNotSupportedCopyWith( + _$_NfcNotSupported value, $Res Function(_$_NfcNotSupported) then) = + __$$_NfcNotSupportedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_NfcNotSupportedCopyWithImpl<$Res> + extends _$NfcPassStateCopyWithImpl<$Res, _$_NfcNotSupported> + implements _$$_NfcNotSupportedCopyWith<$Res> { + __$$_NfcNotSupportedCopyWithImpl( + _$_NfcNotSupported _value, $Res Function(_$_NfcNotSupported) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_NfcNotSupported + with DiagnosticableTreeMixin + implements _NfcNotSupported { + const _$_NfcNotSupported(); + + @override + String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { + return 'NfcPassState.nfcNotSupported()'; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('type', 'NfcPassState.nfcNotSupported')); + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_NfcNotSupported); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function() loading, + required TResult Function(List nfcPasses) loaded, + required TResult Function() nfcNotExist, + required TResult Function(String cause) error, + required TResult Function() nfcDisabled, + required TResult Function() nfcNotSupported, + }) { + return nfcNotSupported(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function()? loading, + TResult? Function(List nfcPasses)? loaded, + TResult? Function()? nfcNotExist, + TResult? Function(String cause)? error, + TResult? Function()? nfcDisabled, + TResult? Function()? nfcNotSupported, + }) { + return nfcNotSupported?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function()? loading, + TResult Function(List nfcPasses)? loaded, + TResult Function()? nfcNotExist, + TResult Function(String cause)? error, + TResult Function()? nfcDisabled, + TResult Function()? nfcNotSupported, + required TResult orElse(), + }) { + if (nfcNotSupported != null) { + return nfcNotSupported(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Initial value) initial, + required TResult Function(_Loading value) loading, + required TResult Function(_Loaded value) loaded, + required TResult Function(_NfcNotExist value) nfcNotExist, + required TResult Function(_Error value) error, + required TResult Function(_NfcDisabled value) nfcDisabled, + required TResult Function(_NfcNotSupported value) nfcNotSupported, + }) { + return nfcNotSupported(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Initial value)? initial, + TResult? Function(_Loading value)? loading, + TResult? Function(_Loaded value)? loaded, + TResult? Function(_NfcNotExist value)? nfcNotExist, + TResult? Function(_Error value)? error, + TResult? Function(_NfcDisabled value)? nfcDisabled, + TResult? Function(_NfcNotSupported value)? nfcNotSupported, + }) { + return nfcNotSupported?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Initial value)? initial, + TResult Function(_Loading value)? loading, + TResult Function(_Loaded value)? loaded, + TResult Function(_NfcNotExist value)? nfcNotExist, + TResult Function(_Error value)? error, + TResult Function(_NfcDisabled value)? nfcDisabled, + TResult Function(_NfcNotSupported value)? nfcNotSupported, + required TResult orElse(), + }) { + if (nfcNotSupported != null) { + return nfcNotSupported(this); + } + return orElse(); + } +} + +abstract class _NfcNotSupported implements NfcPassState { + const factory _NfcNotSupported() = _$_NfcNotSupported; +} diff --git a/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_event.dart b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_event.dart new file mode 100644 index 00000000..c359b5ce --- /dev/null +++ b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_event.dart @@ -0,0 +1,19 @@ +part of 'nfc_pass_bloc.dart'; + +@freezed +class NfcPassEvent with _$NfcPassEvent { + const factory NfcPassEvent.started() = _Started; + const factory NfcPassEvent.connectNfcPass( + String code, String studentId, String deviceId, String deviceName) = + _ConnectNfcPass; + const factory NfcPassEvent.getNfcPasses( + String code, String studentId, String deviceId) = _GetNfcPasses; + + /// Event for fetching NFC code from server. If device is connected to the + /// server, it will return NFC code. If not, it will clear NFC code from + /// the device (Secure Storage) + /// + /// This event must be called after application is started, user is logged in + /// and device is connected to the server. + const factory NfcPassEvent.fetchNfcCode() = _FetchNfcCode; +} diff --git a/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_state.dart b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_state.dart new file mode 100644 index 00000000..5f8e945f --- /dev/null +++ b/lib/presentation/bloc/nfc_pass_bloc/nfc_pass_state.dart @@ -0,0 +1,15 @@ +part of 'nfc_pass_bloc.dart'; + +@freezed +class NfcPassState with _$NfcPassState { + const factory NfcPassState.initial() = _Initial; + + /// Loading state when the app is tring to get Device NFC availability status + /// and get NFC passes from the server + const factory NfcPassState.loading() = _Loading; + const factory NfcPassState.loaded(List nfcPasses) = _Loaded; + const factory NfcPassState.nfcNotExist() = _NfcNotExist; + const factory NfcPassState.error(String cause) = _Error; + const factory NfcPassState.nfcDisabled() = _NfcDisabled; + const factory NfcPassState.nfcNotSupported() = _NfcNotSupported; +} diff --git a/lib/presentation/bloc/profile_bloc/profile_bloc.dart b/lib/presentation/bloc/profile_bloc/profile_bloc.dart deleted file mode 100644 index 9e7088b7..00000000 --- a/lib/presentation/bloc/profile_bloc/profile_bloc.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:bloc/bloc.dart'; -import 'package:equatable/equatable.dart'; -import 'package:rtu_mirea_app/domain/entities/user.dart'; -import 'package:rtu_mirea_app/domain/usecases/get_user_data.dart'; - -part 'profile_event.dart'; -part 'profile_state.dart'; - -class ProfileBloc extends Bloc { - final GetUserData getUserData; - - ProfileBloc({required this.getUserData}) : super(ProfileInitial()) { - on(_onProfileGetUserData); - } - - void _onProfileGetUserData( - ProfileGetUserData event, - Emitter emit, - ) async { - // To get profile data only once - if (state.runtimeType != ProfileLoaded) { - emit(ProfileLoading()); - final user = await getUserData(GetUserDataParams(event.token)); - user.fold((failure) => emit(ProfileInitial()), - (r) => emit(ProfileLoaded(user: r))); - } - } -} diff --git a/lib/presentation/bloc/profile_bloc/profile_event.dart b/lib/presentation/bloc/profile_bloc/profile_event.dart deleted file mode 100644 index 7a9b6abc..00000000 --- a/lib/presentation/bloc/profile_bloc/profile_event.dart +++ /dev/null @@ -1,14 +0,0 @@ -part of 'profile_bloc.dart'; - -abstract class ProfileEvent extends Equatable { - const ProfileEvent(); - - @override - List get props => []; -} - -class ProfileGetUserData extends ProfileEvent { - final String token; - - const ProfileGetUserData(this.token); -} diff --git a/lib/presentation/bloc/profile_bloc/profile_state.dart b/lib/presentation/bloc/profile_bloc/profile_state.dart deleted file mode 100644 index 20de792f..00000000 --- a/lib/presentation/bloc/profile_bloc/profile_state.dart +++ /dev/null @@ -1,21 +0,0 @@ -part of 'profile_bloc.dart'; - -abstract class ProfileState extends Equatable { - const ProfileState(); - - @override - List get props => []; -} - -class ProfileInitial extends ProfileState {} - -class ProfileLoading extends ProfileState {} - -class ProfileLoaded extends ProfileState { - final User user; - - const ProfileLoaded({required this.user}); - - @override - List get props => [user]; -} diff --git a/lib/presentation/bloc/scores_bloc/scores_bloc.dart b/lib/presentation/bloc/scores_bloc/scores_bloc.dart index bd3034e5..28116073 100644 --- a/lib/presentation/bloc/scores_bloc/scores_bloc.dart +++ b/lib/presentation/bloc/scores_bloc/scores_bloc.dart @@ -45,7 +45,7 @@ class ScoresBloc extends Bloc { if (state.runtimeType != ScoresLoaded) { emit(ScoresLoading()); - final scores = await getScores(GetScoresParams(event.token)); + final scores = await getScores(); scores.fold((failure) => emit(ScoresLoadError()), (result) { emit(ScoresLoaded( diff --git a/lib/presentation/bloc/scores_bloc/scores_event.dart b/lib/presentation/bloc/scores_bloc/scores_event.dart index cabed0e2..8a4ae1d8 100644 --- a/lib/presentation/bloc/scores_bloc/scores_event.dart +++ b/lib/presentation/bloc/scores_bloc/scores_event.dart @@ -8,14 +8,10 @@ abstract class ScoresEvent extends Equatable { } class LoadScores extends ScoresEvent { - final String token; - - const LoadScores({ - required this.token, - }); + const LoadScores(); @override - List get props => [token]; + List get props => []; } class ChangeSelectedScoresSemester extends ScoresEvent { diff --git a/lib/presentation/bloc/user_bloc/user_bloc.dart b/lib/presentation/bloc/user_bloc/user_bloc.dart new file mode 100644 index 00000000..b1d9065f --- /dev/null +++ b/lib/presentation/bloc/user_bloc/user_bloc.dart @@ -0,0 +1,100 @@ +import 'package:bloc/bloc.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:rtu_mirea_app/domain/entities/user.dart'; +import 'package:rtu_mirea_app/domain/usecases/get_auth_token.dart'; +import 'package:rtu_mirea_app/domain/usecases/get_user_data.dart'; +import 'package:rtu_mirea_app/domain/usecases/log_in.dart'; +import 'package:rtu_mirea_app/domain/usecases/log_out.dart'; + +part 'user_event.dart'; +part 'user_state.dart'; +part 'user_bloc.freezed.dart'; + +class UserBloc extends Bloc { + final LogIn logIn; + final LogOut logOut; + final GetUserData getUserData; + final GetAuthToken getAuthToken; + + UserBloc({ + required this.logIn, + required this.logOut, + required this.getUserData, + required this.getAuthToken, + }) : super(const _Unauthorized()) { + on<_LogIn>(_onLogInEvent); + on<_LogOut>(_onLogOutEvent); + on<_Started>(_onGetUserDataEvent); + on<_GetUserData>(_onGetUserDataEvent); + } + + void _onLogInEvent( + UserEvent event, + Emitter emit, + ) async { + if (state is _Loading) return; + + emit(const _Loading()); + // We use oauth2 to get token. So we don't need to pass login and password + // to the server. We just need to pass them to the oauth2 server. + + bool loggedIn = false; + + (await logIn()).fold( + (failure) => emit(_LogInError( + failure.cause ?? "Ошибка при авторизации. Повторите попытку")), + (res) { + loggedIn = true; + }, + ); + + if (loggedIn) { + final user = await getUserData(); + + user.fold( + (failure) => emit(const _Unauthorized()), + (user) { + FirebaseAnalytics.instance.logLogin(); + emit(_LogInSuccess(user)); + }, + ); + } + } + + void _onLogOutEvent( + UserEvent event, + Emitter emit, + ) async { + final res = await logOut(); + res.fold((failure) => null, (r) => emit(const _Unauthorized())); + } + + void _onGetUserDataEvent( + UserEvent event, + Emitter emit, + ) async { + // To get profile data only once (If state is not loading) + if (state is _Loading) return; + + final token = await getAuthToken(); + + bool loggedIn = false; + + // If token in the storage, user is authorized at least once and we can + // try to get user data + token.fold((failure) => emit(const _Unauthorized()), (r) { + loggedIn = true; + }); + + if (loggedIn) { + emit(const _Loading()); + final user = await getUserData(); + + user.fold( + (failure) => emit(const _Unauthorized()), + (r) => emit(_LogInSuccess(r)), + ); + } + } +} diff --git a/lib/presentation/bloc/user_bloc/user_bloc.freezed.dart b/lib/presentation/bloc/user_bloc/user_bloc.freezed.dart new file mode 100644 index 00000000..fc3448bd --- /dev/null +++ b/lib/presentation/bloc/user_bloc/user_bloc.freezed.dart @@ -0,0 +1,1125 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'user_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +mixin _$UserEvent { + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function() logIn, + required TResult Function() logOut, + required TResult Function() getUserData, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function()? logIn, + TResult? Function()? logOut, + TResult? Function()? getUserData, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function()? logIn, + TResult Function()? logOut, + TResult Function()? getUserData, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_LogIn value) logIn, + required TResult Function(_LogOut value) logOut, + required TResult Function(_GetUserData value) getUserData, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_LogIn value)? logIn, + TResult? Function(_LogOut value)? logOut, + TResult? Function(_GetUserData value)? getUserData, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_LogIn value)? logIn, + TResult Function(_LogOut value)? logOut, + TResult Function(_GetUserData value)? getUserData, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserEventCopyWith<$Res> { + factory $UserEventCopyWith(UserEvent value, $Res Function(UserEvent) then) = + _$UserEventCopyWithImpl<$Res, UserEvent>; +} + +/// @nodoc +class _$UserEventCopyWithImpl<$Res, $Val extends UserEvent> + implements $UserEventCopyWith<$Res> { + _$UserEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_StartedCopyWith<$Res> { + factory _$$_StartedCopyWith( + _$_Started value, $Res Function(_$_Started) then) = + __$$_StartedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_StartedCopyWithImpl<$Res> + extends _$UserEventCopyWithImpl<$Res, _$_Started> + implements _$$_StartedCopyWith<$Res> { + __$$_StartedCopyWithImpl(_$_Started _value, $Res Function(_$_Started) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Started implements _Started { + const _$_Started(); + + @override + String toString() { + return 'UserEvent.started()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Started); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function() logIn, + required TResult Function() logOut, + required TResult Function() getUserData, + }) { + return started(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function()? logIn, + TResult? Function()? logOut, + TResult? Function()? getUserData, + }) { + return started?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function()? logIn, + TResult Function()? logOut, + TResult Function()? getUserData, + required TResult orElse(), + }) { + if (started != null) { + return started(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_LogIn value) logIn, + required TResult Function(_LogOut value) logOut, + required TResult Function(_GetUserData value) getUserData, + }) { + return started(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_LogIn value)? logIn, + TResult? Function(_LogOut value)? logOut, + TResult? Function(_GetUserData value)? getUserData, + }) { + return started?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_LogIn value)? logIn, + TResult Function(_LogOut value)? logOut, + TResult Function(_GetUserData value)? getUserData, + required TResult orElse(), + }) { + if (started != null) { + return started(this); + } + return orElse(); + } +} + +abstract class _Started implements UserEvent { + const factory _Started() = _$_Started; +} + +/// @nodoc +abstract class _$$_LogInCopyWith<$Res> { + factory _$$_LogInCopyWith(_$_LogIn value, $Res Function(_$_LogIn) then) = + __$$_LogInCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_LogInCopyWithImpl<$Res> + extends _$UserEventCopyWithImpl<$Res, _$_LogIn> + implements _$$_LogInCopyWith<$Res> { + __$$_LogInCopyWithImpl(_$_LogIn _value, $Res Function(_$_LogIn) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_LogIn implements _LogIn { + const _$_LogIn(); + + @override + String toString() { + return 'UserEvent.logIn()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_LogIn); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function() logIn, + required TResult Function() logOut, + required TResult Function() getUserData, + }) { + return logIn(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function()? logIn, + TResult? Function()? logOut, + TResult? Function()? getUserData, + }) { + return logIn?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function()? logIn, + TResult Function()? logOut, + TResult Function()? getUserData, + required TResult orElse(), + }) { + if (logIn != null) { + return logIn(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_LogIn value) logIn, + required TResult Function(_LogOut value) logOut, + required TResult Function(_GetUserData value) getUserData, + }) { + return logIn(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_LogIn value)? logIn, + TResult? Function(_LogOut value)? logOut, + TResult? Function(_GetUserData value)? getUserData, + }) { + return logIn?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_LogIn value)? logIn, + TResult Function(_LogOut value)? logOut, + TResult Function(_GetUserData value)? getUserData, + required TResult orElse(), + }) { + if (logIn != null) { + return logIn(this); + } + return orElse(); + } +} + +abstract class _LogIn implements UserEvent { + const factory _LogIn() = _$_LogIn; +} + +/// @nodoc +abstract class _$$_LogOutCopyWith<$Res> { + factory _$$_LogOutCopyWith(_$_LogOut value, $Res Function(_$_LogOut) then) = + __$$_LogOutCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_LogOutCopyWithImpl<$Res> + extends _$UserEventCopyWithImpl<$Res, _$_LogOut> + implements _$$_LogOutCopyWith<$Res> { + __$$_LogOutCopyWithImpl(_$_LogOut _value, $Res Function(_$_LogOut) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_LogOut implements _LogOut { + const _$_LogOut(); + + @override + String toString() { + return 'UserEvent.logOut()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_LogOut); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function() logIn, + required TResult Function() logOut, + required TResult Function() getUserData, + }) { + return logOut(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function()? logIn, + TResult? Function()? logOut, + TResult? Function()? getUserData, + }) { + return logOut?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function()? logIn, + TResult Function()? logOut, + TResult Function()? getUserData, + required TResult orElse(), + }) { + if (logOut != null) { + return logOut(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_LogIn value) logIn, + required TResult Function(_LogOut value) logOut, + required TResult Function(_GetUserData value) getUserData, + }) { + return logOut(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_LogIn value)? logIn, + TResult? Function(_LogOut value)? logOut, + TResult? Function(_GetUserData value)? getUserData, + }) { + return logOut?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_LogIn value)? logIn, + TResult Function(_LogOut value)? logOut, + TResult Function(_GetUserData value)? getUserData, + required TResult orElse(), + }) { + if (logOut != null) { + return logOut(this); + } + return orElse(); + } +} + +abstract class _LogOut implements UserEvent { + const factory _LogOut() = _$_LogOut; +} + +/// @nodoc +abstract class _$$_GetUserDataCopyWith<$Res> { + factory _$$_GetUserDataCopyWith( + _$_GetUserData value, $Res Function(_$_GetUserData) then) = + __$$_GetUserDataCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_GetUserDataCopyWithImpl<$Res> + extends _$UserEventCopyWithImpl<$Res, _$_GetUserData> + implements _$$_GetUserDataCopyWith<$Res> { + __$$_GetUserDataCopyWithImpl( + _$_GetUserData _value, $Res Function(_$_GetUserData) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_GetUserData implements _GetUserData { + const _$_GetUserData(); + + @override + String toString() { + return 'UserEvent.getUserData()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_GetUserData); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() started, + required TResult Function() logIn, + required TResult Function() logOut, + required TResult Function() getUserData, + }) { + return getUserData(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? started, + TResult? Function()? logIn, + TResult? Function()? logOut, + TResult? Function()? getUserData, + }) { + return getUserData?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? started, + TResult Function()? logIn, + TResult Function()? logOut, + TResult Function()? getUserData, + required TResult orElse(), + }) { + if (getUserData != null) { + return getUserData(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Started value) started, + required TResult Function(_LogIn value) logIn, + required TResult Function(_LogOut value) logOut, + required TResult Function(_GetUserData value) getUserData, + }) { + return getUserData(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Started value)? started, + TResult? Function(_LogIn value)? logIn, + TResult? Function(_LogOut value)? logOut, + TResult? Function(_GetUserData value)? getUserData, + }) { + return getUserData?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Started value)? started, + TResult Function(_LogIn value)? logIn, + TResult Function(_LogOut value)? logOut, + TResult Function(_GetUserData value)? getUserData, + required TResult orElse(), + }) { + if (getUserData != null) { + return getUserData(this); + } + return orElse(); + } +} + +abstract class _GetUserData implements UserEvent { + const factory _GetUserData() = _$_GetUserData; +} + +/// @nodoc +mixin _$UserState { + @optionalTypeArgs + TResult when({ + required TResult Function() unauthorized, + required TResult Function() loading, + required TResult Function(String cause) logInError, + required TResult Function(User user) logInSuccess, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? unauthorized, + TResult? Function()? loading, + TResult? Function(String cause)? logInError, + TResult? Function(User user)? logInSuccess, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? unauthorized, + TResult Function()? loading, + TResult Function(String cause)? logInError, + TResult Function(User user)? logInSuccess, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Unauthorized value) unauthorized, + required TResult Function(_Loading value) loading, + required TResult Function(_LogInError value) logInError, + required TResult Function(_LogInSuccess value) logInSuccess, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Unauthorized value)? unauthorized, + TResult? Function(_Loading value)? loading, + TResult? Function(_LogInError value)? logInError, + TResult? Function(_LogInSuccess value)? logInSuccess, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Unauthorized value)? unauthorized, + TResult Function(_Loading value)? loading, + TResult Function(_LogInError value)? logInError, + TResult Function(_LogInSuccess value)? logInSuccess, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserStateCopyWith<$Res> { + factory $UserStateCopyWith(UserState value, $Res Function(UserState) then) = + _$UserStateCopyWithImpl<$Res, UserState>; +} + +/// @nodoc +class _$UserStateCopyWithImpl<$Res, $Val extends UserState> + implements $UserStateCopyWith<$Res> { + _$UserStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$_UnauthorizedCopyWith<$Res> { + factory _$$_UnauthorizedCopyWith( + _$_Unauthorized value, $Res Function(_$_Unauthorized) then) = + __$$_UnauthorizedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_UnauthorizedCopyWithImpl<$Res> + extends _$UserStateCopyWithImpl<$Res, _$_Unauthorized> + implements _$$_UnauthorizedCopyWith<$Res> { + __$$_UnauthorizedCopyWithImpl( + _$_Unauthorized _value, $Res Function(_$_Unauthorized) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Unauthorized implements _Unauthorized { + const _$_Unauthorized(); + + @override + String toString() { + return 'UserState.unauthorized()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Unauthorized); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() unauthorized, + required TResult Function() loading, + required TResult Function(String cause) logInError, + required TResult Function(User user) logInSuccess, + }) { + return unauthorized(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? unauthorized, + TResult? Function()? loading, + TResult? Function(String cause)? logInError, + TResult? Function(User user)? logInSuccess, + }) { + return unauthorized?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? unauthorized, + TResult Function()? loading, + TResult Function(String cause)? logInError, + TResult Function(User user)? logInSuccess, + required TResult orElse(), + }) { + if (unauthorized != null) { + return unauthorized(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Unauthorized value) unauthorized, + required TResult Function(_Loading value) loading, + required TResult Function(_LogInError value) logInError, + required TResult Function(_LogInSuccess value) logInSuccess, + }) { + return unauthorized(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Unauthorized value)? unauthorized, + TResult? Function(_Loading value)? loading, + TResult? Function(_LogInError value)? logInError, + TResult? Function(_LogInSuccess value)? logInSuccess, + }) { + return unauthorized?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Unauthorized value)? unauthorized, + TResult Function(_Loading value)? loading, + TResult Function(_LogInError value)? logInError, + TResult Function(_LogInSuccess value)? logInSuccess, + required TResult orElse(), + }) { + if (unauthorized != null) { + return unauthorized(this); + } + return orElse(); + } +} + +abstract class _Unauthorized implements UserState { + const factory _Unauthorized() = _$_Unauthorized; +} + +/// @nodoc +abstract class _$$_LoadingCopyWith<$Res> { + factory _$$_LoadingCopyWith( + _$_Loading value, $Res Function(_$_Loading) then) = + __$$_LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$_LoadingCopyWithImpl<$Res> + extends _$UserStateCopyWithImpl<$Res, _$_Loading> + implements _$$_LoadingCopyWith<$Res> { + __$$_LoadingCopyWithImpl(_$_Loading _value, $Res Function(_$_Loading) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$_Loading implements _Loading { + const _$_Loading(); + + @override + String toString() { + return 'UserState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$_Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() unauthorized, + required TResult Function() loading, + required TResult Function(String cause) logInError, + required TResult Function(User user) logInSuccess, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? unauthorized, + TResult? Function()? loading, + TResult? Function(String cause)? logInError, + TResult? Function(User user)? logInSuccess, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? unauthorized, + TResult Function()? loading, + TResult Function(String cause)? logInError, + TResult Function(User user)? logInSuccess, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Unauthorized value) unauthorized, + required TResult Function(_Loading value) loading, + required TResult Function(_LogInError value) logInError, + required TResult Function(_LogInSuccess value) logInSuccess, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Unauthorized value)? unauthorized, + TResult? Function(_Loading value)? loading, + TResult? Function(_LogInError value)? logInError, + TResult? Function(_LogInSuccess value)? logInSuccess, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Unauthorized value)? unauthorized, + TResult Function(_Loading value)? loading, + TResult Function(_LogInError value)? logInError, + TResult Function(_LogInSuccess value)? logInSuccess, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class _Loading implements UserState { + const factory _Loading() = _$_Loading; +} + +/// @nodoc +abstract class _$$_LogInErrorCopyWith<$Res> { + factory _$$_LogInErrorCopyWith( + _$_LogInError value, $Res Function(_$_LogInError) then) = + __$$_LogInErrorCopyWithImpl<$Res>; + @useResult + $Res call({String cause}); +} + +/// @nodoc +class __$$_LogInErrorCopyWithImpl<$Res> + extends _$UserStateCopyWithImpl<$Res, _$_LogInError> + implements _$$_LogInErrorCopyWith<$Res> { + __$$_LogInErrorCopyWithImpl( + _$_LogInError _value, $Res Function(_$_LogInError) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? cause = null, + }) { + return _then(_$_LogInError( + null == cause + ? _value.cause + : cause // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc + +class _$_LogInError implements _LogInError { + const _$_LogInError(this.cause); + + @override + final String cause; + + @override + String toString() { + return 'UserState.logInError(cause: $cause)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_LogInError && + (identical(other.cause, cause) || other.cause == cause)); + } + + @override + int get hashCode => Object.hash(runtimeType, cause); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_LogInErrorCopyWith<_$_LogInError> get copyWith => + __$$_LogInErrorCopyWithImpl<_$_LogInError>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() unauthorized, + required TResult Function() loading, + required TResult Function(String cause) logInError, + required TResult Function(User user) logInSuccess, + }) { + return logInError(cause); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? unauthorized, + TResult? Function()? loading, + TResult? Function(String cause)? logInError, + TResult? Function(User user)? logInSuccess, + }) { + return logInError?.call(cause); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? unauthorized, + TResult Function()? loading, + TResult Function(String cause)? logInError, + TResult Function(User user)? logInSuccess, + required TResult orElse(), + }) { + if (logInError != null) { + return logInError(cause); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Unauthorized value) unauthorized, + required TResult Function(_Loading value) loading, + required TResult Function(_LogInError value) logInError, + required TResult Function(_LogInSuccess value) logInSuccess, + }) { + return logInError(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Unauthorized value)? unauthorized, + TResult? Function(_Loading value)? loading, + TResult? Function(_LogInError value)? logInError, + TResult? Function(_LogInSuccess value)? logInSuccess, + }) { + return logInError?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Unauthorized value)? unauthorized, + TResult Function(_Loading value)? loading, + TResult Function(_LogInError value)? logInError, + TResult Function(_LogInSuccess value)? logInSuccess, + required TResult orElse(), + }) { + if (logInError != null) { + return logInError(this); + } + return orElse(); + } +} + +abstract class _LogInError implements UserState { + const factory _LogInError(final String cause) = _$_LogInError; + + String get cause; + @JsonKey(ignore: true) + _$$_LogInErrorCopyWith<_$_LogInError> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$_LogInSuccessCopyWith<$Res> { + factory _$$_LogInSuccessCopyWith( + _$_LogInSuccess value, $Res Function(_$_LogInSuccess) then) = + __$$_LogInSuccessCopyWithImpl<$Res>; + @useResult + $Res call({User user}); +} + +/// @nodoc +class __$$_LogInSuccessCopyWithImpl<$Res> + extends _$UserStateCopyWithImpl<$Res, _$_LogInSuccess> + implements _$$_LogInSuccessCopyWith<$Res> { + __$$_LogInSuccessCopyWithImpl( + _$_LogInSuccess _value, $Res Function(_$_LogInSuccess) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? user = null, + }) { + return _then(_$_LogInSuccess( + null == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as User, + )); + } +} + +/// @nodoc + +class _$_LogInSuccess implements _LogInSuccess { + const _$_LogInSuccess(this.user); + + @override + final User user; + + @override + String toString() { + return 'UserState.logInSuccess(user: $user)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$_LogInSuccess && + (identical(other.user, user) || other.user == user)); + } + + @override + int get hashCode => Object.hash(runtimeType, user); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$_LogInSuccessCopyWith<_$_LogInSuccess> get copyWith => + __$$_LogInSuccessCopyWithImpl<_$_LogInSuccess>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() unauthorized, + required TResult Function() loading, + required TResult Function(String cause) logInError, + required TResult Function(User user) logInSuccess, + }) { + return logInSuccess(user); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? unauthorized, + TResult? Function()? loading, + TResult? Function(String cause)? logInError, + TResult? Function(User user)? logInSuccess, + }) { + return logInSuccess?.call(user); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? unauthorized, + TResult Function()? loading, + TResult Function(String cause)? logInError, + TResult Function(User user)? logInSuccess, + required TResult orElse(), + }) { + if (logInSuccess != null) { + return logInSuccess(user); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Unauthorized value) unauthorized, + required TResult Function(_Loading value) loading, + required TResult Function(_LogInError value) logInError, + required TResult Function(_LogInSuccess value) logInSuccess, + }) { + return logInSuccess(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Unauthorized value)? unauthorized, + TResult? Function(_Loading value)? loading, + TResult? Function(_LogInError value)? logInError, + TResult? Function(_LogInSuccess value)? logInSuccess, + }) { + return logInSuccess?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Unauthorized value)? unauthorized, + TResult Function(_Loading value)? loading, + TResult Function(_LogInError value)? logInError, + TResult Function(_LogInSuccess value)? logInSuccess, + required TResult orElse(), + }) { + if (logInSuccess != null) { + return logInSuccess(this); + } + return orElse(); + } +} + +abstract class _LogInSuccess implements UserState { + const factory _LogInSuccess(final User user) = _$_LogInSuccess; + + User get user; + @JsonKey(ignore: true) + _$$_LogInSuccessCopyWith<_$_LogInSuccess> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/presentation/bloc/user_bloc/user_event.dart b/lib/presentation/bloc/user_bloc/user_event.dart new file mode 100644 index 00000000..834e1120 --- /dev/null +++ b/lib/presentation/bloc/user_bloc/user_event.dart @@ -0,0 +1,9 @@ +part of 'user_bloc.dart'; + +@freezed +class UserEvent with _$UserEvent { + const factory UserEvent.started() = _Started; + const factory UserEvent.logIn() = _LogIn; + const factory UserEvent.logOut() = _LogOut; + const factory UserEvent.getUserData() = _GetUserData; +} diff --git a/lib/presentation/bloc/user_bloc/user_state.dart b/lib/presentation/bloc/user_bloc/user_state.dart new file mode 100644 index 00000000..50da8ea5 --- /dev/null +++ b/lib/presentation/bloc/user_bloc/user_state.dart @@ -0,0 +1,9 @@ +part of 'user_bloc.dart'; + +@freezed +class UserState with _$UserState { + const factory UserState.unauthorized() = _Unauthorized; + const factory UserState.loading() = _Loading; + const factory UserState.logInError(String cause) = _LogInError; + const factory UserState.logInSuccess(User user) = _LogInSuccess; +} diff --git a/lib/presentation/core/routes/routes.dart b/lib/presentation/core/routes/routes.dart index 00c2f073..7858af3b 100644 --- a/lib/presentation/core/routes/routes.dart +++ b/lib/presentation/core/routes/routes.dart @@ -14,6 +14,7 @@ import 'package:rtu_mirea_app/presentation/pages/profile/profile_announces_page. import 'package:rtu_mirea_app/presentation/pages/profile/profile_attendance_page.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/profile_detail_page.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/profile_lectors_page.dart'; +import 'package:rtu_mirea_app/presentation/pages/profile/profile_nfc_pass_page.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/profile_scores_page.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/profile_page.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/profile_settings_page.dart'; @@ -103,6 +104,10 @@ import 'package:rtu_mirea_app/presentation/pages/schedule/schedule_page.dart'; path: 'settings', page: ProfileSettingsPage, ), + AutoRoute( + path: 'nfc-pass', + page: ProfileNfcPassPage, + ) ], ), ], diff --git a/lib/presentation/core/routes/routes.gr.dart b/lib/presentation/core/routes/routes.gr.dart index 67bbdf1a..669b8db2 100644 --- a/lib/presentation/core/routes/routes.gr.dart +++ b/lib/presentation/core/routes/routes.gr.dart @@ -11,13 +11,13 @@ // ignore_for_file: type=lint // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:auto_route/auto_route.dart' as _i19; +import 'package:auto_route/auto_route.dart' as _i20; import 'package:auto_route/empty_router_widgets.dart' as _i4; -import 'package:flutter/material.dart' as _i20; -import 'package:rtu_mirea_app/domain/entities/news_item.dart' as _i23; -import 'package:rtu_mirea_app/domain/entities/story.dart' as _i22; -import 'package:rtu_mirea_app/domain/entities/user.dart' as _i24; -import 'package:rtu_mirea_app/presentation/core/routes/routes.dart' as _i21; +import 'package:flutter/material.dart' as _i21; +import 'package:rtu_mirea_app/domain/entities/news_item.dart' as _i24; +import 'package:rtu_mirea_app/domain/entities/story.dart' as _i23; +import 'package:rtu_mirea_app/domain/entities/user.dart' as _i25; +import 'package:rtu_mirea_app/presentation/core/routes/routes.dart' as _i22; import 'package:rtu_mirea_app/presentation/pages/home_page.dart' as _i1; import 'package:rtu_mirea_app/presentation/pages/login/login_page.dart' as _i11; import 'package:rtu_mirea_app/presentation/pages/map/map_page.dart' as _i5; @@ -38,6 +38,8 @@ import 'package:rtu_mirea_app/presentation/pages/profile/profile_detail_page.dar as _i15; import 'package:rtu_mirea_app/presentation/pages/profile/profile_lectors_page.dart' as _i16; +import 'package:rtu_mirea_app/presentation/pages/profile/profile_nfc_pass_page.dart' + as _i19; import 'package:rtu_mirea_app/presentation/pages/profile/profile_page.dart' as _i10; import 'package:rtu_mirea_app/presentation/pages/profile/profile_scores_page.dart' @@ -49,83 +51,83 @@ import 'package:rtu_mirea_app/presentation/pages/schedule/groups_select_page.dar import 'package:rtu_mirea_app/presentation/pages/schedule/schedule_page.dart' as _i6; -class AppRouter extends _i19.RootStackRouter { - AppRouter([_i20.GlobalKey<_i20.NavigatorState>? navigatorKey]) +class AppRouter extends _i20.RootStackRouter { + AppRouter([_i21.GlobalKey<_i21.NavigatorState>? navigatorKey]) : super(navigatorKey); @override - final Map pagesMap = { + final Map pagesMap = { HomeRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i1.HomePage(), ); }, OnBoardingRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i2.OnBoardingPage(), ); }, StoriesWrapperRoute.name: (routeData) { final args = routeData.argsAs(); - return _i19.CustomPage( + return _i20.CustomPage( routeData: routeData, child: _i3.StoriesWrapper( key: args.key, stories: args.stories, storyIndex: args.storyIndex, ), - customRouteBuilder: _i21.transparentRoute, + customRouteBuilder: _i22.transparentRoute, opaque: false, barrierDismissible: false, ); }, ScheduleRouter.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i4.EmptyRouterPage(), ); }, NewsRouter.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i4.EmptyRouterPage(), ); }, MapRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i5.MapPage(), ); }, ProfileRouter.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i4.EmptyRouterPage(), ); }, ScheduleRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i6.SchedulePage(), ); }, GroupsSelectRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i7.GroupsSelectPage(), ); }, NewsRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i8.NewsPage(), ); }, NewsDetailsRoute.name: (routeData) { final args = routeData.argsAs(); - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: _i9.NewsDetailsPage( key: args.key, @@ -134,38 +136,38 @@ class AppRouter extends _i19.RootStackRouter { ); }, ProfileRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i10.ProfilePage(), ); }, LoginRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i11.LoginPage(), ); }, AboutAppRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i12.AboutAppPage(), ); }, ProfileAnnouncesRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i13.ProfileAnnouncesPage(), ); }, ProfileAttendanceRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i14.ProfileAttendancePage(), ); }, ProfileDetailRoute.name: (routeData) { final args = routeData.argsAs(); - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: _i15.ProfileDetailPage( key: args.key, @@ -174,140 +176,151 @@ class AppRouter extends _i19.RootStackRouter { ); }, ProfileLectrosRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i16.ProfileLectrosPage(), ); }, ProfileScoresRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i17.ProfileScoresPage(), ); }, ProfileSettingsRoute.name: (routeData) { - return _i19.AdaptivePage( + return _i20.AdaptivePage( routeData: routeData, child: const _i18.ProfileSettingsPage(), ); }, + ProfileNfcPassRoute.name: (routeData) { + return _i20.AdaptivePage( + routeData: routeData, + child: const _i19.ProfileNfcPassPage(), + ); + }, }; @override - List<_i19.RouteConfig> get routes => [ - _i19.RouteConfig( + List<_i20.RouteConfig> get routes => [ + _i20.RouteConfig( HomeRoute.name, path: '/', children: [ - _i19.RouteConfig( + _i20.RouteConfig( '#redirect', path: '', parent: HomeRoute.name, redirectTo: 'schedule', fullMatch: true, ), - _i19.RouteConfig( + _i20.RouteConfig( ScheduleRouter.name, path: 'schedule', parent: HomeRoute.name, children: [ - _i19.RouteConfig( + _i20.RouteConfig( ScheduleRoute.name, path: '', parent: ScheduleRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( GroupsSelectRoute.name, path: 'select-group', parent: ScheduleRouter.name, ), ], ), - _i19.RouteConfig( + _i20.RouteConfig( NewsRouter.name, path: 'news', parent: HomeRoute.name, children: [ - _i19.RouteConfig( + _i20.RouteConfig( NewsRoute.name, path: '', parent: NewsRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( NewsDetailsRoute.name, path: 'details', parent: NewsRouter.name, ), ], ), - _i19.RouteConfig( + _i20.RouteConfig( MapRoute.name, path: 'map', parent: HomeRoute.name, ), - _i19.RouteConfig( + _i20.RouteConfig( ProfileRouter.name, path: 'profile', parent: HomeRoute.name, children: [ - _i19.RouteConfig( + _i20.RouteConfig( ProfileRoute.name, path: '', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( LoginRoute.name, path: 'login', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( AboutAppRoute.name, path: 'about', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( ProfileAnnouncesRoute.name, path: 'announces', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( ProfileAttendanceRoute.name, path: 'attendance', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( ProfileDetailRoute.name, path: 'details', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( ProfileLectrosRoute.name, path: 'lectors', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( ProfileScoresRoute.name, path: 'scores', parent: ProfileRouter.name, ), - _i19.RouteConfig( + _i20.RouteConfig( ProfileSettingsRoute.name, path: 'settings', parent: ProfileRouter.name, ), + _i20.RouteConfig( + ProfileNfcPassRoute.name, + path: 'nfc-pass', + parent: ProfileRouter.name, + ), ], ), ], ), - _i19.RouteConfig( + _i20.RouteConfig( OnBoardingRoute.name, path: '/onboarding', ), - _i19.RouteConfig( + _i20.RouteConfig( StoriesWrapperRoute.name, path: '/story', ), - _i19.RouteConfig( + _i20.RouteConfig( '*#redirect', path: '*', redirectTo: '/', @@ -318,8 +331,8 @@ class AppRouter extends _i19.RootStackRouter { /// generated route for /// [_i1.HomePage] -class HomeRoute extends _i19.PageRouteInfo { - const HomeRoute({List<_i19.PageRouteInfo>? children}) +class HomeRoute extends _i20.PageRouteInfo { + const HomeRoute({List<_i20.PageRouteInfo>? children}) : super( HomeRoute.name, path: '/', @@ -331,7 +344,7 @@ class HomeRoute extends _i19.PageRouteInfo { /// generated route for /// [_i2.OnBoardingPage] -class OnBoardingRoute extends _i19.PageRouteInfo { +class OnBoardingRoute extends _i20.PageRouteInfo { const OnBoardingRoute() : super( OnBoardingRoute.name, @@ -343,10 +356,10 @@ class OnBoardingRoute extends _i19.PageRouteInfo { /// generated route for /// [_i3.StoriesWrapper] -class StoriesWrapperRoute extends _i19.PageRouteInfo { +class StoriesWrapperRoute extends _i20.PageRouteInfo { StoriesWrapperRoute({ - _i20.Key? key, - required List<_i22.Story> stories, + _i21.Key? key, + required List<_i23.Story> stories, required int storyIndex, }) : super( StoriesWrapperRoute.name, @@ -368,9 +381,9 @@ class StoriesWrapperRouteArgs { required this.storyIndex, }); - final _i20.Key? key; + final _i21.Key? key; - final List<_i22.Story> stories; + final List<_i23.Story> stories; final int storyIndex; @@ -382,8 +395,8 @@ class StoriesWrapperRouteArgs { /// generated route for /// [_i4.EmptyRouterPage] -class ScheduleRouter extends _i19.PageRouteInfo { - const ScheduleRouter({List<_i19.PageRouteInfo>? children}) +class ScheduleRouter extends _i20.PageRouteInfo { + const ScheduleRouter({List<_i20.PageRouteInfo>? children}) : super( ScheduleRouter.name, path: 'schedule', @@ -395,8 +408,8 @@ class ScheduleRouter extends _i19.PageRouteInfo { /// generated route for /// [_i4.EmptyRouterPage] -class NewsRouter extends _i19.PageRouteInfo { - const NewsRouter({List<_i19.PageRouteInfo>? children}) +class NewsRouter extends _i20.PageRouteInfo { + const NewsRouter({List<_i20.PageRouteInfo>? children}) : super( NewsRouter.name, path: 'news', @@ -408,7 +421,7 @@ class NewsRouter extends _i19.PageRouteInfo { /// generated route for /// [_i5.MapPage] -class MapRoute extends _i19.PageRouteInfo { +class MapRoute extends _i20.PageRouteInfo { const MapRoute() : super( MapRoute.name, @@ -420,8 +433,8 @@ class MapRoute extends _i19.PageRouteInfo { /// generated route for /// [_i4.EmptyRouterPage] -class ProfileRouter extends _i19.PageRouteInfo { - const ProfileRouter({List<_i19.PageRouteInfo>? children}) +class ProfileRouter extends _i20.PageRouteInfo { + const ProfileRouter({List<_i20.PageRouteInfo>? children}) : super( ProfileRouter.name, path: 'profile', @@ -433,7 +446,7 @@ class ProfileRouter extends _i19.PageRouteInfo { /// generated route for /// [_i6.SchedulePage] -class ScheduleRoute extends _i19.PageRouteInfo { +class ScheduleRoute extends _i20.PageRouteInfo { const ScheduleRoute() : super( ScheduleRoute.name, @@ -445,7 +458,7 @@ class ScheduleRoute extends _i19.PageRouteInfo { /// generated route for /// [_i7.GroupsSelectPage] -class GroupsSelectRoute extends _i19.PageRouteInfo { +class GroupsSelectRoute extends _i20.PageRouteInfo { const GroupsSelectRoute() : super( GroupsSelectRoute.name, @@ -457,7 +470,7 @@ class GroupsSelectRoute extends _i19.PageRouteInfo { /// generated route for /// [_i8.NewsPage] -class NewsRoute extends _i19.PageRouteInfo { +class NewsRoute extends _i20.PageRouteInfo { const NewsRoute() : super( NewsRoute.name, @@ -469,10 +482,10 @@ class NewsRoute extends _i19.PageRouteInfo { /// generated route for /// [_i9.NewsDetailsPage] -class NewsDetailsRoute extends _i19.PageRouteInfo { +class NewsDetailsRoute extends _i20.PageRouteInfo { NewsDetailsRoute({ - _i20.Key? key, - required _i23.NewsItem newsItem, + _i21.Key? key, + required _i24.NewsItem newsItem, }) : super( NewsDetailsRoute.name, path: 'details', @@ -491,9 +504,9 @@ class NewsDetailsRouteArgs { required this.newsItem, }); - final _i20.Key? key; + final _i21.Key? key; - final _i23.NewsItem newsItem; + final _i24.NewsItem newsItem; @override String toString() { @@ -503,7 +516,7 @@ class NewsDetailsRouteArgs { /// generated route for /// [_i10.ProfilePage] -class ProfileRoute extends _i19.PageRouteInfo { +class ProfileRoute extends _i20.PageRouteInfo { const ProfileRoute() : super( ProfileRoute.name, @@ -515,7 +528,7 @@ class ProfileRoute extends _i19.PageRouteInfo { /// generated route for /// [_i11.LoginPage] -class LoginRoute extends _i19.PageRouteInfo { +class LoginRoute extends _i20.PageRouteInfo { const LoginRoute() : super( LoginRoute.name, @@ -527,7 +540,7 @@ class LoginRoute extends _i19.PageRouteInfo { /// generated route for /// [_i12.AboutAppPage] -class AboutAppRoute extends _i19.PageRouteInfo { +class AboutAppRoute extends _i20.PageRouteInfo { const AboutAppRoute() : super( AboutAppRoute.name, @@ -539,7 +552,7 @@ class AboutAppRoute extends _i19.PageRouteInfo { /// generated route for /// [_i13.ProfileAnnouncesPage] -class ProfileAnnouncesRoute extends _i19.PageRouteInfo { +class ProfileAnnouncesRoute extends _i20.PageRouteInfo { const ProfileAnnouncesRoute() : super( ProfileAnnouncesRoute.name, @@ -551,7 +564,7 @@ class ProfileAnnouncesRoute extends _i19.PageRouteInfo { /// generated route for /// [_i14.ProfileAttendancePage] -class ProfileAttendanceRoute extends _i19.PageRouteInfo { +class ProfileAttendanceRoute extends _i20.PageRouteInfo { const ProfileAttendanceRoute() : super( ProfileAttendanceRoute.name, @@ -563,10 +576,10 @@ class ProfileAttendanceRoute extends _i19.PageRouteInfo { /// generated route for /// [_i15.ProfileDetailPage] -class ProfileDetailRoute extends _i19.PageRouteInfo { +class ProfileDetailRoute extends _i20.PageRouteInfo { ProfileDetailRoute({ - _i20.Key? key, - required _i24.User user, + _i21.Key? key, + required _i25.User user, }) : super( ProfileDetailRoute.name, path: 'details', @@ -585,9 +598,9 @@ class ProfileDetailRouteArgs { required this.user, }); - final _i20.Key? key; + final _i21.Key? key; - final _i24.User user; + final _i25.User user; @override String toString() { @@ -597,7 +610,7 @@ class ProfileDetailRouteArgs { /// generated route for /// [_i16.ProfileLectrosPage] -class ProfileLectrosRoute extends _i19.PageRouteInfo { +class ProfileLectrosRoute extends _i20.PageRouteInfo { const ProfileLectrosRoute() : super( ProfileLectrosRoute.name, @@ -609,7 +622,7 @@ class ProfileLectrosRoute extends _i19.PageRouteInfo { /// generated route for /// [_i17.ProfileScoresPage] -class ProfileScoresRoute extends _i19.PageRouteInfo { +class ProfileScoresRoute extends _i20.PageRouteInfo { const ProfileScoresRoute() : super( ProfileScoresRoute.name, @@ -621,7 +634,7 @@ class ProfileScoresRoute extends _i19.PageRouteInfo { /// generated route for /// [_i18.ProfileSettingsPage] -class ProfileSettingsRoute extends _i19.PageRouteInfo { +class ProfileSettingsRoute extends _i20.PageRouteInfo { const ProfileSettingsRoute() : super( ProfileSettingsRoute.name, @@ -630,3 +643,15 @@ class ProfileSettingsRoute extends _i19.PageRouteInfo { static const String name = 'ProfileSettingsRoute'; } + +/// generated route for +/// [_i19.ProfileNfcPassPage] +class ProfileNfcPassRoute extends _i20.PageRouteInfo { + const ProfileNfcPassRoute() + : super( + ProfileNfcPassRoute.name, + path: 'nfc-pass', + ); + + static const String name = 'ProfileNfcPassRoute'; +} diff --git a/lib/presentation/pages/login/login_page.dart b/lib/presentation/pages/login/login_page.dart index fb9a40fc..c1fc21b4 100644 --- a/lib/presentation/pages/login/login_page.dart +++ b/lib/presentation/pages/login/login_page.dart @@ -1,7 +1,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/auth_bloc/auth_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; import 'package:rtu_mirea_app/presentation/theme.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/primary_button.dart'; import 'package:rtu_mirea_app/presentation/widgets/forms/labelled_input.dart'; @@ -23,13 +23,15 @@ class _LoginPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - body: BlocListener( + body: BlocConsumer( listener: (context, state) { - if (state is LogInSuccess) { - context.router.pop(); - } + state.whenOrNull( + logInSuccess: (st) { + context.router.pop(); + }, + ); }, - child: SafeArea( + builder: (context, state) => SafeArea( bottom: false, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), @@ -75,26 +77,22 @@ class _LoginPageState extends State { ], ), ), - BlocBuilder(builder: (context, state) { - if (state is LogInError && state.cause != '') { - return Padding( - padding: const EdgeInsets.only(top: 10), - child: Text( - state.cause, - style: AppTextStyle.bodyRegular - .copyWith(color: AppTheme.colors.colorful07), - ), - ); - } - return Container(); - }), + state.maybeMap( + logInError: (st) => Padding( + padding: const EdgeInsets.only(top: 10), + child: Text( + st.cause, + style: AppTextStyle.bodyRegular + .copyWith(color: AppTheme.colors.colorful07), + ), + ), + orElse: () => Container(), + ), const SizedBox(height: 40), PrimaryButton( text: 'Войти', onClick: () { - context.read().add(AuthLogInEvent( - login: _emailController.text, - password: _passController.text)); + context.read().add(const UserEvent.logIn()); }, ), ], diff --git a/lib/presentation/pages/map/map_page.dart b/lib/presentation/pages/map/map_page.dart index 837321b4..76c2f9a9 100644 --- a/lib/presentation/pages/map/map_page.dart +++ b/lib/presentation/pages/map/map_page.dart @@ -77,7 +77,6 @@ class _MapPageState extends State { // TODO: implement search bar without using [ImplicitlyAnimatedList]. // Package implicitly_animated_reorderable_list is DISCONTINUED and // project compilation fails because of it. - // Widget _buildSearchBar() { // return FloatingSearchBar( // accentColor: AppTheme.colors.primary, diff --git a/lib/presentation/pages/profile/profile_attendance_page.dart b/lib/presentation/pages/profile/profile_attendance_page.dart index 44dd8745..4cdf05aa 100644 --- a/lib/presentation/pages/profile/profile_attendance_page.dart +++ b/lib/presentation/pages/profile/profile_attendance_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/attendance_bloc/attendance_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/auth_bloc/auth_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/widgets/attendance_card.dart'; import 'package:intl/intl.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/select_range_date_button.dart'; @@ -42,14 +42,14 @@ class _ProfileAttendancePageState extends State { ), body: SafeArea( bottom: false, - child: BlocBuilder( - builder: (context, authState) { - if (authState is LogInSuccess) { - return BlocBuilder( + child: BlocBuilder( + builder: (context, userState) { + return userState.maybeMap( + logInSuccess: (value) => + BlocBuilder( builder: (context, state) { if (state is AttendanceInitial) { context.read().add(LoadAttendance( - token: authState.token, startDate: _getTextDates(_getFirstAndLastWeekDaysText())[0], endDate: @@ -79,7 +79,6 @@ class _ProfileAttendancePageState extends State { onDateSelected: (date) { context.read().add( LoadAttendance( - token: authState.token, startDate: _getTextDates(date)[0], endDate: _getTextDates(date)[1]), ); @@ -135,9 +134,9 @@ class _ProfileAttendancePageState extends State { ], ); }, - ); - } - return Container(); + ), + orElse: () => const Center(child: Text("Ошибка")), + ); }, ), ), diff --git a/lib/presentation/pages/profile/profile_lectors_page.dart b/lib/presentation/pages/profile/profile_lectors_page.dart index d1f4fa0c..7df99b87 100644 --- a/lib/presentation/pages/profile/profile_lectors_page.dart +++ b/lib/presentation/pages/profile/profile_lectors_page.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:material_floating_search_bar/material_floating_search_bar.dart'; -import 'package:rtu_mirea_app/presentation/bloc/auth_bloc/auth_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/employee_bloc/employee_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/widgets/lector_search_card.dart'; import 'package:rtu_mirea_app/presentation/typography.dart'; import 'package:rtu_mirea_app/presentation/theme.dart'; @@ -44,10 +44,10 @@ class _ProfileLectrosPageState extends State { backgroundColor: AppTheme.colors.background01, body: SafeArea( bottom: false, - child: BlocBuilder( - builder: (context, authState) { - if (authState is LogInSuccess) { - return BlocBuilder( + child: BlocBuilder( + builder: (context, userState) { + return userState.maybeMap( + logInSuccess: (value) => BlocBuilder( builder: (context, state) { return FloatingSearchBar( key: _searchBarKey, @@ -84,8 +84,9 @@ class _ProfileLectrosPageState extends State { progress: state is EmployeeLoading, onQueryChanged: (query) { if (query.length > 2) { - context.read().add( - LoadEmployees(token: authState.token, name: query)); + context + .read() + .add(LoadEmployees(name: query)); } }, transition: CircularFloatingSearchBarTransition(), @@ -126,9 +127,9 @@ class _ProfileLectrosPageState extends State { }, ); }, - ); - } - return Container(); + ), + orElse: () => Container(), + ); }, ), ), diff --git a/lib/presentation/pages/profile/profile_nfc_pass_page.dart b/lib/presentation/pages/profile/profile_nfc_pass_page.dart new file mode 100644 index 00000000..779598d1 --- /dev/null +++ b/lib/presentation/pages/profile/profile_nfc_pass_page.dart @@ -0,0 +1,695 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:get/get.dart'; +import 'package:rtu_mirea_app/domain/entities/nfc_pass.dart'; +import 'package:rtu_mirea_app/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.dart'; + +import 'package:rtu_mirea_app/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; +import 'package:rtu_mirea_app/presentation/widgets/buttons/colorful_button.dart'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:rtu_mirea_app/presentation/widgets/buttons/primary_button.dart'; + +import '../../widgets/buttons/text_outlined_button.dart'; +import 'package:rtu_mirea_app/presentation/typography.dart'; +import 'package:rtu_mirea_app/presentation/theme.dart'; +import 'package:app_settings/app_settings.dart'; + +import 'package:flutter/cupertino.dart'; + +class ProfileNfcPassPage extends StatefulWidget { + const ProfileNfcPassPage({Key? key}) : super(key: key); + + @override + State createState() => _ProfileNfcPageState(); +} + +class _ProfileNfcPageState extends State { + DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + + void _showSnackBarLoadInfo() { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Загружаем пропуск в устройство"), + ), + ); + } + + bool _showMyDevices = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("NFC-пропуск"), + ), + body: SafeArea( + bottom: false, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: BlocBuilder( + builder: (context, state) { + state.whenOrNull( + logInSuccess: (user) => context + .read() + .add(const NfcPassEvent.started())); + + return state.maybeMap( + logInSuccess: (state) { + final student = state.user; + return ListView( + children: [ + const SizedBox(height: 24), + FutureBuilder( + future: deviceInfo.androidInfo, + builder: (context, snapshot) { + if (snapshot.hasData) { + if (snapshot.data == null) { + return const _ErrorAndroidDataFetch(); + } + return BlocConsumer( + listener: (context, state) { + state.whenOrNull( + loaded: (nfcPasses) { + if (!NfcPassBloc.isNfcFetched) { + // If current device is not connected to + // any nfc pass + if (!nfcPasses.any((element) => + element.connected && + element.deviceId == + snapshot.data!.id)) { + return; + } + + _showSnackBarLoadInfo(); + context.read().add( + const NfcPassEvent.fetchNfcCode()); + } + }, + ); + }, + builder: (context, state) => state.map( + initial: (_) { + context.read().add( + NfcPassEvent.getNfcPasses( + student.code, + student.studentId, + snapshot.data!.id, + ), + ); + return const Center( + child: CircularProgressIndicator(), + ); + }, + loading: (_) => const Center( + child: CircularProgressIndicator(), + ), + loaded: (state) { + final connectedDevice = state.nfcPasses + .firstWhereOrNull((element) => + element.connected && + element.deviceId == + snapshot.data!.id); + + if (state.nfcPasses.isEmpty) { + return _NfcNotConnected( + onPressed: () => + context.read().add( + NfcPassEvent.connectNfcPass( + student.code, + student.studentId, + snapshot.data!.id, + snapshot.data!.model, + ), + ), + ); + } + if (!_showMyDevices && + connectedDevice != null) { + return _NfcPassCard( + deviceId: connectedDevice.deviceId, + deviceName: connectedDevice.deviceName, + onClick: () { + setState(() { + _showMyDevices = true; + }); + }, + ); + } else { + return Column( + children: [ + Text( + "Подключенные устройства", + style: AppTextStyle.title, + ), + const SizedBox(height: 16), + // Сначала подключенные устройства + for (final nfcPass in state.nfcPasses) + if (nfcPass.connected) + _NfcPassDeviceCard( + nfcPass: nfcPass, + ), + // Потом остальные + for (final nfcPass in state.nfcPasses) + if (!nfcPass.connected) + _NfcPassDeviceCard( + nfcPass: nfcPass, + ), + const SizedBox(height: 16), + // Если нет ни одного подключенного или подключенное устройство не текущее + if (state.nfcPasses.every((element) => + !element.connected) || + state.nfcPasses.any((element) => + element.connected && + element.deviceId != + snapshot.data!.id)) + ColorfulButton( + text: + "Привязать пропуск к этому устройству", + backgroundColor: + AppTheme.colors.primary, + onClick: () { + context.read().add( + NfcPassEvent.connectNfcPass( + student.code, + student.studentId, + snapshot.data!.id, + snapshot.data!.model, + ), + ); + }, + ), + ], + ); + } + }, + nfcDisabled: (_) => + const _NfcNotAviable(disabled: true), + nfcNotSupported: (_) => + const _NfcNotAviable(disabled: false), + error: (st) => Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Произошла ошибка:", + style: AppTextStyle.titleM, + ), + const SizedBox(height: 16), + Text( + st.cause, + style: AppTextStyle.body, + ), + ], + ), + ), + nfcNotExist: (_) => BlocBuilder( + builder: (context, state) => state.map( + initial: (_) { + final fullName = + "${student.name} ${student.secondName.replaceAll(" ", "").isNotEmpty ? "${student.secondName} " : ""}${student.lastName}"; + + return _NfcPassNotExistOnAccount( + onClick: () => context + .read() + .add( + NfcFeedbackEvent.sendFeedback( + fullName: fullName, + group: student.academicGroup, + personalNumber: + student.personalNumber, + studentId: + student.id.toString(), + ), + ), + fullName: fullName, + personalNumber: student.personalNumber, + ); + }, + loading: (_) => const Center( + child: CircularProgressIndicator(), + ), + success: (state) => + // Сообщение о том что заявка на привязку пропуска отправлена + Column( + mainAxisAlignment: + MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Icon( + Icons.check_circle, + color: AppTheme.colors.colorful04, + size: 48, + ), + const SizedBox(height: 16), + Text( + "Заявка на привязку пропуска отправлена", + style: AppTextStyle.title, + ), + const SizedBox(height: 16), + Text( + "Подождите, пока администратор подтвердит вашу заявку. " + "Время ожидания может занять до 7 рабочих дней", + style: AppTextStyle.body, + ), + ], + ), + failure: (st) => Center( + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Text( + "Произошла ошибка:", + style: AppTextStyle.titleM, + ), + const SizedBox(height: 16), + Text( + st.message, + style: AppTextStyle.body, + ), + ], + ), + ), + ), + ), + ), + ); + } else { + return const Center( + child: CircularProgressIndicator(), + ); + } + }, + ) + ], + ); + }, + orElse: () => const Center( + child: CircularProgressIndicator(), + ), + ); + }, + ), + ), + ), + ); + } +} + +class _NfcPassCard extends StatelessWidget { + const _NfcPassCard( + {Key? key, + required this.deviceId, + required this.deviceName, + required this.onClick}) + : super(key: key); + + final String deviceId; + final String deviceName; + final VoidCallback onClick; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const SizedBox(height: 16), + Text( + "Приложите телефон\nк турникету", + style: AppTextStyle.titleM, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Container( + width: 200, + height: 300, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: AppTheme.colors.active, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.25), + offset: const Offset(0, 4), + blurRadius: 4, + ), + ], + ), + child: Stack( + children: [ + Positioned( + top: 16, + left: 16, + child: Image.asset( + "assets/icons/gerb.ico", + width: 32, + height: 32, + ), + ), + Positioned( + top: 64, + left: 0, + right: 0, + child: Align( + alignment: Alignment.center, + child: Transform.rotate( + angle: pi / 2, + child: Icon( + CupertinoIcons.radiowaves_left, + color: AppTheme.colors.background02, + size: 80, + ), + ), + ), + ), + Positioned( + bottom: 16, + left: 16, + right: 16, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "ID", + style: AppTextStyle.titleM.copyWith( + color: AppTheme.colors.background01, + fontWeight: FontWeight.w700), + ), + const SizedBox(height: 4), + Text( + deviceId, + style: AppTextStyle.titleM.copyWith( + color: AppTheme.colors.background01, + fontSize: 14, + fontWeight: FontWeight.w400), + ), + const SizedBox(height: 16), + // device + Text( + "Устройство", + style: AppTextStyle.titleM.copyWith( + color: AppTheme.colors.background01, + fontWeight: FontWeight.w700), + ), + const SizedBox(height: 4), + Text( + deviceName, + style: AppTextStyle.titleM.copyWith( + color: AppTheme.colors.background01, + fontSize: 14, + fontWeight: FontWeight.w400), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 48), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: const EdgeInsets.only(top: 4), + width: 24, + height: 24, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: AppTheme.colors.colorful04, + ), + child: Icon( + CupertinoIcons.checkmark_alt, + size: 16, + color: AppTheme.colors.background01, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Это устройство зарегистрировано как основное", + style: AppTextStyle.titleM), + const SizedBox(height: 4), + Text( + "Пропуск работает только на одном устройстве. " + "При входе на другом устройстве, пропуск на этом будет " + "отключен!", + style: AppTextStyle.body, + ), + ], + ), + ), + ], + ), + const SizedBox(height: 48), + PrimaryButton( + onClick: onClick, + text: "Мои устройства", + ), + ], + ); + } +} + +class _NfcPassNotExistOnAccount extends StatelessWidget { + const _NfcPassNotExistOnAccount({ + Key? key, + required this.onClick, + required this.fullName, + required this.personalNumber, + }) : super(key: key); + + final VoidCallback onClick; + final String fullName; + final String personalNumber; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 16), + Text( + "Пропуск не привязан к вашей учетной записи", + style: AppTextStyle.title, + ), + const SizedBox(height: 16), + Text( + "Ваш NFC-пропуск не привязан к вашей учетной записи и не может быть использован в данный момент.\n\n" + "Чтобы привязать пропуск к вашей учетной записи, необходимо оставить заявку.\n\n" + "Время обработки - до 7 рабочих дней, после чего ваш NFC-пропуск будет автоматически активирован, " + " а эта ошибка больше не будет отображаться.", + style: AppTextStyle.body, + ), + const SizedBox(height: 36), + Text( + "Информация о заявке", + style: AppTextStyle.titleM, + ), + const SizedBox(height: 8), + Text( + "Имя: $fullName", + style: AppTextStyle.bodyL, + ), + const SizedBox(height: 4), + Text( + "Персональный номер: $personalNumber", + style: AppTextStyle.bodyL, + ), + const SizedBox(height: 16), + ColorfulButton( + text: "Оставить заявку", + backgroundColor: AppTheme.colors.primary, + onClick: onClick, + ), + ], + ); + } +} + +// Виджет с иноформацией о том, что пропуск ещё не подключен ни к одному устройству +class _NfcNotConnected extends StatelessWidget { + const _NfcNotConnected({ + Key? key, + required this.onPressed, + }) : super(key: key); + + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const SizedBox(height: 16), + Text( + "Пропуск не подключен", + style: AppTextStyle.titleM, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Text( + "Ваш NFC-пропуск ещё не подключен ни к одному устройству и не может быть использован. Чтобы подключить пропуск, нажмите на кнопку ниже.", + style: AppTextStyle.body, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ColorfulButton( + text: "Подключить пропуск", + onClick: onPressed, + backgroundColor: AppTheme.colors.primary, + ), + ], + ); + } +} + +class _ErrorAndroidDataFetch extends StatelessWidget { + const _ErrorAndroidDataFetch({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const SizedBox(height: 16), + Text( + "Не удалось получить данные об устройстве", + style: AppTextStyle.titleM, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Text( + "Приложение не может получить данные об устройстве. Попробуйте перезагрузить приложение или предоставить приложению нужные разрешения.", + style: AppTextStyle.bodyL, + textAlign: TextAlign.center, + ), + ], + ); + } +} + +class _NfcPassDeviceCard extends StatelessWidget { + const _NfcPassDeviceCard({ + Key? key, + required this.nfcPass, + }) : super(key: key); + + final NfcPass nfcPass; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Card( + color: AppTheme.colors.background02, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + elevation: 0, + margin: const EdgeInsets.all(0), + child: Container( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Row( + children: [ + const Icon(Icons.nfc), + const SizedBox(width: 8), + Text( + "NFC-пропуск", + style: AppTextStyle.titleS, + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + Text( + "ID: ", + style: AppTextStyle.body, + ), + Text( + nfcPass.deviceId, + style: AppTextStyle.body, + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + Text( + "Модель: ", + style: AppTextStyle.body, + ), + Text( + nfcPass.deviceName, + style: AppTextStyle.body, + ), + ], + ), + const SizedBox(height: 8), + if (nfcPass.connected) + Row( + children: [ + Icon( + Icons.check_circle, + color: AppTheme.colors.colorful04, + ), + const SizedBox(width: 8), + Text( + "Это устройство подключено к пропуску", + style: AppTextStyle.body, + ), + ], + ), + ], + ), + ), + ), + ); + } +} + +class _NfcNotAviable extends StatelessWidget { + const _NfcNotAviable({Key? key, required this.disabled}) : super(key: key); + + final bool disabled; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Icon( + Icons.error, + color: AppTheme.colors.colorful07, + size: 64, + ), + const SizedBox(height: 16), + Text( + disabled ? "NFC отключено" : "Ваше устройство не поддерживает NFC", + style: AppTextStyle.titleM, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + Text( + disabled + ? "Включите NFC в настройках вашего устройства" + : "Ваше устройство не поддерживает NFC. Пропуск по NFC недоступен", + style: AppTextStyle.bodyL, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + if (disabled) + TextOutlinedButton( + content: "Включить NFC", + onPressed: () { + AppSettings.openNFCSettings(); + }, + ), + ], + ); + } +} diff --git a/lib/presentation/pages/profile/profile_page.dart b/lib/presentation/pages/profile/profile_page.dart index 1a3a6963..0c50a2a3 100644 --- a/lib/presentation/pages/profile/profile_page.dart +++ b/lib/presentation/pages/profile/profile_page.dart @@ -1,7 +1,10 @@ +import 'dart:io'; + import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/auth_bloc/auth_bloc.dart'; +import 'package:rtu_mirea_app/domain/entities/user.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/colorful_button.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/icon_button.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/settings_button.dart'; @@ -9,7 +12,6 @@ import 'package:rtu_mirea_app/presentation/core/routes/routes.gr.dart'; import 'package:url_launcher/url_launcher_string.dart'; import '../../bloc/announces_bloc/announces_bloc.dart'; -import '../../bloc/profile_bloc/profile_bloc.dart'; import '../../widgets/buttons/text_outlined_button.dart'; import '../../widgets/container_label.dart'; import 'package:rtu_mirea_app/presentation/typography.dart'; @@ -37,161 +39,21 @@ class _ProfilePageState extends State { return SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24), - child: BlocBuilder( + child: BlocBuilder( builder: (context, state) { - // return const _InitialProfileStatePage(); - - if (state is LogInSuccess) { - context - .read() - .add(ProfileGetUserData(state.token)); - return BlocBuilder( - builder: (context, profileState) { - if (profileState is ProfileLoaded) { - return Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - CircleAvatar( - radius: 68, - backgroundImage: Image.network( - 'https://lk.mirea.ru${profileState.user.photoUrl}') - .image, - ), - Padding( - padding: - const EdgeInsets.only(top: 13, bottom: 4), - child: Text( - '${profileState.user.name} ${profileState.user.lastName}', - style: AppTextStyle.h5, - ), - ), - ShaderMask( - shaderCallback: (bounds) => - AppTheme.colors.gradient07.createShader( - Rect.fromLTWH( - 0, 0, bounds.width, bounds.height), - ), - child: Text( - profileState.user.login, - style: AppTextStyle.titleS, - ), - ), - const SizedBox(height: 12), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextOutlinedButton( - width: 160, - content: "Профиль", - onPressed: () => context.router.push( - ProfileDetailRoute( - user: profileState.user), - ), - ), - const SizedBox(width: 12), - SizedBox( - width: 146, - height: 45, - child: SocialIconButton( - assetImage: const AssetImage( - 'assets/icons/gerb.ico'), - onClick: () { - launchUrlString( - profileState.user.authShortlink != - null - ? "https://lk.mirea.ru/auth/link/?url=${profileState.user.authShortlink!}" - : "https://lk.mirea.ru/auth", - mode: LaunchMode - .externalApplication); - }, - text: "Вход в ЛКС", - ), - ), - ]), - - const SizedBox(height: 40), - const ContainerLabel(label: "Информация"), - const SizedBox(height: 20), - SettingsButton( - text: 'Объявления', - icon: Icons.message_rounded, - onClick: () { - context - .read() - .add(LoadAnnounces(token: state.token)); - context.router.push( - const ProfileAnnouncesRoute(), - ); - }), - // const SizedBox(height: 8), - // SettingsButton( - // text: 'Адреса', - // icon: Icons.map_rounded, - // onClick: () {}), - const SizedBox(height: 8), - SettingsButton( - text: 'Преподаватели', - icon: Icons.people_alt_rounded, - onClick: () => context.router - .push(const ProfileLectrosRoute()), - ), - const SizedBox(height: 8), - SettingsButton( - text: 'Посещения', - icon: Icons.access_time_rounded, - onClick: () => context.router - .push(const ProfileAttendanceRoute()), - ), - const SizedBox(height: 8), - SettingsButton( - text: 'Зачетная книжка', - icon: Icons.menu_book_rounded, - onClick: () => context.router - .push(const ProfileScoresRoute())), - const SizedBox(height: 8), - SettingsButton( - text: 'О приложении', - icon: Icons.apps_rounded, - onClick: () => - context.router.push(const AboutAppRoute()), - ), - const SizedBox(height: 8), - SettingsButton( - text: 'Настройки', - icon: Icons.settings_rounded, - onClick: () => { - context.router - .push(const ProfileSettingsRoute()), - }), - const SizedBox(height: 8), - ColorfulButton( - text: 'Выйти', - onClick: () => context - .read() - .add(AuthLogOut()), - backgroundColor: AppTheme.colors.colorful07), - ], - ); - } else if (profileState is ProfileLoading) { - return SizedBox( - height: MediaQuery.of(context).size.height, - child: const Center( - child: CircularProgressIndicator())); - } - return Container(); - }); - } else if (state is LogInError || - state is AuthUnauthorized) { - return const _InitialProfileStatePage(); - } else if (state is AuthUnknown) { - return ConstrainedBox( + return state.map( + unauthorized: (_) => const _InitialProfileStatePage(), + loading: (_) => ConstrainedBox( constraints: BoxConstraints( minHeight: viewportConstraints.maxHeight, ), - child: const Center(child: CircularProgressIndicator()), - ); - } - return Container(); + child: const Center( + child: CircularProgressIndicator(), + ), + ), + logInError: (st) => const _InitialProfileStatePage(), + logInSuccess: (st) => _UserLoggedInView(user: st.user), + ); }, ), ), @@ -203,6 +65,134 @@ class _ProfilePageState extends State { } } +class _UserLoggedInView extends StatelessWidget { + const _UserLoggedInView({Key? key, required this.user}) : super(key: key); + + final User user; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CircleAvatar( + radius: 68, + backgroundImage: + Image.network('https://lk.mirea.ru${user.photoUrl}').image, + ), + Padding( + padding: const EdgeInsets.only(top: 13, bottom: 4), + child: Text( + '${user.name} ${user.lastName}', + style: AppTextStyle.h5, + ), + ), + ShaderMask( + shaderCallback: (bounds) => AppTheme.colors.gradient07.createShader( + Rect.fromLTWH(0, 0, bounds.width, bounds.height), + ), + child: Text( + user.login, + style: AppTextStyle.titleS, + ), + ), + const SizedBox(height: 12), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + TextOutlinedButton( + width: 160, + content: "Профиль", + onPressed: () => context.router.push( + ProfileDetailRoute(user: user), + ), + ), + const SizedBox(width: 12), + SizedBox( + width: 146, + height: 45, + child: SocialIconButton( + assetImage: const AssetImage('assets/icons/gerb.ico'), + onClick: () { + launchUrlString( + user.authShortlink != null + ? "https://lk.mirea.ru/auth/link/?url=${user.authShortlink!}" + : "https://lk.mirea.ru/auth", + mode: LaunchMode.externalApplication); + }, + text: "Вход в ЛКС", + ), + ), + ]), + + const SizedBox(height: 40), + const ContainerLabel(label: "Информация"), + const SizedBox(height: 20), + SettingsButton( + text: 'Объявления', + icon: Icons.message_rounded, + onClick: () { + context.read().add(const LoadAnnounces()); + context.router.push( + const ProfileAnnouncesRoute(), + ); + }), + // const SizedBox(height: 8), + // SettingsButton( + // text: 'Адреса', + // icon: Icons.map_rounded, + // onClick: () {}), + const SizedBox(height: 8), + SettingsButton( + text: 'Преподаватели', + icon: Icons.people_alt_rounded, + onClick: () => context.router.push(const ProfileLectrosRoute()), + ), + const SizedBox(height: 8), + SettingsButton( + text: 'Посещения', + icon: Icons.access_time_rounded, + onClick: () => context.router.push(const ProfileAttendanceRoute()), + ), + const SizedBox(height: 8), + SettingsButton( + text: 'Зачетная книжка', + icon: Icons.menu_book_rounded, + onClick: () => context.router.push(const ProfileScoresRoute())), + const SizedBox(height: 8), + SettingsButton( + text: 'О приложении', + icon: Icons.apps_rounded, + onClick: () => context.router.push(const AboutAppRoute()), + ), + + // Display only for android devices because of + // NFC support only for android + if (Platform.isAndroid) ...[ + const SizedBox(height: 8), + SettingsButton( + text: 'NFC пропуск', + icon: Icons.nfc_rounded, + onClick: () => context.router.push(const ProfileNfcPassRoute()), + ), + ], + + const SizedBox(height: 8), + SettingsButton( + text: 'Настройки', + icon: Icons.settings_rounded, + onClick: () => { + context.router.push(const ProfileSettingsRoute()), + }), + const SizedBox(height: 8), + ColorfulButton( + text: 'Выйти', + onClick: () => + context.read().add(const UserEvent.logOut()), + backgroundColor: AppTheme.colors.colorful07), + ], + ); + } +} + class _InitialProfileStatePage extends StatelessWidget { const _InitialProfileStatePage({Key? key}) : super(key: key); @@ -217,8 +207,7 @@ class _InitialProfileStatePage extends StatelessWidget { // вместо того, чтобы открывать страницу с логином и паролем, // мы просто вызываем событие авторизации, которое откроет // страницу авторизации в браузере. - context.read().add( - const AuthLogInEvent(login: 'login', password: 'password')); + context.read().add(const UserEvent.logIn()); // Страница с вводом логина и пароля: // context.router.push(const LoginRoute()); diff --git a/lib/presentation/pages/profile/profile_scores_page.dart b/lib/presentation/pages/profile/profile_scores_page.dart index bd4bc252..d2908c27 100644 --- a/lib/presentation/pages/profile/profile_scores_page.dart +++ b/lib/presentation/pages/profile/profile_scores_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:rtu_mirea_app/domain/entities/score.dart'; -import 'package:rtu_mirea_app/presentation/bloc/auth_bloc/auth_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/scores_bloc/scores_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; import 'package:rtu_mirea_app/presentation/pages/profile/widgets/scores_chart_modal.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:rtu_mirea_app/presentation/widgets/buttons/primary_tab_button.dart'; @@ -53,15 +53,13 @@ class _ProfileScoresPageState extends State { backgroundColor: AppTheme.colors.background01, body: SafeArea( bottom: false, - child: BlocBuilder( - builder: (context, authState) { - if (authState is LogInSuccess) { - return BlocBuilder( + child: BlocBuilder( + builder: (context, userState) { + return userState.maybeMap( + logInSuccess: (_) => BlocBuilder( builder: (context, state) { if (state is ScoresInitial) { - context - .read() - .add(LoadScores(token: authState.token)); + context.read().add(const LoadScores()); } else if (state is ScoresLoaded) { _tabValueNotifier.value = state.scores.keys .toList() @@ -153,9 +151,9 @@ class _ProfileScoresPageState extends State { } return Container(); }, - ); - } - return Container(); + ), + orElse: () => Container(), + ); }, ), ), diff --git a/lib/service_locator.dart b/lib/service_locator.dart index 5e076bca..ea80cae4 100644 --- a/lib/service_locator.dart +++ b/lib/service_locator.dart @@ -1,3 +1,4 @@ +import 'package:device_info_plus/device_info_plus.dart'; import 'package:dio/dio.dart'; import 'package:get_it/get_it.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -27,7 +28,9 @@ import 'package:rtu_mirea_app/domain/repositories/github_repository.dart'; import 'package:rtu_mirea_app/domain/repositories/schedule_repository.dart'; import 'package:rtu_mirea_app/domain/repositories/strapi_repository.dart'; import 'package:rtu_mirea_app/domain/repositories/user_repository.dart'; +import 'package:rtu_mirea_app/domain/usecases/connect_nfc_pass.dart'; import 'package:rtu_mirea_app/domain/usecases/delete_schedule.dart'; +import 'package:rtu_mirea_app/domain/usecases/fetch_nfc_code.dart'; import 'package:rtu_mirea_app/domain/usecases/get_active_group.dart'; import 'package:rtu_mirea_app/domain/usecases/get_announces.dart'; import 'package:rtu_mirea_app/domain/usecases/get_app_settings.dart'; @@ -39,6 +42,7 @@ import 'package:rtu_mirea_app/domain/usecases/get_employees.dart'; import 'package:rtu_mirea_app/domain/usecases/get_groups.dart'; import 'package:rtu_mirea_app/domain/usecases/get_news.dart'; import 'package:rtu_mirea_app/domain/usecases/get_news_tags.dart'; +import 'package:rtu_mirea_app/domain/usecases/get_nfc_passes.dart'; import 'package:rtu_mirea_app/domain/usecases/get_patrons.dart'; import 'package:rtu_mirea_app/domain/usecases/get_schedule.dart'; import 'package:rtu_mirea_app/domain/usecases/get_schedule_settings.dart'; @@ -48,6 +52,7 @@ import 'package:rtu_mirea_app/domain/usecases/get_update_info.dart'; import 'package:rtu_mirea_app/domain/usecases/get_user_data.dart'; import 'package:rtu_mirea_app/domain/usecases/log_in.dart'; import 'package:rtu_mirea_app/domain/usecases/log_out.dart'; +import 'package:rtu_mirea_app/domain/usecases/send_nfc_not_exist_feedback.dart'; import 'package:rtu_mirea_app/domain/usecases/set_active_group.dart'; import 'package:rtu_mirea_app/domain/usecases/set_app_settings.dart'; import 'package:rtu_mirea_app/domain/usecases/set_schedule_settings.dart'; @@ -56,16 +61,19 @@ import 'package:rtu_mirea_app/presentation/bloc/about_app_bloc/about_app_bloc.da import 'package:rtu_mirea_app/presentation/bloc/announces_bloc/announces_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/app_cubit/app_cubit.dart'; import 'package:rtu_mirea_app/presentation/bloc/attendance_bloc/attendance_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/auth_bloc/auth_bloc.dart'; + import 'package:rtu_mirea_app/presentation/bloc/employee_bloc/employee_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/map_cubit/map_cubit.dart'; import 'package:rtu_mirea_app/presentation/bloc/news_bloc/news_bloc.dart'; -import 'package:rtu_mirea_app/presentation/bloc/profile_bloc/profile_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/nfc_feedback_bloc/nfc_feedback_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/nfc_pass_bloc/nfc_pass_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/schedule_bloc/schedule_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/scores_bloc/scores_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/stories_bloc/stories_bloc.dart'; import 'package:rtu_mirea_app/presentation/bloc/update_info_bloc/update_info_bloc.dart'; +import 'package:rtu_mirea_app/presentation/bloc/user_bloc/user_bloc.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart'; import 'data/repositories/schedule_repository_impl.dart'; @@ -97,14 +105,11 @@ Future setup() async { getIt.registerFactory( () => AboutAppBloc(getContributors: getIt(), getForumPatrons: getIt())); getIt.registerFactory(() => MapCubit()); - getIt.registerFactory( - () => AuthBloc( - logOut: getIt(), - getAuthToken: getIt(), - logIn: getIt(), - getUserData: getIt()), - ); - getIt.registerFactory(() => ProfileBloc(getUserData: getIt())); + getIt.registerFactory(() => UserBloc( + logIn: getIt(), + logOut: getIt(), + getUserData: getIt(), + getAuthToken: getIt())); getIt.registerFactory(() => AnnouncesBloc(getAnnounces: getIt())); getIt.registerFactory(() => EmployeeBloc(getEmployees: getIt())); getIt.registerFactory(() => ScoresBloc(getScores: getIt())); @@ -123,6 +128,16 @@ Future setup() async { setAppSettings: getIt(), ), ); + getIt.registerFactory(() => NfcPassBloc( + getNfcPasses: getIt(), + connectNfcPass: getIt(), + deviceInfo: getIt(), + fetchNfcCode: getIt(), + getAuthToken: getIt(), + getUserData: getIt(), + )); + getIt + .registerFactory(() => NfcFeedbackBloc(sendNfcNotExistFeedback: getIt())); // Usecases getIt.registerLazySingleton(() => GetStories(getIt())); @@ -149,6 +164,10 @@ Future setup() async { getIt.registerLazySingleton(() => SetScheduleSettings(getIt())); getIt.registerLazySingleton(() => SetAppSettings(getIt())); getIt.registerLazySingleton(() => GetAppSettings(getIt())); + getIt.registerLazySingleton(() => GetNfcPasses(getIt())); + getIt.registerLazySingleton(() => ConnectNfcPass(getIt())); + getIt.registerLazySingleton(() => FetchNfcCode(getIt())); + getIt.registerLazySingleton(() => SendNfcNotExistFeedback(getIt())); // Repositories getIt.registerLazySingleton( @@ -193,8 +212,8 @@ Future setup() async { localDataSource: getIt(), )); - getIt.registerLazySingleton( - () => UserLocalDataImpl(sharedPreferences: getIt())); + getIt.registerLazySingleton(() => + UserLocalDataImpl(sharedPreferences: getIt(), secureStorage: getIt())); getIt.registerLazySingleton( () => UserRemoteDataImpl(httpClient: getIt(), lksOauth2: getIt())); getIt.registerLazySingleton( @@ -223,8 +242,17 @@ Future setup() async { getIt.registerLazySingleton(() => Dio(BaseOptions(receiveTimeout: 20000))); final sharedPreferences = await SharedPreferences.getInstance(); getIt.registerLazySingleton(() => sharedPreferences); + const secureStorage = FlutterSecureStorage( + aOptions: AndroidOptions( + encryptedSharedPreferences: true, + )); + getIt.registerLazySingleton(() => secureStorage); getIt.registerLazySingleton(() => InternetConnectionCheckerPlus()); final PackageInfo packageInfo = await PackageInfo.fromPlatform(); getIt.registerLazySingleton(() => packageInfo); getIt.registerLazySingleton(() => LksOauth2()); + final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + getIt.registerLazySingleton(() => deviceInfo); + final AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; + getIt.registerLazySingleton(() => androidInfo); } diff --git a/pubspec.yaml b/pubspec.yaml index 9fa8dbc2..ea053662 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,7 @@ publish_to: 'none' # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.2.3+9 +version: 1.3.0+12 environment: sdk: ">=2.19.0 <3.0.0" @@ -43,11 +43,11 @@ dependencies: # State management library. # See https://pub.dev/packages/bloc - bloc: ^8.0.2 + bloc: ^8.1.1 # Widgets that make it easy to implement the BLoC. # See https://pub.dev/packages/flutter_bloc - flutter_bloc: ^8.0.1 + flutter_bloc: ^8.1.2 # SVG rendering widget for Flutter. # See https://pub.dev/packages/flutter_svg @@ -173,12 +173,26 @@ dependencies: firebase_analytics: ^10.1.0 firebase_crashlytics: ^3.0.11 - oauth2_client: ^3.0.0 + oauth2_client: ^3.1.0 # Flutter Secure Storage provides API to store data in secure storage. # See https://pub.dev/packages/flutter_secure_storage - flutter_secure_storage: ^6.0.0 + flutter_secure_storage: ^7.0.1 + + # Flutter plugin providing detailed information about the device (make, model, etc.), + # and Android or iOS version the app is running on. + # See https://pub.dev/packages/device_info_plus + device_info_plus: ^8.0.0 + + # Provide NFC functionality on Android, iOS & Web, including reading metadata, read & write + # NDEF records, and transceive layer 3 & 4 data with NFC tags / cards + # See https://pub.dev/packages/flutter_nfc_kit + flutter_nfc_kit: ^3.3.1 + # A Flutter plugin for opening iOS and Android phone settings from an app. + # See https://pub.dev/packages/app_settings + app_settings: ^4.2.0 + dev_dependencies: # The "flutter_lints" package below contains a set of recommended lints to