First Commit:

Version 1.0 [Non Optimized Version]
This commit is contained in:
Diassdp
2025-01-19 11:52:27 +07:00
commit f299dfb3a0
92 changed files with 4558 additions and 0 deletions

View File

@ -0,0 +1,111 @@
package com.healthjournal.algorithm
import com.healthjournal.data.HealthData
class AlgoritmaKesehatan {
fun recommendationOfTheDay(healthData: HealthData): HashMap<String, Any> {
val bloodSugarAnalysis = getBloodSugarAnalysis(healthData)
val bloodPressureAnalysis = getBloodPressureAnalysis(healthData)
val BMIAnalysis = getBMIAnalysis(healthData)
val tasks = getTaskBasedData(healthData)
return hashMapOf(
"bloodSugarAnalysis" to bloodSugarAnalysis,
"bloodPressureAnalysis" to bloodPressureAnalysis,
"BMIAnalysis" to BMIAnalysis,
"tasks" to tasks
)
}
fun getBloodSugarAnalysis(healthData: HealthData): String {
return when (healthData.gender) {
"Female", "Other" -> when {
healthData.bloodSugar < 70 -> "Gula darah rendah, konsumsi makanan manis seperti buah atau madu."
healthData.bloodSugar in 70.0..140.0 -> "Gula darah normal, pertahankan pola makan sehat."
healthData.bloodSugar > 140 -> "Gula darah tinggi, kurangi makanan manis dan lakukan olahraga teratur."
else -> "Data gula darah tidak valid."
}
"Male" -> when {
healthData.bloodSugar < 70 -> "Gula darah rendah, segera konsumsi makanan berkarbohidrat."
healthData.bloodSugar in 70.0..130.0 -> "Gula darah normal, jaga pola makan seimbang."
healthData.bloodSugar > 130 -> "Gula darah tinggi, batasi konsumsi gula dan periksa kesehatan secara berkala."
else -> "Data gula darah tidak valid."
}
else -> "Data gula darah tidak valid."
}
}
fun getBloodPressureAnalysis(healthData: HealthData): String {
return when (healthData.gender) {
"Female", "Other" -> when {
healthData.systolicBP < 90 || healthData.diastolicBP < 60 -> "Tekanan darah rendah, tingkatkan asupan cairan dan garam."
healthData.systolicBP in 90..120 && healthData.diastolicBP in 60..80 -> "Tekanan darah normal, pertahankan gaya hidup sehat."
healthData.systolicBP > 120 || healthData.diastolicBP > 80 -> "Tekanan darah tinggi, kurangi garam dan tingkatkan aktivitas fisik."
else -> "Data tekanan darah tidak valid."
}
"Male" -> when {
healthData.systolicBP < 100 || healthData.diastolicBP < 60 -> "Tekanan darah rendah, perbanyak cairan dan istirahat."
healthData.systolicBP in 100..130 && healthData.diastolicBP in 60..85 -> "Tekanan darah normal, pertahankan pola makan sehat."
healthData.systolicBP > 130 || healthData.diastolicBP > 85 -> "Tekanan darah tinggi, konsultasikan dengan dokter untuk pemeriksaan lebih lanjut."
else -> "Data tekanan darah tidak valid."
}
else -> "Data tekanan darah tidak valid."
}
}
fun getBMIAnalysis(healthData: HealthData): String {
return when (healthData.gender) {
"Female", "Other" -> when {
healthData.BMI < 18.5 -> "BMI rendah, tingkatkan asupan kalori dengan makanan bernutrisi."
healthData.BMI in 18.5..24.9 -> "BMI normal, pertahankan pola makan seimbang."
healthData.BMI > 24.9 -> "BMI tinggi, lakukan olahraga teratur dan perbaiki pola makan."
else -> "Data BMI tidak valid."
}
"Male" -> when {
healthData.BMI < 20 -> "BMI rendah, tambahkan asupan protein dan makanan bergizi."
healthData.BMI in 20.0..25.0 -> "BMI normal, teruskan pola hidup sehat."
healthData.BMI > 25 -> "BMI tinggi, perbanyak aktivitas fisik dan atur pola makan rendah lemak."
else -> "Data BMI tidak valid."
}
else -> "Data BMI tidak valid."
}
}
fun getTaskBasedData(healthData: HealthData): List<Map<String, Any>> {
val tasks = mutableListOf<Map<String, Any>>()
// Task for Blood Sugar Control
if (healthData.bloodSugar > 140) {
tasks.add(mapOf("task" to "Cek kadar gula darah 2 kali sehari.", "completed" to false))
tasks.add(mapOf("task" to "Kurangi konsumsi makanan tinggi gula.", "completed" to false))
} else if (healthData.bloodSugar < 70) {
tasks.add(mapOf("task" to "Sediakan camilan sehat seperti buah atau kacang.", "completed" to false))
}
// Task for Blood Pressure Control
if (healthData.systolicBP > 120 || healthData.diastolicBP > 80) {
tasks.add(mapOf("task" to "Lakukan olahraga ringan seperti jalan kaki selama 30 menit.", "completed" to false))
tasks.add(mapOf("task" to "Kurangi makanan asin dan berlemak.", "completed" to false))
} else if (healthData.systolicBP < 90) {
tasks.add(mapOf("task" to "Perbanyak minum air putih dan istirahat.", "completed" to false))
}
// Task for BMI Control
if (healthData.BMI > 25) {
tasks.add(mapOf("task" to "Lakukan olahraga rutin minimal 3 kali seminggu.", "completed" to false))
tasks.add(mapOf("task" to "Konsumsi lebih banyak sayuran dan serat.", "completed" to false))
} else if (healthData.BMI < 18.5) {
tasks.add(mapOf("task" to "Tambahkan makanan tinggi kalori seperti kacang dan susu.", "completed" to false))
}
// Age and Gender Specific Tasks
if (healthData.age > 50) {
tasks.add(mapOf("task" to "Lakukan pemeriksaan kesehatan rutin setiap bulan.", "completed" to false))
}
if (healthData.gender == "Female" || healthData.gender == "Other") {
tasks.add(mapOf("task" to "Perhatikan kebutuhan kalsium dan zat besi.", "completed" to false))
}
return tasks
}
}

View File

@ -0,0 +1,23 @@
package com.healthjournal.data
import java.io.Serializable
data class HealthData(
val bloodSugar: Float,
val diastolicBP: Int,
val systolicBP: Int,
val BMI: Float,
val age: Int,
val gender: String
)
data class ResultData(
val journalID: String,
val bloodSugar: Float,
val diastolicBP: Int,
val systolicBP: Int,
val BMI: Float,
val date: String
) : Serializable

View File

@ -0,0 +1,8 @@
package com.healthjournal.model
data class SessionModel (
val userId: String,
val name: String,
val statusLogin: Boolean,
val loginTimestamp: Long
)

View File

@ -0,0 +1,109 @@
package com.healthjournal.ui.custom
import android.content.Context
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.text.Editable
import android.text.InputFilter
import android.text.InputType
import android.text.TextWatcher
import android.util.AttributeSet
import android.util.Patterns
import androidx.core.content.ContextCompat
import com.healthjournal.R
import com.google.android.material.textfield.TextInputEditText
class CustomEditText : TextInputEditText {
private var errorBackground: Drawable? = null
private var defaultBackground: Drawable? = null
private var isError: Boolean = false
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
init()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
background = if (isError) {
errorBackground
} else {
defaultBackground
}
}
private fun init() {
errorBackground = ContextCompat.getDrawable(context, R.drawable.bg_edt_error)
defaultBackground = ContextCompat.getDrawable(context, R.drawable.bg_edt_default)
if (inputType == InputType.TYPE_CLASS_NUMBER) {
filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
source.filter { it.isDigit() }
})
}
addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
val input = p0.toString()
if (input.isEmpty()) {
error = context.getString(R.string.empty_field)
isError = true
} else {
error = null
isError = false
validateInput(input)
}
}
override fun afterTextChanged(p0: Editable?) {}
})
}
private fun validateInput(input: String) {
when (inputType) {
EMAIL -> {
if (!Patterns.EMAIL_ADDRESS.matcher(input).matches()) {
error = context.getString(R.string.email_validation)
isError = true
} else {
isError = false
}
}
PASSWORD -> {
if (input.length < 6) {
error = context.getString(R.string.password_length)
isError = true
} else {
isError = false
}
}
InputType.TYPE_CLASS_NUMBER -> {
if (!input.matches("\\d+".toRegex())) {
error = context.getString(R.string.empty_field)
isError = true
} else {
isError = false
}
}
}
}
companion object {
const val EMAIL = 0x00000021
const val PASSWORD = 0x00000081
}
}

View File

@ -0,0 +1,227 @@
package com.healthjournal.ui.dashboard
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.database
import com.healthjournal.R
import com.healthjournal.data.ResultData
import com.healthjournal.databinding.ActivityMainBinding
import com.healthjournal.ui.journal.input.JournalInputActivity
import com.healthjournal.ui.login.LoginActivity
import com.healthjournal.ui.profile.ProfileActivity
import com.healthjournal.ui.recommendation.RecommendationActivity
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var user: FirebaseAuth
private lateinit var mainAdapter: MainAdapter
private val healthDataList: MutableList<ResultData> = mutableListOf()
private val database = Firebase.database
private var dailyReport = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
user = FirebaseAuth.getInstance()
userCheck()
setupListener()
populateHistory()
navigationBottomBar()
}
private fun navigationBottomBar(){
binding.bottomNavigation.setOnItemSelectedListener {
when(it.itemId){
R.id.nav_add -> addJournal()
R.id.nav_home -> home()
R.id.nav_profile -> profile()
}
true
}
}
private fun getWeekCount() {
val today = Calendar.getInstance()
val userID = user.currentUser!!.uid
var count = 0
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
today.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
val startDate = dateFormat.format(today.time)
val endDate = today.clone() as Calendar
endDate.add(Calendar.DAY_OF_WEEK, 6)
val endDateString = dateFormat.format(endDate.time)
database.getReference("users").child(userID).child("journal")
.get()
.addOnCompleteListener { task ->
if (task.isSuccessful) {
count = task.result.children.count { snapshot ->
val date = snapshot.child("date").value.toString()
date >= startDate && date <= endDateString
}
Log.d("debug", "Entries found: $count for week: $startDate - $endDateString")
binding.tvDailyCounter.text = "$count/7"
} else {
Log.e("error", task.exception?.message.toString())
Toast.makeText(this, task.exception?.message, Toast.LENGTH_SHORT).show()
}
}
}
private fun addJournal(){
if (dailyReport != false){
Toast.makeText(this, "Daily Report Already Created", Toast.LENGTH_SHORT).show()
} else {
startActivity(Intent(this, JournalInputActivity::class.java))
}
}
private fun home(){
}
private fun profile(){
intent = Intent(this, ProfileActivity::class.java)
startActivity(intent)
}
private fun setupListener(){
binding.btnRecomendation.setOnClickListener {
startActivity(Intent(this, RecommendationActivity::class.java))
finish()
}
binding.btnInputData.setOnClickListener {
startActivity(Intent(this, JournalInputActivity::class.java))
finish()
}
}
private fun dailycheck() {
val today = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(android.icu.util.Calendar.getInstance().time).toString()
val userID = user.currentUser!!.uid
database.getReference("users").child(userID).child("journal").get().addOnCompleteListener { task ->
if (task.isSuccessful) {
task.result.children.forEach {
if (it.child("date").value.toString() == today) {
dailyReport = true
switchLayout()
populateTodayReport()
}
}
} else {
Log.d("error", task.exception!!.message.toString())
Toast.makeText(this, task.exception!!.message, Toast.LENGTH_SHORT).show()
}
}
}
private fun switchLayout(){
if (binding.clDailyReport1.visibility == View.VISIBLE){
binding.clDailyReport1.visibility = View.INVISIBLE
binding.clDailyReport2.visibility = View.VISIBLE
binding.btnRecomendation.visibility = View.VISIBLE
binding.ivCuboidIndicator1Green.visibility = View.VISIBLE
binding.ivCuboidIndicator2Green.visibility = View.VISIBLE
binding.ivCuboidIndicator1Orange.visibility = View.INVISIBLE
binding.ivCuboidIndicator2Orange.visibility = View.INVISIBLE
} else {
binding.clDailyReport1.visibility = View.VISIBLE
binding.clDailyReport2.visibility = View.INVISIBLE
binding.btnRecomendation.visibility = View.GONE
binding.ivCuboidIndicator1Green.visibility = View.INVISIBLE
binding.ivCuboidIndicator2Green.visibility = View.INVISIBLE
binding.ivCuboidIndicator1Orange.visibility = View.VISIBLE
binding.ivCuboidIndicator2Orange.visibility = View.VISIBLE
}
}
private fun userCheck() {
val user = FirebaseAuth.getInstance().currentUser
if (user == null) {
Toast.makeText(this, "Please Login to an account", Toast.LENGTH_SHORT).show()
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
finish()
} else {
Toast.makeText(this, "Welcome back!", Toast.LENGTH_SHORT).show()
dailycheck()
getWeekCount()
}
}
private fun populateHistory() {
val userID = user.currentUser!!.uid
mainAdapter = MainAdapter(healthDataList)
binding.rvHealthHistory.apply {
adapter = mainAdapter
layoutManager = LinearLayoutManager(this@MainActivity)
}
database.getReference("users").child(userID).child("journal").get()
.addOnCompleteListener { task ->
if (task.isSuccessful) {
healthDataList.clear()
task.result.children.forEach { snapshot ->
val journalID = snapshot.child("date").value.toString()
val bloodSugar = snapshot.child("bloodSugar").value.toString().toFloatOrNull() ?: 0f
val diastolicBP = snapshot.child("bloodPressureDIA").value.toString().toIntOrNull() ?: 0
val systolicBP = snapshot.child("bloodPressureSYS").value.toString().toIntOrNull() ?: 0
val BMI = snapshot.child("bmi").value.toString().toFloatOrNull() ?: 0f
val date = snapshot.child("date").value.toString()
val resultData = ResultData(journalID, bloodSugar, diastolicBP, systolicBP, BMI, date)
healthDataList.add(resultData)
}
mainAdapter.notifyDataSetChanged()
} else {
Log.d("error", task.exception?.message.toString())
Toast.makeText(this, task.exception?.message, Toast.LENGTH_SHORT).show()
}
}
}
private fun populateTodayReport(){
val today = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(android.icu.util.Calendar.getInstance().time).toString()
val userID = user.currentUser!!.uid
database.getReference("users").child(userID).child("journal").get().addOnCompleteListener { task ->
if (task.isSuccessful) {
task.result.children.forEach {
if (it.child("date").value.toString() == today) {
binding.tvBloodsugarLevel.text = it.child("bloodSugar").value.toString()+" mg/dL"
binding.tvBloodsugarDesc.text = it.child("recommendation").child("bloodSugarAnalysis").value.toString()
binding.tvBloodpressureLevel.text = it.child("bloodPressureDIA").value.toString()+"/"+it.child("bloodPressureSYS").value.toString()+" mm Hg"
binding.tvBloodpressureDesc.text = it.child("recommendation").child("bloodPressureAnalysis").value.toString()
binding.tvBmiLevel.text = it.child("BMI").value.toString() +" BMI"
binding.tvBmiDesc.text = it.child("recommendation").child("BMIAnalysis").value.toString()
}
}
} else {
Log.d("error", task.exception!!.message.toString())
Toast.makeText(this, task.exception!!.message, Toast.LENGTH_SHORT).show()
}
}
}
}

View File

@ -0,0 +1,73 @@
package com.healthjournal.ui.dashboard
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.healthjournal.R
import com.healthjournal.data.ResultData
import com.healthjournal.ui.journal.detail.DetailJournalActivity
import java.text.SimpleDateFormat
import java.util.Locale
class MainAdapter(private val healthDataList: MutableList<ResultData>) : RecyclerView.Adapter<MainAdapter.HealthViewHolder>() {
class HealthViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvDay: TextView = view.findViewById(R.id.tv_day)
val tvDate: TextView = view.findViewById(R.id.tv_date)
val tvBloodSugar: TextView = view.findViewById(R.id.tv_BS_Level)
val tvBloodPressure: TextView = view.findViewById(R.id.tv_BP_Level)
}
// Function to update the list and notify the adapter
fun setData(newData: List<ResultData>) {
healthDataList.clear()
healthDataList.addAll(newData)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HealthViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_health_history, parent, false)
return HealthViewHolder(view)
}
private fun dayOfWeek(date: String): String {
return try {
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
val parsedDate = dateFormat.parse(date)
if (parsedDate != null) {
SimpleDateFormat("EEEE", Locale.getDefault()).format(parsedDate)
} else {
"Invalid Date"
}
} catch (e: Exception) {
"Invalid Date"
}
}
private fun countGoals (){
}
override fun onBindViewHolder(holder: HealthViewHolder, position: Int) {
val healthData = healthDataList[position]
holder.tvDay.text = dayOfWeek(healthData.date)
holder.tvDate.text = healthData.date
holder.tvBloodSugar.text = "${healthData.bloodSugar} mg/dL"
holder.tvBloodPressure.text = "${healthData.diastolicBP}/${healthData.systolicBP} mm Hg"
holder.itemView.setOnClickListener {
val context = holder.itemView.context
val intent = Intent(context, DetailJournalActivity::class.java).apply {
putExtra("HEALTH_DATA", healthData)
}
context.startActivity(intent)
}
}
override fun getItemCount(): Int = healthDataList.size
}

View File

@ -0,0 +1,92 @@
package com.healthjournal.ui.journal.detail
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.database
import com.healthjournal.R
import com.healthjournal.data.ResultData
import com.healthjournal.databinding.ActivityDetailJournalBinding
class DetailJournalActivity : AppCompatActivity() {
private lateinit var binding: ActivityDetailJournalBinding
private lateinit var user: FirebaseAuth
private val database = Firebase.database
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailJournalBinding.inflate(layoutInflater)
setContentView(binding.root)
val healthData = intent.getSerializableExtra("HEALTH_DATA") as? ResultData
}
private fun populateDetailJournal() {
val userID = user.currentUser?.uid
val journalDate = intent.getStringExtra("JOURNAL_DATE")
if (userID != null && journalDate != null) {
database.getReference("users").child(userID).child("journal").child(journalDate).get()
.addOnCompleteListener(DetailJournalActivity()) {
if (it.isSuccessful) {
val data = it.result
if (data != null) {
/*
binding.tvBloodsugarLevel2.text = data.bloodSugarLevel
binding.tvBloodsugarDesc.text = data.bloodSugarDesc
binding.tvBloodpressureLevel2.text = data.bloodPressureLevel
binding.tvBloodpressureDesc.text = data.bloodPressureDesc
binding.tvBMILevel2.text = data.bmiLevel
binding.tvBMIDesc.text = data.bmiDesc
binding.tvGoals2.text = countGoalsCompleted(data.goalsCompleted)
binding.tvJournalNote.text = data.journalNote
*/
}
} else {
Toast.makeText(this, it.exception!!.message, Toast.LENGTH_SHORT).show()
Log.d("error", it.exception!!.message.toString())
}
}
}
}
private fun countGoalsCompleted(goalsCompleted: List<Boolean>): String {
var count = 0
for (completed in goalsCompleted) {
if (completed) {
count++
}
}
return count.toString()
}
private fun deleteHistory() {
val userID = user.currentUser?.uid
val journalDate = intent.getStringExtra("JOURNAL_DATE")
if (userID != null && journalDate != null) {
database.getReference("users").child(userID).child("journal").child(journalDate)
.removeValue()
.addOnCompleteListener(DetailJournalActivity()) {
if (it.isSuccessful) {
Toast.makeText(this, "History deleted successfully", Toast.LENGTH_SHORT)
.show()
finish()
} else {
Toast.makeText(this, it.exception!!.message, Toast.LENGTH_SHORT).show()
}
}
}
}
private fun setupListener() {
binding.btnDeleteHistory.setOnClickListener() {
deleteHistory()
}
}
}

View File

@ -0,0 +1,127 @@
package com.healthjournal.ui.journal.input
import android.content.Intent
import android.icu.util.Calendar
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
import com.healthjournal.algorithm.AlgoritmaKesehatan
import com.healthjournal.databinding.ActivityJournalInputBinding
import com.healthjournal.ui.dashboard.MainActivity
import com.healthjournal.data.HealthData
import java.text.SimpleDateFormat
import java.util.Locale
class JournalInputActivity : AppCompatActivity() {
private lateinit var binding: ActivityJournalInputBinding
private lateinit var user: FirebaseAuth
private lateinit var database: FirebaseDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityJournalInputBinding.inflate(layoutInflater)
setContentView(binding.root)
user = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance()
val userId = user.currentUser?.uid
if (userId != null) {
database.getReference("users").child(userId).get()
.addOnCompleteListener { task ->
if (task.isSuccessful && task.result.exists()) {
binding.edtInputWeight.setText(task.result.child("weight").value.toString())
binding.edtHeight.setText(task.result.child("height").value.toString())
binding.edtAge.setText(task.result.child("date").value.toString())
binding.edtGender.setText(task.result.child("gender").value.toString())
} else {
Toast.makeText(this, "Error: ${task.exception?.message}", Toast.LENGTH_SHORT).show()
Log.d("error", task.exception?.message.toString())
}
}
} else {
Toast.makeText(this, "User not logged in", Toast.LENGTH_SHORT).show()
finish()
}
setupListener()
}
private fun setupListener() {
binding.btnInputData.setOnClickListener {
submitData()
}
}
private fun calculateBMI(weight: Int, height: Int): Float {
val heightInMeters = height / 100f
val BMI = weight / (heightInMeters * heightInMeters)
return BMI
}
fun calculateAge(birthDate: String): Int {
val sdf = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
val date = sdf.parse(birthDate)
val birthCalendar = Calendar.getInstance()
birthCalendar.time = date
val today = Calendar.getInstance()
var age = today.get(Calendar.YEAR) - birthCalendar.get(Calendar.YEAR)
if (today.get(Calendar.DAY_OF_YEAR) < birthCalendar.get(Calendar.DAY_OF_YEAR)) {
age--
}
return age
}
private fun submitData() {
val userId = user.currentUser?.uid
if (userId == null) {
Toast.makeText(this, "User not logged in", Toast.LENGTH_SHORT).show()
return
}
val journalDate = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(Calendar.getInstance().time).toString()
val bloodPressureSYS = binding.edtInputBloodPressureSYS.text.toString()
val bloodPressureDIA = binding.edtInputBloodPressureDIA.text.toString()
val bloodSugar = binding.edtInputBloodSugar.text.toString()
val weight = binding.edtInputWeight.text.toString().toInt()
val height = binding.edtHeight.text.toString().toInt()
val note = binding.edtInputNote.text.toString()
val age = calculateAge(binding.edtAge.text.toString())
val gender = binding.edtGender.text.toString()
Log.d("journalDate", journalDate)
if (weight != null && bloodPressureSYS.isNotEmpty() && bloodPressureDIA.isNotEmpty() && bloodSugar.isNotEmpty()) {
database.getReference("users").child(userId).child("height").get().addOnSuccessListener { snapshot ->
val BMI = calculateBMI(weight, height)
val healthData = HealthData(bloodSugar.toFloat(), bloodPressureSYS.toInt(), bloodPressureDIA.toInt(), BMI,age,gender)
val recommendation = AlgoritmaKesehatan().recommendationOfTheDay(healthData)
val data = hashMapOf(
"date" to journalDate,
"bloodPressureSYS" to bloodPressureSYS,
"bloodPressureDIA" to bloodPressureDIA,
"bloodSugar" to bloodSugar,
"BMI" to BMI,
"note" to note,
"recommendation" to recommendation
)
database.getReference("users").child(userId).child("journal").push().setValue(data).addOnCompleteListener {
if (it.isSuccessful) {
Toast.makeText(this, "Data Input Success", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
} else {
Toast.makeText(this, it.exception?.message, Toast.LENGTH_SHORT).show()
Log.d("error", it.exception?.message.toString())
}
}
}
} else {
Toast.makeText(this, "Please fill all fields correctly", Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -0,0 +1,57 @@
package com.healthjournal.ui.login
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth
import com.healthjournal.databinding.ActivityLoginBinding
import com.healthjournal.ui.dashboard.MainActivity
import com.healthjournal.ui.register.RegisterActivity
class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
private lateinit var user: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
user = FirebaseAuth.getInstance()
setuplistener()
}
private fun setuplistener() {
binding.btnLogin.setOnClickListener{
loginUser()
}
binding.btnRegister.setOnClickListener{
startActivity(Intent(this@LoginActivity, RegisterActivity::class.java))
finish()
}
}
private fun loginUser() {
val email = binding.edtEmail.text.toString()
val password = binding.edtPassword.text.toString()
if (email.isEmpty() || password.isEmpty()) {
if (email.isEmpty()) binding.edtEmail.error = "Email cannot be empty"
if (password.isEmpty()) binding.edtPassword.error = "Password cannot be empty"
Toast.makeText(this, "Email & Password cannot be empty", Toast.LENGTH_SHORT).show()
} else {
user.signInWithEmailAndPassword(email, password).addOnCompleteListener(LoginActivity()){ task ->
if (task.isSuccessful) {
Toast.makeText(this, "Login Success", Toast.LENGTH_SHORT).show()
startActivity(Intent(this@LoginActivity, MainActivity::class.java))
finish()
}
else{
Toast.makeText(this, task.exception!!.message, Toast.LENGTH_SHORT).show()
Log.d("error", task.exception!!.message.toString())
}
}
}
}
}

View File

@ -0,0 +1,81 @@
package com.healthjournal.ui.profile
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.database
import com.healthjournal.R
import com.healthjournal.databinding.ActivityProfileBinding
import com.healthjournal.ui.login.LoginActivity
class ProfileActivity : AppCompatActivity() {
private lateinit var binding: ActivityProfileBinding
private lateinit var user: FirebaseAuth
private val database = Firebase.database
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityProfileBinding.inflate(layoutInflater)
setContentView(binding.root)
setupListener()
populateData()
}
private fun setupListener() {
binding.btnLogout.setOnClickListener {
logout()
}
binding.btnUpdateData.setOnClickListener {
updateData()
}
}
private fun logout(){
user.signOut()
startActivity(Intent(this, LoginActivity::class.java))
finish()
}
private fun updateData(){
val userID = user.currentUser?.uid
val name = binding.edtName.text.toString()
val email = binding.edtEmail.text.toString()
val date = binding.edtDates.text.toString()
val weight = binding.edtInputWeight.text.toString()
val height = binding.edtInputHeight.text.toString()
val userRef = database.getReference("users").child(userID!!)
userRef.child("name").setValue(name)
userRef.child("email").setValue(email)
userRef.child("date").setValue(date)
userRef.child("weight").setValue(weight)
userRef.child("height").setValue(height)
Toast.makeText(this, "Data Updated", Toast.LENGTH_SHORT).show()
populateData()
}
private fun populateData(){
val userID = user.currentUser?.uid
val userRef = database.getReference("users").child(userID!!)
userRef.get().addOnCompleteListener(ProfileActivity()){
if (it.isSuccessful){
binding.edtName.setText(it.result.child("name").value.toString())
binding.edtDates.setText(it.result.child("date").value.toString())
binding.edtInputHeight.setText(it.result.child("height").value.toString())
binding.edtInputWeight.setText(it.result.child("weight").value.toString())
} else {
Toast.makeText(this, it.exception.toString(), Toast.LENGTH_SHORT).show()
Log.d("ProfileActivity", it.exception.toString())
}
}
}
}

View File

@ -0,0 +1,40 @@
package com.healthjournal.ui.recommendation
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.healthjournal.R
class RecommendationAdapter(
private val recommendationList: List<Pair<String, Boolean>>,
private val onCheckedChange: (position: Int, isChecked: Boolean) -> Unit
) : RecyclerView.Adapter<RecommendationAdapter.RecommendationViewHolder>() {
inner class RecommendationViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val tvGoalName: TextView = view.findViewById(R.id.tv_goal_name)
val checkBox: CheckBox = view.findViewById(R.id.toggle)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecommendationViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_goals_recommendation, parent, false)
return RecommendationViewHolder(view)
}
override fun onBindViewHolder(holder: RecommendationViewHolder, position: Int) {
val (task, isCompleted) = recommendationList[position]
holder.tvGoalName.text = task
holder.checkBox.isChecked = isCompleted
holder.checkBox.setOnCheckedChangeListener { _, isChecked ->
onCheckedChange(position, isChecked)
}
holder.itemView.setOnClickListener {
holder.checkBox.isChecked = !holder.checkBox.isChecked
}
}
override fun getItemCount(): Int = recommendationList.size
}

View File

@ -0,0 +1,99 @@
package com.healthjournal.ui.recommendation
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
import com.healthjournal.databinding.ActivityRecommendationBinding
import java.text.SimpleDateFormat
import java.util.Locale
class RecommendationActivity : AppCompatActivity() {
private lateinit var binding: ActivityRecommendationBinding
private lateinit var user: FirebaseAuth
private lateinit var database: FirebaseDatabase
private lateinit var adapter: RecommendationAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRecommendationBinding.inflate(layoutInflater)
setContentView(binding.root)
user = FirebaseAuth.getInstance()
database = FirebaseDatabase.getInstance()
populateData()
}
private fun populateData() {
val userID = user.currentUser?.uid ?: return
val today = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
.format(android.icu.util.Calendar.getInstance().time)
database.getReference("users").child(userID).child("journal")
.get()
.addOnCompleteListener { task ->
if (task.isSuccessful) {
task.result.children.forEach {
if (it.child("date").value.toString() == today) {
binding.tvBloodsugarLevel2.text = "${it.child("bloodSugar").value} mg/dL"
binding.tvBloodsugarDesc.text = it.child("recommendation").child("bloodSugarAnalysis").value.toString()
binding.tvBloodpressureLevel2.text = "${it.child("bloodPressureDIA").value}/${it.child("bloodPressureSYS").value} mm Hg"
binding.tvBloodpressureDesc.text = it.child("recommendation").child("bloodPressureAnalysis").value.toString()
binding.tvBMILevel2.text = "${it.child("BMI").value} BMI"
binding.tvBMIDesc.text = it.child("recommendation").child("BMIAnalysis").value.toString()
val tasks = it.child("recommendation").child("tasks").value
val referencePath = it.key ?: return@forEach
populateRecomendation(tasks, userID, referencePath)
}
}
} else {
Log.e("error", task.exception?.message.toString())
Toast.makeText(this, task.exception?.message, Toast.LENGTH_SHORT).show()
}
}
}
private fun populateRecomendation(tasks: Any?, userID: String, journalKey: String) {
val taskList = mutableListOf<Pair<String, Boolean>>()
// Handle List format for tasks
if (tasks is List<*>) {
tasks.forEach { taskData ->
if (taskData is Map<*, *> && taskData["task"] != null && taskData["completed"] != null) {
val taskDescription = taskData["task"].toString()
val isCompleted = taskData["completed"] as? Boolean ?: false
taskList.add(Pair(taskDescription, isCompleted))
}
}
// Set up RecyclerView and Adapter
adapter = RecommendationAdapter(taskList) { position, isChecked ->
taskList[position] = taskList[position].copy(second = isChecked)
// Update Firebase
database.getReference("users")
.child(userID)
.child("journal")
.child(journalKey)
.child("recommendation")
.child("tasks")
.child(position.toString())
.child("completed")
.setValue(isChecked)
}
binding.rvTasks.apply {
layoutManager = LinearLayoutManager(this@RecommendationActivity)
adapter = this@RecommendationActivity.adapter
}
} else {
Log.e("error", "Invalid tasks data format")
Log.e("error", tasks.toString())
}
}
}

View File

@ -0,0 +1,60 @@
package com.healthjournal.ui.register
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth
import com.healthjournal.databinding.ActivityRegisterBinding
import com.healthjournal.ui.users.UsersInputActivity
class RegisterActivity : AppCompatActivity() {
private lateinit var binding: ActivityRegisterBinding
private lateinit var user: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRegisterBinding.inflate(layoutInflater)
setContentView(binding.root)
user = FirebaseAuth.getInstance()
setuplistener()
}
private fun setuplistener(){
binding.btnRegister.setOnClickListener{
registerUser()
}
binding.btnLogin.setOnClickListener{
}
}
private fun registerUser(){
val email = binding.edtEmail.text.toString()
val password = binding.edtPassword.text.toString()
val confirmPassword = binding.edtPasswordConfirm.text.toString()
if (email.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()){
if (email.isEmpty()) binding.edtEmail.error = "Email cannot be empty"
if (password.isEmpty()) binding.edtPassword.error = "Password cannot be empty"
if (confirmPassword.isEmpty()) binding.edtPasswordConfirm.error = "Confirm Password cannot be empty"
} else {
if (password == confirmPassword){
user.createUserWithEmailAndPassword(email, password).addOnCompleteListener(RegisterActivity()){ task ->
if(task.isSuccessful){
Toast.makeText(this, "Register Success", Toast.LENGTH_SHORT).show()
startActivity(Intent(this@RegisterActivity,UsersInputActivity::class.java))
finish()
} else{
Toast.makeText(this, task.exception!!.message, Toast.LENGTH_SHORT).show()
Log.d("error", task.exception!!.message.toString())
}
}
} else {
binding.edtPasswordConfirm.error = "Password does not match"
}
}
}
}

View File

@ -0,0 +1,21 @@
package com.healthjournal.ui.splashscreen
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.healthjournal.R
class SplashscreenActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_splashscreen)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
}
}

View File

@ -0,0 +1,101 @@
package com.healthjournal.ui.users
import android.app.DatePickerDialog
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.Firebase
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.database
import com.healthjournal.databinding.ActivityUsersInputBinding
import com.healthjournal.ui.dashboard.MainActivity
import java.util.Calendar
class UsersInputActivity : AppCompatActivity() {
private lateinit var binding: ActivityUsersInputBinding
private lateinit var user: FirebaseAuth
private val database = Firebase.database
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityUsersInputBinding.inflate(layoutInflater)
setContentView(binding.root)
user = FirebaseAuth.getInstance()
val gender = arrayOf("Male", "Female", "Other")
// Adapter for conditions
val conditionAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, gender)
binding.dropdownGender.setAdapter(conditionAdapter)
userCheck()
setuplistener()
}
private fun userCheck(){
if(user.currentUser != null){
user.currentUser?.let {
binding.tvEmail.text = it.email
}
}
}
private fun setuplistener(){
binding.btnInput.setOnClickListener{
inputUserData()
}
binding.edtDateOfBirth.setOnClickListener{
datepicker()
}
}
private fun datepicker(){
val calendar = Calendar.getInstance()
val year = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH)
val day = calendar.get(Calendar.DAY_OF_MONTH)
val datePickerDialog = DatePickerDialog(
this,
{ _, selectedYear, selectedMonth, selectedDay ->
val selectedDate = "$selectedDay/${selectedMonth + 1}/$selectedYear"
binding.edtDateOfBirth.setText(selectedDate)
},
year, month, day
)
datePickerDialog.show()
}
private fun inputUserData() {
val userID = user.currentUser?.uid
val name = binding.edtName.text.toString()
val gender = binding.dropdownGender.text.toString()
val date = binding.edtDateOfBirth.text.toString()
val weight = binding.edtInputWeight.text.toString()
val height = binding.edtInputHeigh.text.toString()
if(userID != null){
if (name.isNotEmpty() && gender.isNotEmpty() && date.isNotEmpty() && weight.isNotEmpty() && height.isNotEmpty()){
val data = hashMapOf(
"name" to name,
"gender" to gender,
"date" to date,
"height" to height,
"weight" to weight)
database.getReference("users").child(userID).setValue(data).addOnCompleteListener(UsersInputActivity()){
if(it.isSuccessful){
Toast.makeText(this, "Data Input Success", Toast.LENGTH_SHORT).show()
startActivity(Intent(this@UsersInputActivity, MainActivity::class.java))
finish()
} else{
Toast.makeText(this, it.exception!!.message, Toast.LENGTH_SHORT).show()
Log.d("error", it.exception!!.message.toString())
}
}
}
}
}
}