From 60ab216652ae62bf72a7dd2256f4f5bcfaa3890a Mon Sep 17 00:00:00 2001 From: kirkadev Date: Tue, 16 Mar 2021 10:16:28 +0500 Subject: [PATCH] Reading Categories and Question from Firestore added; Firebase Crashlytics added. --- app/build.gradle | 40 ++++++---- .../socialquiz/InstrumentedTest.kt | 6 +- .../socialquiz/MainActivity.kt | 1 - .../socialquiz/api/in/ApiClientFirebase.kt | 22 ++++-- ...ionCallback.kt => GetQuestionsCallback.kt} | 2 +- .../socialquiz/ui/home/HomeFragment.kt | 79 ++++++++++--------- .../socialquiz/ui/home/HomeViewModel.kt | 8 +- .../ui/question/QuestionResultFragment.kt | 14 ++-- .../socialquiz/ApiClientUnitTests.kt | 10 ++- build.gradle | 18 +++-- gradle/wrapper/gradle-wrapper.properties | 4 +- 11 files changed, 114 insertions(+), 90 deletions(-) rename app/src/main/java/com/desiredsoftware/socialquiz/data/model/question/{GetQuestionCallback.kt => GetQuestionsCallback.kt} (77%) diff --git a/app/build.gradle b/app/build.gradle index 839ce80..28f2bc5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ plugins { android { compileSdkVersion 30 - buildToolsVersion "30.0.2" + buildToolsVersion "30.0.3" defaultConfig { applicationId "com.desiredsoftware.socialquiz" @@ -35,39 +35,45 @@ android { apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.firebase.crashlytics' dependencies { - implementation 'com.google.firebase:firebase-firestore:21.4.0' + implementation 'com.google.firebase:firebase-firestore:22.1.1' apply plugin: 'kotlin-android-extensions' - apply plugin: "androidx.navigation.safeargs" + apply plugin: 'androidx.navigation.safeargs' // Import the Firebase BoM - implementation platform('com.google.firebase:firebase-bom:26.1.0') - // Add the dependency for the Firebase SDK for Google Analytics - // When using the BoM, don't specify versions in Firebase dependencies + implementation platform('com.google.firebase:firebase-bom:26.7.0') + implementation 'com.google.firebase:firebase-analytics-ktx' - implementation 'androidx.activity:activity-ktx:1.2.0-beta01' - implementation 'androidx.fragment:fragment:1.3.0-beta01' + implementation 'androidx.activity:activity-ktx:1.3.0-alpha04' + implementation 'androidx.fragment:fragment:1.3.1' implementation 'androidx.recyclerview:recyclerview:1.1.0' - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.31" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.2.1' + implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' - implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.4' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.4' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0' + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.4' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.4' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - testImplementation 'junit:junit:4.13.1' + + //Crashlytics & analytics + implementation 'com.google.firebase:firebase-crashlytics-ktx' + implementation 'com.google.firebase:firebase-analytics-ktx' + + // Testing androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + testImplementation 'junit:junit:4.13.1' // Work with media diff --git a/app/src/androidTest/java/com/desiredsoftware/socialquiz/InstrumentedTest.kt b/app/src/androidTest/java/com/desiredsoftware/socialquiz/InstrumentedTest.kt index b8fb8a9..5c3a951 100644 --- a/app/src/androidTest/java/com/desiredsoftware/socialquiz/InstrumentedTest.kt +++ b/app/src/androidTest/java/com/desiredsoftware/socialquiz/InstrumentedTest.kt @@ -3,8 +3,6 @@ package com.desiredsoftware.socialquiz import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.desiredsoftware.socialquiz.api.`in`.ApiClientFirebase -import com.desiredsoftware.socialquiz.data.model.question.GetQuestionCallback -import org.junit.Assert import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -31,13 +29,13 @@ class InstrumentedTest { lateinit var questions: ArrayList - client.getQuestion(category, object : GetQuestionCallback { +/* client.getQuestion(category, object : GetQuestionsCallback { override fun onCallback(questionsArray: ArrayList) { questions = questionsArray Assert.assertEquals(true, false) } - }) + })*/ } } \ No newline at end of file diff --git a/app/src/main/java/com/desiredsoftware/socialquiz/MainActivity.kt b/app/src/main/java/com/desiredsoftware/socialquiz/MainActivity.kt index fd96287..1cbd591 100644 --- a/app/src/main/java/com/desiredsoftware/socialquiz/MainActivity.kt +++ b/app/src/main/java/com/desiredsoftware/socialquiz/MainActivity.kt @@ -41,6 +41,5 @@ class MainActivity : AppCompatActivity() { Manifest.permission.WRITE_EXTERNAL_STORAGE, ) ) - } } \ No newline at end of file diff --git a/app/src/main/java/com/desiredsoftware/socialquiz/api/in/ApiClientFirebase.kt b/app/src/main/java/com/desiredsoftware/socialquiz/api/in/ApiClientFirebase.kt index 66e78af..8abebe7 100644 --- a/app/src/main/java/com/desiredsoftware/socialquiz/api/in/ApiClientFirebase.kt +++ b/app/src/main/java/com/desiredsoftware/socialquiz/api/in/ApiClientFirebase.kt @@ -2,10 +2,10 @@ package com.desiredsoftware.socialquiz.api.`in` import android.util.Log import com.desiredsoftware.socialquiz.api.`in`.category.GetCategoriesCallback -import com.desiredsoftware.socialquiz.data.model.question.GetQuestionCallback -import com.desiredsoftware.socialquiz.data.model.question.Question +import com.desiredsoftware.socialquiz.data.model.question.GetQuestionsCallback import com.desiredsoftware.socialquiz.data.model.question.QuestionCategory import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.FirebaseFirestoreSettings class ApiClientFirebase { @@ -13,10 +13,21 @@ class ApiClientFirebase { val CategoryCollectionName : String = "question_category" val QuestionsCollectionName : String = "questions" + var db = FirebaseFirestore.getInstance() + init { + val settings = FirebaseFirestoreSettings.Builder() + .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED) + .build() + db.firestoreSettings = settings + } + + fun getCategories(callback: GetCategoriesCallback) { + // TODO: Make read categories from cached version for next cases + //if (usingCachedDataMode) db.disableNetwork() else db.enableNetwork() db.collection(CategoryCollectionName) .get() .addOnCompleteListener { task -> @@ -24,7 +35,6 @@ class ApiClientFirebase { var questionCategories : ArrayList = ArrayList() if (task.isSuccessful) { - for (document in task.result!!) { Log.d("Firebase read", document.id + " => " + document.data) questionCategories.add(QuestionCategory( @@ -42,13 +52,11 @@ class ApiClientFirebase { } } - fun getQuestion(questionCategory: String, callback: GetQuestionCallback) + fun getQuestionsArrayByCategory(questionCategory: String, callback: GetQuestionsCallback) { - var answersArray : ArrayList = ArrayList() - var answersSomeObjects : ArrayList = ArrayList() + // TODO: Make read questions from cached version for next cases val collectionName = "questions" - db.collection(collectionName) .whereEqualTo("categoryName", questionCategory) .get() diff --git a/app/src/main/java/com/desiredsoftware/socialquiz/data/model/question/GetQuestionCallback.kt b/app/src/main/java/com/desiredsoftware/socialquiz/data/model/question/GetQuestionsCallback.kt similarity index 77% rename from app/src/main/java/com/desiredsoftware/socialquiz/data/model/question/GetQuestionCallback.kt rename to app/src/main/java/com/desiredsoftware/socialquiz/data/model/question/GetQuestionsCallback.kt index 0fbf3df..4bad77d 100644 --- a/app/src/main/java/com/desiredsoftware/socialquiz/data/model/question/GetQuestionCallback.kt +++ b/app/src/main/java/com/desiredsoftware/socialquiz/data/model/question/GetQuestionsCallback.kt @@ -1,5 +1,5 @@ package com.desiredsoftware.socialquiz.data.model.question -interface GetQuestionCallback { +interface GetQuestionsCallback { fun onCallback(questions : ArrayList) } diff --git a/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeFragment.kt b/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeFragment.kt index 22cee21..f150cc6 100644 --- a/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeFragment.kt @@ -16,27 +16,29 @@ import androidx.recyclerview.widget.RecyclerView import com.desiredsoftware.socialquiz.R import com.desiredsoftware.socialquiz.api.`in`.ApiClientFirebase import com.desiredsoftware.socialquiz.api.`in`.category.GetCategoriesCallback -import com.desiredsoftware.socialquiz.data.model.question.GetQuestionCallback +import com.desiredsoftware.socialquiz.data.model.question.GetQuestionsCallback import com.desiredsoftware.socialquiz.data.model.question.QuestionCategory import com.desiredsoftware.socialquiz.ui.components.CategoriesAdapter import com.desiredsoftware.socialquiz.ui.components.OnClickCategoryListener import com.desiredsoftware.socialquiz.utils.convertToQuestion +import java.util.* +import kotlin.collections.ArrayList class HomeFragment : Fragment() { private lateinit var homeViewModel: HomeViewModel - lateinit var navController : NavController + lateinit var navController: NavController - val apiClient : ApiClientFirebase = ApiClientFirebase() + val apiClient: ApiClientFirebase = ApiClientFirebase() lateinit var categoriesList: ArrayList - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java) val root = inflater.inflate(R.layout.fragment_home, container, false) @@ -47,36 +49,37 @@ class HomeFragment : Fragment() { textView.text = it }) - categoriesList = ArrayList() - - navController = requireParentFragment().findNavController() - - apiClient.getCategories(object : GetCategoriesCallback { - override fun onCallback(categories : ArrayList) { - categoriesList = categories - - recyclerView.layoutManager = GridLayoutManager(requireContext(), 3) - - recyclerView.adapter = CategoriesAdapter( - categoriesList, - object : OnClickCategoryListener { - override fun onClicked(categoryName: String) { - Log.d("RecyclerView clicked", "Category name = $categoryName was selected") - homeViewModel.getNextQuestion(categoryName, object : GetQuestionCallback { - override fun onCallback(questions: ArrayList) { - if (questions!=null) - { - // TODO : Delete this hardcode - val currentQuestion = convertToQuestion(questions[0] as HashMap) - val action = HomeFragmentDirections.actionNavigationHomeToQuestionShowingFragment(currentQuestion) - navController.navigate(action) - } - } - }) - } - }) - } - }) + categoriesList = ArrayList() + + navController = requireParentFragment().findNavController() + + apiClient.getCategories(object : GetCategoriesCallback { + override fun onCallback(categories: ArrayList) { + categoriesList = categories + + recyclerView.layoutManager = GridLayoutManager(requireContext(), 3) + + recyclerView.adapter = CategoriesAdapter( + categoriesList, + object : OnClickCategoryListener { + override fun onClicked(categoryName: String) { + Log.d("RecyclerView clicked", "Category name = $categoryName was selected") + homeViewModel.getQuestionsInCategory(categoryName, object : GetQuestionsCallback { + override fun onCallback(questions: ArrayList) { + if (questions != null) { + // Select random question + + val randomNumber = Random().nextInt(questions.size) + val currentQuestion = convertToQuestion(questions[randomNumber] as HashMap) + val action = HomeFragmentDirections.actionNavigationHomeToQuestionShowingFragment(currentQuestion) + navController.navigate(action) + } + } + }) + } + }) + } + }) return root } diff --git a/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeViewModel.kt b/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeViewModel.kt index 7d6af6a..01b99fa 100644 --- a/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/desiredsoftware/socialquiz/ui/home/HomeViewModel.kt @@ -4,7 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.desiredsoftware.socialquiz.api.`in`.ApiClientFirebase -import com.desiredsoftware.socialquiz.data.model.question.GetQuestionCallback +import com.desiredsoftware.socialquiz.data.model.question.GetQuestionsCallback import com.desiredsoftware.socialquiz.data.model.question.Question import com.desiredsoftware.socialquiz.utils.generateQuestion @@ -17,9 +17,11 @@ class HomeViewModel : ViewModel() { val apiClient: ApiClientFirebase = ApiClientFirebase() - fun getNextQuestion(questionCategory : String, callback : GetQuestionCallback) : Question + lateinit var localQuestionArray : ArrayList + + fun getQuestionsInCategory(questionCategory : String, callback : GetQuestionsCallback) : Question { - apiClient.getQuestion(questionCategory, callback) + apiClient.getQuestionsArrayByCategory(questionCategory, callback) return generateQuestion() } diff --git a/app/src/main/java/com/desiredsoftware/socialquiz/ui/question/QuestionResultFragment.kt b/app/src/main/java/com/desiredsoftware/socialquiz/ui/question/QuestionResultFragment.kt index 9642d75..f46d837 100644 --- a/app/src/main/java/com/desiredsoftware/socialquiz/ui/question/QuestionResultFragment.kt +++ b/app/src/main/java/com/desiredsoftware/socialquiz/ui/question/QuestionResultFragment.kt @@ -60,14 +60,12 @@ class QuestionResultFragment : Fragment() { } }) - buttonNextQuestion.setOnClickListener(object : View.OnClickListener{ - override fun onClick(v: View?) { - // TODO: Replace for real method, at now imitation working - val nextQuestion : Question = getNextQuestion() - val action = QuestionResultFragmentDirections.actionQuestionResultFragmentToQuestionShowingFragment(nextQuestion) - requireParentFragment().findNavController().navigate(action) - } - }) + buttonNextQuestion.setOnClickListener { + // TODO: Replace for real method, at now imitation working + val nextQuestion: Question = getNextQuestion() + val action = QuestionResultFragmentDirections.actionQuestionResultFragmentToQuestionShowingFragment(nextQuestion) + requireParentFragment().findNavController().navigate(action) + } buttonChangeCategory.setOnClickListener(object : View.OnClickListener{ override fun onClick(v: View?) { diff --git a/app/src/test/java/com/desiredsoftware/socialquiz/ApiClientUnitTests.kt b/app/src/test/java/com/desiredsoftware/socialquiz/ApiClientUnitTests.kt index 59f8f30..ac1bc95 100644 --- a/app/src/test/java/com/desiredsoftware/socialquiz/ApiClientUnitTests.kt +++ b/app/src/test/java/com/desiredsoftware/socialquiz/ApiClientUnitTests.kt @@ -1,7 +1,7 @@ package com.desiredsoftware.socialquiz import com.desiredsoftware.socialquiz.api.`in`.ApiClientFirebase -import com.desiredsoftware.socialquiz.data.model.question.GetQuestionCallback +import com.desiredsoftware.socialquiz.data.model.question.GetQuestionsCallback import org.junit.Assert import org.junit.Test @@ -13,18 +13,20 @@ class ApiClientUnitTests { val category: String = "Music" val client: ApiClientFirebase = ApiClientFirebase() - val questionCallback: GetQuestionCallback + val questionsCallback: GetQuestionsCallback lateinit var questions: ArrayList - client.getQuestion(category, object : GetQuestionCallback { +/* + client.getQuestion(category, object : GetQuestionsCallback { override fun onCallback(questionsArray: ArrayList) { questions = questionsArray } }) +*/ - Assert.assertEquals(true, true) + Assert.assertEquals(true, false) } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 24d1382..9b0c57f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,24 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.4.10" repositories { google() jcenter() } dependencies { - classpath "com.android.tools.build:gradle:4.1.0" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "com.android.tools.build:gradle:4.1.2" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31" + classpath 'com.google.gms:google-services:4.3.5' - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + + // Safe args for navigation + def nav_version = "2.3.2" + classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" + + // Google services + classpath 'com.google.gms:google-services:4.3.5' + + // Crashlytics + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1' } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f781ad1..392418c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Nov 23 18:05:46 YEKT 2020 +#Mon Nov 30 17:17:28 YEKT 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip