diff --git a/lib/models/app_tour.dart b/lib/models/app_tour.dart index a956c805d..4905bb541 100644 --- a/lib/models/app_tour.dart +++ b/lib/models/app_tour.dart @@ -124,7 +124,6 @@ class FocusTarget { builder: (context, controller) { return GestureDetector( onTap: () { - // ignore: avoid_dynamic_calls next?.call(); appTour.tutorialCoachMark.next(); @@ -174,7 +173,7 @@ class FocusTarget { AppTour appTour; /// next callback that is executed on pressing this target. - Function? next; + Function()? next; /// next target's crossAxisAlignment. CrossAxisAlignment nextCrossAlign; diff --git a/lib/models/post/post_model.dart b/lib/models/post/post_model.dart index 212120f9c..1e5b52a69 100644 --- a/lib/models/post/post_model.dart +++ b/lib/models/post/post_model.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid_dynamic_calls - import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/models/user/user_info.dart'; @@ -40,13 +38,13 @@ class Post { : null; if (json['likedBy'] != null) { likedBy = []; - json['likedBy'].forEach((v) { + (json['likedBy'] as List).forEach((v) { likedBy?.add(LikedBy.fromJson(v as Map)); }); } if (json['comments'] != null) { comments = []; - json['comments'].forEach((v) { + (json['comments'] as List).forEach((v) { comments?.add(Comments.fromJson(v as Map)); }); } diff --git a/lib/services/chat_service.dart b/lib/services/chat_service.dart index 3aafc2de8..1a5025d3a 100644 --- a/lib/services/chat_service.dart +++ b/lib/services/chat_service.dart @@ -1,6 +1,3 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - import 'dart:async'; import 'package:flutter/foundation.dart'; @@ -12,33 +9,47 @@ import 'package:talawa/services/database_mutation_functions.dart'; import 'package:talawa/services/user_config.dart'; import 'package:talawa/utils/chat_queries.dart'; -/// ChatService class provides different services for direct chats of the user. +/// Provides different services for direct chats of the user. /// /// Services include: /// * `sendMessageToDirectChat` - used to send messages. /// * `getDirectChatsByUserId` - used to get all chats by the user. -/// * `getDirectChatMessagesByChatId` - used to get all chats of a user with another user. +/// * `getDirectChatMessagesByChatId` - gets all chats of a user with +/// another user. class ChatService { ChatService() { _dbFunctions = locator(); _chatListStream = _chatController.stream.asBroadcastStream(); _chatMessagesStream = _chatMessageController.stream.asBroadcastStream(); } + + /// Database mutation functions. late DataBaseMutationFunctions _dbFunctions; + + /// Stream for chat list data. late Stream _chatListStream; + + /// Stream for chat messages. late Stream _chatMessagesStream; + /// User configuration instance. final _userConfig = locator(); + /// Stream for GraphQL query results. late Stream chatStream; + /// Controller for chat list stream. final StreamController _chatController = StreamController(); + /// Controller for chat messages stream. final StreamController _chatMessageController = StreamController(); + /// Getter for chat list stream. Stream get chatListStream => _chatListStream; + + /// Getter for chat messages stream. Stream get chatMessagesStream => _chatMessagesStream; // Stream getMessagesFromDirectChat() async* { @@ -50,11 +61,15 @@ class ChatService { // _cha // } - /// This function is used to send the message in the direct chats. + /// Sends a message to a direct chat. + /// + /// **params**: + /// * `chatId`: The ID of the chat where the message will be sent. + /// * `messageContent`: The content of the message to be sent. /// - /// parameters required: - /// * [chatId] - id of the direct chat where message need to be send. - /// * [messageContent] - the text that need to be send. + /// **returns**: + /// * `Future`: A promise that will be fulfilled + /// when the message is successfully sent. Future sendMessageToDirectChat( String chatId, String messageContent, @@ -66,7 +81,8 @@ class ChatService { ); final message = ChatMessage.fromJson( - result.data['sendMessageToDirectChat'] as Map, + (result as QueryResult).data?['sendMessageToDirectChat'] + as Map, ); _chatMessageController.add(message); @@ -74,21 +90,28 @@ class ChatService { debugPrint(result.data.toString()); } - /// This function is used to get all the chats by the user. + /// Retrieves direct chats by user ID. /// - /// parameters required: - /// * [usedId] - current user id, to get all the direct chats associated with this id. + /// **params**: + /// None + /// + /// **returns**: + /// * `Future`: A promise that will be fulfilled + /// when the direct chats are successfully retrieved. Future getDirectChatsByUserId() async { final userId = _userConfig.currentUser.id; - // trigger graphQL query to get all the chats of the user using [userId]. + // trigger graphQL query to get all the chats + // of the user using [userId]. final String query = ChatQueries().fetchDirectChatsByUserId(userId!); final result = await _dbFunctions.gqlAuthQuery(query); - final directMessageList = result.data['directChatsByUserID'] as List; + final directMessageList = + (result as QueryResult).data?['directChatsByUserID'] as List; - // loop through the result [directMessageList] and append the element to the directChat. + // loop through the result [directMessageList] + // and append the element to the directChat. directMessageList.forEach((chat) { final directChat = ChatListTileDataModel.fromJson(chat as Map); @@ -99,18 +122,25 @@ class ChatService { }); } - /// This function is used to get all the chat messages of a particular chat by the user. + /// This function retrieves direct chat messages by chat ID. + /// + /// **params**: + /// * `chatId`: The ID of the chat for which messages + /// are to be retrieved. /// - /// parameters required: - /// * [chatId] - id of the direct chat. + /// **returns**: + /// * `Future`: A promise that will be fulfilled + /// when the chat messages are successfully retrieved. Future getDirectChatMessagesByChatId(chatId) async { - // trigger graphQL query to get all the chat messages of a particular chat using [chatId]. + // trigger graphQL query to get all the chat messages + // of a particular chat using [chatId]. final String query = ChatQueries().fetchDirectChatMessagesByChatId(chatId as String); final result = await _dbFunctions.gqlAuthQuery(query); - final messages = result.data['directChatsMessagesByChatID'] as List; + final messages = + (result as QueryResult).data?['directChatsMessagesByChatID'] as List; messages.forEach((message) { final chatMessage = ChatMessage.fromJson(message as Map); diff --git a/lib/services/event_service.dart b/lib/services/event_service.dart index 5b82993f7..e8235436c 100644 --- a/lib/services/event_service.dart +++ b/lib/services/event_service.dart @@ -1,8 +1,7 @@ -// ignore_for_file: avoid_dynamic_calls - import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:talawa/constants/routing_constants.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/models/events/event_model.dart'; @@ -83,7 +82,8 @@ class EventService { final result = await _dbFunctions.gqlAuthMutation(mutation); if (result == null) return; - final List eventsJson = result.data!["eventsByOrganization"] as List; + final List eventsJson = + (result as QueryResult).data!["eventsByOrganization"] as List; eventsJson.forEach((eventJsonData) { final Event event = Event.fromJson(eventJsonData as Map); event.isRegistered = event.registrants?.any( diff --git a/lib/services/org_service.dart b/lib/services/org_service.dart index 8119c7705..40b4e5703 100644 --- a/lib/services/org_service.dart +++ b/lib/services/org_service.dart @@ -1,12 +1,10 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - +import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/models/user/user_info.dart'; import 'package:talawa/services/database_mutation_functions.dart'; import 'package:talawa/utils/queries.dart'; -/// OrganizationService class provides the in the context of organizations. +/// Provides the Services in the context of organizations. /// /// Services include: /// * `getOrgMembersList` : to get all organizations members @@ -17,16 +15,22 @@ class OrganizationService { } late DataBaseMutationFunctions _dbFunctions; - /// This function fetch and returns the list of organization members. + /// Retrieves a list of organization members. + /// + /// **params**: + /// * `orgId`: The ID of the organization to fetch members from. /// - /// params: - /// * [orgId] : id of the organization for which members list need be fetched. + /// **returns**: + /// * `Future>`: A promise that will be fulfilled + /// with the list of organization members. Future> getOrgMembersList(String orgId) async { final String query = Queries().fetchOrgDetailsById(orgId); // fetching from database using graphQL mutations. final result = await _dbFunctions.gqlAuthMutation(query); + final organizations = + (result as QueryResult).data?['organizations'] as List; final List orgMembersResult = - result.data['organizations'][0]['members'] as List; + (organizations[0] as Map)['members'] as List; final List orgMembersList = []; orgMembersResult.forEach((jsonElement) { final User member = diff --git a/lib/services/post_service.dart b/lib/services/post_service.dart index 43ed5c3fd..4c11ebca3 100644 --- a/lib/services/post_service.dart +++ b/lib/services/post_service.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/models/post/post_model.dart'; @@ -68,13 +69,11 @@ class PostService { final result = await _dbFunctions.gqlAuthQuery(query); //Checking if the dbFunctions return the postJSON, if not return. - // ignore:avoid_dynamic_calls - if (result == null || result.data == null) { + if (result == null || (result as QueryResult).data == null) { // Handle the case where the result or result.data is null return; } - // ignore:avoid_dynamic_calls final List postsJson = result.data!['postsByOrganization'] as List; postsJson.forEach((postJson) { diff --git a/lib/services/task_service.dart b/lib/services/task_service.dart index 65877e3d6..199ac7363 100644 --- a/lib/services/task_service.dart +++ b/lib/services/task_service.dart @@ -1,14 +1,12 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - import 'package:flutter/painting.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/models/task/task_model.dart'; import 'package:talawa/services/database_mutation_functions.dart'; import 'package:talawa/services/user_config.dart'; import 'package:talawa/utils/task_queries.dart'; -/// PostService class provides functions in the context of a Task. +/// Provides functions in the context of a Task. /// /// Services include: /// * `getTasksForEvent` : to get the task for the event. @@ -19,15 +17,24 @@ import 'package:talawa/utils/task_queries.dart'; class TaskService { final _databaseMutationFunctions = locator(); final _userConfig = locator(); + + /// callBack to NotifyListeners. late VoidCallback callbackNotifyListeners; final _tasks = []; + + /// List of Tasks. List get tasks => _tasks; - /// This function is used to get all the tasks for the event. + /// Retrieves tasks for a specific event. /// - /// params: - /// * [eventId] : id of an event for which tasks need to fetched, + /// **params**: + /// * `eventId`: The ID of the event for which tasks + /// are to be retrieved. + /// + /// **returns**: + /// * `Future`: A promise that will be fulfilled after + /// tasks for the event are retrieved. Future getTasksForEvent(String eventId) async { await _databaseMutationFunctions .refreshAccessToken(_userConfig.currentUser.refreshToken!); @@ -43,7 +50,14 @@ class TaskService { } } - /// This function is used to fetch and return all tasks added by the current user. + /// Retrieves tasks associated with the current user. + /// + /// **params**: + /// None + /// + /// **returns**: + /// * `Future`: A promise that will be fulfilled after + /// the user's tasks are retrieved. Future getTasksByUser() async { await _databaseMutationFunctions .refreshAccessToken(_userConfig.currentUser.refreshToken!); @@ -59,13 +73,18 @@ class TaskService { } } - /// This function is used to edit the task created by the user. + /// Edits a task with the provided details. + /// + /// **params**: + /// * `title`: The new title for the task. + /// * `description`: The new description for the task. + /// * `deadline`: The new deadline for the task. + /// * `taskId`: The ID of the task to be edited. /// - /// params: - /// * [title] : task title. - /// * [description] : task description. - /// * [deadline] : task deadline. - /// * [taskId] : task Id. + /// **returns**: + /// * `Future`: A promise that will be fulfilled + /// with a boolean value indicating whether the task + /// was successfully edited. Future editTask({ required String title, required String description, @@ -85,7 +104,8 @@ class TaskService { // if res is not null. if (res != null) { - final updatedtaskJson = res.data!['updateTask'] as Map; + final updatedtaskJson = + (res as QueryResult).data!['updateTask'] as Map; final index = _tasks.indexWhere((task) => task.id == taskId); if (index == -1) return false; final updatedtask = Task.fromJson(updatedtaskJson); @@ -98,13 +118,19 @@ class TaskService { return false; } - /// This function is used to create a new task for the event. + /// Creates a new task with the provided details. /// - /// params: - /// * [title] : task title. - /// * [description] : task description. - /// * [deadline] : task deadline. - /// * [eventId] : Event for which task need to be create. + /// **params**: + /// * `title`: The title for the new task. + /// * `description`: The description for the new task. + /// * `deadline`: The deadline for the new task. + /// * `eventId`: The ID of the event associated with + /// the new task. + /// + /// **returns**: + /// * `Future`: A promise that will be fulfilled + /// with a boolean value indicating whether the task + /// was successfully created. Future createTask({ required String title, required String description, @@ -123,7 +149,8 @@ class TaskService { ); if (res != null) { - final task = res.data!['createTask'] as Map; + final task = + (res as QueryResult).data!['createTask'] as Map; _tasks.add(Task.fromJson(task)); callbackNotifyListeners(); return true; @@ -131,11 +158,15 @@ class TaskService { return false; } - /// This function is used to delete a task. + /// Deletes a task given its ID and the creator's ID. + /// + /// **params**: + /// * `taskId`: The ID of the task to be deleted. + /// * `creatorId`: The ID of the task's creator. /// - /// params: - /// * [taskId] : id of a task need to be deleted. - /// * [creatorId] : id of the task creator. + /// **returns**: + /// * `Future`: A promise that will be fulfilled + /// after the task deletion process completes. Future deleteTask(String taskId, String creatorId) async { if (creatorId == _userConfig.currentUser.id) { await _databaseMutationFunctions diff --git a/lib/services/user_config.dart b/lib/services/user_config.dart index 62683ad02..ce6b53b2f 100644 --- a/lib/services/user_config.dart +++ b/lib/services/user_config.dart @@ -1,5 +1,3 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls - import 'dart:async'; import 'package:flutter/material.dart'; @@ -11,13 +9,14 @@ import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/models/user/user_info.dart'; import 'package:talawa/widgets/custom_progress_dialog.dart'; -/// UserConfig class provides different services in the context of the User. +/// Provides different services in the context of the User. /// /// Services include: /// * `userLoggedIn` : helps to make user logged in to the application. /// * `updateUserJoinedOrg` : helps to update the user joined organization. /// * `updateUserCreatedOrg` : helps to update the user created organization. -/// * `updateUserMemberRequestOrg` : helps to update the User membership request for the organization. +/// * `updateUserMemberRequestOrg` : helps to update the User membership +/// request for the organization. /// * `updateUserAdminOrg` : helps to update the Admin of the Organization. /// * `updateAccessToken` : helps to update the access token of an user. /// * `updateUser` : helps to update the user. @@ -29,29 +28,29 @@ class UserConfig { final StreamController _currentOrgInfoController = StreamController.broadcast(); - /// Getter method to retrieve the stream of current organization information. + /// Retrieves the stream of current organization information. Stream get currentOrgInfoStream => _currentOrgInfoStream; - /// Getter method to retrieve the stream controller for current organization information. + /// Retrieves the stream controller for current organization information. StreamController get currentOrgInfoController => _currentOrgInfoController; - /// Getter method to retrieve the current organization information. + /// Retrieves the current organization information. OrgInfo get currentOrg => _currentOrg!; - /// Getter method to retrieve the name of the current organization. + /// Retrieves the name of the current organization. String get currentOrgName => _currentOrg!.name!; - /// Getter method to check if a user is logged in. + /// Checks if a user is logged in. bool get loggedIn => _currentUser?.id != 'null'; - /// Setter method to update the current organization information. + /// Updates the current organization information. set currentOrg(OrgInfo org) => _currentOrg = org; - /// Getter method to retrieve the current user. + /// Retrieves the current user. User get currentUser => _currentUser!; - /// Setter method to update the current user. + /// Updates the current user. set currentUser(User user) { _currentUser = user; } @@ -98,8 +97,9 @@ class UserConfig { queries.fetchUserInfo, variables: {'id': currentUser.id}, ) as QueryResult; + final List users = result.data!['users'] as List; final User userInfo = User.fromJson( - result.data!['users'][0] as Map, + users[0] as Map, fromOrg: true, ); userInfo.authToken = userConfig.currentUser.authToken; @@ -122,7 +122,7 @@ class UserConfig { return true; } - /// This function logs out the current user. + /// Logs out the current user. /// /// **params**: /// None @@ -166,7 +166,7 @@ class UserConfig { return true; } - /// This function is used to update the user joined organization. + /// Updates the user joined organization. /// /// **params**: /// * `orgDetails`: details of the organization that user joined. @@ -178,7 +178,7 @@ class UserConfig { saveUserInHive(); } - /// This function is used to update the user created organization. + /// Updates the user created organization. /// /// **params**: /// * `orgDetails`: details of the organization that user joined. @@ -190,7 +190,7 @@ class UserConfig { saveUserInHive(); } - /// This function is used to update the user request to join the organization. + /// Updates the user request to join the organization. /// /// **params**: /// * `orgDetails`: details of the organization that user joined. @@ -202,7 +202,7 @@ class UserConfig { saveUserInHive(); } - /// This function is used to update the organization admin. + /// Updates the organization admin. /// /// **params**: /// * `orgDetails`: details of the organization that user joined. @@ -214,7 +214,7 @@ class UserConfig { saveUserInHive(); } - /// This function is used to updated the access token of the user. + /// Updates the access token of the user. /// /// **params**: /// * `accessToken`: current user's accesstoken. @@ -231,10 +231,11 @@ class UserConfig { saveUserInHive(); } - /// This function is used to update the user details. + /// Updates the user details. /// /// **params**: - /// * `updatedUserDetails`: `User` type variable containing all the details of an user need to be updated. + /// * `updatedUserDetails`: `User` type variable containing + /// all the details of an user need to be updated. /// /// **returns**: /// * `Future`: returns future of bool type. diff --git a/lib/view_model/pre_auth_view_models/login_view_model.dart b/lib/view_model/pre_auth_view_models/login_view_model.dart index 3a8b637a6..f3150792d 100644 --- a/lib/view_model/pre_auth_view_models/login_view_model.dart +++ b/lib/view_model/pre_auth_view_models/login_view_model.dart @@ -1,7 +1,6 @@ -// ignore_for_file: avoid_dynamic_calls - import 'package:flutter/material.dart'; -// import 'package:hive/hive.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; + import 'package:talawa/constants/routing_constants.dart'; import 'package:talawa/locator.dart'; // import 'package:talawa/main.dart'; @@ -11,25 +10,45 @@ import 'package:talawa/utils/encryptor.dart'; import 'package:talawa/view_model/base_view_model.dart'; import 'package:talawa/widgets/custom_progress_dialog.dart'; -/// LoginViewModel class helps to interact with model to serve data -/// and react to user's input in Login View. +/// LoginViewModel class helps to interact with model to serve data. +/// +/// Reacts to user's input in Login View. /// /// Methods include: /// * `login` class LoginViewModel extends BaseModel { - // variables + /// GlobalKey to identify and manage the state of a form widget. final formKey = GlobalKey(); + + /// List of maps to store greetings.. late List> greeting; + + /// TextEditingController for handling password input field. TextEditingController password = TextEditingController(); + + /// TextEditingController for handling email input field. TextEditingController email = TextEditingController(); + + /// FocusNode to manage focus for the password input field. FocusNode passwordFocus = FocusNode(); + + /// FocusNode to manage focus for the email input field. FocusNode emailFocus = FocusNode(); + + /// Determines when to perform automatic validation of form fields. AutovalidateMode validate = AutovalidateMode.disabled; + + /// Toggles password visibility (true for hidden, false for visible). bool hidePassword = true; - // initialiser + /// Initializes the greeting message. + /// + /// **params**: + /// None + /// + /// **returns**: + /// None void initialize() { - // greating message greeting = [ { 'text': "We're ", @@ -60,7 +79,33 @@ class LoginViewModel extends BaseModel { ]; } - /// This function is used to sign-in the user into application. + /// Performs the login operation. + /// + /// Handles the login process by performing the following steps: + /// 1. Unfocusing the email and password text fields. + /// 2. Setting validation mode to `AutovalidateMode.always`. + /// 3. Validating the email and password fields using the form key. + /// 4. If validation is successful, disabling auto-validation mode + /// and initiating the login process. + /// 5. Displaying a custom progress dialog during login. + /// 6. Initializing database functions. + /// 7. Performing a GraphQL mutation to login the user by providing + /// the email and encrypted password. + /// 8. Handling the result of the login operation: + /// - Updating the current user with the received data. + /// - Redirecting the user based on their status in the application. + /// - Handling Firebase options for Android and iOS if available. + /// - Configuring Firebase and saving FCM token to the database. + /// + /// In case of any exceptions during the login process, + /// this function catches and prints the error. + /// + /// **params**: + /// None + /// + /// **returns**: + /// * `Future`: a promise that indicates the completion + /// of the login process. Future login() async { emailFocus.unfocus(); passwordFocus.unfocus(); @@ -72,7 +117,8 @@ class LoginViewModel extends BaseModel { .pushDialog(const CustomProgressDialog(key: Key('LoginProgress'))); databaseFunctions.init(); try { - // run the graph QL query to login the user, passing `email` and `password`. + // run the graph QL query to login the user, + // passing `email` and `password`. final result = await databaseFunctions.gqlNonAuthMutation( queries.loginUser( email.text, @@ -84,8 +130,9 @@ class LoginViewModel extends BaseModel { navigationService.pop(); // if user found. if (result != null) { - final User loggedInUser = - User.fromJson(result.data!['login'] as Map); + final User loggedInUser = User.fromJson( + (result as QueryResult).data!['login'] as Map, + ); userConfig.updateUser(loggedInUser); // if user has not already joined any organization. if (userConfig.currentUser.joinedOrganizations!.isEmpty) { diff --git a/lib/view_model/pre_auth_view_models/signup_details_view_model.dart b/lib/view_model/pre_auth_view_models/signup_details_view_model.dart index dfa90d01d..e25261cdc 100644 --- a/lib/view_model/pre_auth_view_models/signup_details_view_model.dart +++ b/lib/view_model/pre_auth_view_models/signup_details_view_model.dart @@ -1,6 +1,3 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - import 'package:flutter/material.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:talawa/constants/routing_constants.dart'; @@ -13,26 +10,51 @@ import 'package:talawa/utils/encryptor.dart'; import 'package:talawa/view_model/base_view_model.dart'; import 'package:talawa/widgets/custom_progress_dialog.dart'; -/// SignupDetailsViewModel class helps to interact with model to serve data -/// and react to user's input for Sign Up Details section. +/// SignupDetailsViewModel class helps to interact with model to serve data and react to user's input for Sign Up Details section. /// /// Methods include: /// * `signUp` class SignupDetailsViewModel extends BaseModel { - // variables + /// GlobalKey to identify and manage the state of a form widget. final formKey = GlobalKey(); + + /// List of maps to store greeting information, where each greeting is represented by a map with String keys and dynamic values. late List> greeting; + + /// Represents information about the selected organization. late OrgInfo selectedOrganization; + + /// TextEditingController for handling confirmation password input field. TextEditingController confirmPassword = TextEditingController(); + + /// TextEditingController for handling first name input field. TextEditingController firstName = TextEditingController(); + + /// TextEditingController for handling last name input field. TextEditingController lastName = TextEditingController(); + + /// TextEditingController for handling password input field. TextEditingController password = TextEditingController(); + + /// TextEditingController for handling email input field. TextEditingController email = TextEditingController(); + + /// AutovalidateMode to determine when to perform automatic validation of form fields. AutovalidateMode validate = AutovalidateMode.disabled; + + /// FocusNode to manage focus for the confirmation password input field. FocusNode confirmFocus = FocusNode(); + + /// Boolean to toggle password visibility (true for hidden, false for visible). bool hidePassword = true; - // initialiser + /// Initializes the greeting message for a selected organization. + /// + /// **params**: + /// * `org`: OrgInfo - the organization information to set as selected. + /// + /// **returns**: + /// None void initialise(OrgInfo org) { selectedOrganization = org; // greeting message @@ -65,8 +87,31 @@ class SignupDetailsViewModel extends BaseModel { ]; } - /// This function is used to sign up the user into the application by passing the data to database query. - /// The function uses `gqlNonAuthMutation` method provided by `databaseFunctions` services. + /// Initiates the sign-up process. + /// + /// Handles the sign-up process by performing the following steps: + /// 1. Unfocusing the current focus scope. + /// 2. Setting the view state to `ViewState.busy`. + /// 3. Setting validation mode to `AutovalidateMode.always`. + /// 4. Setting the view state to `ViewState.idle`. + /// 5. Validating the form using the form key. + /// 6. If validation is successful, disabling auto-validation mode and initiating the sign-up. + /// 7. Displaying a custom progress dialog during sign-up. + /// 8. Initializing database functions. + /// 9. Performing a GraphQL mutation to register the user with provided details (first name, last name, email, password). + /// 10. Handling the result of the sign-up operation: + /// - Updating the current user with the received data. + /// - Refreshing the access token. + /// - Joining a public organization or sending a membership request based on the selected organization. + /// + /// In case of any exceptions during the sign-up process, this function catches and prints the error + /// and displays a Talawa error snackbar with a corresponding message. + /// + /// **params**: + /// None + /// + /// **returns**: + /// * `Future`: a promise that indicates the completion of the sign-up process. Future signUp() async { FocusScope.of(navigationService.navigatorKey.currentContext!).unfocus(); setState(ViewState.busy); @@ -90,8 +135,9 @@ class SignupDetailsViewModel extends BaseModel { ); navigationService.pop(); if (result != null) { - final User signedInUser = - User.fromJson(result.data!['signUp'] as Map); + final User signedInUser = User.fromJson( + (result as QueryResult).data!['signUp'] as Map, + ); final bool userSaved = await userConfig.updateUser(signedInUser); final bool tokenRefreshed = await graphqlConfig.getToken() as bool; // if user successfully saved and access token is also generated. @@ -104,9 +150,10 @@ class SignupDetailsViewModel extends BaseModel { queries.joinOrgById(selectedOrganization.id!), ) as QueryResult; - final List? joinedOrg = (result - .data!['joinPublicOrganization'] - ['joinedOrganizations'] as List?) + final joinPublicOrganization = result + .data!['joinPublicOrganization'] as Map; + final List? joinedOrg = (joinPublicOrganization[ + 'joinedOrganizations'] as List?) ?.map((e) => OrgInfo.fromJson(e as Map)) .toList(); userConfig.updateUserJoinedOrg(joinedOrg!); @@ -133,9 +180,10 @@ class SignupDetailsViewModel extends BaseModel { queries.sendMembershipRequest(selectedOrganization.id!), ) as QueryResult; + final sendMembershipRequest = result + .data!['sendMembershipRequest'] as Map; final OrgInfo membershipRequest = OrgInfo.fromJson( - result.data!['sendMembershipRequest']['organization'] - as Map, + sendMembershipRequest['organization'] as Map, ); userConfig.updateUserMemberRequestOrg([membershipRequest]); navigationService.pop(); diff --git a/lib/widgets/custom_alert_dialog.dart b/lib/widgets/custom_alert_dialog.dart index 74121a8c9..a918f48da 100644 --- a/lib/widgets/custom_alert_dialog.dart +++ b/lib/widgets/custom_alert_dialog.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid_dynamic_calls - import 'package:flutter/material.dart'; import 'package:talawa/locator.dart'; import 'package:talawa/services/size_config.dart'; @@ -37,10 +35,10 @@ class CustomAlertDialog extends StatelessWidget { final bool reverse; /// Function triggered upon tapping the primary action button. - final Function success; + final Function() success; /// Function triggered upon tapping the secondary action button. - final Function? secondaryButtonTap; + final Function()? secondaryButtonTap; /// Text displayed on the primary action button. final String? successText; diff --git a/lib/widgets/custom_list_tile.dart b/lib/widgets/custom_list_tile.dart index 40678aac8..54c02ddfa 100644 --- a/lib/widgets/custom_list_tile.dart +++ b/lib/widgets/custom_list_tile.dart @@ -38,7 +38,7 @@ class CustomListTile extends StatelessWidget { final Options? option; /// Object containing all the necessary info regarding the onTapOption. - final Function? onTapOption; + final Function()? onTapOption; /// Function to handle the tap on user info. final Function()? onTapUserInfo; @@ -57,7 +57,6 @@ class CustomListTile extends StatelessWidget { ? onTapOrgInfo!(orgInfo!) : type == TileType.user ? onTapUserInfo!() - // ignore: avoid_dynamic_calls : onTapOption!(), child: Padding( padding: const EdgeInsets.all(18.0), diff --git a/lib/widgets/event_date_time_tile.dart b/lib/widgets/event_date_time_tile.dart index 588462001..09a86b220 100644 --- a/lib/widgets/event_date_time_tile.dart +++ b/lib/widgets/event_date_time_tile.dart @@ -1,6 +1,3 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - import 'package:flutter/material.dart'; import 'package:talawa/services/size_config.dart'; @@ -13,11 +10,18 @@ class DateTimeTile extends StatelessWidget { required this.setDate, required this.setTime, }); - // variables + + /// Represents a date in string format. final String date; + + /// Represents a time in string format. final String time; - final Function setDate; - final Function setTime; + + /// Function that sets the date. + final Function() setDate; + + /// Function that sets the time. + final Function() setTime; @override Widget build(BuildContext context) { diff --git a/lib/widgets/member_name_tile.dart b/lib/widgets/member_name_tile.dart index 86e908030..643b13b00 100644 --- a/lib/widgets/member_name_tile.dart +++ b/lib/widgets/member_name_tile.dart @@ -1,13 +1,11 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - import 'package:flutter/material.dart'; import 'package:talawa/services/size_config.dart'; /// This widget returns a tile containing the name of the member. -/// Along with the name, there is a circle avatar which either contains -/// the image uploaded by the user or the first character of his/her name in -/// uppercase. +/// +/// Along with the name, there is a circle avatar which +/// either contains the image uploaded by the user or the +/// first character of his/her name in uppercase. class MemberNameTile extends StatelessWidget { const MemberNameTile({ super.key, @@ -15,8 +13,14 @@ class MemberNameTile extends StatelessWidget { this.userImage, required this.onDelete, }); + + /// Represents the user's name. final String userName; - final Function onDelete; + + /// Triggers the deletion of the user. + final Function() onDelete; + + /// Represents the URL or path to the user's image. final String? userImage; @override @@ -40,8 +44,10 @@ class MemberNameTile extends StatelessWidget { radius: SizeConfig.screenHeight! * 0.0201, backgroundImage: NetworkImage(userImage!), ) - // If the user has not uploaded his/her image, then a circle avatar is created. - // It has the first character of the user's name in uppercase and the default background color. + // If the user has not uploaded his/her image, + // then a circle avatar is created. + // It has the first character of the user's name + //in uppercase and the default background color. : CircleAvatar( radius: SizeConfig.screenHeight! * 0.0201, backgroundColor: Theme.of(context).colorScheme.secondary, diff --git a/lib/widgets/pinned_carousel_widget.dart b/lib/widgets/pinned_carousel_widget.dart index 0a6997a2a..b4f5bcf58 100644 --- a/lib/widgets/pinned_carousel_widget.dart +++ b/lib/widgets/pinned_carousel_widget.dart @@ -1,13 +1,10 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls -// ignore_for_file: talawa_good_doc_comments - import 'package:flutter/material.dart'; import 'package:talawa/models/post/post_model.dart'; import 'package:talawa/services/size_config.dart'; import 'package:talawa/utils/app_localization.dart'; -/// PinnedPostCarousel class returns a widget for pinned posts in -/// the slider/carousel on the top of the Home Screen. +/// Generates carousel for pinned posts on the Home Screen's top. +/// /// Tapping on a post will redirect you to the respective post screen. class PinnedPostCarousel extends StatelessWidget { const PinnedPostCarousel({ @@ -17,9 +14,13 @@ class PinnedPostCarousel extends StatelessWidget { required this.navigateToIndividualPostPage, }); - // variables + /// List of 'Post' objects representing pinned posts. final List pinnedPosts; - final Function navigateToPinnedPostPage; + + /// Function that navigates to a page displaying pinned posts. + final Function() navigateToPinnedPostPage; + + /// Function that navigates to an individual post page. final Function navigateToIndividualPostPage; @override @@ -36,9 +37,12 @@ class PinnedPostCarousel extends StatelessWidget { navigateToIndividualPostPage: navigateToIndividualPostPage, ), ), - // Gesture Detector in Flutter is used to detect the user's gestures on the application. - // It is a non-visual widget. Inside the gesture detector, another widget is placed and - // the gesture detector will capture all these events (gestures) and execute the tasks accordingly. + // Gesture Detector in Flutter is used to detect + // the user's gestures on the application. + // It is a non-visual widget. Inside the gesture detector, + // another widget is placed and + // the gesture detector will capture all these + // events (gestures) and execute the tasks accordingly. GestureDetector( onTap: () => navigateToPinnedPostPage(), child: Container( @@ -76,6 +80,7 @@ class PinnedPostCarousel extends StatelessWidget { } } +/// Class defining custom carousel. @visibleForTesting class CustomCarouselScroller extends StatefulWidget { const CustomCarouselScroller({ @@ -83,24 +88,29 @@ class CustomCarouselScroller extends StatefulWidget { required this.pinnedPosts, required this.navigateToIndividualPostPage, }); + + /// List of pinnedposts. final List pinnedPosts; + + /// function to navigate to IndividualPostPage. final Function navigateToIndividualPostPage; @override CustomCarouselScrollerState createState() => CustomCarouselScrollerState(); } -/// CustomCarouselScrollerState class return a widget that is -/// used to generate slider for pinned post on the top of the Home Screen. @visibleForTesting class CustomCarouselScrollerState extends State { - // variables + /// pageController. final PageController controller = PageController(initialPage: 0); + + /// pageIndex. int pindex = 0; @override Widget build(BuildContext context) { - // Stack is a widget that positions its children relative to the edges of its box. + // Stack is a widget that positions its + // children relative to the edges of its box. return Stack( children: [ Padding( diff --git a/test/helpers/setup_firebase_mocks.dart b/test/helpers/setup_firebase_mocks.dart index ec3064674..227194228 100644 --- a/test/helpers/setup_firebase_mocks.dart +++ b/test/helpers/setup_firebase_mocks.dart @@ -1,11 +1,10 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls +// ignore_for_file: talawa_api_doc // ignore_for_file: talawa_good_doc_comments // ignore_for_file: return_of_invalid_type // import 'package:firebase_core/firebase_core.dart'; // import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart'; -// import 'package:firebase_messaging_platform_interface/firebase_messaging_platform_interface.dart'; // import 'package:flutter/services.dart'; // import 'package:flutter_test/flutter_test.dart'; // import 'package:mockito/mockito.dart'; @@ -45,9 +44,10 @@ // } // if (call.method == 'Firebase#initializeApp') { +// final callArguments = call.arguments as Map; // return { -// 'name': call.arguments['appName'], -// 'options': call.arguments['options'], +// 'name': callArguments['appName'], +// 'options': callArguments['options'], // 'pluginConstants': {}, // }; // } @@ -55,18 +55,20 @@ // return null; // }); -// when(kMockMessagingPlatform.delegateFor(app: anyNamed('app'))) -// .thenReturn(kMockMessagingPlatform); -// when( -// kMockMessagingPlatform.setInitialValues( -// isAutoInitEnabled: anyNamed('isAutoInitEnabled'), -// ), -// ).thenReturn(kMockMessagingPlatform); +// when(kMockMessagingPlatform.delegateFor(app: anyNamed('app'))) +// .thenReturn(kMockMessagingPlatform); +// when( +// kMockMessagingPlatform.setInitialValues( +// isAutoInitEnabled: anyNamed('isAutoInitEnabled'), +// ), +// ).thenReturn(kMockMessagingPlatform); // } -// class MockFirebaseMessaging extends Mock with MockPlatformInterfaceMixin { +// class MockFirebaseMessaging extends Mock +// with MockPlatformInterfaceMixin +// implements FirebaseMessagingPlatform { // MockFirebaseMessaging() { -// // TestFirebaseMessagingPlatform(); +// TestFirebaseMessagingPlatform(); // } // @override @@ -78,36 +80,36 @@ // ); // } -// // @override -// // FirebaseMessagingPlatform delegateFor({FirebaseApp? app}) { -// // return super.noSuchMethod( -// // Invocation.method(#delegateFor, [], {#app: app}), -// // returnValue: TestFirebaseMessagingPlatform(), -// // returnValueForMissingStub: TestFirebaseMessagingPlatform(), -// // ); -// // } - -// // @override -// // FirebaseMessagingPlatform setInitialValues({bool? isAutoInitEnabled}) { -// // return super.noSuchMethod( -// // Invocation.method( -// // #setInitialValues, -// // [], -// // {#isAutoInitEnabled: isAutoInitEnabled}, -// // ), -// // returnValue: TestFirebaseMessagingPlatform(), -// // returnValueForMissingStub: TestFirebaseMessagingPlatform(), -// // ); -// // } - -// // @override -// // Future getInitialMessage() { -// // return super.noSuchMethod( -// // Invocation.method(#getInitialMessage, []), -// // returnValue: neverEndingFuture(), -// // returnValueForMissingStub: neverEndingFuture(), -// // ); -// // } +// @override +// FirebaseMessagingPlatform delegateFor({FirebaseApp? app}) { +// return super.noSuchMethod( +// Invocation.method(#delegateFor, [], {#app: app}), +// returnValue: TestFirebaseMessagingPlatform(), +// returnValueForMissingStub: TestFirebaseMessagingPlatform(), +// ); +// } + +// @override +// FirebaseMessagingPlatform setInitialValues({bool? isAutoInitEnabled}) { +// return super.noSuchMethod( +// Invocation.method( +// #setInitialValues, +// [], +// {#isAutoInitEnabled: isAutoInitEnabled}, +// ), +// returnValue: TestFirebaseMessagingPlatform(), +// returnValueForMissingStub: TestFirebaseMessagingPlatform(), +// ); +// } + +// @override +// Future getInitialMessage() { +// return super.noSuchMethod( +// Invocation.method(#getInitialMessage, []), +// returnValue: neverEndingFuture(), +// returnValueForMissingStub: neverEndingFuture(), +// ); +// } // @override // Future deleteToken() { @@ -154,33 +156,33 @@ // ); // } -// // Comment out the notification logic for the MVP -// // TODO: Re-enable notifications when needed for the final release. - -// // @override -// // Future requestPermission({ -// // bool? alert = true, -// // bool? announcement = false, -// // bool? badge = true, -// // bool? carPlay = false, -// // bool? criticalAlert = false, -// // bool? provisional = false, -// // bool? sound = true, -// // }) { -// // return super.noSuchMethod( -// // Invocation.method(#requestPermission, [], { -// // #alert: alert, -// // #announcement: announcement, -// // #badge: badge, -// // #carPlay: carPlay, -// // #criticalAlert: criticalAlert, -// // #provisional: provisional, -// // #sound: sound, -// // }), -// // returnValue: neverEndingFuture(), -// // returnValueForMissingStub: neverEndingFuture(), -// // ); -// // } +// Comment out the notification logic for the MVP +// TODO: Re-enable notifications when needed for the final release. + +// @override +// Future requestPermission({ +// bool? alert = true, +// bool? announcement = false, +// bool? badge = true, +// bool? carPlay = false, +// bool? criticalAlert = false, +// bool? provisional = false, +// bool? sound = true, +// }) { +// return super.noSuchMethod( +// Invocation.method(#requestPermission, [], { +// #alert: alert, +// #announcement: announcement, +// #badge: badge, +// #carPlay: carPlay, +// #criticalAlert: criticalAlert, +// #provisional: provisional, +// #sound: sound, +// }), +// returnValue: neverEndingFuture(), +// returnValueForMissingStub: neverEndingFuture(), +// ); +// } // @override // Future subscribeToTopic(String? topic) { @@ -201,6 +203,6 @@ // } // } -// // class TestFirebaseMessagingPlatform extends FirebaseMessagingPlatform { -// // TestFirebaseMessagingPlatform() : super(); -// // } +// class TestFirebaseMessagingPlatform extends FirebaseMessagingPlatform { +// TestFirebaseMessagingPlatform() : super(); +// } diff --git a/test/service_tests/event_service_test.dart b/test/service_tests/event_service_test.dart index 12970710d..aa8dace48 100644 --- a/test/service_tests/event_service_test.dart +++ b/test/service_tests/event_service_test.dart @@ -4,6 +4,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:mockito/mockito.dart'; import 'package:talawa/models/events/event_model.dart'; +import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/services/database_mutation_functions.dart'; import 'package:talawa/services/event_service.dart'; import 'package:talawa/utils/event_queries.dart'; @@ -123,19 +124,46 @@ void main() { test('Test getEvents method', () async { final dataBaseMutationFunctions = locator(); final query = TaskQueries.eventTasks('eventId'); + userConfig.currentOrg = OrgInfo(name: 'org', id: 'id'); when( dataBaseMutationFunctions.gqlAuthMutation( - EventQueries().fetchOrgEvents('OrgId'), + EventQueries().fetchOrgEvents('XYZ'), ), ).thenAnswer( (realInvocation) async => QueryResult( options: QueryOptions(document: gql(query)), data: { - 'Events': { - '_id': 'eventId', - 'title': 'Test task', - 'description': 'Test description', - }, + 'eventsByOrganization': [ + { + "_id": "1234567890", + "title": "Sample Event", + "description": "This is a sample event description.", + "attendees": "John Doe, Jane Smith", + "location": "Sample Location", + "longitude": -73.935242, + "latitude": 40.73061, + "recurring": true, + "allDay": false, + "startDate": "2024-01-15", + "endDate": "2024-01-16", + "startTime": "10:00 AM", + "endTime": "4:00 PM", + "recurrence": "Weekly", + "isPublic": true, + "isRegistered": true, + "isRegisterable": true, + "creator": { + "id": "user123", + "name": "Creator Name", + "email": "creator@example.com", + }, + "organization": { + "id": "org123", + "name": "Organization Name", + "description": "Sample organization description.", + }, + } + ], }, source: QueryResultSource.network, ), diff --git a/test/view_model_tests/after_auth_view_model_tests/add_post_view_model_test.dart b/test/view_model_tests/after_auth_view_model_tests/add_post_view_model_test.dart index 227eb914e..01854f677 100644 --- a/test/view_model_tests/after_auth_view_model_tests/add_post_view_model_test.dart +++ b/test/view_model_tests/after_auth_view_model_tests/add_post_view_model_test.dart @@ -1,4 +1,4 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls +// ignore_for_file: talawa_api_doc // ignore_for_file: talawa_good_doc_comments import 'dart:io'; diff --git a/test/view_model_tests/after_auth_view_model_tests/organization_feed_view_model_test.dart b/test/view_model_tests/after_auth_view_model_tests/organization_feed_view_model_test.dart index 553fc7826..e508bf99c 100644 --- a/test/view_model_tests/after_auth_view_model_tests/organization_feed_view_model_test.dart +++ b/test/view_model_tests/after_auth_view_model_tests/organization_feed_view_model_test.dart @@ -1,4 +1,4 @@ -// ignore_for_file: talawa_api_doc, avoid_dynamic_calls +// ignore_for_file: talawa_api_doc // ignore_for_file: talawa_good_doc_comments import 'package:flutter_test/flutter_test.dart'; @@ -88,7 +88,7 @@ void main() { ), ).captured; - expect(captured[0].length, 4); + expect((captured[0] as List).length, 4); }); test('Test addNewPost function', () { diff --git a/test/view_model_tests/main_screen_view_model_test.dart b/test/view_model_tests/main_screen_view_model_test.dart index 19bdf8616..be4e808ca 100644 --- a/test/view_model_tests/main_screen_view_model_test.dart +++ b/test/view_model_tests/main_screen_view_model_test.dart @@ -327,10 +327,8 @@ void main() async { await tester.tap(find.textContaining('tour home')); - // // ignore: avoid_dynamic_calls // print(mainScreenModel.targets[1].description); - // // ignore: avoid_dynamic_calls // mainScreenModel.targets[5].next!(); // verify(navigationService.pop()); diff --git a/test/view_model_tests/pre_auth_view_models/login_view_model_test.dart b/test/view_model_tests/pre_auth_view_models/login_view_model_test.dart index 7f9af6d62..f2b7be22f 100644 --- a/test/view_model_tests/pre_auth_view_models/login_view_model_test.dart +++ b/test/view_model_tests/pre_auth_view_models/login_view_model_test.dart @@ -2,14 +2,22 @@ // ignore_for_file: talawa_good_doc_comments // import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:graphql_flutter/graphql_flutter.dart'; // import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:mockito/mockito.dart'; +import 'package:talawa/constants/routing_constants.dart'; +import 'package:talawa/locator.dart'; // import 'package:talawa/constants/routing_constants.dart'; // import 'package:talawa/locator.dart'; import 'package:talawa/models/organization/org_info.dart'; import 'package:talawa/models/user/user_info.dart'; import 'package:talawa/services/user_config.dart'; +import 'package:talawa/utils/queries.dart'; +import 'package:talawa/view_model/pre_auth_view_models/login_view_model.dart'; + +import '../../helpers/test_helpers.dart'; // import 'package:talawa/utils/queries.dart'; // import 'package:talawa/view_model/pre_auth_view_models/login_view_model.dart'; @@ -31,123 +39,118 @@ final data = { bool empty = false; Future main() async { - // setUp(() async { - // locator.registerSingleton(Queries()); - // registerServices(); - // await locator.unregister(); - // }); - // tearDown(() async { - // await locator.unregister(); - // }); - - // group('LoginViewModel Test -', () { - // testWidgets( - // 'Check if login() is working fine when organisation is not empty', - // (tester) async { - // locator.registerSingleton(MockUserConfig()); - - // final model = LoginViewModel(); - - // await tester.pumpWidget( - // Form( - // key: model.formKey, - // child: Container(), - // ), - // ); - - // final result = QueryResult( - // source: QueryResultSource.network, - // data: data, - // options: QueryOptions(document: gql(queries.loginUser('', ''))), - // ); - - // when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) - // .thenAnswer((_) async => result); - - // await model.login(); - - // expect(model.validate, AutovalidateMode.disabled); - - // verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); - // }); - // testWidgets('Check if login() is working fine when organisation empty', - // (tester) async { - // empty = true; - // locator.registerSingleton(MockUserConfig()); - - // final model = LoginViewModel(); - - // await tester.pumpWidget( - // Form( - // key: model.formKey, - // child: Container(), - // ), - // ); - - // final result = QueryResult( - // source: QueryResultSource.network, - // data: data, - // options: QueryOptions(document: gql(queries.loginUser('', ''))), - // ); - - // when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) - // .thenAnswer((_) async => result); - - // await model.login(); - - // expect(model.validate, AutovalidateMode.disabled); - - // verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); - // }); - // testWidgets('Check if login() is working fine when invalid credentials', - // (tester) async { - // reset(navigationService); - // final model = LoginViewModel(); - - // await tester.pumpWidget( - // Form( - // key: model.formKey, - // child: Container(), - // ), - // ); - - // when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) - // .thenAnswer((_) async => null); - - // await model.login(); - - // expect(model.validate, AutovalidateMode.disabled); - - // verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); - - // verifyNever( - // navigationService.removeAllAndPush( - // Routes.waitingScreen, - // Routes.splashScreen, - // ), - // ); - // }); - // testWidgets('Check if login() is working fine when throws error', - // (tester) async { - // final model = LoginViewModel(); - - // await tester.pumpWidget( - // Form( - // key: model.formKey, - // child: Container(), - // ), - // ); - - // when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) - // .thenThrow(Exception()); - - // await model.login(); - - // expect(model.validate, AutovalidateMode.disabled); - - // verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); - // }); - // }); + // setupFirebaseMocks(); + // await Firebase.initializeApp(); + // FirebaseMessagingPlatform.instance = kMockMessagingPlatform; + + setUp(() async { + locator.registerSingleton(Queries()); + registerServices(); + await locator.unregister(); + }); + tearDown(() async { + await locator.unregister(); + }); + + group('LoginViewModel Test -', () { + testWidgets( + 'Check if login() is working fine when organisation is not empty', + (tester) async { + locator.registerSingleton(MockUserConfig()); + + final model = LoginViewModel(); + + await tester.pumpWidget( + Form( + key: model.formKey, + child: Container(), + ), + ); + + final result = QueryResult( + source: QueryResultSource.network, + data: data, + options: QueryOptions(document: gql(queries.loginUser('', ''))), + ); + + when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) + .thenAnswer((_) async => result); + + await model.login(); + expect(model.validate, AutovalidateMode.disabled); + verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); + }); + testWidgets('Check if login() is working fine when organisation empty', + (tester) async { + empty = true; + locator.registerSingleton(MockUserConfig()); + + final model = LoginViewModel(); + + await tester.pumpWidget( + Form( + key: model.formKey, + child: Container(), + ), + ); + + final result = QueryResult( + source: QueryResultSource.network, + data: data, + options: QueryOptions(document: gql(queries.loginUser('', ''))), + ); + + when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) + .thenAnswer((_) async => result); + + await model.login(); + expect(model.validate, AutovalidateMode.disabled); + verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); + }); + testWidgets('Check if login() is working fine when invalid credentials', + (tester) async { + reset(navigationService); + final model = LoginViewModel(); + + await tester.pumpWidget( + Form( + key: model.formKey, + child: Container(), + ), + ); + + when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) + .thenAnswer((_) async => null); + + await model.login(); + expect(model.validate, AutovalidateMode.disabled); + verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); + verifyNever( + navigationService.removeAllAndPush( + Routes.waitingScreen, + Routes.splashScreen, + ), + ); + }); + testWidgets('Check if login() is working fine when throws error', + (tester) async { + final model = LoginViewModel(); + + await tester.pumpWidget( + Form( + key: model.formKey, + child: Container(), + ), + ); + + when(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))) + .thenThrow(Exception()); + + await model.login(); + expect(model.validate, AutovalidateMode.disabled); + verify(databaseFunctions.gqlNonAuthMutation(queries.loginUser('', ''))); + }); + }); } class MockUserConfig extends Mock implements UserConfig {