Skip to content

Integrated room db and trigged the room function in the Login and Signup screen. #26

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

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
12 changes: 12 additions & 0 deletions meal_mate/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ dependencies {

// Data Store
implementation(libs.androidx.datastore.preferences)

// RoomDB
implementation(libs.androidx.room.runtime)
annotationProcessor(libs.androidx.room.compiler)

// Compose runtime
implementation(libs.androidx.runtime.livedata)
// Kotlin Extensions and Coroutines support for Room
implementation(libs.androidx.room.ktx)

// To use Kotlin annotation processing tool (kapt)
kapt(libs.androidx.room.compiler)
}

kapt {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.android.engineer.mealmate.data.local.roomdb

import androidx.room.Database
import androidx.room.RoomDatabase

@Database(entities = [User::class], version = 1)
abstract class MealUserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.android.engineer.mealmate.data.local.roomdb

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "users_table")
data class User(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val username: String,
val firstName: String,
val lastName: String,
val email: String,
val password: String,
val hash: String
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.android.engineer.mealmate.data.local.roomdb

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query

@Dao
interface UserDao {

@Insert
suspend fun insertUser(user: User): Long

@Query("SELECT * FROM users_table WHERE username = :username AND password = :password")
suspend fun getUser(username: String, password: String): User?

@Query("SELECT email FROM USERS_TABLE WHERE username = :username")
suspend fun getEmail(username: String): String?

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.android.engineer.mealmate.data.remote.model.request.RegisterRequest
import com.android.engineer.mealmate.data.remote.model.response.RegisterResponse
import com.android.engineer.mealmate.data.remote.MealAPI
import com.android.engineer.mealmate.data.utils.API_KEY_VALUE
import com.android.engineer.mealmate.domain.repository.AuthRepository
import com.android.engineer.mealmate.repository.remote.AuthRepository
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.android.engineer.mealmate.data.remote.model.response.IngredientsRespo
import com.android.engineer.mealmate.data.remote.model.response.NutrientsResponseItem
import com.android.engineer.mealmate.data.remote.model.response.RecipeInfoByIdResponse
import com.android.engineer.mealmate.data.utils.API_KEY_VALUE
import com.android.engineer.mealmate.domain.repository.RecipeSearchRepository
import com.android.engineer.mealmate.repository.remote.RecipeSearchRepository
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.android.engineer.mealmate.data.repository

import com.android.engineer.mealmate.data.local.roomdb.User
import com.android.engineer.mealmate.data.local.roomdb.UserDao
import com.android.engineer.mealmate.repository.local.UserRepository
import javax.inject.Inject

class UserRepositoryImpl @Inject constructor(private val userDao: UserDao): UserRepository {
override suspend fun insertUser(user: User): Long {
return userDao.insertUser(user)
}
override suspend fun getUser(username: String, password: String): User? {
return userDao.getUser(username, password)
}
override suspend fun getEmail(username: String): String {
return userDao.getEmail(username) ?: ""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ const val API_KEY_VALUE = "7a36c50e0e72420eb8515d694a2b2af4" // Currently placin

const val DATASTORE_NAME = "meal_data_store"
const val USERNAME = "username"
const val PASSWORD = "password"
const val HASH = "hash"
const val IS_LOGGED_IN = "isLoggedIn"
const val EMAIL = "email"

const val MIN_CARBS_KEY = "minCarbs"
const val MAX_CARBS_KEY = "maxCarbs"
Expand All @@ -28,4 +25,6 @@ const val INGREDIENTS_KEY = "ingredients"
const val SEARCH_BY_NUTRIENTS = "recipes/findByNutrients"
const val SEARCH_BY_INGREDIENTS = "recipes/findByIngredients"
const val RECIPE_INFO_BY_ID = "recipes/{id}/information"
const val REGISTER_API = "users/connect"
const val REGISTER_API = "users/connect"

const val USER_DATABASE_NAME = "meal_user_database"
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.android.engineer.mealmate.di

import android.content.Context
import androidx.room.Room
import com.android.engineer.mealmate.data.local.roomdb.MealUserDatabase
import com.android.engineer.mealmate.data.local.roomdb.UserDao
import com.android.engineer.mealmate.data.utils.USER_DATABASE_NAME
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
object DatabaseModule {
@Provides
fun provideUserDao(mealUserDatabase: MealUserDatabase): UserDao {
return mealUserDatabase.userDao()
}

@Singleton
@Provides
fun provideUserDatabase(@ApplicationContext context: Context): MealUserDatabase {
return Room.databaseBuilder(
context = context,
MealUserDatabase::class.java,
USER_DATABASE_NAME
).fallbackToDestructiveMigration().build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package com.android.engineer.mealmate.di
import android.app.Application
import com.android.engineer.mealmate.data.local.datastore.MealDataStore
import com.android.engineer.mealmate.data.local.datastore.MealDataStoreImpl
import com.android.engineer.mealmate.data.local.roomdb.UserDao
import com.android.engineer.mealmate.data.remote.MealAPI
import com.android.engineer.mealmate.data.repository.AuthRepositoryImpl
import com.android.engineer.mealmate.data.repository.RecipeSearchRepositoryImpl
import com.android.engineer.mealmate.domain.repository.AuthRepository
import com.android.engineer.mealmate.domain.repository.RecipeSearchRepository
import com.android.engineer.mealmate.data.repository.UserRepositoryImpl
import com.android.engineer.mealmate.repository.local.UserRepository
import com.android.engineer.mealmate.repository.remote.AuthRepository
import com.android.engineer.mealmate.repository.remote.RecipeSearchRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -34,4 +37,10 @@ object MealAppModule {
fun provideAuthRepository(api: MealAPI): AuthRepository {
return AuthRepositoryImpl(api)
}

@Provides
@Singleton
fun provideUserRepository(userDao: UserDao): UserRepository {
return UserRepositoryImpl(userDao = userDao)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.android.engineer.mealmate.repository.local

import com.android.engineer.mealmate.data.local.roomdb.User

interface UserRepository {

suspend fun insertUser(user: User): Long

suspend fun getUser(username: String, password: String): User?

suspend fun getEmail(username: String): String
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.android.engineer.mealmate.domain.repository
package com.android.engineer.mealmate.repository.remote

import com.android.engineer.mealmate.data.remote.model.request.RegisterRequest
import com.android.engineer.mealmate.data.remote.model.response.RegisterResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.android.engineer.mealmate.domain.repository
package com.android.engineer.mealmate.repository.remote

import com.android.engineer.mealmate.data.remote.model.response.IngredientsResponseItem
import com.android.engineer.mealmate.data.remote.model.response.NutrientsResponseItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.android.engineer.mealmate.data.local.datastore.MealDataStore
import com.android.engineer.mealmate.data.local.roomdb.User
import com.android.engineer.mealmate.data.remote.model.request.RegisterRequest
import com.android.engineer.mealmate.data.utils.HASH
import com.android.engineer.mealmate.data.utils.IS_LOGGED_IN
import com.android.engineer.mealmate.data.utils.PASSWORD
import com.android.engineer.mealmate.data.utils.USERNAME
import com.android.engineer.mealmate.domain.repository.AuthRepository
import com.android.engineer.mealmate.repository.local.UserRepository
import com.android.engineer.mealmate.repository.remote.AuthRepository
import com.android.engineer.mealmate.view.features.auth.state.VisitingRegisterUiState
import com.android.engineer.mealmate.view.utils.UtilConst
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -23,7 +23,8 @@ import javax.inject.Inject
@HiltViewModel
class AuthViewModel @Inject constructor(
private val repository: AuthRepository,
private val dataStore: MealDataStore
private val dataStore: MealDataStore,
private val userRepository: UserRepository
): ViewModel() {

val isLoggedIn = mutableStateOf(false)
Expand All @@ -44,6 +45,9 @@ class AuthViewModel @Inject constructor(
private val _email = MutableStateFlow("")
val email = _email.asStateFlow()

private val _userPassword = MutableStateFlow("")
val userPassword = _userPassword.asStateFlow()

val userNameErrorMsg = mutableStateOf("")
val userNameError = mutableStateOf(false)

Expand All @@ -56,6 +60,9 @@ class AuthViewModel @Inject constructor(
val emailErrorMsg = mutableStateOf("")
val emailError = mutableStateOf(false)

val passwordErrorMsg = mutableStateOf("")
val passwordError = mutableStateOf(false)

val isScreenLoading = mutableStateOf(false)

fun onSignUpClicked(onCallBack: (VisitingRegisterUiState) -> Unit) {
Expand Down Expand Up @@ -97,12 +104,17 @@ class AuthViewModel @Inject constructor(
val visitRegister = repository.registerAccount(registerRequest)
visitRegister.collectLatest { registerResponse ->
if (registerResponse.status == "success") {
dataStore.putString(USERNAME, registerResponse.username)
dataStore.putString(PASSWORD, registerResponse.spoonacularPassword)
dataStore.putString(HASH, registerResponse.hash)
dataStore.putBoolean(IS_LOGGED_IN, true)
isScreenLoading.value = false
onCallBack(VisitingRegisterUiState.Success())
val user = User(username = registerResponse.username, firstName = _firstName.value, lastName = _lastName.value, email = _email.value, password = registerResponse.spoonacularPassword, hash = registerResponse.hash)
val result = userRepository.insertUser(user)
if(result > 0) {
isScreenLoading.value = false
onCallBack(VisitingRegisterUiState.Success())
Log.d("testing", registerResponse.spoonacularPassword)

} else {
isScreenLoading.value = false
onCallBack(VisitingRegisterUiState.Error("Error inserting into DB, Try again!"))
}
}
}
} catch (e: Exception) {
Expand All @@ -114,12 +126,56 @@ class AuthViewModel @Inject constructor(
}
}

fun onValueChanged(signUpEnum: UtilConst.SignUpEnum, newValue: String) {
when(signUpEnum) {
UtilConst.SignUpEnum.USERNAME -> { _userName.value = newValue }
UtilConst.SignUpEnum.FIRSTNAME -> { _firstName.value = newValue }
UtilConst.SignUpEnum.LASTNAME -> { _lastName.value = newValue }
UtilConst.SignUpEnum.EMAIL -> { _email.value = newValue }
fun onLoginClicked(onCallBack: (VisitingRegisterUiState) -> Unit) {
if(_userName.value.isEmpty()) {
userNameErrorMsg.value = "Enter the username"
userNameError.value = true
passwordError.value = false
} else if(_userPassword.value.isEmpty()) {
passwordErrorMsg.value = "Enter the password"
passwordError.value = true
userNameError.value = false
} else {
userNameError.value = false
passwordError.value = false
isScreenLoading.value = true

viewModelScope.launch {
try {
val user = userRepository.getUser(_userName.value, _userPassword.value)

if(user != null) {
dataStore.putString(USERNAME, user.username)
dataStore.putBoolean(IS_LOGGED_IN, true)
isScreenLoading.value = false
onCallBack(VisitingRegisterUiState.Success())
} else {
isScreenLoading.value = false
onCallBack(VisitingRegisterUiState.Error("Invalid username or password"))
}

} catch (e: Exception) {
Log.d("onLoginClicked", "There is an error")
isScreenLoading.value = false
e.printStackTrace()
onCallBack(VisitingRegisterUiState.Error("An error occurred, please try again"))
}
}

}
}

fun onValueChanged(authEnum: UtilConst.AuthEnum, newValue: String) {
when(authEnum) {
UtilConst.AuthEnum.USERNAME -> { _userName.value = newValue }
UtilConst.AuthEnum.FIRSTNAME -> { _firstName.value = newValue }
UtilConst.AuthEnum.LASTNAME -> { _lastName.value = newValue }
UtilConst.AuthEnum.EMAIL -> { _email.value = newValue }
UtilConst.AuthEnum.PASSWORD -> { _userPassword.value = newValue }
}
}




}
Loading