Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huy #2

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 4 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,10 @@ dependencies {
debugImplementation 'androidx.compose.ui:ui-test-manifest'

implementation 'com.github.yuyakaido:CardStackView:v2.3.4'

//send OPT
implementation 'com.sendgrid:sendgrid-java:4.7.4'

implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'de.hdodenhof:circleimageview:3.1.0'
implementation 'com.sun.mail:android-mail:1.6.7'
implementation 'com.sun.mail:android-activation:1.6.7'
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

}
20 changes: 17 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-feature android:name="android.hardware.camera"
android:required="false" />
<uses-feature android:name="android.hardware.telephony" android:required="false" />

<uses-feature
android:name="android.hardware.telephony"
android:required="false" />

<uses-permission android:name="android.permission.INTERNET" />

<application
Expand All @@ -23,6 +26,16 @@
android:theme="@style/Theme.FreshCard"
tools:targetApi="31">
<activity
android:name=".WordTypingActivity"
android:exported="false" />
<activity
android:name=".ResultPointsActivity"
android:exported="false" />
<activity
android:name=".ResultCricleActivity"
android:exported="false" />
<activity
android:name=".ChooseTypeActivity"
android:name=".MultipleChoicesTestActivity"
android:exported="false" />
<activity
Expand All @@ -42,7 +55,8 @@
android:exported="false" />
<activity
android:name=".SendForgotPasswordEmailActivity"
tools:targetApi="31" />

tools:targetApi="31"/>
<activity
android:name=".FlashCardLearnActivity"
android:exported="false"
Expand Down
79 changes: 79 additions & 0 deletions app/src/main/java/com/example/freshcard/ChooseTypeActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.example.freshcard

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.freshcard.databinding.ActivityChooseTypeBinding

class ChooseTypeActivity : AppCompatActivity() {
private lateinit var binding: ActivityChooseTypeBinding
private var isBtnVntoengSelected = false
private var isBtnEngtovnSelected = false

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

var idTopic = intent.getStringExtra("idTopicTest")
binding = ActivityChooseTypeBinding.inflate(layoutInflater)
setContentView(binding.root)

binding.btnBack.setOnClickListener {
finish()
}

binding.btnEngtovn.setOnClickListener {
isBtnEngtovnSelected = true
isBtnVntoengSelected = false

binding.btnEngtovn.backgroundTintList = resources.getColorStateList(R.color.mediumGreen)
binding.btnEngtovn.setTextColor(ContextCompat.getColor(this, R.color.white))

binding.btnVntoeng.backgroundTintList = resources.getColorStateList(R.color.white)
binding.btnVntoeng.setTextColor(ContextCompat.getColor(this, R.color.mediumGreen))
updateSubmitButtonState()
}

binding.btnVntoeng.setOnClickListener {
isBtnVntoengSelected = true
isBtnEngtovnSelected = false

binding.btnVntoeng.backgroundTintList = resources.getColorStateList(R.color.mediumGreen)
binding.btnVntoeng.setTextColor(ContextCompat.getColor(this, R.color.white))

binding.btnEngtovn.backgroundTintList = resources.getColorStateList(R.color.white)
binding.btnEngtovn.setTextColor(ContextCompat.getColor(this, R.color.mediumGreen))

updateSubmitButtonState()
}

binding.btnSubmit.isEnabled = false
updateSubmitButtonState()

binding.btnSubmit.setOnClickListener {
if(isBtnVntoengSelected){
val intent = Intent(this, WordTypingActivity::class.java)
intent.putExtra("selectedButton", "btnVntoeng") // Gửi thông điệp về nút được chọn
intent.putExtra("idTopicTest", idTopic)
startActivity(intent)
}else if (isBtnEngtovnSelected){
val intent = Intent(this, WordTypingActivity::class.java)
intent.putExtra("selectedButton", "btnEngtovn") // Gửi thông điệp về nút được chọn
intent.putExtra("idTopicTest", idTopic)
startActivity(intent)
}
}
}

private fun updateSubmitButtonState() {
if (isBtnVntoengSelected || isBtnEngtovnSelected) {
// Kích hoạt btn_submit và đặt màu nền cho nó
binding.btnSubmit.isEnabled = true
binding.btnSubmit.backgroundTintList = resources.getColorStateList(R.color.mediumGreen)
} else {
// Vô hiệu hóa btn_submit và đặt màu nền về mặc định
binding.btnSubmit.isEnabled = false
binding.btnSubmit.backgroundTintList = resources.getColorStateList(R.color.grayDefault)
}
}
}
20 changes: 20 additions & 0 deletions app/src/main/java/com/example/freshcard/DAO/ImageDAO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,26 @@ class ImageDAO {
return fileName
}

public fun uploadAvtar(context: Context, imageUri: Uri): String {
progressDialog = ProgressDialog(context)
progressDialog!!.setTitle("Uploading File....")
progressDialog!!.show()
val formatter = SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.CANADA)
val now = Date()
val fileName: String = formatter.format(now)
storageReference = FirebaseStorage.getInstance().getReference("avatars/$fileName")
storageReference.putFile(imageUri)
.addOnSuccessListener(OnSuccessListener<Any?> {
Toast.makeText(context, "Successfully Uploaded", Toast.LENGTH_SHORT)
.show()
if (progressDialog!!.isShowing()) progressDialog!!.dismiss()
}).addOnFailureListener(OnFailureListener {
if (progressDialog!!.isShowing()) progressDialog!!.dismiss()
Toast.makeText(context, "Failed to Upload", Toast.LENGTH_SHORT).show()
})
return fileName
}

public fun getImage(filename:String, imageView: ImageView, path : String) {
var bitmap: Bitmap
var storageReference = FirebaseStorage.getInstance().getReference("$path/$filename")
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/example/freshcard/DAO/ResultTestDAO.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.freshcard.DAO

import com.example.freshcard.Structure.Database
import com.example.freshcard.Structure.ResultTest
import com.google.firebase.database.DatabaseReference

public class ResultTestDAO {
var topicResult: DatabaseReference = Database().getReference("resultTopic")

fun resultSave(idUser: String, amountCorrect: Int, duration: Int, time: String, type: String): Boolean{
val key = topicResult.push().key

if (key != null){
var newResult = ResultTest(idUser, amountCorrect, duration,
time, type)
topicResult.child(key).setValue(newResult)
return true
}else{
return false
}
}

}
83 changes: 70 additions & 13 deletions app/src/main/java/com/example/freshcard/DAO/UserDAO.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.example.freshcard.DAO


import android.content.Context
import android.util.Log
import at.favre.lib.crypto.bcrypt.BCrypt
import com.example.freshcard.MainActivity
import com.example.freshcard.Structure.Database
Expand All @@ -20,6 +19,23 @@ import com.google.firebase.database.ValueEventListener
import java.util.Random
import android.os.Handler
import android.os.Looper
import android.util.Log
import com.google.firebase.database.getValue
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import java.util.Properties
import javax.mail.Authenticator
import javax.mail.Message
import javax.mail.MessagingException
import javax.mail.PasswordAuthentication
import javax.mail.Session
import javax.mail.Transport
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeMessage
import kotlinx.coroutines.tasks.await
import java.time.LocalDateTime
import java.time.ZoneOffset
Expand Down Expand Up @@ -125,24 +141,63 @@ public class UserDAO() {
userRef.child("forgotPasswordCode").removeValue()
userRef.child("forgotPasswordCodeTime").removeValue()
}, 2 * 60 * 1000)

sendForgotPasswordEmail(email, otpCode)
// Trả về kết quả thành công
onResult(hashMapOf("state" to true, "message" to "Đã gửi mã OTP đến thông báo của bạn", "otp" to otpCode))
onResult(hashMapOf("state" to true, "message" to "Encrypted OTP sent to your email", "otp" to otpCode))

} else {
// Email không tồn tại
onResult(hashMapOf("state" to false, "message" to "Email không tồn tại"))
onResult(hashMapOf("state" to false, "message" to "Email does not exist"))
}
}

override fun onCancelled(error: DatabaseError) {
// Lỗi database
onResult(hashMapOf("state" to false, "message" to "Đã có lỗi xảy ra"))
onResult(hashMapOf("state" to false, "message" to "An error has occurred"))
}
}

query.addListenerForSingleValueEvent(valueEventListener)
}

private fun sendForgotPasswordEmail(email: String, otpCode: String) {
GlobalScope.launch(Dispatchers.IO) {
// Gửi email sử dụng thư viện JavaMail
val senderEmail = "[email protected]"
val senderPassword = "qrngpzsdxdlmzbjj"

val properties = Properties()
properties["mail.smtp.auth"] = "true"
properties["mail.smtp.starttls.enable"] = "true"
properties["mail.smtp.host"] = "smtp.gmail.com" // Đối với Gmail
properties["mail.smtp.port"] = "587"

val session = Session.getInstance(properties, object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(senderEmail, senderPassword)
}
})

try {
val message = MimeMessage(session)
message.setFrom(InternetAddress(senderEmail))
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email))
message.subject = "Forgot Password Code"
message.setText("Your OTP code is: $otpCode")

// Gửi email
Transport.send(message)

// Log thông báo sau khi gửi thành công (có thể thay thế bằng cách khác)
Log.d("Email", "Email sent successfully")

} catch (e: MessagingException) {
// Log thông báo nếu có lỗi
Log.e("Email", "Error sending email", e)
}
}
}

fun checkForgotPasswordCode(email: String, enteredCode: String, onResult: (HashMap<String, Any?>?) -> Unit) {
val query = db.orderByChild("email").equalTo(email)

Expand All @@ -164,18 +219,18 @@ public class UserDAO() {

if (currentTime - storedCodeTime <= expirationTime) {
// Mã OTP hợp lệ
onResult(hashMapOf("state" to true, "message" to " OTP hợp lệ"))
onResult(hashMapOf("state" to true, "message" to "Valid OTP code"))
} else {
// Mã OTP đã hết hạn
onResult(hashMapOf("state" to false, "message" to "OTP đã hết hạn"))
onResult(hashMapOf("state" to false, "message" to "OTP code has expired"))
}
} else {
// Mã OTP không đúng
onResult(hashMapOf("state" to false, "message" to "OTP không đúng"))
onResult(hashMapOf("state" to false, "message" to "OTP code is incorrect"))
}
} else {
// Email không tồn tại
onResult(hashMapOf("state" to false, "message" to "Email không tồn tại"))
onResult(hashMapOf("state" to false, "message" to "Email does not exist"))
}
}

Expand Down Expand Up @@ -261,10 +316,11 @@ public class UserDAO() {
userRef.child("phoneNumber").setValue(newPhoneNumber)

// Trả về kết quả thành công
onResult(hashMapOf("state" to true, "message" to "Thông tin người dùng đã được cập nhật"))
onResult(hashMapOf("state" to true, "message" to "\n" +
"User information has been updated"))
} else {
// Không tìm thấy người dùng với ID tương ứng
onResult(hashMapOf("state" to false, "message" to "Không tìm thấy người dùng"))
onResult(hashMapOf("state" to false, "message" to "User not found"))
}
}

Expand Down Expand Up @@ -302,6 +358,7 @@ public class UserDAO() {
userRef.child("password").setValue(hashedPassword)

// Trả về kết quả thành công
onResult(hashMapOf("state" to true, "message" to "Password has been changed"))
onResult(
hashMapOf(
"state" to true,
Expand All @@ -310,11 +367,11 @@ public class UserDAO() {
)
} else {
// Mật khẩu cũ không đúng
onResult(hashMapOf("state" to false, "message" to "Mật khẩu cũ không đúng"))
onResult(hashMapOf("state" to false, "message" to "The old password is incorrect"))
}
} else {
// Email không tồn tại
onResult(hashMapOf("state" to false, "message" to "Email không tồn tại"))
onResult(hashMapOf("state" to false, "message" to "Email does not exist"))
}
}

Expand Down
Loading