diff options
| author | Alberto Duarte (PWC) <alberto.duarte.delgado@pwc.com> | 2023-07-18 11:16:31 +0100 |
|---|---|---|
| committer | Alberto Duarte (PWC) <alberto.duarte.delgado@pwc.com> | 2023-07-18 11:16:31 +0100 |
| commit | 7dd32dceac9e87bc204fe1997a5ff3a1a24b3aed (patch) | |
| tree | 5cb2a1f4b9dd175a52887f5607cb03e8af1841e6 | |
| parent | ee5818d91fdd89ab14b982f5ab04eb100a1c3b81 (diff) | |
mejora de la estructura conexion con firecloud para usuarios y scores guardados en room
34 files changed, 701 insertions, 100 deletions
diff --git a/app/build.gradle b/app/build.gradle index eda17b6..2efcdc8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -72,6 +72,7 @@ dependencies { implementation platform('com.google.firebase:firebase-bom:32.1.1') implementation 'com.google.firebase:firebase-analytics-ktx' implementation 'androidx.navigation:navigation-compose:2.5.3' + implementation ("io.coil-kt:coil-compose:2.4.0") implementation("androidx.room:room-runtime:2.5.0") annotationProcessor("androidx.room:room-compiler:2.5.0") diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/DB.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/DB.kt index 8f4ab68..a8209bb 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/DB.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/DB.kt @@ -3,9 +3,12 @@ package com.frannazario.proyectoandroid.data import androidx.room.Database import androidx.room.RoomDatabase import com.frannazario.proyectoandroid.data.dao.QuestionDao +import com.frannazario.proyectoandroid.data.dao.ScoreDao import com.frannazario.proyectoandroid.data.models.Question +import com.frannazario.proyectoandroid.data.models.Score -@Database(entities = [Question::class], version = 1) +@Database(entities = [Question::class, Score::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun questionDao(): QuestionDao + abstract fun scoreDao(): ScoreDao } diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/dao/QuestionDAO.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/dao/QuestionDAO.kt index ed23243..cfc2c5f 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/dao/QuestionDAO.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/dao/QuestionDAO.kt @@ -11,6 +11,9 @@ interface QuestionDao { @Query("SELECT * FROM question") fun getAll(): List<Question> + @Query("SELECT * FROM question WHERE category LIKE :id") + fun getByCategory(id: Int): List<Question> + @Insert fun insertAll(vararg questions: Question) diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/dao/ScoreDAO.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/dao/ScoreDAO.kt new file mode 100644 index 0000000..d9f678d --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/dao/ScoreDAO.kt @@ -0,0 +1,28 @@ +package com.frannazario.proyectoandroid.data.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import com.frannazario.proyectoandroid.data.models.Score + +@Dao +interface ScoreDao { + @Query("SELECT * FROM score") + fun getAll(): List<Score> + + @Query("SELECT * FROM score WHERE category LIKE :id") + fun getByCategory(id: Int): Score + + @Insert + fun insert(score: Score) + + @Delete + fun delete(score: Score) + + @Query("DELETE FROM score") + fun wipe() + + @Query("DELETE FROM score WHERE category != 'total'") + fun wipeScores() +} diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/dao/UserDAO.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/dao/UserDAO.kt new file mode 100644 index 0000000..bfa7d99 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/dao/UserDAO.kt @@ -0,0 +1,22 @@ +package com.frannazario.proyectoandroid.data.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import com.frannazario.proyectoandroid.data.models.User + +@Dao +interface UserDao { + @Query("SELECT * FROM user") + fun getAll(): List<User> + +// @Query("SELECT * FROM user WHERE category LIKE :id") +// fun getByCategory(id: Int): List<User> +// +// @Insert +// fun insertAll(vararg user: User) +// +// @Delete +// fun delete(user: User) +} diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsDataSource.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsDataSource.kt index 21d4df5..285a52e 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsDataSource.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsDataSource.kt @@ -4,6 +4,6 @@ import android.content.Context import com.frannazario.proyectoandroid.data.models.Question interface QuestionsDataSource { - suspend fun getQuestions(context: Context): List<Question> + suspend fun getQuestions(context: Context, id: Int): List<Question> fun saveQuestions(context: Context, questions: List<Question>) }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsLocalDataSource.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsLocalDataSource.kt index 9cc17a7..62d23e6 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsLocalDataSource.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsLocalDataSource.kt @@ -7,12 +7,12 @@ import com.frannazario.proyectoandroid.data.models.Question class QuestionsLocalDataSource: QuestionsDataSource { - override suspend fun getQuestions(context: Context): List<Question> { + override suspend fun getQuestions(context: Context, id: Int): List<Question> { val dbLocal = Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, "database-name" ).build() - return dbLocal.questionDao().getAll() + return dbLocal.questionDao().getByCategory(id) } override fun saveQuestions(context: Context, questions: List<Question>) { diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsRemoteDataSource.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsRemoteDataSource.kt index c8965df..a8bafa3 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsRemoteDataSource.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsRemoteDataSource.kt @@ -1,8 +1,6 @@ package com.frannazario.proyectoandroid.data.datasources -import android.content.ContentValues.TAG import android.content.Context -import android.util.Log import com.frannazario.proyectoandroid.data.models.Question import com.google.firebase.firestore.ktx.firestore import com.google.firebase.firestore.ktx.toObject @@ -12,24 +10,21 @@ import kotlinx.coroutines.tasks.await class QuestionsRemoteDataSource: QuestionsDataSource { private val db = Firebase.firestore private val questionList = mutableListOf<Question>() - override suspend fun getQuestions(context: Context): List<Question> { + override suspend fun getQuestions(context: Context, id: Int): List<Question> { val response = db.collection("Preguntas") .get() .await() -// .addOnSuccessListener { result -> for (document in response) { try { val pregunta = document.toObject<Question>() - questionList.add(pregunta) + if (pregunta.category == id){ + questionList.add(pregunta) + } } catch (e: Exception){ e.printStackTrace() } } -// } -// .addOnFailureListener { exception -> -// Log.w(TAG, "Error getting documents.", exception) -// } return questionList } diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/ScoreLocalDataSource.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/ScoreLocalDataSource.kt new file mode 100644 index 0000000..0407296 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/ScoreLocalDataSource.kt @@ -0,0 +1,35 @@ +package com.frannazario.proyectoandroid.data.datasources + +import android.content.Context +import androidx.room.Room +import com.frannazario.proyectoandroid.data.AppDatabase +import com.frannazario.proyectoandroid.data.models.Score + +class ScoreLocalDataSource { + + suspend fun getScores(context: Context): List<Score> { + val dbLocal = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, "database-name" + ).build() + return dbLocal.scoreDao().getAll() + } + + fun saveScore(context: Context, score: Score): List<Score> { + val dbLocal = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, "database-name" + ).build() + dbLocal.scoreDao().insert(score) + return dbLocal.scoreDao().getAll() + } + + fun wipeScores(context: Context): List<Score> { + val dbLocal = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, "database-name" + ).build() + dbLocal.scoreDao().wipeScores() + return dbLocal.scoreDao().getAll() + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/UsersRemoteDataSource.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/UsersRemoteDataSource.kt new file mode 100644 index 0000000..3068d2b --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/UsersRemoteDataSource.kt @@ -0,0 +1,41 @@ +package com.frannazario.proyectoandroid.data.datasources + +import android.util.Log +import com.frannazario.proyectoandroid.data.models.User +import com.google.firebase.firestore.ktx.firestore +import com.google.firebase.firestore.ktx.toObject +import com.google.firebase.ktx.Firebase +import kotlinx.coroutines.tasks.await + +class UsersRemoteDataSource { + private val db = Firebase.firestore + +suspend fun getUser(uid: String, email: String): User { + try { + val response = db.collection("Usuarios") + .document(uid) + .get() + .await() + + if (response.exists()) { + // User found, return the user object + return response.toObject<User>() ?: User(username = "gato") + } else { + // User not found, create a new user + val newUser = User(username = email) + db.collection("Usuarios") + .document(uid) + .set(newUser) + .await() + return newUser + } + } catch (e: Exception) { + e.printStackTrace() + Log.e("pruebax", e.toString()) + } + + // Return a default user if there was an error + return User(username = "perro", userimage = "https://upload.wikimedia.org/wikipedia/commons/8/89/Portrait_Placeholder.png") +} + +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/models/QuestionDTO.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/models/QuestionDTO.kt index bf717e9..a06f9de 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/models/QuestionDTO.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/models/QuestionDTO.kt @@ -6,8 +6,8 @@ import androidx.room.PrimaryKey @Entity data class Question( - @PrimaryKey (autoGenerate = true) var id: Int = 0, - @ColumnInfo var question: String = "", +// @PrimaryKey (autoGenerate = true) var id: Int = 0, + @PrimaryKey var question: String = "", @ColumnInfo var response1: String = "", @ColumnInfo var response2: String = "", @ColumnInfo var response3: String = "", diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/models/ScoreDTO.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/models/ScoreDTO.kt new file mode 100644 index 0000000..37126f7 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/models/ScoreDTO.kt @@ -0,0 +1,12 @@ +package com.frannazario.proyectoandroid.data.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class Score( + @PrimaryKey(autoGenerate = true) var id: Int = 0, + @ColumnInfo var score: String = "", + @ColumnInfo var category: String = "", +) diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/models/UserDTO.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/models/UserDTO.kt new file mode 100644 index 0000000..77f1818 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/models/UserDTO.kt @@ -0,0 +1,12 @@ +package com.frannazario.proyectoandroid.data.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class User( + @PrimaryKey (autoGenerate = true) var id: Int = 0, + @ColumnInfo var username: String = "", + @ColumnInfo var userimage: String = "", +) diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/QuestionsRepository.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/QuestionsRepository.kt index 61bb9ec..2d20347 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/QuestionsRepository.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/QuestionsRepository.kt @@ -12,14 +12,17 @@ class QuestionsRepository { private val remoteDataSource = QuestionsRemoteDataSource() private val localDataSource = QuestionsLocalDataSource() - fun getQuestions(context: Context) = flow { + fun getQuestions(context: Context, id: Int) = flow { try { - val questions = remoteDataSource.getQuestions(context = context) + val questions = remoteDataSource.getQuestions(context = context, id) + if (questions.isEmpty()){ + throw Exception() + } localDataSource.saveQuestions(context = context, questions = questions) emit(QuestionsResponse.Success(questions = questions)) } catch (e: Exception) { try { - val questions = localDataSource.getQuestions(context = context) + val questions = localDataSource.getQuestions(context = context, id = id) emit(QuestionsResponse.Success(questions = questions)) }catch (e: Exception){ emit(QuestionsResponse.Error(e.message ?: "Error genérico")) diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/ScoreRepository.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/ScoreRepository.kt new file mode 100644 index 0000000..62c56b7 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/ScoreRepository.kt @@ -0,0 +1,37 @@ +package com.frannazario.proyectoandroid.data.repositories + +import android.content.Context +import com.frannazario.proyectoandroid.data.datasources.ScoreLocalDataSource +import com.frannazario.proyectoandroid.data.models.Score +import com.frannazario.proyectoandroid.data.responses.ScoresResponse +import kotlinx.coroutines.flow.flow + +class ScoreRepository { + private val localDataSource = ScoreLocalDataSource() + + fun getScores(context: Context) = flow { + try { + val scores = localDataSource.getScores(context = context) + emit(ScoresResponse.Success(scores = scores)) + }catch (e: Exception){ + emit(ScoresResponse.Error(e.message ?: "Error genérico")) + } + } + fun saveScore(context: Context, score: Score) = flow { + try { + val scores = localDataSource.saveScore(context = context, score) + emit(ScoresResponse.Success(scores = scores)) + }catch (e: Exception){ + emit(ScoresResponse.Error(e.message ?: "Error genérico")) + } + } + fun wipeScores(context: Context) = flow { + try { + val scores = localDataSource.wipeScores(context = context) + emit(ScoresResponse.Success(scores = scores)) + }catch (e: Exception){ + emit(ScoresResponse.Error(e.message ?: "Error genérico")) + } + } + +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/UserRepository.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/UserRepository.kt new file mode 100644 index 0000000..eea7e56 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/UserRepository.kt @@ -0,0 +1,21 @@ +package com.frannazario.proyectoandroid.data.repositories + +import android.content.Context +import android.util.Log +import com.frannazario.proyectoandroid.data.datasources.UsersRemoteDataSource +import com.frannazario.proyectoandroid.data.responses.UsersResponse +import kotlinx.coroutines.flow.flow + +class UserRepository { + private val remoteDataSource = UsersRemoteDataSource() + + fun getUser(uid: String, email: String) = flow { + try { + val user = remoteDataSource.getUser(uid, email) + emit(UsersResponse.Success(user = user)) + } catch (e: Exception) { + emit(UsersResponse.Error(e.message ?: "Error genérico")) + Log.e("", e.message ?: "Error generico") + } + } +} diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/ScoresResponse.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/ScoresResponse.kt new file mode 100644 index 0000000..0fc4ecd --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/ScoresResponse.kt @@ -0,0 +1,8 @@ +package com.frannazario.proyectoandroid.data.responses + +import com.frannazario.proyectoandroid.data.models.Score + +sealed class ScoresResponse { + data class Success(val scores: List<Score>) : ScoresResponse() + data class Error(val error: String): ScoresResponse() +} diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/UsersResponse.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/UsersResponse.kt new file mode 100644 index 0000000..2319640 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/UsersResponse.kt @@ -0,0 +1,8 @@ +package com.frannazario.proyectoandroid.data.responses + +import com.frannazario.proyectoandroid.data.models.User + +sealed class UsersResponse { + data class Success(val user: User): UsersResponse() + data class Error(val error: String): UsersResponse() +} diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PlayViewModel.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PlayViewModel.kt index 1166d8f..a027328 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PlayViewModel.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PlayViewModel.kt @@ -5,8 +5,11 @@ import androidx.compose.runtime.MutableState import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.frannazario.proyectoandroid.data.models.Question +import com.frannazario.proyectoandroid.data.models.Score import com.frannazario.proyectoandroid.data.repositories.QuestionsRepository +import com.frannazario.proyectoandroid.data.repositories.ScoreRepository import com.frannazario.proyectoandroid.data.responses.QuestionsResponse +import com.frannazario.proyectoandroid.data.responses.ScoresResponse import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -15,21 +18,77 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update -class PlayViewModel(private val repository: QuestionsRepository = QuestionsRepository()): ViewModel() { - private val mutableState = MutableStateFlow(QuestionsViewState()) - val questionsViewState: StateFlow<QuestionsViewState> = mutableState +class PlayViewModel(private val context: Context, private val repositoryScores: ScoreRepository = ScoreRepository(), private val repositoryQuestions: QuestionsRepository = QuestionsRepository()): ViewModel() { + private val mutableStateQuestions = MutableStateFlow(QuestionsViewState()) + val questionsViewState: StateFlow<QuestionsViewState> = mutableStateQuestions + private val mutableStateScores = MutableStateFlow(ScoreViewState()) + val scoresViewState: StateFlow<ScoreViewState> = mutableStateScores - fun getQuestionList(context: Context) { - mutableState.update { it.copy(isLoading = true) } - val response = repository.getQuestions(context = context) + fun getQuestionList(id: Int) { + mutableStateQuestions.update { it.copy(isLoading = true) } + val response = repositoryQuestions.getQuestions(context = context , id) response.onEach { questionsResponse -> when (questionsResponse) { is QuestionsResponse.Success -> { - mutableState.update { it.copy(questions = questionsResponse.questions, isLoading = false) } + mutableStateQuestions.update { it.copy(questions = questionsResponse.questions, isLoading = false) } } is QuestionsResponse.Error -> { - mutableState.update { it.copy(error = questionsResponse.error, isLoading = false) } + mutableStateQuestions.update { it.copy(error = questionsResponse.error, isLoading = false) } + } + } + }.flowOn(Dispatchers.IO).launchIn(viewModelScope) + } + + fun getScoreList() { + val response = repositoryScores.getScores(context = context) + response.onEach { scoresResponse -> + when (scoresResponse) { + is ScoresResponse.Success -> { + mutableStateScores.update { it.copy(scores = scoresResponse.scores) } + } + is ScoresResponse.Error -> { + mutableStateScores.update { it.copy(error = scoresResponse.error) } + } + } + }.flowOn(Dispatchers.IO).launchIn(viewModelScope) + } + + fun saveScore(score: Score) { + val response = repositoryScores.saveScore(context = context, score) + response.onEach { scoresResponse -> + when (scoresResponse) { + is ScoresResponse.Success -> { + mutableStateScores.update { it.copy(scores = scoresResponse.scores) + } + if(score.category != "total"){ + mutableStateScores.update { currentState -> + currentState.copy(scoresDone = currentState.scoresDone + 1) + } + } + } + is ScoresResponse.Error -> { + mutableStateScores.update { it.copy(error = scoresResponse.error) } + } + } + }.flowOn(Dispatchers.IO).launchIn(viewModelScope) + } + + fun saveTotalScore() { + var totalScore: Int = 0 + scoresViewState.value.scores?.forEach { score -> + totalScore += score.score.toInt() + } + saveScore(Score(score = totalScore.toString(), category = "total")) + val response = repositoryScores.wipeScores(context = context) + response.onEach { scoresResponse -> + when (scoresResponse) { + is ScoresResponse.Success -> { + mutableStateScores.update { it.copy(scores = scoresResponse.scores, scoresDone = 0) + } + } + is ScoresResponse.Error -> { + mutableStateScores.update { it.copy(error = scoresResponse.error) } } } }.flowOn(Dispatchers.IO).launchIn(viewModelScope) @@ -48,15 +107,15 @@ class PlayViewModel(private val repository: QuestionsRepository = QuestionsRepos randomQuestion.value?.response2 ?: "2", randomQuestion.value?.response3 ?: "3" ).shuffled() - - - - - } data class QuestionsViewState( val questions: List<Question>? = null, val error: String? = null, val isLoading: Boolean = false -)
\ No newline at end of file +) +data class ScoreViewState( + val scores: List<Score>? = null, + var scoresDone: Int = 0, + val error: String? = null, +) diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/UserViewModel.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/UserViewModel.kt new file mode 100644 index 0000000..00cf311 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/UserViewModel.kt @@ -0,0 +1,41 @@ +package com.frannazario.proyectoandroid.data.viewmodels + +import android.content.Context +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.frannazario.proyectoandroid.data.models.User +import com.frannazario.proyectoandroid.data.repositories.UserRepository +import com.frannazario.proyectoandroid.data.responses.UsersResponse +import com.google.firebase.auth.FirebaseAuth +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update + +class UserViewModel(private val userRepository: UserRepository = UserRepository()): ViewModel() { + + private val auth: FirebaseAuth = FirebaseAuth.getInstance() + private val mutableStateQuestions = MutableStateFlow(UserViewState()) + val userViewState: StateFlow<UserViewState> = mutableStateQuestions + + fun getUser() { + val response = userRepository.getUser(uid = auth.uid ?: "", email = auth.currentUser?.email ?: "No Account") + response.onEach { userResponse -> + when (userResponse) { + is UsersResponse.Success -> { + mutableStateQuestions.update { it.copy(user = userResponse.user) } + } + is UsersResponse.Error -> { + mutableStateQuestions.update { it.copy(error = userResponse.error) } + } + } + }.flowOn(Dispatchers.IO).launchIn(viewModelScope) + } +} +data class UserViewState( + val user: User = User(), + val error: String? = null, +)
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppNavigation.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppNavigation.kt index b11f307..fc2b6ae 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppNavigation.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppNavigation.kt @@ -1,7 +1,6 @@ package com.frannazario.proyectoandroid.presentation.navigation import androidx.compose.runtime.Composable -import androidx.navigation.NavHostController import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -32,5 +31,6 @@ fun AppNavigation() { ) } } + } } diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppScreens.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppScreens.kt index 72da5e5..b91dbbd 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppScreens.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppScreens.kt @@ -3,8 +3,11 @@ package com.frannazario.proyectoandroid.presentation.navigation sealed class AppScreens(val route: String) { object CategoryListScreen: AppScreens("category_list_screen") object CategoryDetailScreen: AppScreens("category_detail_screen") + object PlayListScreen: AppScreens("play_list_screen") object PlayScreen: AppScreens("play_screen") object ScoreScreen: AppScreens("score_screen") object SettingsScreen: AppScreens("settings_screen") object BaseBottomNav: AppScreens("BottomNavScreen") + + object TotalScoreScreen: AppScreens("total_score_screen") } diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/BaseBottomNavScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/BaseBottomNavScreen.kt index c90f05c..ebb2894 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/BaseBottomNavScreen.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/BaseBottomNavScreen.kt @@ -7,29 +7,52 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.navigation.NavController -import androidx.navigation.NavHostController +import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import com.frannazario.proyectoandroid.data.viewmodels.PlayViewModel +import com.frannazario.proyectoandroid.data.viewmodels.UserViewModel import com.frannazario.proyectoandroid.presentation.ui.widgets.BottomNav import com.frannazario.proyectoandroid.presentation.navigation.AppScreens +import com.frannazario.proyectoandroid.presentation.ui.widgets.TopBar @OptIn(ExperimentalMaterial3Api::class) @Composable fun BaseBottomNavScreen(mainNavController: NavController) { + val context = LocalContext.current val bottomNavController = rememberNavController() + val viewModel by remember {mutableStateOf(PlayViewModel(context))} + val scoreViewState = viewModel.scoresViewState.collectAsState() + val userViewModel by remember {mutableStateOf(UserViewModel())} + val userViewState = userViewModel.userViewState.collectAsState() + + LaunchedEffect(Unit) { + viewModel.getScoreList() + userViewModel.getUser() + } Scaffold( bottomBar = { BottomNav(bottomNavController) + }, + topBar = { + TopBar(user = userViewState.value.user) } ) { Surface( modifier = Modifier .fillMaxSize() - .padding(bottom = it.calculateBottomPadding()), + .padding(bottom = it.calculateBottomPadding(), top = it.calculateTopPadding()), color = MaterialTheme.colorScheme.background ) { NavHost( @@ -37,16 +60,30 @@ fun BaseBottomNavScreen(mainNavController: NavController) { startDestination = AppScreens.CategoryListScreen.route ) { composable(AppScreens.CategoryListScreen.route) { - CategoryListScreen(mainNavController) + CategoryListScreen(mainNavController, viewModel) } composable(AppScreens.ScoreScreen.route) { - ScoreScreen(mainNavController) + ScoreScreen(mainNavController, viewModel) } - composable(AppScreens.PlayScreen.route) { - PlayScreen(mainNavController) + composable(AppScreens.TotalScoreScreen.route) { + TotalScoreScreen(mainNavController, viewModel) + } + composable(AppScreens.PlayListScreen.route) { + PlayListScreen(bottomNavController, viewModel) } composable(AppScreens.SettingsScreen.route) { - SettingsScreen(mainNavController) + SettingsScreen(mainNavController, viewModel) + } + composable( + route = "${AppScreens.PlayScreen.route}/{id}", + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.getInt("id")?.let { id -> + PlayScreen( + id = id, + viewModel = viewModel + ) + } } } } diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryListScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryListScreen.kt index b4236e7..23029f0 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryListScreen.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryListScreen.kt @@ -1,49 +1,29 @@ package com.frannazario.proyectoandroid.presentation.screens import android.widget.Toast -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.shadow import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.NavController -import com.frannazario.proyectoandroid.R import com.frannazario.proyectoandroid.data.viewmodels.CategoriesViewModel +import com.frannazario.proyectoandroid.data.viewmodels.PlayViewModel import com.frannazario.proyectoandroid.presentation.navigation.AppScreens import com.frannazario.proyectoandroid.presentation.ui.widgets.CategoryCard @OptIn(ExperimentalMaterial3Api::class) @Composable -fun CategoryListScreen(mainNavController: NavController){ +fun CategoryListScreen(mainNavController: NavController, viewModel: PlayViewModel){ val context = LocalContext.current val viewModel by remember { mutableStateOf(CategoriesViewModel()) } val categoriesViewState by viewModel.categoriesViewState.collectAsState() diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayListScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayListScreen.kt new file mode 100644 index 0000000..de8c898 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayListScreen.kt @@ -0,0 +1,60 @@ +package com.frannazario.proyectoandroid.presentation.screens + +import android.widget.Toast +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import com.frannazario.proyectoandroid.R +import com.frannazario.proyectoandroid.data.viewmodels.CategoriesViewModel +import com.frannazario.proyectoandroid.data.viewmodels.PlayViewModel +import com.frannazario.proyectoandroid.presentation.navigation.AppScreens +import com.frannazario.proyectoandroid.presentation.ui.widgets.CategorySmallCard + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PlayListScreen(NavController: NavHostController, viewModelx: PlayViewModel){ + val context = LocalContext.current + val viewModel by remember { mutableStateOf(CategoriesViewModel()) } + val categoriesViewState by viewModel.categoriesViewState.collectAsState() + val scoreViewState = viewModelx.scoresViewState.collectAsState() + + LaunchedEffect(Unit) { + viewModel.getCategories() + } + + LaunchedEffect(categoriesViewState.error) { + categoriesViewState.error?.let { + Toast.makeText(context, it, Toast.LENGTH_LONG).show() + } + } + + Column() { + LazyVerticalGrid(columns = GridCells.Adaptive(200.dp)){ + categoriesViewState.data?.forEach() { category -> + val containsScore = scoreViewState.value.scores?.any { score -> + score.category.toIntOrNull() == category.id + } ?: false + item { + if(containsScore){ + CategorySmallCard(category = category, modifier = Modifier.weight(1f), image = R.drawable.baseline_check_24, enabled = !containsScore) {NavController.navigate("${AppScreens.PlayScreen.route}/${category.id}")} + }else { + CategorySmallCard(category = category, modifier = Modifier.weight(1f), image = R.drawable.baseline_close_24, enabled = !containsScore) {NavController.navigate("${AppScreens.PlayScreen.route}/${category.id}")} + } + } + } + + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayScreen.kt index 4b456f4..f312486 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayScreen.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayScreen.kt @@ -19,21 +19,22 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.navigation.NavController import com.frannazario.proyectoandroid.data.models.Question +import com.frannazario.proyectoandroid.data.models.Score import com.frannazario.proyectoandroid.data.viewmodels.PlayViewModel +import com.frannazario.proyectoandroid.data.viewmodels.ScoreViewState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch -val viewModel by mutableStateOf(PlayViewModel()) @Composable -fun PlayScreen(navController: NavController){ +fun PlayScreen(id: Int, viewModel: PlayViewModel){ val context = LocalContext.current val randomQuestion = remember { mutableStateOf<Question?>(null) } val shuffledResponses = remember {mutableStateOf<List<String>?>(null)} val questionsViewState by viewModel.questionsViewState.collectAsState() + val scoreViewState by viewModel.scoresViewState.collectAsState() var questionList = remember { mutableStateOf(listOf<Question>()) } var isLoading by remember {mutableStateOf(true)} // Initial loading state is true val buttonEnabled = remember {mutableStateOf(true)} // Initial loading state is true @@ -43,26 +44,22 @@ fun PlayScreen(navController: NavController){ val counterCoroutine = rememberCoroutineScope() val delayCoroutine = rememberCoroutineScope() - LaunchedEffect(Unit) { - viewModel.getQuestionList(context) + viewModel.getQuestionList(id) } LaunchedEffect(questionsViewState.questions) { questionsViewState.questions?.let { questionList.value = it - changeQuestion(questionList.value, randomQuestion, shuffledResponses, colorOfBackground, buttonEnabled) + changeQuestion(questionList.value, randomQuestion, shuffledResponses, colorOfBackground, buttonEnabled, viewModel) isLoading = false - startCounter(counter, score, counterCoroutine) + startCounter(counter, score, counterCoroutine, viewModel, id, scoreViewState) } } - if (score.value > 4) { Text(text = "felicidades tu puntuacion es de: ${counter.value}") - }else { - if (isLoading) { // Show loader Text( text = "cargando") @@ -72,7 +69,6 @@ fun PlayScreen(navController: NavController){ .fillMaxSize() .background(color = colorOfBackground.value), contentAlignment = Alignment.Center - ) { Column() { randomQuestion.value?.let { @@ -80,7 +76,6 @@ fun PlayScreen(navController: NavController){ text = it.question ) } - Button(onClick = { compareAnswer( buttonEnabled, @@ -91,14 +86,14 @@ fun PlayScreen(navController: NavController){ questionList.value, randomQuestion, shuffledResponses, - delayCoroutine + delayCoroutine, + viewModel ) }, enabled = buttonEnabled.value ) { Text(text = shuffledResponses.value?.get(0) ?: "bb" ) } - Button(onClick = { compareAnswer( buttonEnabled, @@ -109,7 +104,8 @@ fun PlayScreen(navController: NavController){ questionList.value, randomQuestion, shuffledResponses, - delayCoroutine + delayCoroutine, + viewModel ) }, enabled = buttonEnabled.value @@ -127,7 +123,8 @@ fun PlayScreen(navController: NavController){ questionList.value, randomQuestion, shuffledResponses, - delayCoroutine + delayCoroutine, + viewModel ) }, enabled = buttonEnabled.value @@ -149,7 +146,8 @@ fun changeQuestion( randomQuestion: MutableState<Question?>, shuffledResponses: MutableState<List<String>?>, colorOfBackground: MutableState<Color>, - buttonEnabled: MutableState<Boolean> + buttonEnabled: MutableState<Boolean>, + viewModel: PlayViewModel ) { colorOfBackground.value = Color.White randomQuestion.value = viewModel.getQuestion(questionList) @@ -166,7 +164,8 @@ fun compareAnswer( questionList: List<Question>, randomQuestion: MutableState<Question?>, shuffledResponses: MutableState<List<String>?>, - delayCoroutine: CoroutineScope + delayCoroutine: CoroutineScope, + viewModel: PlayViewModel ) { buttonEnabled.value = false if(viewModel.compareAnswer(s, randomQuestion.value?.response1)){ @@ -177,20 +176,34 @@ fun compareAnswer( colorOfBackground.value = Color.Red } delayCoroutine.launch { - delay(2000) - changeQuestion(questionList, randomQuestion, shuffledResponses, colorOfBackground, buttonEnabled) +// delay(2000) + changeQuestion( + questionList, + randomQuestion, + shuffledResponses, + colorOfBackground, + buttonEnabled, + viewModel + ) } } fun startCounter( counter: MutableState<Int>, score: MutableState<Int>, - counterCoroutine: CoroutineScope + counterCoroutine: CoroutineScope, + viewModel: PlayViewModel, + id: Int, + scoreViewState: ScoreViewState, ) { counterCoroutine.launch { while (score.value < 5) { counter.value++ delay(1000) } + viewModel.saveScore(Score(score = counter.value.toString(), category = id.toString())) + if(scoreViewState.scoresDone > 6){ + viewModel.saveTotalScore() + } } }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/ScoreScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/ScoreScreen.kt index e8e21ce..086a132 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/ScoreScreen.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/ScoreScreen.kt @@ -1,24 +1,30 @@ package com.frannazario.proyectoandroid.presentation.screens -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.navigation.NavController +import com.frannazario.proyectoandroid.data.viewmodels.PlayViewModel @Composable -fun ScoreScreen(navController: NavController){ - Box( - modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Text ( - text = "Score" - ) +fun ScoreScreen(navController: NavController, viewModel: PlayViewModel){ + val scoreViewState = viewModel.scoresViewState.collectAsState() + +Column() { + scoreViewState.value.scores?.forEach { score -> + if(score.category != "total"){ + Row() { + Text(text = score.category) + Text(text = " ") + Text(text = score.score) + } + + } } } +} + diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/SettingsScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/SettingsScreen.kt index b3605d8..8c27e67 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/SettingsScreen.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/SettingsScreen.kt @@ -6,11 +6,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.navigation.NavController +import com.frannazario.proyectoandroid.data.viewmodels.PlayViewModel @Composable -fun SettingsScreen(navController: NavController){ +fun SettingsScreen(navController: NavController, viewModel: PlayViewModel){ Box( modifier = Modifier .fillMaxSize(), diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/TotalScoreScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/TotalScoreScreen.kt new file mode 100644 index 0000000..bb6d1c8 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/TotalScoreScreen.kt @@ -0,0 +1,26 @@ +package com.frannazario.proyectoandroid.presentation.screens + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.navigation.NavController +import com.frannazario.proyectoandroid.data.viewmodels.PlayViewModel + +@Composable +fun TotalScoreScreen(navController: NavController, viewModel: PlayViewModel){ + val scoreViewState = viewModel.scoresViewState.collectAsState() + + Column() { + scoreViewState.value.scores?.forEach { score -> + if (score.category == "total"){ + Text(text = "Total Score: ") + Text(text = score.score) + } + } + } + +} + diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/BottomNav.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/BottomNav.kt index af93bb9..81682da 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/BottomNav.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/BottomNav.kt @@ -21,7 +21,7 @@ fun BottomNav(navController: NavController) { Text(text = "Score") } Button(onClick = { - navController.navigate(AppScreens.PlayScreen.route) + navController.navigate(AppScreens.PlayListScreen.route) }) { Text(text = "Play") } @@ -30,5 +30,10 @@ fun BottomNav(navController: NavController) { }) { Text(text = "Settings") } + Button(onClick = { + navController.navigate(AppScreens.TotalScoreScreen.route) + }) { + Text(text = "Total Score") + } } }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/CategorySmallCard.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/CategorySmallCard.kt new file mode 100644 index 0000000..0d78ab5 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/CategorySmallCard.kt @@ -0,0 +1,91 @@ +package com.frannazario.proyectoandroid.presentation.ui.widgets + +import androidx.annotation.DrawableRes +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.frannazario.proyectoandroid.R +import com.frannazario.proyectoandroid.presentation.utils.CategoryEnum + +@Composable +fun CategorySmallCard( + modifier: Modifier = Modifier, + category: CategoryEnum, + enabled: Boolean, + @DrawableRes image: Int, + onClick: (Int) -> Unit, +) { + OutlinedButton( + modifier = modifier + .shadow( + elevation = 4.dp, + shape = RoundedCornerShape(64.dp) + ) + .border( + border = BorderStroke( + 0.dp, Color.LightGray + ) + ) + .background( + if(enabled){ + Color.White + }else{ + Color.Green + } + ), + shape = RoundedCornerShape(64.dp), + enabled = enabled, + onClick = { onClick(category.id) } + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = 8.dp, + vertical = 4.dp + ), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Image( + painter = painterResource(id = category.icon), + contentDescription = null, + modifier = Modifier + .size(52.dp) + ) + Image( + painter = painterResource(id = image), + contentDescription = null, + modifier = Modifier + .size(52.dp) + ) + } + Row( + ) { + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/TopBar.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/TopBar.kt new file mode 100644 index 0000000..1e57934 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/TopBar.kt @@ -0,0 +1,41 @@ +package com.frannazario.proyectoandroid.presentation.ui.widgets + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import com.frannazario.proyectoandroid.data.models.User + + +@Composable +fun TopBar(user: User) { + Row( + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically + ) { + TopAppBar( + title = { Text(text = user.username)}, + navigationIcon = { + AsyncImage( + model = user.userimage, + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .size(40.dp) + .clip( + RoundedCornerShape(40.dp) + ), + ) + }, + ) + } +}
\ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_check_24.xml b/app/src/main/res/drawable/baseline_check_24.xml new file mode 100644 index 0000000..cf143d4 --- /dev/null +++ b/app/src/main/res/drawable/baseline_check_24.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#000000" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> +</vector> diff --git a/app/src/main/res/drawable/baseline_close_24.xml b/app/src/main/res/drawable/baseline_close_24.xml new file mode 100644 index 0000000..844b6b6 --- /dev/null +++ b/app/src/main/res/drawable/baseline_close_24.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#000000" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> +</vector> |