Skip to content
This repository has been archived by the owner on Jan 31, 2024. It is now read-only.

Linking profile to image upload #228

Merged
merged 21 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
57cb7a1
Linked profile to image upload with hardcoded image
laurislopata May 2, 2022
ea9b282
Finished linking profile with image upload
laurislopata May 2, 2022
45575e1
Added image display on profile
laurislopata May 4, 2022
89f7b22
Fixed tests
laurislopata May 4, 2022
64c4041
Merged with main
laurislopata May 4, 2022
d45e0cf
Merged with main and fixed testrs
laurislopata May 4, 2022
7aee916
Added image download test checker
laurislopata May 4, 2022
2ec01c3
fixed tests
laurislopata May 4, 2022
f9c9282
Merge branch 'main' into laurislopata/link-profile-to-imageUpload
laurislopata May 5, 2022
4d85c3f
Merge branch 'main' into laurislopata/link-profile-to-imageUpload
laurislopata May 5, 2022
d0a08f3
Update app/src/main/java/ch/sdp/vibester/database/ImageGetter.kt
laurislopata May 5, 2022
cf04e42
Update app/src/main/java/ch/sdp/vibester/database/ImageGetter.kt
laurislopata May 5, 2022
a76487a
Update app/src/main/java/ch/sdp/vibester/database/ImageGetter.kt
laurislopata May 5, 2022
231c4fa
Update app/src/main/java/ch/sdp/vibester/database/ImageGetter.kt
laurislopata May 5, 2022
ca09d82
Update app/src/main/java/ch/sdp/vibester/database/ImageGetter.kt
laurislopata May 5, 2022
bb2e831
Update app/src/main/java/ch/sdp/vibester/activity/ProfileActivity.kt
laurislopata May 5, 2022
83dffc4
merged main
laurislopata May 5, 2022
d263915
merged main
laurislopata May 5, 2022
46fd991
Fixed comments
laurislopata May 5, 2022
a62630e
Commented tests
laurislopata May 5, 2022
1d26e0f
Commented tests
laurislopata May 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ dependencies {
implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'junit:junit:4.13.2'
implementation 'com.google.firebase:firebase-firestore-ktx:24.1.1'
implementation "androidx.cardview:cardview:1.0.0"
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.json:json:20180813'
testImplementation 'org.robolectric:robolectric:4.6'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ class CreateProfileActivityTest {
secondArg<(User) -> Unit>().invoke(User())
}

every { mockUsersRepo.getCurrentUser() } answers {
null
}

}

@After
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package ch.sdp.vibester.activity

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.provider.CalendarContract.CalendarCache.URI
import android.widget.ImageView
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
Expand All @@ -13,9 +16,9 @@ import androidx.test.espresso.intent.matcher.IntentMatchers
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import ch.sdp.vibester.R
import ch.sdp.vibester.TestMode
import ch.sdp.vibester.auth.FireBaseAuthenticator
import ch.sdp.vibester.database.DataGetter
import ch.sdp.vibester.database.ImageGetter
import ch.sdp.vibester.user.User
import com.google.firebase.auth.FirebaseUser
import dagger.hilt.android.testing.BindValue
Expand Down Expand Up @@ -64,15 +67,27 @@ class ProfileActivityTest {
@BindValue @JvmField
val mockUsersRepo = mockk<DataGetter>()

private fun createMockInvocation(mockProfile: User) {
@BindValue @JvmField
val mockImageGetter = mockk<ImageGetter>()

private fun createMockDataGetter(mockProfile: User) {
every { mockUsersRepo.getUserData(any(), any()) } answers {
secondArg<(User) -> Unit>().invoke(mockProfile)
}

every {mockUsersRepo.getCurrentUser()} answers {
null
}
every { mockUsersRepo.setFieldValue(any(), any(), any()) } answers {}
every { mockUsersRepo.setFieldValue(any(), any(), any()) } answers {}
}

val mockImageURI = Uri.parse("https://raw.githubusercontent.com/Ashwinvalento/cartoon-avatar/master/lib/images/male/45.png")
private fun createMockImageGetter() {
every {mockImageGetter.fetchImage(any(), any())} answers {
secondArg<(Uri) -> Unit>().invoke(mockImageURI)
}
}

@After
fun clean() {
Intents.release()
Expand All @@ -84,8 +99,9 @@ class ProfileActivityTest {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockInvocation(inputProfile)
createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)

Expand All @@ -101,8 +117,9 @@ class ProfileActivityTest {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockInvocation(inputProfile)
createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)

Expand All @@ -117,8 +134,9 @@ class ProfileActivityTest {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockInvocation(inputProfile)
createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)

Expand All @@ -134,8 +152,9 @@ class ProfileActivityTest {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockInvocation(inputProfile)
createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)
onView(withId(R.id.showQRCode)).perform(click())
Expand All @@ -151,8 +170,9 @@ class ProfileActivityTest {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockInvocation(inputProfile)
createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)
val newUsername = "Lalisa Bon idomesniu"
Expand All @@ -171,8 +191,9 @@ class ProfileActivityTest {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockInvocation(inputProfile)
createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)

Expand All @@ -187,12 +208,29 @@ class ProfileActivityTest {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockInvocation(inputProfile)
createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)
onView(withId(R.id.showQRCode)).perform(click())
onView(withId(R.id.qrCode)).check(matches(isDisplayed()))
}

}
@Test
fun checkIfPictureIsDisplayed() {
val inputProfile = User( "Lalisa Bon","bit.ly/3IUnyAF", "[email protected]", 12, 8, 29, 0, "VvPB47tQCLdjz3YebilS6h5EXdJ3")
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)

createMockDataGetter(inputProfile)
createMockAuthenticatorInvocation()
createMockImageGetter()

val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)

Thread.sleep(5000)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use Completable Future to detect if images have been downloaded?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I'll implement it next week

onView(withId(R.id.avatar)).check(matches(isDisplayed()))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ch.sdp.vibester.R
import ch.sdp.vibester.TestMode
import ch.sdp.vibester.auth.FireBaseAuthenticator
import ch.sdp.vibester.database.DataGetter
import ch.sdp.vibester.database.ImageRepo
import ch.sdp.vibester.database.ImageGetter
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

Expand All @@ -22,7 +22,7 @@ class CreateProfileActivity : AppCompatActivity() {
lateinit var dataGetter: DataGetter

@Inject
lateinit var imageRepo: ImageRepo
lateinit var imageGetter: ImageGetter

private val REQUEST_CODE = 500

Expand Down Expand Up @@ -76,7 +76,7 @@ class CreateProfileActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE){
imageRepo.uploadFile("profileImg/${FireBaseAuthenticator.getCurrentUID()}", data?.data!!) { updateUI() }
imageGetter.uploadFile("profileImg/${FireBaseAuthenticator.getCurrentUID()}", data?.data!!) { updateUI() }
}
}
}
61 changes: 35 additions & 26 deletions app/src/main/java/ch/sdp/vibester/activity/ProfileActivity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.sdp.vibester.activity

import android.graphics.*
import android.net.Uri
import android.os.Bundle
import android.text.InputType
import android.util.Log
Expand All @@ -18,6 +19,7 @@ import ch.sdp.vibester.R
import ch.sdp.vibester.api.BitmapGetterApi
import ch.sdp.vibester.auth.FireBaseAuthenticator
import ch.sdp.vibester.database.DataGetter
import ch.sdp.vibester.database.ImageGetter
import ch.sdp.vibester.helper.IntentSwitcher
import ch.sdp.vibester.user.User
import com.google.android.material.floatingactionbutton.FloatingActionButton
Expand All @@ -42,10 +44,13 @@ import javax.inject.Inject
class ProfileActivity : AppCompatActivity() {
@Inject
lateinit var dataGetter: DataGetter

@Inject
lateinit var authenticator: FireBaseAuthenticator

@Inject
lateinit var imageGetter: ImageGetter

/**
* Generic onCreate method belonging to ProfileActivity.
*/
Expand Down Expand Up @@ -180,6 +185,32 @@ class ProfileActivity : AppCompatActivity() {
}
}


/**
* A function that downloads an image and sets it.
* @param imageURI URI of the image
*/
private fun setImage(imageURI: Uri) {
CoroutineScope(Dispatchers.Main).launch {
val task = async(Dispatchers.IO) {
try {
val bit = BitmapGetterApi.download(imageURI.toString())
bit.get(10, TimeUnit.SECONDS)
} catch (e: Exception){

null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the handle exception is null?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaximeZmt wrote this function I just reused it, so maybe he can answer better :)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It as was null because it was not a critical feature. I mean that the download of an image can fail for many reasons (user, server, Internet Provider, other users, ...)
Therefore if it does not works, As it was implemented at the beginning of the semester I've put null not knowing how to handle it.
Maybe there is a better way to do it now.

}
}
val bm = task.await()

if(bm != null){
val avatar = findViewById<ImageView>(R.id.avatar)
avatar.setImageBitmap(Bitmap.createScaledBitmap(bm, 1000,1000, false))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe put 1000 in a meaningful val?

}
}
}


/**
* Function that sets the text of a given TextView to the string variant of an integer.
* @param id: The id of the TextView to be changed.
Expand Down Expand Up @@ -210,36 +241,15 @@ class ProfileActivity : AppCompatActivity() {
findViewById<TextView>(R.id.username).text = user.username
setTextOfMultipleViews(user)
}
setupProfilePhoto(user)

val imageID = dataGetter.getCurrentUser()?.uid
imageGetter.fetchImage("profileImg/${imageID}", this::setImage)

if (user.uid != "") {
generateQrCode(user.uid)
}
}

/**
* Helper function to setupProfile to set the profile photo of a user.
* @param user: The user whose profile picture we are setting up.
*/
private fun setupProfilePhoto(user: User) {
CoroutineScope(Dispatchers.Main).launch {
val task = async(Dispatchers.IO) {
try {
Log.e(getString(R.string.log_tag),user.image)
val bit = BitmapGetterApi.download("https://raw.githubusercontent.com/Ashwinvalento/cartoon-avatar/master/lib/images/male/45.png")
bit.get(10, TimeUnit.SECONDS)
} catch (e: Exception) {
null
}
}
val bm = task.await()
if (bm != null) {
val avatar = findViewById<ImageView>(R.id.avatar)
avatar.setImageBitmap(Bitmap.createScaledBitmap(bm, 1000,1000, false))
}
}
}

/**
* generate the qr code bitmap of the given data
* @param data Qr Code data
Expand All @@ -264,4 +274,3 @@ class ProfileActivity : AppCompatActivity() {
findViewById<ImageView>(R.id.qrCode).setImageBitmap(bmp)
}
}

7 changes: 6 additions & 1 deletion app/src/main/java/ch/sdp/vibester/database/DataGetter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.util.Log
import ch.sdp.vibester.auth.FireBaseAuthenticator
import ch.sdp.vibester.helper.PartyRoom
import ch.sdp.vibester.user.User
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.ValueEventListener
Expand Down Expand Up @@ -207,6 +208,10 @@ class DataGetter @Inject constructor() {
dbRoomRef.child(partyRoom.getRoomID()).child("emailList").setValue(partyRoom.getEmailList())
}

fun getCurrentUser(): FirebaseUser? {
Copy link
Collaborator

@Tsathogguaa Tsathogguaa May 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder to add documentation for functions that are not private, no matter how obvious they can be. Not too important for this PR as we need a general check over our entire codebase and write docs, but a small reminder

return authenticator.getCurrUser()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it in dataFetter? We need to think of a separation between firebaseUser and Datagetter

}

/**
* This functions fetches the data of the given user from the database
* @param roomName the name of the room to retrieve data from
Expand All @@ -223,7 +228,7 @@ class DataGetter @Inject constructor() {
for (snapshot in dataSnapshot.children) {
val partyRoom: PartyRoom? = snapshot.getValue(PartyRoom::class.java)
if(partyRoom != null) {
val currUserEmail = authenticator.getCurrUser()?.email!!
val currUserEmail = getCurrentUser()?.email!!
if(!partyRoom.getEmailList().contains(currUserEmail)) {
partyRoom.addUserEmail(currUserEmail)
updateRoomUserList(partyRoom)
Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/ch/sdp/vibester/database/ImageGetter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ch.sdp.vibester.database

import android.net.Uri
import com.google.android.gms.tasks.OnSuccessListener
import javax.inject.Inject

/**
* The users class which handled all the interactions with the database that are linked to users
*/
class ImageGetter @Inject constructor() {
private val storageRef = Storage.get().reference

/**
* This function uploads a provided image to the database
* @param filePath file path of the picture on the phone
* @param fileUri URI of the image on the database
* @param callback function to be called when image is done uploading
*/
fun uploadFile(filePath: String, fileUri: Uri, callback: () -> Unit) {
val profilePicRef = storageRef.child(filePath)

val uploadTask = profilePicRef.putFile(fileUri)

uploadTask.addOnSuccessListener { callback() }
}

/**
* This function fetches an image
* @param imageID ID of the image in the database
* @param callback function to be called when image fetched
*/
fun fetchImage(imageID: String, callback: (downloadUR: Uri) -> Unit) {
storageRef.child(imageID).downloadUrl.addOnSuccessListener(
OnSuccessListener(callback))
}

}
23 changes: 0 additions & 23 deletions app/src/main/java/ch/sdp/vibester/database/ImageRepo.kt

This file was deleted.

Loading