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

Commit

Permalink
Merge pull request #227 from MaximeZmt/jwen/qr-code-generator
Browse files Browse the repository at this point in the history
Jwen/qr code generator
  • Loading branch information
jiabaow authored May 2, 2022
2 parents 69cc590 + f3dca7e commit 80c6e1b
Show file tree
Hide file tree
Showing 25 changed files with 474 additions and 234 deletions.
5 changes: 4 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ dependencies {
implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.gms:play-services-auth:20.1.0'
implementation 'com.google.android.gms:play-services-auth:20.2.0'
implementation ('com.github.bumptech.glide:glide:4.13.0', {
exclude group: 'com.android.support'
})
Expand All @@ -116,6 +116,9 @@ dependencies {
testImplementation "io.mockk:mockk:1.12.3"
androidTestImplementation "io.mockk:mockk-android:1.12.3"

implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
implementation 'com.google.zxing:core:3.4.1'
implementation 'com.github.kenglxn.QRGen:android:2.6.0'
}

tasks.withType(Test) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.matcher.IntentMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import ch.sdp.vibester.R
import ch.sdp.vibester.TestMode
Expand All @@ -22,6 +21,7 @@ import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import io.mockk.every
import io.mockk.mockk
import org.hamcrest.CoreMatchers.not
import org.junit.After
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -77,7 +77,7 @@ class ProfileActivityTest {
}

@Test
fun clickBackToMain(){
fun clickBackToMain() {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)
intent.putExtra("isUnitTest", true)
Expand All @@ -88,6 +88,33 @@ class ProfileActivityTest {
Intents.intended(IntentMatchers.hasComponent(WelcomeActivity::class.java.name))
}

@Test
fun shouldShowQrCode() {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)
intent.putExtra("isUnitTest", true)

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

onView(withId(R.id.showQRCode)).perform(click())
onView(withId(R.id.QrCodePage)).check(matches(isDisplayed()))
onView(withId(R.id.profileContent)).check(matches(not(isDisplayed())))
onView(withId(R.id.qrCode)).check(matches(isDisplayed()))
}

@Test
fun clickBackToProfile() {
val ctx = ApplicationProvider.getApplicationContext() as Context
val intent = Intent(ctx, ProfileActivity::class.java)
intent.putExtra("isUnitTest", true)

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


@Test
fun checkEditProfile() {
Expand All @@ -102,14 +129,13 @@ class ProfileActivityTest {
val scn: ActivityScenario<ProfileActivity> = ActivityScenario.launch(intent)

val newUsername = "Lalisa Bon idomesniu"
onView(withId(R.id.editUser)).perform(ViewActions.click())
onView(withId(R.id.editUser)).perform(click())
onView(withId(0)).perform(
ViewActions.typeText(newUsername),
ViewActions.closeSoftKeyboard()
)
onView(withText("OK")).perform(ViewActions.click())
onView(withText("OK")).perform(click())
onView(withId(R.id.username)).check(matches(withText(newUsername)))

}

@Test
Expand All @@ -124,9 +150,24 @@ class ProfileActivityTest {

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

onView(withId(R.id.editUser)).perform(ViewActions.click())
onView(withText("Cancel")).perform(ViewActions.click())
onView(withId(R.id.editUser)).perform(click())
onView(withText("Cancel")).perform(click())
onView(withId(R.id.username)).check(matches(withText("Lalisa Bon")))
}

@Test
fun checkQrCodeGenerator() {
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)
intent.putExtra("isUnitTest", true)
intent.putExtra("userTestProfile", inputProfile)

createMockInvocation(inputProfile)

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

}
Binary file added app/src/main/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 86 additions & 28 deletions app/src/main/java/ch/sdp/vibester/activity/ProfileActivity.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package ch.sdp.vibester.activity

import android.graphics.Bitmap
import android.graphics.*
import android.os.Bundle
import android.text.InputType
import android.util.Log
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.Window
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import ch.sdp.vibester.R
import ch.sdp.vibester.api.BitmapGetterApi
import ch.sdp.vibester.auth.FireBaseAuthenticator
Expand All @@ -19,11 +22,16 @@ import ch.sdp.vibester.helper.IntentSwitcher
import ch.sdp.vibester.user.User
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.firebase.auth.FirebaseAuth
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import net.glxn.qrgen.android.MatrixToImageWriter
import java.util.concurrent.TimeUnit
import javax.inject.Inject

Expand All @@ -32,7 +40,6 @@ class ProfileActivity : AppCompatActivity() {
@Inject
lateinit var dataGetter: DataGetter


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

Expand All @@ -41,41 +48,65 @@ class ProfileActivity : AppCompatActivity() {

setContentView(R.layout.activity_profile)

val editUsername = findViewById<Button>(R.id.editUser)
setEditUserNameBtnListener()
setLogOutBtnListener()
setRetToMainBtnListener()
setShowQrCodeBtnListener()
setQrCodeToProfileBtnListener()

val logoutButton = findViewById<Button>(R.id.logout)
// Do not enable querying database while executing unit test
val isUnitTest: Boolean = intent.getBooleanExtra("isUnitTest", false)

val retToMain = findViewById<FloatingActionButton>(R.id.profile_returnToMain)
if (!isUnitTest) {
queryDatabase()
} else {
val upTest: User? = intent.getSerializableExtra("userTestProfile") as User?
if (upTest == null) {
setupProfile(User())
} else {
setupProfile(upTest)
}
}

editUsername.setOnClickListener {
}

private fun setEditUserNameBtnListener() {
findViewById<Button>(R.id.editUser).setOnClickListener {
showGeneralDialog(R.id.username, "username")
}
}

retToMain.setOnClickListener{
private fun setLogOutBtnListener() {
findViewById<Button>(R.id.logout).setOnClickListener {
FirebaseAuth.getInstance().signOut()
IntentSwitcher.switchBackToWelcome(this)
finish()
}
}

logoutButton.setOnClickListener{
FirebaseAuth.getInstance().signOut()
private fun setRetToMainBtnListener() {
findViewById<FloatingActionButton>(R.id.profile_returnToMain).setOnClickListener {
IntentSwitcher.switchBackToWelcome(this)
finish()
}
}

// Do not enable querying database while executing unit test
val isUnitTest: Boolean = intent.getBooleanExtra("isUnitTest", false)
private fun setShowQrCodeBtnListener() {
findViewById<Button>(R.id.showQRCode).setOnClickListener {
setLayoutVisibility(R.id.QrCodePage, true)
setLayoutVisibility(R.id.profileContent, false)
}
}

if (!isUnitTest) {
queryDatabase()
} else {
var upTest: User? = intent.getSerializableExtra("userTestProfile") as User?
if (upTest == null) {
setupProfile(User())
} else {
setupProfile(upTest)
}
private fun setQrCodeToProfileBtnListener() {
findViewById<FloatingActionButton>(R.id.qrCode_returnToProfile).setOnClickListener {
setLayoutVisibility(R.id.QrCodePage, false)
setLayoutVisibility(R.id.profileContent, true)
}
}

private fun setLayoutVisibility(layout: Int, isVisible: Boolean){
findViewById<ConstraintLayout>(layout).visibility = if (isVisible) VISIBLE else GONE
}

/**
Expand All @@ -86,7 +117,6 @@ class ProfileActivity : AppCompatActivity() {
* @param textId id of the text in the dialog
* @param name of the dialog
*/

private fun showDialog(title: String, hint: String, id: Int, textId: Int, name: String) {
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
builder.setTitle(title)
Expand Down Expand Up @@ -123,15 +153,12 @@ class ProfileActivity : AppCompatActivity() {
* A function that queries the database and fetched the correct user
* Hard coded for now
*/


private fun queryDatabase() {
dataGetter.getUserData(this::setupProfile)
}


private fun setupProfile(user: User){

private fun setupProfile(user: User) {
// Currently assuming that empty username means no user !
if (user.username != ""){
findViewById<TextView>(R.id.username).text = user.username
Expand All @@ -140,24 +167,55 @@ class ProfileActivity : AppCompatActivity() {
findViewById<TextView>(R.id.bestScore).text = user.bestScore.toString()
findViewById<TextView>(R.id.ranking).text = user.ranking.toString()
}
setupProfilePhoto(user)

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

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){
} catch (e: Exception) {
null
}
}
val bm = task.await()

if(bm != null){
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
*/

private fun generateQrCode(data: String) {
val size = 512
val hints = HashMap<EncodeHintType?, Any?>()
hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H

val bits = QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, size, size)
val bmp = MatrixToImageWriter.toBitmap(bits)
val qrCodeCanvas = Canvas(bmp)

val scaleFactor = 4 // resize the image
val logo = BitmapFactory.decodeStream(assets.open("logo.png"))
logo.density = logo.density * scaleFactor
val xLogo = (size - logo.width / scaleFactor) / 2f
val yLogo = (size - logo.height / scaleFactor) / 2f

qrCodeCanvas.drawBitmap(logo, xLogo, yLogo, null)

findViewById<ImageView>(R.id.qrCode).setImageBitmap(bmp)
}
}

Binary file added app/src/main/logo-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 80c6e1b

Please sign in to comment.