From 9e40150a72180692ca76e3867b6efcedb229bbcd Mon Sep 17 00:00:00 2001 From: Aurelien9Code <152640312+Aurelien9Code@users.noreply.github.com> Date: Fri, 20 Dec 2024 01:46:49 +0100 Subject: [PATCH] style(association-manager): format using ktmft formating --- .../model/association/AssociationViewModel.kt | 93 +++-- .../unio/model/event/EventViewModel.kt | 26 +- .../unio/model/functions/CloudFunctions.kt | 40 ++- .../unio/model/search/SearchRepository.kt | 46 ++- .../unio/model/search/SearchViewModel.kt | 9 +- .../association/AssociationTestTags.kt | 2 +- .../unio/ui/association/AssociationProfile.kt | 317 +++++++++--------- .../android/unio/ui/components/SearchBar.kt | 151 +++++---- .../unio/ui/components/SearchPagerSection.kt | 28 +- 9 files changed, 353 insertions(+), 359 deletions(-) diff --git a/app/src/main/java/com/android/unio/model/association/AssociationViewModel.kt b/app/src/main/java/com/android/unio/model/association/AssociationViewModel.kt index b6717440..c7e2c9a5 100644 --- a/app/src/main/java/com/android/unio/model/association/AssociationViewModel.kt +++ b/app/src/main/java/com/android/unio/model/association/AssociationViewModel.kt @@ -66,14 +66,14 @@ constructor( return member.user.element } - /** - * Adds a new role to the specified association in the local list. If the role already exists, - * it will not be added again. The association's roles are updated, and if the association is - * selected, the selected association is also updated. - * - * @param associationId The ID of the association to update. - * @param newRole The new role to add to the association. - */ + /** + * Adds a new role to the specified association in the local list. If the role already exists, it + * will not be added again. The association's roles are updated, and if the association is + * selected, the selected association is also updated. + * + * @param associationId The ID of the association to update. + * @param newRole The new role to add to the association. + */ fun addRoleLocally(associationId: String, newRole: Role) { val association = _associations.value.find { it.uid == associationId } @@ -85,7 +85,6 @@ constructor( return } - val updatedRoles = association.roles + newRole val updatedAssociation = association.copy(roles = updatedRoles) @@ -97,20 +96,19 @@ constructor( if (_selectedAssociation.value?.uid == associationId) { _selectedAssociation.value = updatedAssociation } - } else { Log.e("AssociationViewModel", "Association with ID $associationId not found.") } } - /** - * Edits an existing role of a specified association in the local list. If the role is found, - * it is updated with the new role data. If the role doesn't exist, an error is logged. - * If the association is selected, it is also updated. - * - * @param associationId The ID of the association whose role needs to be edited. - * @param role The updated role to set. - */ + /** + * Edits an existing role of a specified association in the local list. If the role is found, it + * is updated with the new role data. If the role doesn't exist, an error is logged. If the + * association is selected, it is also updated. + * + * @param associationId The ID of the association whose role needs to be edited. + * @param role The updated role to set. + */ fun editRoleLocally(associationId: String, role: Role) { val association = _associations.value.find { it.uid == associationId } @@ -133,19 +131,18 @@ constructor( if (_selectedAssociation.value?.uid == associationId) { _selectedAssociation.value = updatedAssociation } - } else { Log.e("AssociationViewModel", "Association with ID $associationId not found.") } } - /** - * Deletes the specified role from the association's local list of roles. If the role is found, - * it is removed from the association's roles. If the association is selected, it is updated. - * - * @param associationId The ID of the association from which the role will be deleted. - * @param role The role to delete. - */ + /** + * Deletes the specified role from the association's local list of roles. If the role is found, it + * is removed from the association's roles. If the association is selected, it is updated. + * + * @param associationId The ID of the association from which the role will be deleted. + * @param role The role to delete. + */ fun deleteRoleLocally(associationId: String, role: Role) { val association = _associations.value.find { it.uid == associationId } @@ -167,7 +164,6 @@ constructor( if (_selectedAssociation.value?.uid == associationId) { _selectedAssociation.value = updatedAssociation } - } else { Log.e("AssociationViewModel", "Association with ID $associationId not found.") } @@ -222,11 +218,11 @@ constructor( }) } - /** - * Refreshes the selected association by fetching the association and updating the selected - * association's details including events and members. If the association is not found, - * an error is logged. - */ + /** + * Refreshes the selected association by fetching the association and updating the selected + * association's details including events and members. If the association is not found, an error + * is logged. + */ fun refreshAssociation() { if (_selectedAssociation.value == null) { return @@ -330,7 +326,6 @@ constructor( val selectedAssociation = _selectedAssociation.value if (selectedAssociation != null) { selectedAssociation.events.update(event) - } else { Log.e("AssociationViewModel", "No association selected to add or edit event.") } @@ -391,14 +386,14 @@ constructor( } } - /** - * Adds a new role to the selected association. If the role already exists, an error is triggered. - * After adding the role, the association is saved and the local state is updated. - * - * @param role The role to be added to the association. - * @param onSuccess A callback function to be executed after the role is successfully added. - * @param onFailure A callback function to handle errors during the operation. - */ + /** + * Adds a new role to the selected association. If the role already exists, an error is triggered. + * After adding the role, the association is saved and the local state is updated. + * + * @param role The role to be added to the association. + * @param onSuccess A callback function to be executed after the role is successfully added. + * @param onFailure A callback function to handle errors during the operation. + */ fun addRole(role: Role, onSuccess: () -> Unit, onFailure: (Exception) -> Unit) { val currentAssociation = _selectedAssociation.value if (currentAssociation == null) { @@ -426,14 +421,14 @@ constructor( onFailure = onFailure) } - /** - * Removes the specified role from the selected association. If the role does not exist, - * an error is triggered. After removing the role, the association is saved and the local state is updated. - * - * @param role The role to be removed from the association. - * @param onSuccess A callback function to be executed after the role is successfully removed. - * @param onFailure A callback function to handle errors during the operation. - */ + /** + * Removes the specified role from the selected association. If the role does not exist, an error + * is triggered. After removing the role, the association is saved and the local state is updated. + * + * @param role The role to be removed from the association. + * @param onSuccess A callback function to be executed after the role is successfully removed. + * @param onFailure A callback function to handle errors during the operation. + */ fun removeRole(role: Role, onSuccess: () -> Unit, onFailure: (Exception) -> Unit) { val currentAssociation = _selectedAssociation.value if (currentAssociation == null) { diff --git a/app/src/main/java/com/android/unio/model/event/EventViewModel.kt b/app/src/main/java/com/android/unio/model/event/EventViewModel.kt index 8d9ff0d8..07ed63e0 100644 --- a/app/src/main/java/com/android/unio/model/event/EventViewModel.kt +++ b/app/src/main/java/com/android/unio/model/event/EventViewModel.kt @@ -185,17 +185,21 @@ constructor( _events.value += event } - /** - * Adds an image to the specified event. This method uploads the image to the storage and updates - * the event's image URL once the upload is successful. - * - * This method helps in associating an image with an event, allowing the event to display a visual representation. - * - * @param inputStream The input stream of the image to upload. This is typically the raw data of the image selected by the user. - * @param event The event to which the image will be added. - * @param onSuccess A callback that is triggered if the image upload and event update are successful. It passes the updated event as a parameter. - * @param onFailure A callback that is triggered if the image upload or event update fails. It passes the error that occurred as a parameter. - */ + /** + * Adds an image to the specified event. This method uploads the image to the storage and updates + * the event's image URL once the upload is successful. + * + * This method helps in associating an image with an event, allowing the event to display a visual + * representation. + * + * @param inputStream The input stream of the image to upload. This is typically the raw data of + * the image selected by the user. + * @param event The event to which the image will be added. + * @param onSuccess A callback that is triggered if the image upload and event update are + * successful. It passes the updated event as a parameter. + * @param onFailure A callback that is triggered if the image upload or event update fails. It + * passes the error that occurred as a parameter. + */ fun addImageToEvent( inputStream: InputStream, event: Event, diff --git a/app/src/main/java/com/android/unio/model/functions/CloudFunctions.kt b/app/src/main/java/com/android/unio/model/functions/CloudFunctions.kt index 87c78674..08d6e97e 100644 --- a/app/src/main/java/com/android/unio/model/functions/CloudFunctions.kt +++ b/app/src/main/java/com/android/unio/model/functions/CloudFunctions.kt @@ -11,16 +11,16 @@ import java.text.SimpleDateFormat import java.util.Locale import java.util.TimeZone - /** * Retrieves the current user's token ID asynchronously. * - * This function checks if the current user is signed in, and if so, retrieves their Firebase token ID. - * If the user is not signed in, or if there is an issue fetching the token, the `onError` callback is called. - * Otherwise, the `onSuccess` callback is invoked with the token ID. + * This function checks if the current user is signed in, and if so, retrieves their Firebase token + * ID. If the user is not signed in, or if there is an issue fetching the token, the `onError` + * callback is called. Otherwise, the `onSuccess` callback is invoked with the token ID. * * @param onSuccess A callback function that is called when the token ID is successfully retrieved. - * @param onError A callback function that is called if an error occurs while retrieving the token ID. + * @param onError A callback function that is called if an error occurs while retrieving the token + * ID. * @throws Exception If the user is not signed in or token retrieval fails. */ private fun giveCurrentUserTokenID(onSuccess: (String) -> Unit, onError: (Exception) -> Unit) { @@ -47,8 +47,8 @@ private fun giveCurrentUserTokenID(onSuccess: (String) -> Unit, onError: (Except /** * Converts a Firebase [Timestamp] object to a formatted string in ISO 8601 format. * - * This function takes a [Timestamp] object and converts it to a string formatted as "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'". - * It ensures the timestamp is in UTC time zone. + * This function takes a [Timestamp] object and converts it to a string formatted as + * "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'". It ensures the timestamp is in UTC time zone. * * @param timestamp The Firebase [Timestamp] to be converted. * @return A string representation of the timestamp in ISO 8601 format. @@ -62,15 +62,18 @@ fun convertTimestampToString(timestamp: Timestamp): String { /** * Adds or edits an event by calling a Firebase Cloud Function to save the event. * - * This function uploads event details to a Firebase Cloud Function, including the event information and associated data. - * Depending on whether it is a new event or an update, the appropriate action is taken. - * It retrieves the current user's token ID and sends it to the Cloud Function, along with the event data. + * This function uploads event details to a Firebase Cloud Function, including the event information + * and associated data. Depending on whether it is a new event or an update, the appropriate action + * is taken. It retrieves the current user's token ID and sends it to the Cloud Function, along with + * the event data. * * @param newEvent The event object to be added or updated. * @param associationUId The unique identifier of the association to which the event belongs. - * @param onSuccess A callback function that is called when the event is successfully added or updated. + * @param onSuccess A callback function that is called when the event is successfully added or + * updated. * @param onError A callback function that is called if an error occurs during the process. - * @param isNewEvent A boolean value indicating whether the event is new (true) or being edited (false). + * @param isNewEvent A boolean value indicating whether the event is new (true) or being edited + * (false). */ fun addEditEventCloudFunction( newEvent: Event, @@ -82,7 +85,6 @@ fun addEditEventCloudFunction( try { giveCurrentUserTokenID( onSuccess = { tokenId -> - Firebase.functions .getHttpsCallable("saveEvent") .call( @@ -134,14 +136,17 @@ fun addEditEventCloudFunction( /** * Adds or edits a role by calling a Firebase Cloud Function to save the role. * - * This function uploads role details to a Firebase Cloud Function, including role-specific information - * and permissions. It retrieves the current user's token ID and sends it to the Cloud Function, along with the role data. + * This function uploads role details to a Firebase Cloud Function, including role-specific + * information and permissions. It retrieves the current user's token ID and sends it to the Cloud + * Function, along with the role data. * * @param newRole The role object to be added or updated. * @param associationUId The unique identifier of the association to which the role belongs. - * @param onSuccess A callback function that is called when the role is successfully added or updated. + * @param onSuccess A callback function that is called when the role is successfully added or + * updated. * @param onError A callback function that is called if an error occurs during the process. - * @param isNewRole A boolean value indicating whether the role is new (true) or being edited (false). + * @param isNewRole A boolean value indicating whether the role is new (true) or being edited + * (false). */ fun addEditRoleCloudFunction( newRole: Role, @@ -153,7 +158,6 @@ fun addEditRoleCloudFunction( try { giveCurrentUserTokenID( onSuccess = { tokenId -> - Firebase.functions .getHttpsCallable("saveRole") .call( diff --git a/app/src/main/java/com/android/unio/model/search/SearchRepository.kt b/app/src/main/java/com/android/unio/model/search/SearchRepository.kt index 5a9afcbc..158d8168 100644 --- a/app/src/main/java/com/android/unio/model/search/SearchRepository.kt +++ b/app/src/main/java/com/android/unio/model/search/SearchRepository.kt @@ -99,7 +99,6 @@ constructor( // Add the fresh set of associations to AppSearch session?.putAsync(PutDocumentsRequest.Builder().addDocuments(associationDocuments).build()) - } catch (e: Exception) { Log.e("SearchRepository", "Failed to refresh associations in AppSearch", e) } @@ -112,9 +111,7 @@ constructor( */ fun fetchAssociations() { associationRepository.getAssociations( - onSuccess = { associations -> - addAssociations(associations) - }, + onSuccess = { associations -> addAssociations(associations) }, onFailure = { exception -> Log.e("SearchRepository", "failed to fetch associations", exception) }) @@ -160,12 +157,12 @@ constructor( } } - /** - * Extracts and adds the members from the given list of [Association] objects to the search database. - * Each member is associated with their respective association. - * - * @param associations The list of [Association] objects to extract members from. - */ + /** + * Extracts and adds the members from the given list of [Association] objects to the search + * database. Each member is associated with their respective association. + * + * @param associations The list of [Association] objects to extract members from. + */ private fun addMembersFromAssociations(associations: List) { val memberDocuments = associations.flatMap { association -> @@ -174,8 +171,7 @@ constructor( uid = member.uid, userUid = member.user.uid, role = (association.roles.find { it.uid == member.uid }?.displayName ?: ""), - associationUid = association.uid - ) + associationUid = association.uid) } } try { @@ -250,12 +246,12 @@ constructor( } } - /** - * Searches the search database for members that match the given query. - * - * @param query The search query to look for in the database. - * @return A list of [Member] objects that match the search query. - */ + /** + * Searches the search database for members that match the given query. + * + * @param query The search query to look for in the database. + * @return A list of [Member] objects that match the search query. + */ suspend fun searchMembers(query: String): List { return withContext(Dispatchers.IO) { val searchSpec = @@ -332,13 +328,13 @@ constructor( } } - /** - * Converts the given [MemberDocument] to a [Member] object. - * This method fetches the full member details using the [AssociationRepository]. - * - * @param memberDocument The [MemberDocument] to convert. - * @return The corresponding [Member] object. - */ + /** + * Converts the given [MemberDocument] to a [Member] object. This method fetches the full member + * details using the [AssociationRepository]. + * + * @param memberDocument The [MemberDocument] to convert. + * @return The corresponding [Member] object. + */ private suspend fun memberDocumentToMember(memberDocument: MemberDocument): Member { return suspendCoroutine { continuation -> associationRepository.getAssociationWithId( diff --git a/app/src/main/java/com/android/unio/model/search/SearchViewModel.kt b/app/src/main/java/com/android/unio/model/search/SearchViewModel.kt index 7af5ef39..78e7e69b 100644 --- a/app/src/main/java/com/android/unio/model/search/SearchViewModel.kt +++ b/app/src/main/java/com/android/unio/model/search/SearchViewModel.kt @@ -1,6 +1,5 @@ package com.android.unio.model.search -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.android.unio.model.association.Association @@ -148,17 +147,15 @@ class SearchViewModel @Inject constructor(private val repository: SearchReposito } } - /** - * Clears the list of members and sets the search status to [Status.IDLE]. - */ + /** Clears the list of members and sets the search status to [Status.IDLE]. */ private fun clearMembers() { _members.value = emptyList() status.value = Status.IDLE } /** - * Called when the ViewModel is cleared. This is typically used to release any resources or perform cleanup tasks. - * In this case, it closes the search session from the [repository]. + * Called when the ViewModel is cleared. This is typically used to release any resources or + * perform cleanup tasks. In this case, it closes the search session from the [repository]. */ public override fun onCleared() { super.onCleared() diff --git a/app/src/main/java/com/android/unio/model/strings/test_tags/association/AssociationTestTags.kt b/app/src/main/java/com/android/unio/model/strings/test_tags/association/AssociationTestTags.kt index d5efa7d9..11a265b9 100644 --- a/app/src/main/java/com/android/unio/model/strings/test_tags/association/AssociationTestTags.kt +++ b/app/src/main/java/com/android/unio/model/strings/test_tags/association/AssociationTestTags.kt @@ -39,7 +39,7 @@ object AssociationProfileTestTags { const val FOLLOW_BUTTON = "associationFollowButton" } -object AssociationProfileActionsTestTags{ +object AssociationProfileActionsTestTags { const val SCREEN = "associationProfileActionsScreen" const val EVENT_TITLE = "associationEventActionsTitle" const val SMALL_EVENT_TITLE = "associationSmallEventActionsTitle" diff --git a/app/src/main/java/com/android/unio/ui/association/AssociationProfile.kt b/app/src/main/java/com/android/unio/ui/association/AssociationProfile.kt index fa0f72d2..069c3176 100644 --- a/app/src/main/java/com/android/unio/ui/association/AssociationProfile.kt +++ b/app/src/main/java/com/android/unio/ui/association/AssociationProfile.kt @@ -229,7 +229,6 @@ fun AssociationProfileScaffold( if (userPermissions?.hasAnyPermission() == true) { val userRoleColor = Color(userRole.color) - Box( modifier = Modifier.fillMaxWidth() @@ -237,92 +236,84 @@ fun AssociationProfileScaffold( .height(50.dp) .align(Alignment.TopCenter)) { Text( - context.getString(R.string.association_profile_scaffold_role_is) + " " + userRole.displayName, + context.getString(R.string.association_profile_scaffold_role_is) + + " " + + userRole.displayName, color = Color.White, modifier = Modifier.align(Alignment.Center)) } + Box(modifier = Modifier.fillMaxSize().padding(top = 50.dp)) { + Row(modifier = Modifier.fillMaxSize().padding(horizontal = 0.dp)) { + Box(modifier = Modifier.width(2.dp).fillMaxHeight().background(userRoleColor)) - Box( - modifier = - Modifier.fillMaxSize() - .padding(top = 50.dp) - ) { - Row( + // Main content (Conditional based on permission) + if (userPermissions.hasPermission(PermissionType.BETTER_OVERVIEW) && + !(userPermissions.hasPermission(PermissionType.FULL_RIGHTS)) && + userPermissions.getGrantedPermissions().size == 1) { + // Default content without HorizontalPager + Box( modifier = - Modifier.fillMaxSize() - .padding(horizontal = 0.dp) - ) { - Box( - modifier = - Modifier.width(2.dp).fillMaxHeight().background(userRoleColor)) - - // Main content (Conditional based on permission) - if (userPermissions.hasPermission(PermissionType.BETTER_OVERVIEW) && - !(userPermissions.hasPermission(PermissionType.FULL_RIGHTS)) && - userPermissions.getGrantedPermissions().size == 1) { - // Default content without HorizontalPager - Box( - modifier = - Modifier.weight(1f) - .padding(horizontal = 8.dp) - .pullRefresh(pullRefreshState) - .verticalScroll(rememberScrollState())) { - AssociationProfileContent( - navigationAction = navigationAction, - userViewModel = userViewModel, - eventViewModel = eventViewModel, - associationViewModel = associationViewModel) - } - } else { - // Main content with HorizontalPager - Column(modifier = Modifier.weight(1f).padding(horizontal = 8.dp)) { - val nbOfTabs = 2 - val pagerState = rememberPagerState(initialPage = 0) { nbOfTabs } - - // Tab Menu - val tabList = listOf(context.getString(R.string.association_profile_scaffold_overview), context.getString(R.string.association_profile_scaffold_actions)) - SmoothTopBarNavigationMenu(tabList, pagerState) - - // Pager Content - HorizontalPager( - userScrollEnabled = false, - state = pagerState, - modifier = Modifier.fillMaxSize()) { page -> - when (page) { - 0 -> - Box( - modifier = - Modifier.pullRefresh(pullRefreshState) - .verticalScroll(rememberScrollState())) { - AssociationProfileContent( - navigationAction = navigationAction, - userViewModel = userViewModel, - eventViewModel = eventViewModel, - associationViewModel = associationViewModel) - } - 1 -> - Box( - modifier = - Modifier.pullRefresh(pullRefreshState) - .verticalScroll(rememberScrollState())) { - AssociationProfileActionsContent( - navigationAction = navigationAction, - userViewModel = userViewModel, - eventViewModel = eventViewModel, - associationViewModel = associationViewModel, - searchViewModel = searchViewModel) - } - } - } + Modifier.weight(1f) + .padding(horizontal = 8.dp) + .pullRefresh(pullRefreshState) + .verticalScroll(rememberScrollState())) { + AssociationProfileContent( + navigationAction = navigationAction, + userViewModel = userViewModel, + eventViewModel = eventViewModel, + associationViewModel = associationViewModel) + } + } else { + // Main content with HorizontalPager + Column(modifier = Modifier.weight(1f).padding(horizontal = 8.dp)) { + val nbOfTabs = 2 + val pagerState = rememberPagerState(initialPage = 0) { nbOfTabs } + + // Tab Menu + val tabList = + listOf( + context.getString(R.string.association_profile_scaffold_overview), + context.getString(R.string.association_profile_scaffold_actions)) + SmoothTopBarNavigationMenu(tabList, pagerState) + + // Pager Content + HorizontalPager( + userScrollEnabled = false, + state = pagerState, + modifier = Modifier.fillMaxSize()) { page -> + when (page) { + 0 -> + Box( + modifier = + Modifier.pullRefresh(pullRefreshState) + .verticalScroll(rememberScrollState())) { + AssociationProfileContent( + navigationAction = navigationAction, + userViewModel = userViewModel, + eventViewModel = eventViewModel, + associationViewModel = associationViewModel) + } + 1 -> + Box( + modifier = + Modifier.pullRefresh(pullRefreshState) + .verticalScroll(rememberScrollState())) { + AssociationProfileActionsContent( + navigationAction = navigationAction, + userViewModel = userViewModel, + eventViewModel = eventViewModel, + associationViewModel = associationViewModel, + searchViewModel = searchViewModel) + } } } - - Box( - modifier = - Modifier.width(2.dp).fillMaxHeight().background(userRoleColor)) - } + } } + + Box(modifier = Modifier.width(2.dp).fillMaxHeight().background(userRoleColor)) + } + } } else { // Default content without permissions Box( @@ -471,7 +462,6 @@ fun AssociationProfileContent( AssociationDescription(association!!) AssociationEvents(navigationAction, association!!, userViewModel, eventViewModel) AssociationMembers(associationViewModel, association!!.members, onMemberClick) - } } @@ -527,9 +517,7 @@ private fun AssociationProfileActionsContent( Column( modifier = - Modifier.testTag(AssociationProfileActionsTestTags.SCREEN) - .fillMaxWidth() - .padding(24.dp), + Modifier.testTag(AssociationProfileActionsTestTags.SCREEN).fillMaxWidth().padding(24.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { AssociationActionsHeader( association!!, @@ -633,7 +621,8 @@ private fun AssociationMembers( * * @param associationViewModel The ViewModel responsible for managing the association's data. * @param userUid The unique identifier of the current user. - * @param onMemberClick A lambda function to be called when a member's card is clicked, passing the selected member's data. + * @param onMemberClick A lambda function to be called when a member's card is clicked, passing the + * selected member's data. * @param searchViewModel The ViewModel responsible for managing member search functionality. */ @Composable @@ -730,8 +719,9 @@ private fun AssociationActionsMembers( /** * Displays the list of roles for an association and allows creating, editing, and deleting roles. - * Each role is displayed as a clickable card, and users can perform actions like editing or deleting the role. - * A dialog is shown for creating or editing roles, and another dialog confirms deletion. + * Each role is displayed as a clickable card, and users can perform actions like editing or + * deleting the role. A dialog is shown for creating or editing roles, and another dialog confirms + * deletion. * * @param roles The list of roles for the association. * @param associationViewModel The ViewModel responsible for managing the association's data. @@ -775,7 +765,7 @@ fun RoleCard(role: Role, associationViewModel: AssociationViewModel) { var showEditDialog by remember { mutableStateOf(false) } var showDeleteDialog by remember { mutableStateOf(false) } - val context = LocalContext.current + val context = LocalContext.current Card( modifier = @@ -795,12 +785,14 @@ fun RoleCard(role: Role, associationViewModel: AssociationViewModel) { Row { Icon( imageVector = Icons.Default.Edit, - contentDescription = context.getString(R.string.association_profile_role_card_edit_role), + contentDescription = + context.getString(R.string.association_profile_role_card_edit_role), modifier = Modifier.size(24.dp).clickable { showEditDialog = true }.padding(4.dp)) Icon( imageVector = Icons.Default.Delete, - contentDescription = context.getString(R.string.association_profile_role_card_delete_role), + contentDescription = + context.getString(R.string.association_profile_role_card_delete_role), modifier = Modifier.size(24.dp).clickable { showDeleteDialog = true }.padding(4.dp)) } @@ -836,8 +828,7 @@ fun RoleCard(role: Role, associationViewModel: AssociationViewModel) { showEditDialog = false }, associationViewModel = associationViewModel, - initialRole = role - ) + initialRole = role) } // Delete Role Confirmation Dialog @@ -855,22 +846,32 @@ fun RoleCard(role: Role, associationViewModel: AssociationViewModel) { Text(context.getString(R.string.association_profile_role_card_delete)) } }, - dismissButton = { TextButton(onClick = { showDeleteDialog = false }) { Text(context.getString(R.string.association_profile_role_card_cancel)) } }, + dismissButton = { + TextButton(onClick = { showDeleteDialog = false }) { + Text(context.getString(R.string.association_profile_role_card_cancel)) + } + }, title = { Text(context.getString(R.string.association_profile_role_card_delete_role)) }, - text = { Text(context.getString(R.string.association_profile_role_card_sure_delete_role) +" '${role.displayName}'?") }) + text = { + Text( + context.getString(R.string.association_profile_role_card_sure_delete_role) + + " '${role.displayName}'?") + }) } } /** - * Displays a dialog to create or edit a role within the association. - * If an existing role is passed, the dialog will allow editing the role's details, including the display name, - * color, and permissions. If no existing role is passed, the dialog will create a new role. - * Once the role is saved, it triggers the appropriate actions in the [associationViewModel]. + * Displays a dialog to create or edit a role within the association. If an existing role is passed, + * the dialog will allow editing the role's details, including the display name, color, and + * permissions. If no existing role is passed, the dialog will create a new role. Once the role is + * saved, it triggers the appropriate actions in the [associationViewModel]. * * @param onDismiss A lambda function to be called when the dialog is dismissed. - * @param onCreateRole A lambda function to be called after the role is created or updated, passing the role. + * @param onCreateRole A lambda function to be called after the role is created or updated, passing + * the role. * @param associationViewModel The ViewModel responsible for managing the association's data. - * @param initialRole The initial role details to prefill the dialog fields (optional, null if creating a new role). + * @param initialRole The initial role details to prefill the dialog fields (optional, null if + * creating a new role). */ @Composable fun SaveRoleDialog( @@ -890,7 +891,7 @@ fun SaveRoleDialog( } } val allPermissions = PermissionType.values() - val context = LocalContext.current + val context = LocalContext.current AlertDialog( onDismissRequest = onDismiss, @@ -906,29 +907,41 @@ fun SaveRoleDialog( .addPermissions(selectedPermissions.toList()) .build(), color = colorInt, - uid = initialRole?.uid ?: displayName.text - ) + uid = initialRole?.uid ?: displayName.text) associationViewModel.selectedAssociation.value?.let { association -> addEditRoleCloudFunction( saveRole, association.uid, - onSuccess = { - associationViewModel.addRoleLocally(association.uid, saveRole) - }, + onSuccess = { associationViewModel.addRoleLocally(association.uid, saveRole) }, onError = { e -> Log.e("ADD_ROLE", "ERROR: $e") }, isNewRole = initialRole == null) } onCreateRole(saveRole) }) { - Text(if (initialRole != null) context.getString(R.string.association_profile_save_role_dialog_save) else context.getString(R.string.association_profile_save_role_dialog_create)) + Text( + if (initialRole != null) + context.getString(R.string.association_profile_save_role_dialog_save) + else context.getString(R.string.association_profile_save_role_dialog_create)) } }, - dismissButton = { TextButton(onClick = onDismiss) { Text(context.getString(R.string.association_profile_save_role_dialog_cancel)) } }, - title = { Text(if (initialRole != null) context.getString(R.string.association_profile_save_role_dialog_edit_role) else context.getString(R.string.association_profile_save_role_dialog_create_role)) }, + dismissButton = { + TextButton(onClick = onDismiss) { + Text(context.getString(R.string.association_profile_save_role_dialog_cancel)) + } + }, + title = { + Text( + if (initialRole != null) + context.getString(R.string.association_profile_save_role_dialog_edit_role) + else context.getString(R.string.association_profile_save_role_dialog_create_role)) + }, text = { Column(Modifier.fillMaxWidth()) { Column(Modifier.fillMaxWidth().padding(bottom = 16.dp)) { - Text(text = context.getString(R.string.association_profile_save_role_dialog_display_name), style = MaterialTheme.typography.labelMedium) + Text( + text = + context.getString(R.string.association_profile_save_role_dialog_display_name), + style = MaterialTheme.typography.labelMedium) BasicTextField( value = displayName, onValueChange = { displayName = it }, @@ -936,7 +949,9 @@ fun SaveRoleDialog( } Column(Modifier.fillMaxWidth().padding(vertical = 16.dp)) { - Text(context.getString(R.string.association_profile_save_role_dialog_role_color), style = MaterialTheme.typography.labelMedium) + Text( + context.getString(R.string.association_profile_save_role_dialog_role_color), + style = MaterialTheme.typography.labelMedium) HsvColorPicker( modifier = Modifier.fillMaxWidth().height(200.dp).padding(10.dp), controller = controller, @@ -944,7 +959,9 @@ fun SaveRoleDialog( initialColor = selectedColor) } - Text(text = context.getString(R.string.association_profile_save_role_dialog_permissions), style = MaterialTheme.typography.labelMedium) + Text( + text = context.getString(R.string.association_profile_save_role_dialog_permissions), + style = MaterialTheme.typography.labelMedium) LazyColumn(modifier = Modifier.fillMaxWidth()) { items(allPermissions.size) { index -> val permission = allPermissions[index] @@ -1026,9 +1043,9 @@ private fun AssociationEvents( } /** - * Displays events related to an association, along with a search bar, event creation button, - * and event details. The event list is sorted and displayed using a paginated view. - * Users with appropriate permissions can create new events, and a search bar allows for event searching. + * Displays events related to an association, along with a search bar, event creation button, and + * event details. The event list is sorted and displayed using a paginated view. Users with + * appropriate permissions can create new events, and a search bar allows for event searching. * * @param navigationAction The navigation actions to navigate between screens. * @param association The association whose events are being displayed. @@ -1101,7 +1118,6 @@ private fun AssociationActionsEvents( val pagerState = rememberPagerState { sortedEvents.size } val coroutineScope = rememberCoroutineScope() - if (events.isNotEmpty()) { SearchPagerSection( items = sortedEvents, @@ -1131,12 +1147,13 @@ private fun AssociationActionsEvents( } /** - * Displays a button that toggles between "See More" and "See Less" states. - * This component is used to show or hide more content, depending on whether the button has been clicked. + * Displays a button that toggles between "See More" and "See Less" states. This component is used + * to show or hide more content, depending on whether the button has been clicked. * * @param onSeeMore A lambda function that is triggered when the "See More" button is clicked. * @param onSeeLess A lambda function that is triggered when the "See Less" button is clicked. - * @param isSeeMoreClicked A boolean flag indicating whether the "See More" button is clicked or not. + * @param isSeeMoreClicked A boolean flag indicating whether the "See More" button is clicked or + * not. */ @Composable fun AssociationProfileSeeMoreButton( @@ -1169,8 +1186,9 @@ fun AssociationProfileSeeMoreButton( } /** - * Displays a single event inside a card format. This component is typically used in places like the home screen - * to show event details, and it includes an option for editing the event based on the provided permissions. + * Displays a single event inside a card format. This component is typically used in places like the + * home screen to show event details, and it includes an option for editing the event based on the + * provided permissions. * * @param navigationAction The navigation actions to navigate between screens. * @param event The event to be displayed in the card. @@ -1302,54 +1320,47 @@ private fun AssociationActionsHeader( { showNotificationDialog = false }) Row( - modifier = - Modifier.fillMaxWidth().padding(vertical = 0.dp), + modifier = Modifier.fillMaxWidth().padding(vertical = 0.dp), horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier.widthIn(max = 300.dp) - ) { - Text( - text = context.getString(R.string.association_profile_header_broadcast_text), - style = AppTypography.bodyMedium, - modifier = Modifier.padding(end = 8.dp) - ) - } + verticalAlignment = Alignment.CenterVertically) { + Box(modifier = Modifier.widthIn(max = 300.dp)) { + Text( + text = context.getString(R.string.association_profile_header_broadcast_text), + style = AppTypography.bodyMedium, + modifier = Modifier.padding(end = 8.dp)) + } IconButton( onClick = { showNotificationDialog = true }, - modifier = Modifier.testTag(AssociationProfileActionsTestTags.BROADCAST_ICON_BUTTON).size(24.dp)) { + modifier = + Modifier.testTag(AssociationProfileActionsTestTags.BROADCAST_ICON_BUTTON) + .size(24.dp)) { Icon( Icons.AutoMirrored.Filled.Send, - contentDescription = context.getString(R.string.association_profile_header_broadcast_button), - tint = MaterialTheme.colorScheme.primary - ) + contentDescription = + context.getString(R.string.association_profile_header_broadcast_button), + tint = MaterialTheme.colorScheme.primary) } } Row( - modifier = - Modifier.fillMaxWidth().padding(vertical = 0.dp), + modifier = Modifier.fillMaxWidth().padding(vertical = 0.dp), horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier.widthIn(max = 300.dp) - ) { - Text( - text = context.getString(R.string.association_profile_header_edit_text), - style = AppTypography.bodyMedium, - modifier = Modifier.padding(end = 8.dp) - ) - } + verticalAlignment = Alignment.CenterVertically) { + Box(modifier = Modifier.widthIn(max = 300.dp)) { + Text( + text = context.getString(R.string.association_profile_header_edit_text), + style = AppTypography.bodyMedium, + modifier = Modifier.padding(end = 8.dp)) + } IconButton( onClick = { onClickSaveButton() }, - modifier = Modifier.testTag(AssociationProfileActionsTestTags.EDIT_BUTTON).size(24.dp)) { + modifier = + Modifier.testTag(AssociationProfileActionsTestTags.EDIT_BUTTON).size(24.dp)) { Icon( Icons.Filled.Edit, - contentDescription = context.getString(R.string.association_profile_header_edit_button), - tint = MaterialTheme.colorScheme.primary - ) + contentDescription = + context.getString(R.string.association_profile_header_edit_button), + tint = MaterialTheme.colorScheme.primary) } } } diff --git a/app/src/main/java/com/android/unio/ui/components/SearchBar.kt b/app/src/main/java/com/android/unio/ui/components/SearchBar.kt index 8d29e96d..bb118c4d 100644 --- a/app/src/main/java/com/android/unio/ui/components/SearchBar.kt +++ b/app/src/main/java/com/android/unio/ui/components/SearchBar.kt @@ -154,92 +154,91 @@ fun AssociationSearchBar( shouldCloseExpandable: Boolean, onOutsideClickHandled: () -> Unit ) { - var searchQuery by remember { mutableStateOf("") } - var isExpanded by rememberSaveable { mutableStateOf(false) } - val associationResults by searchViewModel.associations.collectAsState() - val searchState by searchViewModel.status.collectAsState() - val context = LocalContext.current + var searchQuery by remember { mutableStateOf("") } + var isExpanded by rememberSaveable { mutableStateOf(false) } + val associationResults by searchViewModel.associations.collectAsState() + val searchState by searchViewModel.status.collectAsState() + val context = LocalContext.current - if (shouldCloseExpandable && isExpanded) { - isExpanded = false - onOutsideClickHandled() - } + if (shouldCloseExpandable && isExpanded) { + isExpanded = false + onOutsideClickHandled() + } - DockedSearchBar( - inputField = { - SearchBarDefaults.InputField( - modifier = Modifier.testTag(ExploreContentTestTags.SEARCH_BAR_INPUT), - query = searchQuery, - onQueryChange = { - searchQuery = it - searchViewModel.debouncedSearch(it, SearchViewModel.SearchType.ASSOCIATION) - }, - onSearch = {}, - expanded = isExpanded, - onExpandedChange = { isExpanded = it }, - placeholder = { - Text( - text = context.getString(R.string.search_placeholder), - style = AppTypography.bodyLarge, - modifier = Modifier.testTag(ExploreContentTestTags.SEARCH_BAR_PLACEHOLDER)) - }, - trailingIcon = { - Icon( - Icons.Default.Search, - contentDescription = - context.getString(R.string.explore_content_description_search_icon), - modifier = Modifier.testTag(ExploreContentTestTags.SEARCH_TRAILING_ICON)) - }, - ) - }, - expanded = isExpanded, - onExpandedChange = { isExpanded = it }, - modifier = Modifier.padding(horizontal = 16.dp).testTag(ExploreContentTestTags.SEARCH_BAR)) { + DockedSearchBar( + inputField = { + SearchBarDefaults.InputField( + modifier = Modifier.testTag(ExploreContentTestTags.SEARCH_BAR_INPUT), + query = searchQuery, + onQueryChange = { + searchQuery = it + searchViewModel.debouncedSearch(it, SearchViewModel.SearchType.ASSOCIATION) + }, + onSearch = {}, + expanded = isExpanded, + onExpandedChange = { isExpanded = it }, + placeholder = { + Text( + text = context.getString(R.string.search_placeholder), + style = AppTypography.bodyLarge, + modifier = Modifier.testTag(ExploreContentTestTags.SEARCH_BAR_PLACEHOLDER)) + }, + trailingIcon = { + Icon( + Icons.Default.Search, + contentDescription = + context.getString(R.string.explore_content_description_search_icon), + modifier = Modifier.testTag(ExploreContentTestTags.SEARCH_TRAILING_ICON)) + }, + ) + }, + expanded = isExpanded, + onExpandedChange = { isExpanded = it }, + modifier = Modifier.padding(horizontal = 16.dp).testTag(ExploreContentTestTags.SEARCH_BAR)) { when (searchState) { - SearchViewModel.Status.ERROR -> { - Box( - modifier = Modifier.fillMaxWidth().padding(16.dp), - contentAlignment = Alignment.Center) { - Text(context.getString(R.string.explore_search_error_message)) + SearchViewModel.Status.ERROR -> { + Box( + modifier = Modifier.fillMaxWidth().padding(16.dp), + contentAlignment = Alignment.Center) { + Text(context.getString(R.string.explore_search_error_message)) } - } - SearchViewModel.Status.LOADING -> { - Box( - modifier = Modifier.fillMaxWidth().padding(16.dp), - contentAlignment = Alignment.Center) { - LinearProgressIndicator() + } + SearchViewModel.Status.LOADING -> { + Box( + modifier = Modifier.fillMaxWidth().padding(16.dp), + contentAlignment = Alignment.Center) { + LinearProgressIndicator() } - } - SearchViewModel.Status.IDLE -> {} - SearchViewModel.Status.SUCCESS -> { - if (associationResults.isEmpty()) { - Box( - modifier = Modifier.fillMaxWidth().padding(16.dp), - contentAlignment = Alignment.Center) { - Text(context.getString(R.string.explore_search_no_results)) - } - } else { - Column(modifier = Modifier.verticalScroll(rememberScrollState())) { - associationResults.forEach { association -> - ListItem( - modifier = - Modifier.clickable { - isExpanded = false - onAssociationSelected(association) - } - .testTag( - ExploreContentTestTags.ASSOCIATION_EXPLORE_RESULT + - association.name), - headlineContent = { Text(association.name) }) - } - } + } + SearchViewModel.Status.IDLE -> {} + SearchViewModel.Status.SUCCESS -> { + if (associationResults.isEmpty()) { + Box( + modifier = Modifier.fillMaxWidth().padding(16.dp), + contentAlignment = Alignment.Center) { + Text(context.getString(R.string.explore_search_no_results)) + } + } else { + Column(modifier = Modifier.verticalScroll(rememberScrollState())) { + associationResults.forEach { association -> + ListItem( + modifier = + Modifier.clickable { + isExpanded = false + onAssociationSelected(association) + } + .testTag( + ExploreContentTestTags.ASSOCIATION_EXPLORE_RESULT + + association.name), + headlineContent = { Text(association.name) }) } + } } + } } - } + } } - /** A search bar specialized for searching events. */ @Composable fun EventSearchBar( diff --git a/app/src/main/java/com/android/unio/ui/components/SearchPagerSection.kt b/app/src/main/java/com/android/unio/ui/components/SearchPagerSection.kt index bc2da525..81ea4b6e 100644 --- a/app/src/main/java/com/android/unio/ui/components/SearchPagerSection.kt +++ b/app/src/main/java/com/android/unio/ui/components/SearchPagerSection.kt @@ -37,7 +37,7 @@ fun SearchPagerSection( searchBar: @Composable () -> Unit, pagerState: PagerState ) { - val context = LocalContext.current + val context = LocalContext.current Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)) { @@ -45,15 +45,13 @@ fun SearchPagerSection( // Sliding Progress Bar (if more than one item exists) if (items.size > 1) { // Search Bar Composable - //Box(modifier = Modifier.fillMaxWidth().padding(horizontal = 20.dp)) { searchBar() } + // Box(modifier = Modifier.fillMaxWidth().padding(horizontal = 20.dp)) { searchBar() } Text( text = context.getString(R.string.search_pager_section_slide), style = AppTypography.bodySmall, modifier = Modifier.padding(vertical = 8.dp)) - ProgressBarBetweenElements( - tabList = items.map { it.toString() }, - pagerState = pagerState) + ProgressBarBetweenElements(tabList = items.map { it.toString() }, pagerState = pagerState) } // Horizontal Pager @@ -62,21 +60,16 @@ fun SearchPagerSection( contentPadding = PaddingValues(horizontal = 16.dp), pageSpacing = 16.dp) { page -> val item = items[page] - Box( - modifier = - Modifier - .fillMaxWidth(), - contentAlignment = Alignment.Center - ) { - cardContent(item) + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + cardContent(item) } } } } /** - * A composable that renders a progress bar between elements in a tab layout, based on the state - * of the pager. The progress bar visually represents the current position and movement between tabs. + * A composable that renders a progress bar between elements in a tab layout, based on the state of + * the pager. The progress bar visually represents the current position and movement between tabs. * * @param tabList The list of tab labels, corresponding to the pager's items. * @param pagerState The state of the pager, providing the current page and offset information. @@ -114,7 +107,6 @@ fun ProgressBarBetweenElements(tabList: List, pagerState: PagerState) { val outerRectangleYStart = height - 45 val outerRectangleYEnd = height - 5 - val tabWidth = sizeList[0]?.first ?: defaultTabWidth val rectangleStartX = progressFromFirstPage * tabWidth + tabWidth / 4 val rectangleEndX = progressFromFirstPage * tabWidth + tabWidth * 3 / 4 @@ -163,11 +155,7 @@ fun ProgressBarBetweenElements(tabList: List, pagerState: PagerState) { sizeList[index] = Pair(it.width.toFloat(), it.height.toFloat()) }, selectedContentColor = colorScheme.primary) { - Spacer( - modifier = - Modifier.height( - 20.dp) - ) + Spacer(modifier = Modifier.height(20.dp)) } } }