diff --git a/app/src/androidTest/java/com/android/unio/components/association/AssociationProfileTest.kt b/app/src/androidTest/java/com/android/unio/components/association/AssociationProfileTest.kt index 8299edcc8..59ce4beea 100644 --- a/app/src/androidTest/java/com/android/unio/components/association/AssociationProfileTest.kt +++ b/app/src/androidTest/java/com/android/unio/components/association/AssociationProfileTest.kt @@ -1,12 +1,16 @@ package com.android.unio.components.association import android.content.Context +import android.net.ConnectivityManager +import android.net.Network import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick +import androidx.core.content.ContextCompat +import androidx.core.content.ContextCompat.getSystemService import androidx.navigation.NavHostController import androidx.test.core.app.ApplicationProvider import com.android.unio.R @@ -79,6 +83,8 @@ class AssociationProfileTest : TearDown() { @MockK private lateinit var userRepository: UserRepositoryFirestore @MockK private lateinit var imageRepository: ImageRepositoryFirebaseStorage + @MockK private lateinit var connectivityManager: ConnectivityManager + @get:Rule val composeTestRule = createComposeRule() @get:Rule val hiltRule = HiltAndroidRule(this) @@ -89,11 +95,14 @@ class AssociationProfileTest : TearDown() { hiltRule.inject() mockkStatic(FirebaseFirestore::class) + mockkStatic(Network::class) + mockkStatic(ContextCompat::class) val db = mockk() val collection = mockk() val query = mockk() val task = mock>() + every { getSystemService(any(), ConnectivityManager::class.java) } returns connectivityManager every { Firebase.firestore } returns db every { db.collection(any()) } returns collection every { collection.whereIn(any(FieldPath::class), any()) } returns query @@ -180,6 +189,8 @@ class AssociationProfileTest : TearDown() { @Test fun testAssociationProfileDisplayComponent() { + every { connectivityManager?.activeNetwork } returns mockk() + composeTestRule.setContent { AssociationProfileScaffold( navigationAction, userViewModel, eventViewModel, associationViewModel) {} @@ -227,6 +238,8 @@ class AssociationProfileTest : TearDown() { @Test fun testFollowAssociation() { + every { connectivityManager?.activeNetwork } returns mockk() + val context: Context = ApplicationProvider.getApplicationContext() composeTestRule.setContent { AssociationProfileScaffold( @@ -258,8 +271,34 @@ class AssociationProfileTest : TearDown() { assert(associationViewModel.selectedAssociation.value!!.followersCount == currentCount) } + @Test + fun testFollowOffline() { + val context: Context = ApplicationProvider.getApplicationContext() + every { connectivityManager?.activeNetwork } returns null + composeTestRule.setContent { + AssociationProfileScaffold( + navigationAction, userViewModel, eventViewModel, associationViewModel) {} + } + // Disable internet connction in the test + + val currentCount = associationViewModel.selectedAssociation.value!!.followersCount + + composeTestRule + .onNodeWithTag(AssociationProfileTestTags.FOLLOW_BUTTON) + .assertDisplayComponentInScroll() + composeTestRule + .onNodeWithText(context.getString(R.string.association_follow)) + .assertIsDisplayed() + + composeTestRule.onNodeWithTag(AssociationProfileTestTags.FOLLOW_BUTTON).performClick() + assert(!userViewModel.user.value?.followedAssociations!!.contains(associations.first().uid)) + assert(associationViewModel.selectedAssociation.value!!.followersCount == currentCount) + } + @Test fun testButtonBehavior() { + every { connectivityManager?.activeNetwork } returns mockk() + composeTestRule.setContent { AssociationProfileScaffold( navigationAction, userViewModel, eventViewModel, associationViewModel) {} @@ -292,6 +331,8 @@ class AssociationProfileTest : TearDown() { @Test fun testGoBackButton() { + every { connectivityManager?.activeNetwork } returns mockk() + composeTestRule.setContent { AssociationProfileScaffold( navigationAction, userViewModel, eventViewModel, associationViewModel) {} @@ -306,6 +347,8 @@ class AssociationProfileTest : TearDown() { @Test fun testAssociationProfileGoodId() { + every { connectivityManager?.activeNetwork } returns mockk() + composeTestRule.setContent { AssociationProfileScaffold( navigationAction, userViewModel, eventViewModel, associationViewModel) {} @@ -317,6 +360,8 @@ class AssociationProfileTest : TearDown() { @Test fun testAssociationProfileNoId() { + every { connectivityManager?.activeNetwork } returns mockk() + associationViewModel.selectAssociation("3") composeTestRule.setContent { AssociationProfileScreen( diff --git a/app/src/main/java/com/android/unio/model/utils/Utils.kt b/app/src/main/java/com/android/unio/model/utils/Utils.kt new file mode 100644 index 000000000..223402c06 --- /dev/null +++ b/app/src/main/java/com/android/unio/model/utils/Utils.kt @@ -0,0 +1,13 @@ +package com.android.unio.model.utils + +import android.content.Context +import android.net.ConnectivityManager +import androidx.core.content.ContextCompat.getSystemService + +object Utils { + + fun checkInternetConnection(context: Context): Boolean { + val connectivityManager = getSystemService(context, ConnectivityManager::class.java) + return connectivityManager?.activeNetwork != null + } +} 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 456e29d25..84b3a34d9 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 @@ -66,6 +66,7 @@ import com.android.unio.model.event.EventViewModel import com.android.unio.model.strings.test_tags.AssociationProfileTestTags import com.android.unio.model.user.User import com.android.unio.model.user.UserViewModel +import com.android.unio.model.utils.Utils import com.android.unio.ui.event.EventCard import com.android.unio.ui.image.AsyncImageWrapper import com.android.unio.ui.navigation.NavigationAction @@ -267,6 +268,7 @@ private fun AssociationProfileContent( eventViewModel: EventViewModel, associationViewModel: AssociationViewModel ) { + val context = LocalContext.current val association by associationViewModel.selectedAssociation.collectAsState() val user by userViewModel.user.collectAsState() @@ -281,13 +283,21 @@ private fun AssociationProfileContent( mutableStateOf(user!!.followedAssociations.contains(association!!.uid)) } var enableButton by remember { mutableStateOf(true) } + val isConnected = Utils.checkInternetConnection(context) + val onFollow = { - enableButton = false - associationViewModel.updateFollow(association!!, user!!, isFollowed) { - userViewModel.refreshUser() - enableButton = true + if (isConnected) { + enableButton = false + associationViewModel.updateFollow(association!!, user!!, isFollowed) { + userViewModel.refreshUser() + enableButton = true + } + isFollowed = !isFollowed + } else { + Toast.makeText( + context, context.getString(R.string.no_internet_connection), Toast.LENGTH_SHORT) + .show() } - isFollowed = !isFollowed } val onMemberClick = { member: User -> @@ -559,6 +569,7 @@ private fun AssociationHeader( style = AppTypography.headlineSmall, modifier = Modifier.padding(bottom = 14.dp).testTag(AssociationProfileTestTags.HEADER_MEMBERS)) + if (isFollowed) { OutlinedButton( enabled = enableButton, diff --git a/app/src/main/java/com/android/unio/ui/authentication/Welcome.kt b/app/src/main/java/com/android/unio/ui/authentication/Welcome.kt index 5089c51d1..ebbba6fe4 100644 --- a/app/src/main/java/com/android/unio/ui/authentication/Welcome.kt +++ b/app/src/main/java/com/android/unio/ui/authentication/Welcome.kt @@ -1,7 +1,6 @@ package com.android.unio.ui.authentication import android.content.Context -import android.net.ConnectivityManager import android.util.Log import android.widget.Toast import androidx.compose.foundation.background @@ -42,7 +41,6 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign.Companion.Center import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat.getSystemService import com.android.unio.R import com.android.unio.model.strings.test_tags.WelcomeTestTags import com.android.unio.model.user.SignInState @@ -50,6 +48,7 @@ import com.android.unio.model.user.UserViewModel import com.android.unio.model.user.isValidEmail import com.android.unio.model.user.isValidPassword import com.android.unio.model.user.signInOrCreateAccount +import com.android.unio.model.utils.Utils.checkInternetConnection import com.android.unio.ui.theme.AppTypography import com.google.firebase.Firebase import com.google.firebase.auth.EmailAuthProvider @@ -169,9 +168,10 @@ fun WelcomeScreen(userViewModel: UserViewModel) { fun handleAuthentication(email: String, password: String, context: Context) { // Check internet connectivity - val connectivityManager = getSystemService(context, ConnectivityManager::class.java) - if (connectivityManager?.activeNetwork == null) { - Toast.makeText(context, "You appear to be offline.", Toast.LENGTH_SHORT).show() + val isConnected = checkInternetConnection(context) + if (!isConnected) { + Toast.makeText(context, context.getString(R.string.no_internet_connection), Toast.LENGTH_SHORT) + .show() return } diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index b7ab41718..74d13b92a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -285,6 +285,9 @@ * Other */ + + Vous semblez être hors-ligne + Évènements à venir Tous diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 65092dbd0..1467df756 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -317,6 +317,9 @@ * Other */ + + You appear to be offline + Upcoming Events All