diff options
| author | Alberto Duarte (PWC) <alberto.duarte.delgado@pwc.com> | 2023-07-06 09:09:09 +0100 |
|---|---|---|
| committer | Alberto Duarte (PWC) <alberto.duarte.delgado@pwc.com> | 2023-07-06 09:09:09 +0100 |
| commit | 2b12e7f68c840214b33e772032aff90b8e47b9e0 (patch) | |
| tree | 99a28c6666677e3b450b646fce0e0c9b9ddf1127 | |
| parent | 35835765585937cf373cbfbd9c6ccf7939969bac (diff) | |
muchos cambios, tieen room y arquitectura mvvm pero aun tiene errores
57 files changed, 1538 insertions, 133 deletions
diff --git a/app/build.gradle b/app/build.gradle index 346814f..eda17b6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,7 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' id 'com.google.gms.google-services' + id 'kotlin-kapt' } android { @@ -61,11 +62,22 @@ dependencies { implementation 'androidx.compose.ui:ui-graphics' implementation 'androidx.compose.ui:ui-tooling-preview' implementation 'androidx.compose.material3:material3' + implementation 'androidx.compose.material:material:1.4.3' implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3' implementation "androidx.fragment:fragment-ktx:1.5.7" implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'com.google.android.material:material:1.9.0' implementation 'com.google.firebase:firebase-auth-ktx:22.0.0' + implementation 'com.google.firebase:firebase-firestore-ktx' + 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("androidx.room:room-runtime:2.5.0") + annotationProcessor("androidx.room:room-compiler:2.5.0") + kapt("androidx.room:room-compiler:2.5.0") + + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 449cc20..aff3be9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,7 +15,6 @@ <activity android:name=".presentation.activities.AuthActivity" android:exported="true" - android:label="@string/app_name" android:theme="@style/Theme.ProyectoAndroid"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -23,6 +22,11 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity + android:name=".presentation.activities.MainActivity" + android:exported="true" + android:theme="@style/Theme.ProyectoAndroid"> + </activity> </application> </manifest>
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/DB.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/DB.kt new file mode 100644 index 0000000..8f4ab68 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/DB.kt @@ -0,0 +1,11 @@ +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.models.Question + +@Database(entities = [Question::class], version = 1) +abstract class AppDatabase : RoomDatabase() { + abstract fun questionDao(): QuestionDao +} 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 new file mode 100644 index 0000000..ed23243 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/dao/QuestionDAO.kt @@ -0,0 +1,19 @@ +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.Question + +@Dao +interface QuestionDao { + @Query("SELECT * FROM question") + fun getAll(): List<Question> + + @Insert + fun insertAll(vararg questions: Question) + + @Delete + fun delete(question: Question) +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/LoginRemoteDataSource.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/LoginRemoteDataSource.kt deleted file mode 100644 index 3f86c06..0000000 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/LoginRemoteDataSource.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.frannazario.proyectoandroid.data.datasources - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import com.frannazario.proyectoandroid.data.responses.LoginResponse -import com.google.firebase.auth.FirebaseAuth - -class LoginRemoteDataSource: LoginDataSource{ - private val auth = FirebaseAuth.getInstance() - - override fun login(email: String, password: String): LiveData<LoginResponse> { - val resultLiveData = MutableLiveData<LoginResponse>() - - auth.signInWithEmailAndPassword(email, password) - .addOnCompleteListener { task -> - if (task.isSuccessful) { - val user = auth.currentUser - resultLiveData.value = LoginResponse.Success(user) - } else { - val error = task.exception?.message ?: "Error desconocido" - resultLiveData.value = LoginResponse.Error(error) - } - } - return resultLiveData - } -}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/PasswordRecoveryRemoteDataSource.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/PasswordRecoveryRemoteDataSource.kt deleted file mode 100644 index 08335ad..0000000 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/PasswordRecoveryRemoteDataSource.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.frannazario.proyectoandroid.data.datasources - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import com.frannazario.proyectoandroid.data.responses.PasswordRecoveryResponse -import com.google.firebase.auth.FirebaseAuth - -class PasswordRecoveryRemoteDataSource: PasswordRecoveryDataSource { - private val auth = FirebaseAuth.getInstance() - - override fun recover (email: String): LiveData<PasswordRecoveryResponse> { - val resultLiveData = MutableLiveData<PasswordRecoveryResponse>() - - auth.sendPasswordResetEmail(email) - .addOnCompleteListener { task -> - if (task.isSuccessful) { - val user = auth.currentUser - resultLiveData.value = PasswordRecoveryResponse.Success(user) - } else { - val error = task.exception?.message ?: "Error desconocido" - resultLiveData.value = PasswordRecoveryResponse.Error(error) - } - } - return resultLiveData - } -}
\ No newline at end of file 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 new file mode 100644 index 0000000..21d4df5 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsDataSource.kt @@ -0,0 +1,9 @@ +package com.frannazario.proyectoandroid.data.datasources + +import android.content.Context +import com.frannazario.proyectoandroid.data.models.Question + +interface QuestionsDataSource { + suspend fun getQuestions(context: Context): 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 new file mode 100644 index 0000000..9cc17a7 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsLocalDataSource.kt @@ -0,0 +1,25 @@ +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.Question + +class QuestionsLocalDataSource: QuestionsDataSource { + + override suspend fun getQuestions(context: Context): List<Question> { + val dbLocal = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, "database-name" + ).build() + return dbLocal.questionDao().getAll() + } + + override fun saveQuestions(context: Context, questions: List<Question>) { + val dbLocal = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, "database-name" + ).build() + return dbLocal.questionDao().insertAll() + } +} 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 new file mode 100644 index 0000000..c8965df --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/datasources/QuestionsRemoteDataSource.kt @@ -0,0 +1,40 @@ +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 +import com.google.firebase.ktx.Firebase +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> { + val response = + db.collection("Preguntas") + .get() + .await() +// .addOnSuccessListener { result -> + for (document in response) { + try { + val pregunta = document.toObject<Question>() + questionList.add(pregunta) + } catch (e: Exception){ + e.printStackTrace() + } + } +// } +// .addOnFailureListener { exception -> +// Log.w(TAG, "Error getting documents.", exception) +// } + return questionList + } + + override fun saveQuestions(context: Context, questions: List<Question>) { + TODO("Not yet implemented") + } + +}
\ 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 new file mode 100644 index 0000000..54b5a4e --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/models/QuestionDTO.kt @@ -0,0 +1,14 @@ +package com.frannazario.proyectoandroid.data.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class Question( + @PrimaryKey var question: String = "", + @ColumnInfo var response1: String = "", + @ColumnInfo var response2: String = "", + @ColumnInfo var response3: String = "", + @ColumnInfo var category: Int = -1 +) diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/CategoriesRepository.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/CategoriesRepository.kt new file mode 100644 index 0000000..23a878e --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/CategoriesRepository.kt @@ -0,0 +1,17 @@ +package com.frannazario.proyectoandroid.data.repositories + +import com.frannazario.proyectoandroid.data.responses.CategoriesResponse +import com.frannazario.proyectoandroid.presentation.utils.CategoryEnum +import kotlinx.coroutines.flow.flow +import java.lang.Exception + +class CategoriesRepository() { + + fun getCategories() = flow { + try { + emit(CategoriesResponse.Success(CategoryEnum.values().toList())) + } catch (e: Exception) { + emit(CategoriesResponse.Error(e.message ?: "Error genérico")) + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/LoginRepository.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/LoginRepository.kt index 9532534..3561d42 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/LoginRepository.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/LoginRepository.kt @@ -1,14 +1,28 @@ package com.frannazario.proyectoandroid.data.repositories import androidx.lifecycle.LiveData -import com.frannazario.proyectoandroid.data.datasources.LoginDataSource -import com.frannazario.proyectoandroid.data.datasources.LoginRemoteDataSource +import androidx.lifecycle.MutableLiveData import com.frannazario.proyectoandroid.data.responses.LoginResponse +import com.frannazario.proyectoandroid.data.utils.FieldEnum +import com.google.firebase.auth.FirebaseAuth -class LoginRepository( - private val remoteDataSource: LoginDataSource = LoginRemoteDataSource() - ) { - fun login (email: String, password: String): LiveData<LoginResponse> { - return remoteDataSource.login(email, password) - } +class LoginRepository(){ + private val auth: FirebaseAuth = FirebaseAuth.getInstance() + + fun login(email: String, password: String): LiveData<LoginResponse> { + val resultLiveData = MutableLiveData<LoginResponse>() + + auth.signInWithEmailAndPassword(email, password) + .addOnCompleteListener { task -> + if (task.isSuccessful) { + val user = auth.currentUser + resultLiveData.value = LoginResponse.Success(user) + } else { + val error = task.exception?.message ?: "Error desconocido" + val field = FieldEnum.EMAIL_FIELD // Replace with the appropriate field + resultLiveData.value = LoginResponse.Error(error, field) + } + } + return resultLiveData + } }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/PasswordRecoveryRepository.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/PasswordRecoveryRepository.kt index 6550ae2..ce7c663 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/PasswordRecoveryRepository.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/PasswordRecoveryRepository.kt @@ -1,14 +1,28 @@ package com.frannazario.proyectoandroid.data.repositories import androidx.lifecycle.LiveData -import com.frannazario.proyectoandroid.data.datasources.PasswordRecoveryDataSource -import com.frannazario.proyectoandroid.data.datasources.PasswordRecoveryRemoteDataSource +import androidx.lifecycle.MutableLiveData import com.frannazario.proyectoandroid.data.responses.PasswordRecoveryResponse +import com.frannazario.proyectoandroid.data.utils.FieldEnum +import com.google.firebase.auth.FirebaseAuth -class PasswordRecoveryRepository ( - private val remoteDataSource: PasswordRecoveryDataSource= PasswordRecoveryRemoteDataSource() - ) { - fun recover(email: String): LiveData<PasswordRecoveryResponse> { - return remoteDataSource.recover(email) - } +class PasswordRecoveryRepository (){ + private val auth: FirebaseAuth = FirebaseAuth.getInstance() + + fun recover (email: String): LiveData<PasswordRecoveryResponse> { + val resultLiveData = MutableLiveData<PasswordRecoveryResponse>() + + auth.sendPasswordResetEmail(email) + .addOnCompleteListener { task -> + if (task.isSuccessful) { + val user = auth.currentUser + resultLiveData.value = PasswordRecoveryResponse.Success(user) + } else { + val error = task.exception?.message ?: "Error desconocido" + val field = FieldEnum.EMAIL_FIELD // Replace with the appropriate field + resultLiveData.value = PasswordRecoveryResponse.Error(error, field) + } + } + return resultLiveData + } }
\ No newline at end of file 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 new file mode 100644 index 0000000..61bb9ec --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/repositories/QuestionsRepository.kt @@ -0,0 +1,31 @@ +package com.frannazario.proyectoandroid.data.repositories + +import android.content.ContentValues.TAG +import android.content.Context +import android.util.Log +import com.frannazario.proyectoandroid.data.datasources.QuestionsLocalDataSource +import com.frannazario.proyectoandroid.data.datasources.QuestionsRemoteDataSource +import com.frannazario.proyectoandroid.data.responses.QuestionsResponse +import kotlinx.coroutines.flow.flow + +class QuestionsRepository { + private val remoteDataSource = QuestionsRemoteDataSource() + private val localDataSource = QuestionsLocalDataSource() + + fun getQuestions(context: Context) = flow { + try { + val questions = remoteDataSource.getQuestions(context = context) + localDataSource.saveQuestions(context = context, questions = questions) + emit(QuestionsResponse.Success(questions = questions)) + } catch (e: Exception) { + try { + val questions = localDataSource.getQuestions(context = context) + emit(QuestionsResponse.Success(questions = questions)) + }catch (e: Exception){ + emit(QuestionsResponse.Error(e.message ?: "Error genérico")) + Log.e(TAG, e.message ?: "Error generico") + } + } + } + +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/CategoriesResponse.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/CategoriesResponse.kt new file mode 100644 index 0000000..141c5df --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/CategoriesResponse.kt @@ -0,0 +1,9 @@ +package com.frannazario.proyectoandroid.data.responses + +import com.frannazario.proyectoandroid.data.utils.FieldEnum +import com.frannazario.proyectoandroid.presentation.utils.CategoryEnum + +sealed class CategoriesResponse { + data class Success(val categories: List<CategoryEnum>) : CategoriesResponse() + data class Error(val error: String): CategoriesResponse() +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/LoginResponse.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/LoginResponse.kt index 9eb5518..8be42bd 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/LoginResponse.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/LoginResponse.kt @@ -1,9 +1,10 @@ package com.frannazario.proyectoandroid.data.responses +import com.frannazario.proyectoandroid.data.utils.FieldEnum import com.google.firebase.auth.FirebaseUser sealed class LoginResponse { data class Success(val user: FirebaseUser?): LoginResponse() - data class Error(val error: String): LoginResponse() + data class Error(val error: String, val field: FieldEnum): LoginResponse() }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/PasswordRecoveryResponse.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/PasswordRecoveryResponse.kt index 98b5e39..56314f2 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/PasswordRecoveryResponse.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/PasswordRecoveryResponse.kt @@ -1,8 +1,9 @@ package com.frannazario.proyectoandroid.data.responses +import com.frannazario.proyectoandroid.data.utils.FieldEnum import com.google.firebase.auth.FirebaseUser sealed class PasswordRecoveryResponse { data class Success(val user: FirebaseUser?): PasswordRecoveryResponse() - data class Error(val error: String): PasswordRecoveryResponse() + data class Error(val error: String, val field: FieldEnum): PasswordRecoveryResponse() }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/responses/QuestionsResponse.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/QuestionsResponse.kt new file mode 100644 index 0000000..93c7f9b --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/responses/QuestionsResponse.kt @@ -0,0 +1,8 @@ +package com.frannazario.proyectoandroid.data.responses + +import com.frannazario.proyectoandroid.data.models.Question + +sealed class QuestionsResponse { + data class Success(val questions: List<Question>) : QuestionsResponse() + data class Error(val error: String): QuestionsResponse() +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/utils/CategoryEnum.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/utils/CategoryEnum.kt new file mode 100644 index 0000000..9c5ac8a --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/utils/CategoryEnum.kt @@ -0,0 +1,23 @@ +package com.frannazario.proyectoandroid.presentation.utils + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import com.frannazario.proyectoandroid.R + +enum class CategoryEnum( + val id: Int, + @StringRes val title: Int, + @DrawableRes val icon: Int, + val url: String +) { + SCIENCE(1, R.string.category_science, R.drawable.ic_science, "https://es.wikipedia.org/wiki/Ciencia"), + ART(2, R.string.category_art, R.drawable.ic_art, "https://es.wikipedia.org/wiki/Arte"), + ENTERTAINMENT(3, R.string.category_entertainment, R.drawable.ic_entertainment, ""), + GEOGRAPHY(4, R.string.category_geography, R.drawable.ic_geography, ""), + HISTORY(5, R.string.category_history, R.drawable.ic_history, ""), + POP(6, R.string.category_pop, R.drawable.ic_pop, ""), + SPORTS(7, R.string.category_sports, R.drawable.ic_sports, ""), + GENERAL(8, R.string.category_general, R.drawable.ic_general, "") +} + +fun getCategoryById(id: Int) = CategoryEnum.values().firstOrNull { it.id == id }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/CategoriesViewModel.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/CategoriesViewModel.kt new file mode 100644 index 0000000..de72ec6 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/CategoriesViewModel.kt @@ -0,0 +1,34 @@ +package com.frannazario.proyectoandroid.data.viewmodels + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.frannazario.proyectoandroid.data.repositories.CategoriesRepository +import com.frannazario.proyectoandroid.data.responses.CategoriesResponse +import com.frannazario.proyectoandroid.presentation.utils.CategoryEnum +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update + +class CategoriesViewModel(val repository: CategoriesRepository = CategoriesRepository()): ViewModel() { + private val mutableState = MutableStateFlow(CategoriesViewState()) + val categoriesViewState: StateFlow<CategoriesViewState> = mutableState + + fun getCategories() { + mutableState.update { CategoriesViewState(isLoading = true) } + repository.getCategories().onEach { response -> + when (response) { + is CategoriesResponse.Success -> mutableState.update { CategoriesViewState(data = response.categories) } + is CategoriesResponse.Error -> mutableState.update { CategoriesViewState(error = response.error) } + } + }.launchIn(viewModelScope) + } + +} + +data class CategoriesViewState( + val data: List<CategoryEnum>? = null, + val error: String? = null, + val isLoading: Boolean = false +)
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/LoginViewModel.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/LoginViewModel.kt index 9fe0988..a413731 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/LoginViewModel.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/LoginViewModel.kt @@ -5,14 +5,39 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.frannazario.proyectoandroid.data.repositories.LoginRepository import com.frannazario.proyectoandroid.data.responses.LoginResponse +import com.frannazario.proyectoandroid.data.utils.FieldEnum +import com.frannazario.proyectoandroid.data.utils.checkEmail +import com.frannazario.proyectoandroid.data.utils.checkPassword class LoginViewModel(private val repository: LoginRepository= LoginRepository()): ViewModel() { private val loginResponseLiveData = MutableLiveData<LoginResponse>() fun getLoginResultLiveData(): LiveData<LoginResponse> { return loginResponseLiveData } - fun login(email: String, password: String) { - val response = repository.login(email, password) - loginResponseLiveData.postValue(response.value) + fun login(email: String?, password: String?) { + val emailState = checkEmail(email) + val passState = checkPassword(password) + + if(emailState == null && passState == null) { + val response = repository.login( + email ?: "", + password ?: "") + response.observeForever { loginResponse -> + loginResponseLiveData.postValue(loginResponse) + } + } else if (emailState != null) { + loginResponseLiveData.postValue( + LoginResponse.Error( + emailState.error, + FieldEnum.EMAIL_FIELD + ) + ) + } else if (passState != null) { + loginResponseLiveData.postValue( + LoginResponse.Error(passState.error, FieldEnum.PASSWORD_FIELD) + ) + } } } + + diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PasswordRecoveryViewModel.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PasswordRecoveryViewModel.kt index b2511a8..3beed26 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PasswordRecoveryViewModel.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PasswordRecoveryViewModel.kt @@ -5,6 +5,8 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.frannazario.proyectoandroid.data.repositories.PasswordRecoveryRepository import com.frannazario.proyectoandroid.data.responses.PasswordRecoveryResponse +import com.frannazario.proyectoandroid.data.utils.FieldEnum +import com.frannazario.proyectoandroid.data.utils.checkEmail class PasswordRecoveryViewModel(private val repository: PasswordRecoveryRepository = PasswordRecoveryRepository()): ViewModel() { private val passwordRecoveryResponseLiveData = MutableLiveData<PasswordRecoveryResponse>() @@ -14,6 +16,22 @@ class PasswordRecoveryViewModel(private val repository: PasswordRecoveryReposito } fun recover (email: String) { + val emailState = checkEmail(email) + + if(emailState == null) { + val response = repository.recover( + email ?: "") + response.observeForever { passwordRecoveryResponse -> + passwordRecoveryResponseLiveData.postValue(passwordRecoveryResponse) + } + } else if (emailState != null) { + passwordRecoveryResponseLiveData.postValue( + PasswordRecoveryResponse.Error( + emailState.error, + FieldEnum.EMAIL_FIELD + ) + ) + } val response = repository.recover(email) passwordRecoveryResponseLiveData.postValue(response.value) } 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 new file mode 100644 index 0000000..f9f3af0 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/PlayViewModel.kt @@ -0,0 +1,214 @@ +package com.frannazario.proyectoandroid.data.viewmodels + +import android.content.Context +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.graphics.Color +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.frannazario.proyectoandroid.data.models.Question +import com.frannazario.proyectoandroid.data.repositories.QuestionsRepository +import com.frannazario.proyectoandroid.data.responses.QuestionsResponse +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +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 +import kotlinx.coroutines.launch + +class PlayViewModel(private val repository: QuestionsRepository = QuestionsRepository()): ViewModel() { + private val mutableState = MutableStateFlow(QuestionsViewState()) + val questionsViewState: StateFlow<QuestionsViewState> = mutableState + + private val randomQuestion = mutableStateOf<Question?>(null) + private val shuffledResponses = mutableStateOf<List<String>?>(null) + private val score = mutableStateOf(0) + private val counter = mutableStateOf(0) + private val isLoading = mutableStateOf(true) + private val buttonEnabled = mutableStateOf(true) + private val colorOfBackground = mutableStateOf(Color.White) + +// mutableState.update { QuestionsViewState(isLoading = true) } +// repository.getQuestions(context).onEach { response -> +// when (response) { +// is QuestionsResponse.Success -> mutableState.update { QuestionsViewState(questions = response.questions) } +// is QuestionsResponse.Error -> mutableState.update { QuestionsViewState(error = response.error) } +// } +// }.launchIn(viewModelScope) +// } +// private suspend fun getQuestions() { +// mutableState.update { it.copy(isLoading = true) } +// val response = repository.getQuestions() +// when (response) { +// is QuestionsResponse.Success -> { +// mutableState.update { it.copy(questions = response.questions, isLoading = false) } +// randomQuestion.value = getQuestion(response.questions) +// shuffledResponses.value = listOf( +// randomQuestion.value!!.response1, +// randomQuestion.value!!.response2, +// randomQuestion.value!!.response3 +// ).shuffled() +// isLoading.value = false +// startCounter() +// } +// is QuestionsResponse.Error -> { +// mutableState.update { it.copy(error = response.error, isLoading = false) } +// } +// } +// } + + fun getQuestions(context: Context) { + mutableState.update { it.copy(isLoading = true) } + val response = repository.getQuestions(context = context) + response.onEach { questionsResponse -> + when (questionsResponse) { + is QuestionsResponse.Success -> { + mutableState.update { it.copy(questions = questionsResponse.questions, isLoading = false) } + randomQuestion.value = getQuestion(questionsResponse.questions) + shuffledResponses.value = listOf( + randomQuestion.value!!.response1, + randomQuestion.value!!.response2, + randomQuestion.value!!.response3 + ).shuffled() + isLoading.value = false + startCounter(counter) + } + is QuestionsResponse.Error -> { + mutableState.update { it.copy(error = questionsResponse.error, isLoading = false) } + } + } + }.flowOn(Dispatchers.IO).launchIn(viewModelScope) + } + + fun getQuestion(questionList: List<Question>): Question { + return questionList.randomOrNull() ?: Question() + } + + fun compareAnswer( + selectedResponse: String, + score: MutableState<Int>, + coroutineScope: CoroutineScope, + randomQuestion: MutableState<Question?>, + shuffledResponses: MutableState<List<String>?>, + counter: MutableState<Int>, + questionList: List<Question> + ) { + buttonEnabled.value = false + val questionModel = this.randomQuestion.value + if (questionModel != null) { + if (selectedResponse == questionModel.response1) { + this.score.value++ + colorOfBackground.value = Color.Green + } else { + this.counter.value += 10 + colorOfBackground.value = Color.Red + } + viewModelScope.launch { + delay(2000) + this@PlayViewModel.randomQuestion.value = getQuestion(questionsViewState.value.questions ?: emptyList()) + this@PlayViewModel.shuffledResponses.value = listOf( + this@PlayViewModel.randomQuestion.value!!.response1, + this@PlayViewModel.randomQuestion.value!!.response2, + this@PlayViewModel.randomQuestion.value!!.response3 + ).shuffled() + colorOfBackground.value = Color.White + buttonEnabled.value = true + } + } + } + + fun startCounter(counter: MutableState<Int>) { + viewModelScope.launch { + while (score.value < 5) { + delay(1000) + counter.value++ + } + } + } + +} + +data class QuestionsViewState( + val questions: List<Question>? = null, + val error: String? = null, + val isLoading: Boolean = false +) + + + +// +//class PlayViewModel(private val repository: QuestionsRepository = QuestionsRepository()) : ViewModel() { +// private val mutableState = MutableStateFlow(QuestionsViewState()) +// val questionsViewState: StateFlow<QuestionsViewState> = mutableState +// +// +// init { +// viewModelScope.launch { +// getQuestions() +// } +// } +// +// private suspend fun getQuestions() { +// mutableState.update { it.copy(isLoading = true) } +// val response = repository.getQuestions() +// when (response) { +// is QuestionsResponse.Success -> { +// mutableState.update { it.copy(questions = response.questions, isLoading = false) } +// randomQuestion.value = getQuestion(response.questions) +// shuffledResponses.value = listOf( +// randomQuestion.value!!.response1, +// randomQuestion.value!!.response2, +// randomQuestion.value!!.response3 +// ).shuffled() +// isLoading.value = false +// startCounter() +// } +// is QuestionsResponse.Error -> { +// mutableState.update { it.copy(error = response.error, isLoading = false) } +// } +// } +// } +// +// private fun getQuestion(questionList: List<Question>): Question { +// return questionList.randomOrNull() ?: Question() +// } +// +// fun compareAnswer(selectedResponse: String) { +// buttonEnabled.value = false +// val questionModel = randomQuestion.value +// if (questionModel != null) { +// if (selectedResponse == questionModel.response1) { +// score.value++ +// colorOfBackground.value = Color.Green +// } else { +// counter.value += 10 +// colorOfBackground.value = Color.Red +// } +// viewModelScope.launch { +// delay(2000) +// randomQuestion.value = getQuestion(questionsViewState.value.questions ?: emptyList()) +// shuffledResponses.value = listOf( +// randomQuestion.value!!.response1, +// randomQuestion.value!!.response2, +// randomQuestion.value!!.response3 +// ).shuffled() +// colorOfBackground.value = Color.White +// buttonEnabled.value = true +// } +// } +// } +// +// fun startCounter() { +// viewModelScope.launch { +// while (score.value < 5) { +// delay(1000) +// counter.value++ +// } +// } +// } +//} +// diff --git a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/SigninViewModel.kt b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/SigninViewModel.kt index 81e8455..794d185 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/SigninViewModel.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/data/viewmodels/SigninViewModel.kt @@ -25,7 +25,6 @@ class SigninViewModel(private val repository: SigninRepository = SigninRepositor val response = repository.register( email ?: "", password ?: "") - signinResponseLiveData.postValue(response.value) response.observeForever { signinResponse -> signinResponseLiveData.postValue(signinResponse) } diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/activities/AuthActivity.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/activities/AuthActivity.kt index ea3c927..5ef61fe 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/activities/AuthActivity.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/activities/AuthActivity.kt @@ -1,15 +1,30 @@ package com.frannazario.proyectoandroid.presentation.activities +import android.content.Intent import android.os.Bundle import androidx.fragment.app.FragmentActivity import com.frannazario.proyectoandroid.databinding.ActivityAuthBinding +import com.google.firebase.auth.FirebaseAuth class AuthActivity : FragmentActivity() { private lateinit var binding: ActivityAuthBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + checkIfLogged() binding = ActivityAuthBinding.inflate(layoutInflater) setContentView(binding.root) } + + private fun checkIfLogged(){ + val auth = FirebaseAuth.getInstance() + auth.currentUser?.apply { + navigateToMain() + } + } + + private fun navigateToMain() { + val intent = Intent(this, MainActivity:: class.java) + startActivity(intent) + } }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/activities/MainActivity.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/activities/MainActivity.kt new file mode 100644 index 0000000..07b481e --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/activities/MainActivity.kt @@ -0,0 +1,40 @@ +package com.frannazario.proyectoandroid.presentation.activities + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.compose.rememberNavController +import com.frannazario.proyectoandroid.presentation.navigation.AppNavigation +import com.frannazario.proyectoandroid.presentation.screens.CategoryListScreen +import com.frannazario.proyectoandroid.presentation.screens.ScoreScreen +import com.frannazario.proyectoandroid.presentation.screens.SettingsScreen +import com.frannazario.proyectoandroid.presentation.ui.theme.ProyectoAndroidTheme +import com.frannazario.proyectoandroid.presentation.ui.widgets.BottomNav + +class MainActivity: ComponentActivity() { + + @OptIn(ExperimentalMaterial3Api::class) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ProyectoAndroidTheme { + Surface( + modifier = Modifier + .fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + AppNavigation() + } + } + } + } + +} diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/LoginFragment.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/LoginFragment.kt index 7167738..7681dfc 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/LoginFragment.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/LoginFragment.kt @@ -1,15 +1,21 @@ package com.frannazario.proyectoandroid.presentation.fragments +import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer import androidx.navigation.fragment.findNavController import com.frannazario.proyectoandroid.R import com.frannazario.proyectoandroid.data.responses.LoginResponse import com.frannazario.proyectoandroid.data.viewmodels.LoginViewModel import com.frannazario.proyectoandroid.databinding.FragmentLoginBinding +import com.frannazario.proyectoandroid.data.utils.FieldEnum +import com.frannazario.proyectoandroid.presentation.activities.MainActivity + class LoginFragment: Fragment() { private lateinit var binding: FragmentLoginBinding @@ -38,11 +44,34 @@ class LoginFragment: Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.getLoginResultLiveData().observe(viewLifecycleOwner) { response -> - when (response) { - is LoginResponse.Success -> {} - is LoginResponse.Error -> {} + viewModel.getLoginResultLiveData().observe(viewLifecycleOwner, Observer<LoginResponse?> { response -> + response?.apply { + when (response) { + is LoginResponse.Success -> { + val intent = Intent(requireContext(), MainActivity::class.java) + startActivity(intent) + } + + is LoginResponse.Error -> { + val intent = Intent(requireContext(), MainActivity::class.java) + startActivity(intent) + if (response.field == FieldEnum.EMAIL_FIELD) { + binding.emailIet.error = response.error + } + else if (response.field == FieldEnum.PASSWORD_FIELD){ + binding.passwordIet.error = response.error + } + } + + else -> {} + } } + }) + binding.loginBtn.setOnClickListener { + viewModel.login( + email = binding.emailIet.text?.toString(), + password = binding.passwordIet.text?.toString() + ) } } }
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/PasswordRecoveryFragment.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/PasswordRecoveryFragment.kt index 7c7d922..fbd2477 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/PasswordRecoveryFragment.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/PasswordRecoveryFragment.kt @@ -4,10 +4,15 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.navigation.fragment.findNavController +import com.frannazario.proyectoandroid.R import com.frannazario.proyectoandroid.data.responses.PasswordRecoveryResponse import com.frannazario.proyectoandroid.data.viewmodels.PasswordRecoveryViewModel import com.frannazario.proyectoandroid.databinding.FragmentPasswordRecoveryBinding +import com.frannazario.proyectoandroid.data.utils.FieldEnum class PasswordRecoveryFragment: Fragment() { private lateinit var binding: FragmentPasswordRecoveryBinding @@ -24,15 +29,35 @@ class PasswordRecoveryFragment: Fragment() { savedInstanceState: Bundle? ): View { binding = FragmentPasswordRecoveryBinding.inflate(inflater, container, false) + binding.loginBtn.setOnClickListener { + findNavController().navigate(R.id.navigate_from_passwordrecoveryfragment_to_loginfragment) + } return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.getPasswordRecoveryResultLiveData().observe(viewLifecycleOwner) { response -> + viewModel.getPasswordRecoveryResultLiveData().observe(viewLifecycleOwner, Observer<PasswordRecoveryResponse?> { response -> + response?.apply { when (response) { - is PasswordRecoveryResponse.Success -> {} - is PasswordRecoveryResponse.Error -> {} + is PasswordRecoveryResponse.Success -> { + Toast.makeText(requireContext(), "Funciona perfect", Toast.LENGTH_LONG) + .show() + } + is PasswordRecoveryResponse.Error -> { + if (response.field == FieldEnum.EMAIL_FIELD) { + binding.emailIet.error = response.error + } + } + else -> {} + } + } + }) + binding.sendEmailBtn.setOnClickListener { + binding.emailIet.text?.toString()?.let { it1 -> + viewModel.recover( + email = it1, + ) } } } diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/SigninFragment.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/SigninFragment.kt index bd974af..8d7d0de 100644 --- a/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/SigninFragment.kt +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/fragments/SigninFragment.kt @@ -7,6 +7,8 @@ import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment import androidx.lifecycle.Observer +import androidx.navigation.fragment.findNavController +import com.frannazario.proyectoandroid.R import com.frannazario.proyectoandroid.data.responses.SigninResponse import com.frannazario.proyectoandroid.data.utils.FieldEnum import com.frannazario.proyectoandroid.data.viewmodels.SigninViewModel @@ -26,6 +28,9 @@ class SigninFragment: Fragment() { savedInstanceState: Bundle? ): View { binding = FragmentSigninBinding.inflate(inflater, container, false) + binding.loginBtn.setOnClickListener { + findNavController().navigate(R.id.navigate_from_signinfragment_to_loginfragment) + } return binding.root } @@ -43,6 +48,9 @@ class SigninFragment: Fragment() { if (response.field == FieldEnum.EMAIL_FIELD) { binding.emailIet.error = response.error } + else if (response.field == FieldEnum.PASSWORD_FIELD){ + binding.passwordIet.error = response.error + } } else -> {} 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 new file mode 100644 index 0000000..b11f307 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppNavigation.kt @@ -0,0 +1,36 @@ +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 +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import com.frannazario.proyectoandroid.presentation.screens.BaseBottomNavScreen +import com.frannazario.proyectoandroid.presentation.screens.CategoryDetailScreen + +@Composable +fun AppNavigation() { + val mainNavController = rememberNavController() + + NavHost(navController = mainNavController, + startDestination = AppScreens.BaseBottomNav.route) { + + composable(route = AppScreens.BaseBottomNav.route) { + BaseBottomNavScreen(mainNavController) + } + + composable( + route = "${AppScreens.CategoryDetailScreen.route}/{id}", + arguments = listOf(navArgument("id") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.getInt("id")?.let { id -> + CategoryDetailScreen( + navController = mainNavController, + id = id + ) + } + } + } +} 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 new file mode 100644 index 0000000..72da5e5 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/navigation/AppScreens.kt @@ -0,0 +1,10 @@ +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 PlayScreen: AppScreens("play_screen") + object ScoreScreen: AppScreens("score_screen") + object SettingsScreen: AppScreens("settings_screen") + object BaseBottomNav: AppScreens("BottomNavScreen") +} 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 new file mode 100644 index 0000000..c90f05c --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/BaseBottomNavScreen.kt @@ -0,0 +1,54 @@ +package com.frannazario.proyectoandroid.presentation.screens + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.NavController +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.frannazario.proyectoandroid.presentation.ui.widgets.BottomNav +import com.frannazario.proyectoandroid.presentation.navigation.AppScreens + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BaseBottomNavScreen(mainNavController: NavController) { + val bottomNavController = rememberNavController() + + Scaffold( + bottomBar = { + BottomNav(bottomNavController) + } + ) { + Surface( + modifier = Modifier + .fillMaxSize() + .padding(bottom = it.calculateBottomPadding()), + color = MaterialTheme.colorScheme.background + ) { + NavHost( + navController = bottomNavController, + startDestination = AppScreens.CategoryListScreen.route + ) { + composable(AppScreens.CategoryListScreen.route) { + CategoryListScreen(mainNavController) + } + composable(AppScreens.ScoreScreen.route) { + ScoreScreen(mainNavController) + } + composable(AppScreens.PlayScreen.route) { + PlayScreen(mainNavController) + } + composable(AppScreens.SettingsScreen.route) { + SettingsScreen(mainNavController) + } + } + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryDetailScreen.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryDetailScreen.kt new file mode 100644 index 0000000..676175b --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryDetailScreen.kt @@ -0,0 +1,23 @@ +package com.frannazario.proyectoandroid.presentation.screens + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.navigation.NavController + +@Composable +fun CategoryDetailScreen(navController: NavController, id: Int){ + Box( + modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text ( + text = id.toString() + ) + } +} + 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 new file mode 100644 index 0000000..b4236e7 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/CategoryListScreen.kt @@ -0,0 +1,76 @@ +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.presentation.navigation.AppScreens +import com.frannazario.proyectoandroid.presentation.ui.widgets.CategoryCard + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CategoryListScreen(mainNavController: NavController){ + val context = LocalContext.current + val viewModel by remember { mutableStateOf(CategoriesViewModel()) } + val categoriesViewState by viewModel.categoriesViewState.collectAsState() + + LaunchedEffect(Unit) { + viewModel.getCategories() + } + + LaunchedEffect(categoriesViewState.error) { + categoriesViewState.error?.let { + Toast.makeText(context, it, Toast.LENGTH_LONG).show() + } + } + + LazyColumn( + modifier = Modifier + .fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + categoriesViewState.data?.forEach() { category -> + item { + CategoryCard(category = category, modifier = Modifier.fillMaxWidth()) {navigateCategoryDetailScreen(mainNavController, category.id)} + } + } + } +} + +fun navigateCategoryDetailScreen (mainNavController: NavController, id: Int){ + mainNavController.navigate("${AppScreens.CategoryDetailScreen.route}/${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 new file mode 100644 index 0000000..f8e2bce --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/PlayScreen.kt @@ -0,0 +1,188 @@ +package com.frannazario.proyectoandroid.presentation.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Button +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.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +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.viewmodels.PlayViewModel +import kotlinx.coroutines.CoroutineScope + +val score = mutableStateOf(0) +var isLoading by mutableStateOf(true) // Initial loading state is true +var buttonEnabled by mutableStateOf(true) // Initial loading state is true +var colorOfBackground by mutableStateOf(Color.White) // Initial loading state is true + + +@Composable +fun PlayScreen(navController: NavController){ + val context = LocalContext.current + val coroutineScope: CoroutineScope = rememberCoroutineScope() + val randomQuestion = remember { mutableStateOf<Question?>(null) } + val counter = remember { mutableStateOf(0) } + val shuffledResponses = remember {mutableStateOf<List<String>?>(null)} +// val viewModel: PlayViewModel = viewModel() + val viewModel by remember { mutableStateOf(PlayViewModel()) } + val questionsViewState by viewModel.questionsViewState.collectAsState() + var questionList = listOf<Question>() + + + LaunchedEffect(Unit) { + viewModel.getQuestions(context) + } + + LaunchedEffect(questionsViewState.questions){ + questionsViewState.questions?.let { + questionList = it + randomQuestion.value = viewModel.getQuestion(questionList) + shuffledResponses.value = listOf( + randomQuestion.value?.response1 ?: "1", + randomQuestion.value?.response2 ?: "2", + randomQuestion.value?.response3 ?: "3" + ).shuffled() + isLoading = false + viewModel.startCounter(counter) + } + } + + + if (score.value > 4) { + Text(text = "felicidades tu puntuacion es de: ${counter.value}") + + }else { + + if (isLoading) { + // Show loader + Text( text = "cargando") + } else { + Box( + modifier = Modifier + .fillMaxSize() + .background(color = colorOfBackground), + contentAlignment = Alignment.Center + + ) { + Column() { + randomQuestion.value?.let { + Text ( + text = it.question + ) + } + + Button(onClick = { + viewModel.compareAnswer( + shuffledResponses.value?.get(0) ?: "bb", + score, + coroutineScope, + randomQuestion, + shuffledResponses, + counter, + questionList + ) + }, + enabled = buttonEnabled + ) { + Text(text = shuffledResponses.value?.get(0) ?: "bb" ) + } + + Button(onClick = { + viewModel.compareAnswer( + shuffledResponses.value?.get(1) ?: "bb", + score, + coroutineScope, + randomQuestion, + shuffledResponses, + counter, + questionList + ) + }, + enabled = buttonEnabled + ) { + Text(text = shuffledResponses.value?.get(1) ?: "bb" ) + } + + Button(onClick = { + viewModel.compareAnswer( + shuffledResponses.value?.get(2) ?: "bb", + score, + coroutineScope, + randomQuestion, + shuffledResponses, + counter, + questionList + ) + }, + enabled = buttonEnabled + ) { + Text(text = shuffledResponses.value?.get(2) ?: "bb" ) + } + + Text(text = "${score.value.toString()}/5") + Text(text = "time: ${counter.value.toString()}") + } + } + } + } + +} + +//fun compareAnswer( +// selectedResponse: String, +// score: MutableState<Int>, +// coroutineScope: CoroutineScope, +// randomQuestion: MutableState<Question?>, +// shuffledResponses: MutableState<List<String>?>, +// counter: MutableState<Int>, +// questionList: List<Question>, +//) { +// buttonEnabled = false +// val questionModel = randomQuestion.value +// if (questionModel != null) { +// if (selectedResponse == questionModel.response1) { +// score.value++ +// colorOfBackground = Color.Green +// } else { +// counter.value += 10 +// colorOfBackground = Color.Red +// } +// coroutineScope.launch { +// delay(2000) +// randomQuestion.value = getQuestion(questionList) +// shuffledResponses.value = listOf( +// randomQuestion.value!!.response1, +// randomQuestion.value!!.response2, +// randomQuestion.value!!.response3 +// ).shuffled() +// colorOfBackground = Color.White +// buttonEnabled = true +// } +// } +//} +// +// +//fun getQuestion(questionList: List<Question>): Question { +// return questionList.randomOrNull() ?: Question() +//} +// +// +//suspend fun counterStart(counter: MutableState<Int>) { +// while(score.value < 5) { +// counter.value++ +// delay(1000) // Delay for 1 second (1000 milliseconds) +// } +//} 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 new file mode 100644 index 0000000..e8e21ce --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/ScoreScreen.kt @@ -0,0 +1,24 @@ +package com.frannazario.proyectoandroid.presentation.screens + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +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 + +@Composable +fun ScoreScreen(navController: NavController){ + Box( + modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text ( + text = "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 new file mode 100644 index 0000000..b3605d8 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/screens/SettingsScreen.kt @@ -0,0 +1,23 @@ +package com.frannazario.proyectoandroid.presentation.screens + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +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 + +@Composable +fun SettingsScreen(navController: NavController){ + Box( + modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text ( + text = "Settings" + ) + } +} 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 new file mode 100644 index 0000000..af93bb9 --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/BottomNav.kt @@ -0,0 +1,34 @@ +package com.frannazario.proyectoandroid.presentation.ui.widgets + +import androidx.compose.runtime.Composable +import androidx.compose.material.BottomNavigation +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.navigation.NavController +import com.frannazario.proyectoandroid.presentation.navigation.AppScreens + +@Composable +fun BottomNav(navController: NavController) { + BottomNavigation() { + Button(onClick = { + navController.navigate(AppScreens.CategoryListScreen.route) + }) { + Text(text = "Categories") + } + Button(onClick = { + navController.navigate(AppScreens.ScoreScreen.route) + }) { + Text(text = "Score") + } + Button(onClick = { + navController.navigate(AppScreens.PlayScreen.route) + }) { + Text(text = "Play") + } + Button(onClick = { + navController.navigate(AppScreens.SettingsScreen.route) + }) { + Text(text = "Settings") + } + } +}
\ No newline at end of file diff --git a/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/CategoryCard.kt b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/CategoryCard.kt new file mode 100644 index 0000000..fb6973d --- /dev/null +++ b/app/src/main/java/com/frannazario/proyectoandroid/presentation/ui/widgets/CategoryCard.kt @@ -0,0 +1,91 @@ +package com.frannazario.proyectoandroid.presentation.ui.widgets + +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.Row +import androidx.compose.foundation.layout.Spacer +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.presentation.utils.CategoryEnum + +@Composable +fun CategoryCard( + modifier: Modifier = Modifier, + category: CategoryEnum, + onClick: (Int) -> Unit +) { + OutlinedButton( + modifier = modifier + .fillMaxWidth() + .padding( + horizontal = 24.dp, + vertical = 12.dp + ) + .shadow( + elevation = 4.dp, + shape = RoundedCornerShape(64.dp) + ) + .border( + border = BorderStroke( + 0.dp, Color.LightGray + ) + ) + .background(Color.White), + shape = RoundedCornerShape(64.dp), + onClick = { onClick(category.id) } + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding( + horizontal = 8.dp, + vertical = 4.dp + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Image( + painter = painterResource(id = category.icon), + contentDescription = null, + modifier = Modifier + .size(52.dp) + ) + + Spacer(modifier = Modifier) + + Text( + text = stringResource(id = category.title), + fontWeight = FontWeight.Bold, + style = TextStyle( + fontSize = 24.sp, + color = Color.Black + ) + ) + } + } +} + +@Preview +@Composable +private fun CategoryCardPreview() { + CategoryCard(category = CategoryEnum.GENERAL) {} +}
\ No newline at end of file diff --git a/app/src/main/res/drawable/button_clicked.xml b/app/src/main/res/drawable/button_clicked.xml index c39a7e3..30a43e9 100644 --- a/app/src/main/res/drawable/button_clicked.xml +++ b/app/src/main/res/drawable/button_clicked.xml @@ -1,13 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <stroke - android:width="5dp" - android:color="@color/black" /> <gradient android:type="linear" android:angle="45" - android:startColor="@color/purple_200" - android:endColor="@color/purple_700" /> + android:startColor="#008477" + android:endColor="#000000" /> <corners android:radius="15dp" /> </shape>
\ No newline at end of file diff --git a/app/src/main/res/drawable/button_stand.xml b/app/src/main/res/drawable/button_stand.xml index 5c58464..d918a01 100644 --- a/app/src/main/res/drawable/button_stand.xml +++ b/app/src/main/res/drawable/button_stand.xml @@ -1,9 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <stroke - android:width="5dp" - android:color="@color/black" /> - <solid android:color="@color/purple_500" /> + <solid android:color="#008477" /> <corners android:radius="15dp" /> </shape>
\ No newline at end of file diff --git a/app/src/main/res/drawable/ic_art.png b/app/src/main/res/drawable/ic_art.png Binary files differnew file mode 100644 index 0000000..77d0b8d --- /dev/null +++ b/app/src/main/res/drawable/ic_art.png diff --git a/app/src/main/res/drawable/ic_entertainment.png b/app/src/main/res/drawable/ic_entertainment.png Binary files differnew file mode 100644 index 0000000..5b7da48 --- /dev/null +++ b/app/src/main/res/drawable/ic_entertainment.png diff --git a/app/src/main/res/drawable/ic_general.png b/app/src/main/res/drawable/ic_general.png Binary files differnew file mode 100644 index 0000000..e837615 --- /dev/null +++ b/app/src/main/res/drawable/ic_general.png diff --git a/app/src/main/res/drawable/ic_geography.png b/app/src/main/res/drawable/ic_geography.png Binary files differnew file mode 100644 index 0000000..53b03e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_geography.png diff --git a/app/src/main/res/drawable/ic_history.png b/app/src/main/res/drawable/ic_history.png Binary files differnew file mode 100644 index 0000000..608ff57 --- /dev/null +++ b/app/src/main/res/drawable/ic_history.png diff --git a/app/src/main/res/drawable/ic_pop.png b/app/src/main/res/drawable/ic_pop.png Binary files differnew file mode 100644 index 0000000..d67332a --- /dev/null +++ b/app/src/main/res/drawable/ic_pop.png diff --git a/app/src/main/res/drawable/ic_science.png b/app/src/main/res/drawable/ic_science.png Binary files differnew file mode 100644 index 0000000..c7b0ecd --- /dev/null +++ b/app/src/main/res/drawable/ic_science.png diff --git a/app/src/main/res/drawable/ic_sports.png b/app/src/main/res/drawable/ic_sports.png Binary files differnew file mode 100644 index 0000000..d3b83a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_sports.png diff --git a/app/src/main/res/drawable/input.xml b/app/src/main/res/drawable/input.xml new file mode 100644 index 0000000..aa0bbc6 --- /dev/null +++ b/app/src/main/res/drawable/input.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <gradient + android:type="linear" + android:angle="45" + android:startColor="#444444" + android:endColor="#222222" /> + <corners android:radius="15dp" /> + +</shape>
\ No newline at end of file diff --git a/app/src/main/res/drawable/input_background.xml b/app/src/main/res/drawable/input_background.xml new file mode 100644 index 0000000..c810750 --- /dev/null +++ b/app/src/main/res/drawable/input_background.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/input" /> +</selector>
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_login.xml b/app/src/main/res/layout/fragment_login.xml index 61f0a8d..6360895 100644 --- a/app/src/main/res/layout/fragment_login.xml +++ b/app/src/main/res/layout/fragment_login.xml @@ -3,19 +3,47 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_margin="10dp" + android:background="#000000" xmlns:app="http://schemas.android.com/apk/res-auto"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/login" + android:textColor="@color/white" + android:textSize="40sp" + app:layout_constraintStart_toStartOf="parent" + android:textAllCaps="true" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toTopOf="@id/layout"/> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/layout" + android:layout_width="300dp" + android:layout_height="wrap_content" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + > + <com.google.android.material.textfield.TextInputLayout android:id="@+id/email_il" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:background="@drawable/input_background" + android:textColorHint="#fff" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <com.google.android.material.textfield.TextInputEditText + android:id="@+id/email_iet" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textColor="@color/white" + android:textColorHint="@color/white" android:hint="@string/field_email" /> </com.google.android.material.textfield.TextInputLayout> @@ -23,42 +51,74 @@ <com.google.android.material.textfield.TextInputLayout android:id="@+id/password_il" android:layout_width="match_parent" + android:layout_marginTop="16dp" android:layout_height="wrap_content" + android:background="@drawable/input_background" + android:textColorHint="#fff" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/email_il"> <com.google.android.material.textfield.TextInputEditText + android:id="@+id/password_iet" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/field_signin" /> + android:textColor="@color/white" + android:textColorHint="@color/white" + android:hint="@string/field_password" /> </com.google.android.material.textfield.TextInputLayout> + <Button + android:id="@+id/forget_password_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="#000000" + android:textColor="#aaaaaa" + app:layout_constraintEnd_toEndOf="@id/layout" + app:layout_constraintTop_toBottomOf="@id/password_il" + android:text="Forgot your password?" /> + <Button android:id="@+id/login_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/password_il" + android:background="@drawable/button_background" + android:textColor="@color/white" + android:paddingHorizontal="10dp" + app:layout_constraintTop_toBottomOf="@id/forget_password_btn" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:text="@string/login" /> - <Button - android:id="@+id/forget_password_btn" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/login_btn" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - android:text="@string/forgot_password" /> + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/layout2" + android:layout_width="300dp" + android:layout_height="wrap_content" + app:layout_constraintStart_toStartOf="@id/layout" + app:layout_constraintTop_toBottomOf="@id/login_btn" + > + <TextView + android:id="@+id/text_passrcv" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Dont have an account?" + android:textColor="@color/white" + android:textSize="17sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + /> <Button android:id="@+id/signin_btn" - android:layout_width="wrap_content" + android:layout_width="70dp" android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/forget_password_btn" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - android:text="@string/signup" /> - + android:background="#000000" + android:textColor="#008477" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/text_passrcv" + android:text="@string/Register" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_password_recovery.xml b/app/src/main/res/layout/fragment_password_recovery.xml index 22d7df4..ecc3cb2 100644 --- a/app/src/main/res/layout/fragment_password_recovery.xml +++ b/app/src/main/res/layout/fragment_password_recovery.xml @@ -1,17 +1,95 @@ <?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.constraintlayout.widget.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="#000000" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="B" - android:textSize="200sp" + android:text="Recovery" + android:textColor="@color/white" + android:textAllCaps="true" + android:textStyle="bold" + android:textSize="40sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toTopOf="@id/layout"/> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/layout" + android:layout_width="300dp" + android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + > + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/email_il" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:background="@drawable/input_background" + android:textColorHint="#fff" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/email_iet" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textColor="@color/white" + android:textColorHint="@color/white" + android:hint="@string/field_email" /> + + </com.google.android.material.textfield.TextInputLayout> + + <Button + android:id="@+id/send_email_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:background="@drawable/button_background" + android:textColor="@color/white" + android:paddingHorizontal="10dp" + app:layout_constraintTop_toBottomOf="@id/email_il" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + android:text="@string/send_email" /> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/layout2" + android:layout_width="300dp" + android:layout_height="wrap_content" + app:layout_constraintStart_toStartOf="@id/layout" + app:layout_constraintTop_toBottomOf="@id/send_email_btn" + > + <TextView + android:id="@+id/text_passrcv" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Did you remembered?" + android:textColor="@color/white" + android:textSize="17sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + /> + <Button + android:id="@+id/login_btn" + android:layout_width="70dp" + android:layout_height="wrap_content" + android:textColor="#008477" + app:layout_constraintTop_toTopOf="parent" + android:background="#000000" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/text_passrcv" + android:text="@string/login" /> + </androidx.constraintlayout.widget.ConstraintLayout> + </androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_signin.xml b/app/src/main/res/layout/fragment_signin.xml index 362a731..5e0f99a 100644 --- a/app/src/main/res/layout/fragment_signin.xml +++ b/app/src/main/res/layout/fragment_signin.xml @@ -1,21 +1,49 @@ <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - xmlns:app="http://schemas.android.com/apk/res-auto"> + android:background="#000000"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/Register" + android:textColor="@color/white" + android:textSize="40sp" + app:layout_constraintStart_toStartOf="parent" + android:textAllCaps="true" + android:textStyle="bold" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toTopOf="@id/layout"/> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/layout" + android:layout_width="300dp" + android:layout_height="wrap_content" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + > <com.google.android.material.textfield.TextInputLayout android:id="@+id/email_il" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" + android:background="@drawable/input_background" + android:layout_marginTop="16dp" + android:textColorHint="#fff" app:layout_constraintTop_toTopOf="parent"> <com.google.android.material.textfield.TextInputEditText android:id="@+id/email_iet" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/field_email" /> + android:hint="@string/field_email" + android:textColor="@color/white" + android:textColorHint="@color/white"/> </com.google.android.material.textfield.TextInputLayout> @@ -23,10 +51,15 @@ android:id="@+id/password_il" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:textColorHint="#fff" + android:background="@drawable/input_background" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/email_il"> <com.google.android.material.textfield.TextInputEditText + android:textColor="#ffffff" + android:textColorHint="#ffffff" android:id="@+id/password_iet" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -34,15 +67,47 @@ </com.google.android.material.textfield.TextInputLayout> - <Button - android:id="@+id/signin_btn" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:layout_constraintTop_toBottomOf="@id/password_il" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - android:textColor="@color/white" - android:background="@drawable/button_background" - android:text="@string/signin" /> + <Button + android:id="@+id/signin_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:paddingHorizontal="10dp" + android:background="@drawable/button_background" + android:textColor="@color/white" + android:text="@string/signup" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/password_il" /> + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/layout2" + android:layout_width="300dp" + android:layout_height="wrap_content" + app:layout_constraintStart_toStartOf="@id/layout" + app:layout_constraintTop_toBottomOf="@id/signin_btn" + > + <TextView + android:id="@+id/text_passrcv" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Already registered?" + android:textColor="@color/white" + android:textSize="17sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + /> + <Button + android:id="@+id/login_btn" + android:layout_width="70dp" + android:layout_height="wrap_content" + android:background="#000000" + android:textColor="#008477" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/text_passrcv" + android:text="@string/login" /> + </androidx.constraintlayout.widget.ConstraintLayout> +</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index cb1a441..cd6c344 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -25,12 +25,24 @@ android:id="@+id/signin_fragment" android:name="com.frannazario.proyectoandroid.presentation.fragments.SigninFragment" android:label="Sign in" - tools:layout="@layout/fragment_signin" /> + tools:layout="@layout/fragment_signin" > + + <action + android:id="@+id/navigate_from_signinfragment_to_loginfragment" + app:destination="@id/login_fragment" /> + + </fragment> <fragment android:id="@+id/password_recovery_fragment" android:name="com.frannazario.proyectoandroid.presentation.fragments.PasswordRecoveryFragment" android:label="Password recovery" - tools:layout="@layout/fragment_password_recovery" /> + tools:layout="@layout/fragment_password_recovery" > + + <action + android:id="@+id/navigate_from_passwordrecoveryfragment_to_loginfragment" + app:destination="@id/login_fragment" /> + + </fragment> </navigation>
\ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index a4a8581..68fdc2f 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -2,9 +2,16 @@ <resources> <string name="field_email">Correo electronico</string> <string name="field_password">Contrasena</string> - <string name="field_signin">Registro</string> - <string name="field_password">Contraseña</string> <string name="forgot_password">Olvidé la contraseña</string> - <string name="signup">Registrarte</string> + <string name="Register">Registrate</string> <string name="login">Acceder</string> + <string name="send_email">Enviar Correo</string> + <string name="category_science">Ciencia</string> + <string name="category_art">Arte</string> + <string name="category_entertainment">Entretenimiento</string> + <string name="category_geography">Geografia</string> + <string name="category_history">Historia</string> + <string name="category_pop">Cultura Pop</string> + <string name="category_sports">Deportes</string> + <string name="category_general">Conocimiento general</string> </resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b04b94d..4804cf2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,9 +3,17 @@ <string name="field_email">Email</string> <string name="field_password">Password</string> - <string name="field_signin">Sign in</string> - <string name="field_password">Password</string> <string name="forgot_password">Forget password</string> - <string name="signup">Sign Up</string> + <string name="signup">SignUp</string> + <string name="Register">Register</string> <string name="login">Login</string> + <string name="send_email">Send Email</string> + <string name="category_science">Science</string> + <string name="category_art">Art</string> + <string name="category_entertainment">Entertainment</string> + <string name="category_geography">Geography</string> + <string name="category_history">History</string> + <string name="category_pop">Pop Culture</string> + <string name="category_sports">Sports</string> + <string name="category_general">General Knowledge</string> </resources>
\ No newline at end of file |