From 35df23c15b5ba4cf28038938cd0912b46821f167 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Wed, 12 Jun 2024 17:40:05 +0530 Subject: [PATCH 01/15] fix --- .../database/entities/OfflineAttemptAnswer.kt | 9 ++++++ .../database/entities/OfflineAttemptItem.kt | 32 +++++++++++++++++++ .../entities/OfflineAttemptQuestion.kt | 16 ++++++++++ .../entities/OfflineAttemptSection.kt | 18 +++++++++++ .../entities/OfflineUserUploadedFile.kt | 10 ++++++ 5 files changed, 85 insertions(+) create mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt create mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt create mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt create mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt create mode 100644 core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt new file mode 100644 index 000000000..9e75644a9 --- /dev/null +++ b/core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt @@ -0,0 +1,9 @@ +package `in`.testpress.database.entities + +import androidx.room.Entity + +@Entity +data class OfflineAttemptAnswer( + var textHtml: String? = null, + var id: Int? = null, +) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt new file mode 100644 index 000000000..80e3a4f1e --- /dev/null +++ b/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt @@ -0,0 +1,32 @@ +package `in`.testpress.database.entities + +import androidx.room.Entity + +@Entity +data class OfflineAttemptItem( + val id: Int? = null, + val url: String? = null, + val question: OfflineAttemptQuestion? = null, + val selectedAnswers: List = ArrayList(), + val review: Boolean? = null, + var savedAnswers: List = ArrayList(), + val index: Int? = null, + val currentReview: Boolean? = null, + val shortText: String? = null, + val currentShortText: String? = null, + val attemptSection: OfflineAttemptSection? = null, + val essayText: String? = null, + val localEssayText: String? = null, + val files: List = ArrayList(), + val unSyncedFiles: List = ArrayList() +) + + + + + + + + + + diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt new file mode 100644 index 000000000..de532f609 --- /dev/null +++ b/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt @@ -0,0 +1,16 @@ +package `in`.testpress.database.entities + +import androidx.room.Entity + +@Entity +data class OfflineAttemptQuestion( + val questionHtml: String? = null, + val answers: List = ArrayList(), + val subject: String? = null, + val direction: String? = null, + val type: String? = null, + val language: String? = null, + val translations: ArrayList = ArrayList(), + val marks: String? = null, + val negativeMarks: String? = null +) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt new file mode 100644 index 000000000..59765f918 --- /dev/null +++ b/core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt @@ -0,0 +1,18 @@ +package `in`.testpress.database.entities + +import androidx.room.Entity + +@Entity +data class OfflineAttemptSection( + val attemptSectionId: Long? = null, + val state: String? = null, + val questionsUrl: String? = null, + val startUrl: String? = null, + val endUrl: String? = null, + var remainingTime: String? = null, + val name: String? = null, + val duration: String? = null, + val order: Int? = null, + val instructions: String? = null, + val attemptId: Long? = null, +) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt b/core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt new file mode 100644 index 000000000..fe9c15692 --- /dev/null +++ b/core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt @@ -0,0 +1,10 @@ +package `in`.testpress.database.entities + +import androidx.room.Entity + +@Entity +data class OfflineUserUploadedFile( + val id: Long? = null, + val url: String? = null, + val path: String? = null +) From 888fe55080a5c3e6f44809476f501e0273d89596 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Wed, 12 Jun 2024 17:55:18 +0530 Subject: [PATCH 02/15] refcator --- .../in/testpress/database/entities/OfflineAttemptItem.kt | 4 ++++ .../testpress/database/entities/OfflineAttemptQuestion.kt | 3 +++ .../main/java/in/testpress/database/entities/Question.kt | 8 +++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt index 80e3a4f1e..9f77df514 100644 --- a/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt +++ b/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt @@ -1,11 +1,13 @@ package `in`.testpress.database.entities +import androidx.room.Embedded import androidx.room.Entity @Entity data class OfflineAttemptItem( val id: Int? = null, val url: String? = null, + @Embedded val question: OfflineAttemptQuestion? = null, val selectedAnswers: List = ArrayList(), val review: Boolean? = null, @@ -14,9 +16,11 @@ data class OfflineAttemptItem( val currentReview: Boolean? = null, val shortText: String? = null, val currentShortText: String? = null, + @Embedded val attemptSection: OfflineAttemptSection? = null, val essayText: String? = null, val localEssayText: String? = null, + @Embedded val files: List = ArrayList(), val unSyncedFiles: List = ArrayList() ) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt index de532f609..3fd17af34 100644 --- a/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt +++ b/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt @@ -1,15 +1,18 @@ package `in`.testpress.database.entities +import androidx.room.Embedded import androidx.room.Entity @Entity data class OfflineAttemptQuestion( val questionHtml: String? = null, + @Embedded val answers: List = ArrayList(), val subject: String? = null, val direction: String? = null, val type: String? = null, val language: String? = null, + @Embedded val translations: ArrayList = ArrayList(), val marks: String? = null, val negativeMarks: String? = null diff --git a/core/src/main/java/in/testpress/database/entities/Question.kt b/core/src/main/java/in/testpress/database/entities/Question.kt index 76de88ed9..a09c1febb 100644 --- a/core/src/main/java/in/testpress/database/entities/Question.kt +++ b/core/src/main/java/in/testpress/database/entities/Question.kt @@ -14,4 +14,10 @@ data class Question( val answerIds: List? = null, val directionId: Long? = null, val translations: ArrayList = arrayListOf(), -) \ No newline at end of file +) + + + + + + From 1734fec2fc098edd242d30c9018d4a0cf745ca3e Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Wed, 12 Jun 2024 17:58:50 +0530 Subject: [PATCH 03/15] refcator --- .../database/entities/OfflineAttemptItem.kt | 12 +----------- .../java/in/testpress/database/entities/Question.kt | 8 +------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt index 9f77df514..d576ad101 100644 --- a/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt +++ b/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt @@ -23,14 +23,4 @@ data class OfflineAttemptItem( @Embedded val files: List = ArrayList(), val unSyncedFiles: List = ArrayList() -) - - - - - - - - - - +) \ No newline at end of file diff --git a/core/src/main/java/in/testpress/database/entities/Question.kt b/core/src/main/java/in/testpress/database/entities/Question.kt index a09c1febb..76de88ed9 100644 --- a/core/src/main/java/in/testpress/database/entities/Question.kt +++ b/core/src/main/java/in/testpress/database/entities/Question.kt @@ -14,10 +14,4 @@ data class Question( val answerIds: List? = null, val directionId: Long? = null, val translations: ArrayList = arrayListOf(), -) - - - - - - +) \ No newline at end of file From 58493ccf752d8bc821e6444521174d171880d5df Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Thu, 13 Jun 2024 13:17:33 +0530 Subject: [PATCH 04/15] refcator --- .../in/testpress/database/entities/OfflineLanguage.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt diff --git a/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt b/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt new file mode 100644 index 000000000..596ba7d12 --- /dev/null +++ b/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt @@ -0,0 +1,11 @@ +package `in`.testpress.database.entities + +import androidx.room.Entity + +@Entity +data class OfflineLanguage( + val id: Long? = null, + val code: String? = null, + val title: String? = null, + val examId: Long? = null +) \ No newline at end of file From bbe5ac9d55d32503d4c7950ee2e7acea1e02828a Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Thu, 13 Jun 2024 13:25:47 +0530 Subject: [PATCH 05/15] refcator --- .../main/java/in/testpress/database/entities/OfflineLanguage.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt b/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt index 596ba7d12..32810f8da 100644 --- a/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt +++ b/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt @@ -3,7 +3,7 @@ package `in`.testpress.database.entities import androidx.room.Entity @Entity -data class OfflineLanguage( +data class Language( val id: Long? = null, val code: String? = null, val title: String? = null, From de02260fe924225cd2e7233f80e42927590aa1f9 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Thu, 13 Jun 2024 13:27:06 +0530 Subject: [PATCH 06/15] refcator --- .../in/testpress/database/entities/OfflineLanguage.kt | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt diff --git a/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt b/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt deleted file mode 100644 index 32810f8da..000000000 --- a/core/src/main/java/in/testpress/database/entities/OfflineLanguage.kt +++ /dev/null @@ -1,11 +0,0 @@ -package `in`.testpress.database.entities - -import androidx.room.Entity - -@Entity -data class Language( - val id: Long? = null, - val code: String? = null, - val title: String? = null, - val examId: Long? = null -) \ No newline at end of file From c59bfe408f2d2e4e43edc23c21d37c6a88641eb1 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Thu, 20 Jun 2024 12:43:33 +0530 Subject: [PATCH 07/15] fix --- .../database/entities/OfflineAttemptAnswer.kt | 9 ------- .../database/entities/OfflineAttemptItem.kt | 26 ------------------- .../entities/OfflineAttemptQuestion.kt | 19 -------------- .../entities/OfflineAttemptSection.kt | 18 ------------- .../entities/OfflineUserUploadedFile.kt | 10 ------- 5 files changed, 82 deletions(-) delete mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt delete mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt delete mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt delete mode 100644 core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt delete mode 100644 core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt deleted file mode 100644 index 9e75644a9..000000000 --- a/core/src/main/java/in/testpress/database/entities/OfflineAttemptAnswer.kt +++ /dev/null @@ -1,9 +0,0 @@ -package `in`.testpress.database.entities - -import androidx.room.Entity - -@Entity -data class OfflineAttemptAnswer( - var textHtml: String? = null, - var id: Int? = null, -) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt deleted file mode 100644 index d576ad101..000000000 --- a/core/src/main/java/in/testpress/database/entities/OfflineAttemptItem.kt +++ /dev/null @@ -1,26 +0,0 @@ -package `in`.testpress.database.entities - -import androidx.room.Embedded -import androidx.room.Entity - -@Entity -data class OfflineAttemptItem( - val id: Int? = null, - val url: String? = null, - @Embedded - val question: OfflineAttemptQuestion? = null, - val selectedAnswers: List = ArrayList(), - val review: Boolean? = null, - var savedAnswers: List = ArrayList(), - val index: Int? = null, - val currentReview: Boolean? = null, - val shortText: String? = null, - val currentShortText: String? = null, - @Embedded - val attemptSection: OfflineAttemptSection? = null, - val essayText: String? = null, - val localEssayText: String? = null, - @Embedded - val files: List = ArrayList(), - val unSyncedFiles: List = ArrayList() -) \ No newline at end of file diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt deleted file mode 100644 index 3fd17af34..000000000 --- a/core/src/main/java/in/testpress/database/entities/OfflineAttemptQuestion.kt +++ /dev/null @@ -1,19 +0,0 @@ -package `in`.testpress.database.entities - -import androidx.room.Embedded -import androidx.room.Entity - -@Entity -data class OfflineAttemptQuestion( - val questionHtml: String? = null, - @Embedded - val answers: List = ArrayList(), - val subject: String? = null, - val direction: String? = null, - val type: String? = null, - val language: String? = null, - @Embedded - val translations: ArrayList = ArrayList(), - val marks: String? = null, - val negativeMarks: String? = null -) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt b/core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt deleted file mode 100644 index 59765f918..000000000 --- a/core/src/main/java/in/testpress/database/entities/OfflineAttemptSection.kt +++ /dev/null @@ -1,18 +0,0 @@ -package `in`.testpress.database.entities - -import androidx.room.Entity - -@Entity -data class OfflineAttemptSection( - val attemptSectionId: Long? = null, - val state: String? = null, - val questionsUrl: String? = null, - val startUrl: String? = null, - val endUrl: String? = null, - var remainingTime: String? = null, - val name: String? = null, - val duration: String? = null, - val order: Int? = null, - val instructions: String? = null, - val attemptId: Long? = null, -) diff --git a/core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt b/core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt deleted file mode 100644 index fe9c15692..000000000 --- a/core/src/main/java/in/testpress/database/entities/OfflineUserUploadedFile.kt +++ /dev/null @@ -1,10 +0,0 @@ -package `in`.testpress.database.entities - -import androidx.room.Entity - -@Entity -data class OfflineUserUploadedFile( - val id: Long? = null, - val url: String? = null, - val path: String? = null -) From c2caf7d9cb8cf25875755fa833335d94d8ce1ed4 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Thu, 20 Jun 2024 15:07:25 +0530 Subject: [PATCH 08/15] temp --- commonlib/commonlib.aar | 4 +-- .../fragments/BaseExamWidgetFragment.kt | 15 ++++++++ .../testpress/course/network/CourseService.kt | 4 +++ .../repository/OfflineExamRepository.kt | 34 +++++++++++++++++++ .../course/viewmodels/OfflineExamViewModel.kt | 11 ++++++ .../src/main/res/layout/exam_start_screen.xml | 17 +++++++++- mobilertc/mobilertc.aar | 4 +-- .../core/TestpressCoreSampleActivity.java | 4 +-- 8 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt create mode 100644 course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt diff --git a/commonlib/commonlib.aar b/commonlib/commonlib.aar index 956289700..31e82d6de 100644 --- a/commonlib/commonlib.aar +++ b/commonlib/commonlib.aar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d5543d28b82831f63372e0e72f6c07bf27c6970f8cf03b2838a7bede3935aa5 -size 1060342 +oid sha256:0f01ce2466a88f245ce7e9ddd9d9e806ae8a2c0e7ada3b84ff1809936860b8c2 +size 4093070 diff --git a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt index 856ea833c..c6fe4ac41 100644 --- a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt +++ b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt @@ -14,10 +14,12 @@ import `in`.testpress.exam.domain.toGreenDaoModels import `in`.testpress.enums.Status import `in`.testpress.network.Resource import `in`.testpress.course.repository.ExamContentRepository +import `in`.testpress.course.repository.OfflineExamRepository import `in`.testpress.course.ui.ContentActivity import `in`.testpress.course.ui.QuizActivity import `in`.testpress.course.ui.WebViewWithSSO import `in`.testpress.course.viewmodels.ExamContentViewModel +import `in`.testpress.course.viewmodels.OfflineExamViewModel import `in`.testpress.exam.TestpressExam import `in`.testpress.exam.api.TestpressExamApiClient import `in`.testpress.exam.util.MultiLanguagesUtil @@ -36,7 +38,9 @@ import androidx.lifecycle.ViewModelProvider open class BaseExamWidgetFragment : Fragment() { lateinit var startButton: Button + lateinit var downloadExamButton: Button protected lateinit var viewModel: ExamContentViewModel + protected lateinit var offlineExamViewModel: OfflineExamViewModel protected lateinit var content: DomainContent protected var contentId: Long = -1 lateinit var contentAttempts: ArrayList @@ -51,6 +55,13 @@ open class BaseExamWidgetFragment : Fragment() { ) as T } }).get(ExamContentViewModel::class.java) + offlineExamViewModel = ViewModelProvider(this, object : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return OfflineExamViewModel( + OfflineExamRepository(context!!) + ) as T + } + }).get(OfflineExamViewModel::class.java) } override fun onAttach(context: Context) { @@ -65,6 +76,7 @@ open class BaseExamWidgetFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) startButton = view.findViewById(R.id.start_exam) + downloadExamButton = view.findViewById(R.id.download_exam) contentId = requireArguments().getLong(ContentActivity.CONTENT_ID) viewModel.getContent(contentId).observe(viewLifecycleOwner, Observer { @@ -129,6 +141,9 @@ open class BaseExamWidgetFragment : Fragment() { updateStartButtonTextAndVisibility(exam, pausedAttempt) updateStartButtonListener(exam, pausedAttempt) + downloadExamButton.setOnClickListener { + offlineExamViewModel.fetch(contentId) + } } private fun updateStartButtonTextAndVisibility(exam: DomainExamContent, pausedAttempt: DomainContentAttempt?) { diff --git a/course/src/main/java/in/testpress/course/network/CourseService.kt b/course/src/main/java/in/testpress/course/network/CourseService.kt index 33bcd53c4..0618f1af9 100644 --- a/course/src/main/java/in/testpress/course/network/CourseService.kt +++ b/course/src/main/java/in/testpress/course/network/CourseService.kt @@ -130,4 +130,8 @@ class CourseNetwork(context: Context) : TestpressApiClient(context, TestpressSdk suspend fun getUpcomingContents(courseId: Long, arguments: HashMap): ApiResponse> { return getCourseService().getUpcomingContents(courseId, arguments) } + + fun getNetworkContentWithId(contentId: Long): RetrofitCall { + return getCourseService().getNetworkContent("https://lmsdemo.testpress.in/api/v2.4/contents/$contentId/") + } } \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt new file mode 100644 index 000000000..8c872829d --- /dev/null +++ b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt @@ -0,0 +1,34 @@ +package `in`.testpress.course.repository + +import `in`.testpress.core.TestpressCallback +import `in`.testpress.core.TestpressException +import `in`.testpress.course.network.CourseNetwork +import `in`.testpress.course.network.NetworkContent +import android.content.Context + +class OfflineExamRepository(val context: Context) { + + fun get(){ + + } + + fun getAll() { + + } + + fun fetch(contentId: Long) { + val courseClient = CourseNetwork(context) + courseClient.getNetworkContentWithId(contentId).enqueue( + object : TestpressCallback() { + override fun onSuccess(result: NetworkContent?) { + println(result) + } + + override fun onException(exception: TestpressException?) { + } + + } + ) + } + +} \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt b/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt new file mode 100644 index 000000000..ca342578e --- /dev/null +++ b/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt @@ -0,0 +1,11 @@ +package `in`.testpress.course.viewmodels + +import `in`.testpress.course.repository.OfflineExamRepository +import androidx.lifecycle.ViewModel + +class OfflineExamViewModel(private val offlineExamViewModel: OfflineExamRepository): ViewModel() { + + fun fetch(contentId: Long) { + offlineExamViewModel.fetch(contentId) + } +} \ No newline at end of file diff --git a/course/src/main/res/layout/exam_start_screen.xml b/course/src/main/res/layout/exam_start_screen.xml index f90c96f80..8008034f3 100644 --- a/course/src/main/res/layout/exam_start_screen.xml +++ b/course/src/main/res/layout/exam_start_screen.xml @@ -13,7 +13,8 @@ + android:layout_marginBottom="50dp" + android:orientation="vertical"> + + \ No newline at end of file diff --git a/mobilertc/mobilertc.aar b/mobilertc/mobilertc.aar index b8d0cd140..0a443ccdc 100644 --- a/mobilertc/mobilertc.aar +++ b/mobilertc/mobilertc.aar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d0b81522154d395a42dca703872e64406f662bc3a603a3d1f9bd15daf7842dc -size 115487216 +oid sha256:7ce42b087a71eef490699a7fa682d0a7875b0b516ea94a1792db5f1a88fd3e86 +size 241348514 diff --git a/samples/src/main/java/in/testpress/samples/core/TestpressCoreSampleActivity.java b/samples/src/main/java/in/testpress/samples/core/TestpressCoreSampleActivity.java index 20c4bf296..5eb1ca97f 100644 --- a/samples/src/main/java/in/testpress/samples/core/TestpressCoreSampleActivity.java +++ b/samples/src/main/java/in/testpress/samples/core/TestpressCoreSampleActivity.java @@ -119,8 +119,8 @@ public void onClick(View view) { } private void authenticate(String userId, String accessToken, TestpressSdk.Provider provider) { - InstituteSettings instituteSettings = new InstituteSettings("https://sandbox.testpress.in"); - instituteSettings.setWhiteLabeledHostUrl("https://sandbox.testpress.in"); + InstituteSettings instituteSettings = new InstituteSettings("https://lmsdemo.testpress.in"); + instituteSettings.setWhiteLabeledHostUrl("https://lmsdemo.testpress.in"); instituteSettings.setAndroidSentryDns("https://186f9948d5294b4c9c03aa9d2a11c982@sentry.testpress.in/3"); TestpressSdk.initialize(this, instituteSettings, userId, accessToken, provider, new TestpressCallback() { From 4c9c58467c07567baaf288035173bae13059fad9 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Thu, 20 Jun 2024 19:58:07 +0530 Subject: [PATCH 09/15] refcator --- .../in/testpress/database/dao/LanguageDao.kt | 19 +++++++++++++++++++ .../testpress/database/dao/OfflineExamDao.kt | 17 +++++++++++++++++ .../network/NetworkOfflineQuestionResponse.kt | 4 ++++ .../course/ui/OfflineExamListActivity.kt | 4 ++++ .../res/layout/activity_offline_exam_list.xml | 6 ++++++ .../src/main/res/layout/item_offline_exam.xml | 6 ++++++ 6 files changed, 56 insertions(+) create mode 100644 core/src/main/java/in/testpress/database/dao/LanguageDao.kt create mode 100644 core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt create mode 100644 course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt create mode 100644 course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt create mode 100644 course/src/main/res/layout/activity_offline_exam_list.xml create mode 100644 course/src/main/res/layout/item_offline_exam.xml diff --git a/core/src/main/java/in/testpress/database/dao/LanguageDao.kt b/core/src/main/java/in/testpress/database/dao/LanguageDao.kt new file mode 100644 index 000000000..69856c99b --- /dev/null +++ b/core/src/main/java/in/testpress/database/dao/LanguageDao.kt @@ -0,0 +1,19 @@ +package `in`.testpress.database.dao + +import `in`.testpress.database.BaseDao +import `in`.testpress.database.entities.CategoryEntity +import `in`.testpress.database.entities.OfflineExam +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Query + +@Dao +interface OfflineExamDao: BaseDao { + + @Query("SELECT * FROM OfflineExam ") + fun getAll(): LiveData> + + @Query("SELECT * FROM OfflineExam WHERE id = :examId") + fun get(examId: Long): OfflineExam? + +} \ No newline at end of file diff --git a/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt b/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt new file mode 100644 index 000000000..6b75b540c --- /dev/null +++ b/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt @@ -0,0 +1,17 @@ +package `in`.testpress.database.dao + +import `in`.testpress.database.BaseDao +import `in`.testpress.database.entities.CategoryEntity +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Query + +@Dao +interface CategoryDao: BaseDao { + + @Query("SELECT * FROM CATEGORYENTITY ") + fun getAll(): LiveData> + + @Query("DELETE FROM CATEGORYENTITY") + suspend fun deleteAll() +} \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt b/course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt new file mode 100644 index 000000000..f3367d44f --- /dev/null +++ b/course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt @@ -0,0 +1,4 @@ +package `in`.testpress.course.network + +class NetworkOfflineQuestionResponse { +} \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt new file mode 100644 index 000000000..e83a093fe --- /dev/null +++ b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt @@ -0,0 +1,4 @@ +package `in`.testpress.course.ui + +class OfflineExamListActivity { +} \ No newline at end of file diff --git a/course/src/main/res/layout/activity_offline_exam_list.xml b/course/src/main/res/layout/activity_offline_exam_list.xml new file mode 100644 index 000000000..cdc89f25a --- /dev/null +++ b/course/src/main/res/layout/activity_offline_exam_list.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/course/src/main/res/layout/item_offline_exam.xml b/course/src/main/res/layout/item_offline_exam.xml new file mode 100644 index 000000000..cdc89f25a --- /dev/null +++ b/course/src/main/res/layout/item_offline_exam.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file From e1ac1ca5f1962cfd13dee61309e6132c8ddafb93 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Thu, 20 Jun 2024 19:58:27 +0530 Subject: [PATCH 10/15] temo2 --- .../main/java/in/testpress/database/Room.kt | 2 + .../in/testpress/database/dao/LanguageDao.kt | 11 +-- .../testpress/database/dao/OfflineExamDao.kt | 12 ++- course/src/main/AndroidManifest.xml | 5 + .../fragments/BaseExamWidgetFragment.kt | 48 ++++++++- .../testpress/course/network/CourseService.kt | 24 +++++ .../course/network/NetworkContent.kt | 47 +++++++++ .../network/NetworkOfflineQuestionResponse.kt | 11 ++- .../repository/OfflineExamRepository.kt | 98 ++++++++++++++++--- .../course/ui/OfflineExamListActivity.kt | 74 +++++++++++++- .../course/viewmodels/OfflineExamViewModel.kt | 72 +++++++++++++- .../res/layout/activity_offline_exam_list.xml | 15 ++- .../src/main/res/layout/exam_start_screen.xml | 9 ++ .../src/main/res/layout/item_offline_exam.xml | 46 ++++++++- .../testpress/exam/network/NetworkLanguage.kt | 15 +++ .../samples/course/CourseSampleActivity.java | 13 +++ .../src/main/res/layout/activity_open_in.xml | 5 + 17 files changed, 466 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/in/testpress/database/Room.kt b/core/src/main/java/in/testpress/database/Room.kt index 2fadaefd3..70773a346 100644 --- a/core/src/main/java/in/testpress/database/Room.kt +++ b/core/src/main/java/in/testpress/database/Room.kt @@ -68,6 +68,8 @@ abstract class TestpressDatabase : RoomDatabase() { abstract fun productCategoryDao(): ProductCategoryDao abstract fun contentLiteDao(): ContentLiteDao abstract fun contentLiteRemoteKeyDao():ContentLiteRemoteKeyDao + abstract fun offlineExamDao():OfflineExamDao + abstract fun languageDao(): LanguageDao companion object { private lateinit var INSTANCE: TestpressDatabase diff --git a/core/src/main/java/in/testpress/database/dao/LanguageDao.kt b/core/src/main/java/in/testpress/database/dao/LanguageDao.kt index 69856c99b..bd5c2e471 100644 --- a/core/src/main/java/in/testpress/database/dao/LanguageDao.kt +++ b/core/src/main/java/in/testpress/database/dao/LanguageDao.kt @@ -2,18 +2,11 @@ package `in`.testpress.database.dao import `in`.testpress.database.BaseDao import `in`.testpress.database.entities.CategoryEntity +import `in`.testpress.database.entities.Language import `in`.testpress.database.entities.OfflineExam import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Query @Dao -interface OfflineExamDao: BaseDao { - - @Query("SELECT * FROM OfflineExam ") - fun getAll(): LiveData> - - @Query("SELECT * FROM OfflineExam WHERE id = :examId") - fun get(examId: Long): OfflineExam? - -} \ No newline at end of file +interface LanguageDao: BaseDao \ No newline at end of file diff --git a/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt b/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt index 6b75b540c..69856c99b 100644 --- a/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt +++ b/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt @@ -2,16 +2,18 @@ package `in`.testpress.database.dao import `in`.testpress.database.BaseDao import `in`.testpress.database.entities.CategoryEntity +import `in`.testpress.database.entities.OfflineExam import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Query @Dao -interface CategoryDao: BaseDao { +interface OfflineExamDao: BaseDao { - @Query("SELECT * FROM CATEGORYENTITY ") - fun getAll(): LiveData> + @Query("SELECT * FROM OfflineExam ") + fun getAll(): LiveData> + + @Query("SELECT * FROM OfflineExam WHERE id = :examId") + fun get(examId: Long): OfflineExam? - @Query("DELETE FROM CATEGORYENTITY") - suspend fun deleteAll() } \ No newline at end of file diff --git a/course/src/main/AndroidManifest.xml b/course/src/main/AndroidManifest.xml index 58cbe89ba..ce92d02f4 100644 --- a/course/src/main/AndroidManifest.xml +++ b/course/src/main/AndroidManifest.xml @@ -104,6 +104,11 @@ android:configChanges="orientation|keyboardHidden|screenSize" android:theme="@style/TestpressTheme" /> + + diff --git a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt index c6fe4ac41..e42f6b81c 100644 --- a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt +++ b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt @@ -30,6 +30,8 @@ import android.content.Intent import android.os.Bundle import android.view.View import android.widget.Button +import android.widget.ProgressBar +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import androidx.lifecycle.Observer @@ -38,7 +40,8 @@ import androidx.lifecycle.ViewModelProvider open class BaseExamWidgetFragment : Fragment() { lateinit var startButton: Button - lateinit var downloadExamButton: Button + private lateinit var downloadExamButton: Button + private lateinit var loadingProgressBar: ProgressBar protected lateinit var viewModel: ExamContentViewModel protected lateinit var offlineExamViewModel: OfflineExamViewModel protected lateinit var content: DomainContent @@ -77,6 +80,7 @@ open class BaseExamWidgetFragment : Fragment() { super.onViewCreated(view, savedInstanceState) startButton = view.findViewById(R.id.start_exam) downloadExamButton = view.findViewById(R.id.download_exam) + loadingProgressBar = view.findViewById(R.id.loading_progress_bar) contentId = requireArguments().getLong(ContentActivity.CONTENT_ID) viewModel.getContent(contentId).observe(viewLifecycleOwner, Observer { @@ -84,12 +88,51 @@ open class BaseExamWidgetFragment : Fragment() { Status.SUCCESS -> { content = it.data!! loadAttemptsAndUpdateStartButton() + checkExamIsDownloaded() + observeViewModelLoading() + observeDownloadComplete() + downloadExamButton.setOnClickListener { + offlineExamViewModel.downloadExam(contentId, content.exam?.id!!, content.exam?.slug!!) + } } else -> {} } }) } + private fun checkExamIsDownloaded() { + offlineExamViewModel.checkIfExamIsDownloaded(content.exam?.id!!) + offlineExamViewModel.isExamDownloaded.observe(viewLifecycleOwner, Observer { isDownloaded -> + if (isDownloaded) { + downloadExamButton.visibility = View.VISIBLE + downloadExamButton.text = "Start Exam in Offline" + } else { + downloadExamButton.visibility = View.VISIBLE + } + }) + } + + private fun observeViewModelLoading() { + offlineExamViewModel.isLoading.observe(requireActivity(), Observer { isLoading -> + loadingProgressBar.visibility = if (isLoading) View.VISIBLE else View.GONE + downloadExamButton.visibility = if (isLoading) View.GONE else View.VISIBLE + }) + } + + private fun observeDownloadComplete() { + offlineExamViewModel.downloadComplete.observe(requireActivity(), Observer { result -> + val message = when (result.status) { + Status.SUCCESS -> { + downloadExamButton.text = "Start Exam in Offline" + "Download successful" + } + Status.ERROR -> "Download failed: ${result.exception?.message}" + Status.LOADING -> return@Observer + } + Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() + }) + } + fun loadAttemptsAndUpdateStartButton() { val observer = Observer>> { resource -> examRefreshListener.showOrHideRefresh(false) @@ -141,9 +184,6 @@ open class BaseExamWidgetFragment : Fragment() { updateStartButtonTextAndVisibility(exam, pausedAttempt) updateStartButtonListener(exam, pausedAttempt) - downloadExamButton.setOnClickListener { - offlineExamViewModel.fetch(contentId) - } } private fun updateStartButtonTextAndVisibility(exam: DomainExamContent, pausedAttempt: DomainContentAttempt?) { diff --git a/course/src/main/java/in/testpress/course/network/CourseService.kt b/course/src/main/java/in/testpress/course/network/CourseService.kt index 0618f1af9..0d133107a 100644 --- a/course/src/main/java/in/testpress/course/network/CourseService.kt +++ b/course/src/main/java/in/testpress/course/network/CourseService.kt @@ -5,7 +5,9 @@ import `in`.testpress.course.api.TestpressCourseApiClient import `in`.testpress.course.api.TestpressCourseApiClient.* import `in`.testpress.database.entities.ContentEntityLite import `in`.testpress.database.entities.ProductCategoryEntity +import `in`.testpress.exam.api.TestpressExamApiClient import `in`.testpress.exam.network.NetworkAttempt +import `in`.testpress.exam.network.NetworkLanguage import `in`.testpress.models.TestpressApiResponse import `in`.testpress.models.greendao.Course import `in`.testpress.network.RetrofitCall @@ -73,6 +75,17 @@ interface CourseService { @Path(value = "course_id", encoded = true) courseId: Long, @QueryMap queryParams: HashMap ): ApiResponse> + + @GET("api/v2.4/exams/{exam_id}/questions/") + fun getQuestions( + @Path(value = "exam_id", encoded = true) examId: Long, + @QueryMap queryParams: HashMap + ): RetrofitCall> + + @GET("${TestpressExamApiClient.EXAMS_LIST_v2_3_PATH}{exam_slug}${TestpressExamApiClient.LANGUAGES_PATH}") + fun getLanguages( + @Path(value = "exam_slug", encoded = true) examSlug: String? + ): RetrofitCall> } @@ -134,4 +147,15 @@ class CourseNetwork(context: Context) : TestpressApiClient(context, TestpressSdk fun getNetworkContentWithId(contentId: Long): RetrofitCall { return getCourseService().getNetworkContent("https://lmsdemo.testpress.in/api/v2.4/contents/$contentId/") } + + fun getQuestions( + examId: Long, + queryParams: HashMap + ): RetrofitCall> { + return getCourseService().getQuestions(examId, queryParams) + } + + fun getLanguages(slug: String): RetrofitCall> { + return getCourseService().getLanguages(slug) + } } \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/network/NetworkContent.kt b/course/src/main/java/in/testpress/course/network/NetworkContent.kt index d434345d1..d017443a9 100644 --- a/course/src/main/java/in/testpress/course/network/NetworkContent.kt +++ b/course/src/main/java/in/testpress/course/network/NetworkContent.kt @@ -1,8 +1,10 @@ package `in`.testpress.course.network import `in`.testpress.database.ContentEntity +import `in`.testpress.database.entities.OfflineExam import `in`.testpress.exam.network.NetworkExamContent import `in`.testpress.models.greendao.Content +import android.util.Log data class NetworkContent( val id: Long, @@ -141,3 +143,48 @@ fun NetworkContent.asGreenDaoModel(): Content { this.examId ) } + +fun NetworkContent.asOfflineExam(): OfflineExam { + return OfflineExam( + this.exam?.id, + this.exam?.totalMarks, + this.exam?.url, + this.exam?.attemptsCount, + this.exam?.pausedAttemptsCount, + this.exam?.title, + this.exam?.description, + this.exam?.startDate, + this.exam?.endDate, + this.exam?.duration, + this.exam?.numberOfQuestions, + this.exam?.negativeMarks, + this.exam?.markPerQuestion, + this.exam?.templateType, + this.exam?.allowRetake, + this.exam?.allowPdf, + this.exam?.showAnswers, + this.exam?.maxRetakes, + this.exam?.attemptsUrl, + this.exam?.deviceAccessControl, + this.exam?.commentsCount, + this.exam?.slug, + selectedLanguage = null, + this.exam?.variableMarkPerQuestion, + this.exam?.passPercentage, + this.exam?.enableRanks, + this.exam?.showScore, + this.exam?.showPercentile, + categories = null, + isDetailsFetched = null, + this.exam?.isGrowthHackEnabled, + this.exam?.shareTextForSolutionUnlock, + this.exam?.showAnalytics, + this.exam?.instructions, + this.exam?.hasAudioQuestions, + this.exam?.rankPublishingDate, + this.exam?.enableQuizMode, + this.exam?.disableAttemptResume, + this.exam?.allowPreemptiveSectionEnding, + examDataModifiedOn = null + ) +} diff --git a/course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt b/course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt index f3367d44f..edebbc69c 100644 --- a/course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt +++ b/course/src/main/java/in/testpress/course/network/NetworkOfflineQuestionResponse.kt @@ -1,4 +1,11 @@ package `in`.testpress.course.network -class NetworkOfflineQuestionResponse { -} \ No newline at end of file +import `in`.testpress.database.entities.* + +class NetworkOfflineQuestionResponse( + val directions: List, + val subjects: List, + val sections: List
, + val examQuestions: List, + val questions: List +) \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt index 8c872829d..9554e76c0 100644 --- a/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt +++ b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt @@ -4,31 +4,107 @@ import `in`.testpress.core.TestpressCallback import `in`.testpress.core.TestpressException import `in`.testpress.course.network.CourseNetwork import `in`.testpress.course.network.NetworkContent +import `in`.testpress.course.network.NetworkOfflineQuestionResponse +import `in`.testpress.course.network.asOfflineExam +import `in`.testpress.database.TestpressDatabase +import `in`.testpress.database.entities.OfflineExam +import `in`.testpress.exam.network.NetworkLanguage +import `in`.testpress.exam.network.asRoomModels +import `in`.testpress.models.TestpressApiResponse +import `in`.testpress.network.Resource +import `in`.testpress.v2_4.models.ApiResponse import android.content.Context +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class OfflineExamRepository(val context: Context) { - fun get(){ + private val courseClient = CourseNetwork(context) + private val database = TestpressDatabase.invoke(context) + private var offlineExamDao = database.offlineExamDao() + private var languageDao = database.languageDao() + private val _downloadExamResult = MutableLiveData>() + val downloadExamResult: LiveData> get() = _downloadExamResult + + private val _downloadQuestionsResult = MutableLiveData>() + val downloadQuestionsResult: LiveData> get() = _downloadQuestionsResult + + private val _downloadLanguagesResult = MutableLiveData>() + val downloadLanguagesResult: LiveData> get() = _downloadLanguagesResult + + fun downloadExam(contentId: Long) { + courseClient.getNetworkContentWithId(contentId) + .enqueue(object : TestpressCallback() { + override fun onSuccess(result: NetworkContent) { + CoroutineScope(Dispatchers.IO).launch { + offlineExamDao.insert(result.asOfflineExam()) + _downloadExamResult.postValue(Resource.success(true)) + } + } + + override fun onException(exception: TestpressException) { + _downloadExamResult.postValue(Resource.error(exception, null)) + } + }) } - fun getAll() { + fun downloadQuestions(examId: Long) { + var page = 1 + fun fetchQuestionsPage() { + val queryParams = hashMapOf("page" to page) + courseClient.getQuestions(examId, queryParams) + .enqueue(object : TestpressCallback>() { + override fun onSuccess(result: ApiResponse) { + if (result.next != null) { + // Save questions in db + page++ + fetchQuestionsPage() + } else { + // Save questions in db + _downloadQuestionsResult.postValue(Resource.success(true)) + } + } + + override fun onException(exception: TestpressException) { + _downloadQuestionsResult.postValue(Resource.error(exception, null)) + } + }) + } + + fetchQuestionsPage() } - fun fetch(contentId: Long) { - val courseClient = CourseNetwork(context) - courseClient.getNetworkContentWithId(contentId).enqueue( - object : TestpressCallback() { - override fun onSuccess(result: NetworkContent?) { - println(result) + fun downloadLanguages(examId: Long, examSlug: String) { + courseClient.getLanguages(examSlug) + .enqueue(object : TestpressCallback>() { + override fun onSuccess(result: TestpressApiResponse) { + CoroutineScope(Dispatchers.IO).launch { + languageDao.insertAll(result.results.asRoomModels(examId)) + _downloadLanguagesResult.postValue(Resource.success(true)) + } } - override fun onException(exception: TestpressException?) { + override fun onException(exception: TestpressException) { + _downloadLanguagesResult.postValue(Resource.error(exception, null)) } + }) + } + + suspend fun isExamDownloaded(examId: Long): Boolean { + return withContext(Dispatchers.IO) { + val offlineExam = offlineExamDao.get(examId) + offlineExam != null + } + } - } - ) + fun getAllOfflineExams(): LiveData> { + return offlineExamDao.getAll() } } \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt index e83a093fe..022dced4e 100644 --- a/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt +++ b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt @@ -1,4 +1,76 @@ package `in`.testpress.course.ui -class OfflineExamListActivity { +import `in`.testpress.course.R +import `in`.testpress.course.repository.OfflineExamRepository +import `in`.testpress.course.viewmodels.OfflineExamViewModel +import `in`.testpress.database.entities.OfflineExam +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView + +class OfflineExamListActivity : AppCompatActivity() { + + private lateinit var recyclerView: RecyclerView + private lateinit var adapter: OfflineExamAdapter + private lateinit var offlineExamViewModel: OfflineExamViewModel + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_offline_exam_list) + + offlineExamViewModel = ViewModelProvider(this, object : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return OfflineExamViewModel( + OfflineExamRepository(this@OfflineExamListActivity) + ) as T + } + }).get(OfflineExamViewModel::class.java) + + recyclerView = findViewById(R.id.recyclerView) + recyclerView.layoutManager = LinearLayoutManager(this) + adapter = OfflineExamAdapter(emptyList()) + recyclerView.adapter = adapter + + offlineExamViewModel.getAllOfflineExams().observe(this) { exams -> + adapter = OfflineExamAdapter(exams) + recyclerView.adapter = adapter + } + } + + inner class OfflineExamAdapter(private val exams: List) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExamViewHolder { + val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_offline_exam, parent, false) + return ExamViewHolder(itemView) + } + + override fun onBindViewHolder(holder: ExamViewHolder, position: Int) { + val exam = exams[position] + holder.bind(exam) + } + + override fun getItemCount(): Int { + return exams.size + } + + inner class ExamViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + private val titleTextView: TextView = itemView.findViewById(R.id.titleTextView) + private val totalTime: TextView = itemView.findViewById(R.id.total_time) + private val totalQuestion: TextView = itemView.findViewById(R.id.number_of_questions) + + fun bind(exam: OfflineExam) { + titleTextView.text = exam.title + totalTime.text = exam.duration + totalQuestion.text = exam.numberOfQuestions.toString() + // Bind other properties of OfflineExam as needed + } + } + } } \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt b/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt index ca342578e..2da513c9e 100644 --- a/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt +++ b/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt @@ -1,11 +1,77 @@ package `in`.testpress.course.viewmodels +import `in`.testpress.core.TestpressException import `in`.testpress.course.repository.OfflineExamRepository +import `in`.testpress.database.entities.OfflineExam +import `in`.testpress.enums.Status +import `in`.testpress.network.Resource +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.launch -class OfflineExamViewModel(private val offlineExamViewModel: OfflineExamRepository): ViewModel() { +class OfflineExamViewModel(private val repository: OfflineExamRepository) : ViewModel() { + private val _isLoading = MutableLiveData() + val isLoading: LiveData get() = _isLoading - fun fetch(contentId: Long) { - offlineExamViewModel.fetch(contentId) + private val _downloadComplete = MutableLiveData>() + val downloadComplete: LiveData> get() = _downloadComplete + + private val _isExamDownloaded = MutableLiveData() + val isExamDownloaded: LiveData get() = _isExamDownloaded + + fun checkIfExamIsDownloaded(examId: Long) { + viewModelScope.launch { + _isExamDownloaded.value = repository.isExamDownloaded(examId) + } + } + + fun downloadExam(courseId: Long, examId: Long, examSlug: String) { + _isLoading.value = true + + repository.downloadExam(courseId) + repository.downloadQuestions(examId) + repository.downloadLanguages(examId, examSlug) + + val results = mutableListOf>() + + repository.downloadExamResult.observeForever { examResult -> + if (examResult != null) { + results.add(examResult) + checkAllResultsComplete(results) + } + } + repository.downloadQuestionsResult.observeForever { questionsResult -> + if (questionsResult != null) { + results.add(questionsResult) + checkAllResultsComplete(results) + } + } + + repository.downloadLanguagesResult.observeForever { languagesResult -> + if (languagesResult != null) { + results.add(languagesResult) + checkAllResultsComplete(results) + } + } + } + + private fun checkAllResultsComplete(results: List>) { + if (results.size == 3) { // Assuming you have exactly 3 API calls + val finalResult = if (results.all { it.status == Status.SUCCESS }) { + Resource.success(true) + } else { + results.firstOrNull { it.status == Status.ERROR } ?: Resource.error( + TestpressException.unexpectedError(Exception("Download Failed")), null + ) + } + _downloadComplete.postValue(finalResult) + _isLoading.postValue(false) + } + } + + fun getAllOfflineExams(): LiveData> { + return repository.getAllOfflineExams() } } \ No newline at end of file diff --git a/course/src/main/res/layout/activity_offline_exam_list.xml b/course/src/main/res/layout/activity_offline_exam_list.xml index cdc89f25a..c45694095 100644 --- a/course/src/main/res/layout/activity_offline_exam_list.xml +++ b/course/src/main/res/layout/activity_offline_exam_list.xml @@ -1,6 +1,17 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".ui.OfflineExamListActivity"> + + \ No newline at end of file diff --git a/course/src/main/res/layout/exam_start_screen.xml b/course/src/main/res/layout/exam_start_screen.xml index 8008034f3..27a0c4299 100644 --- a/course/src/main/res/layout/exam_start_screen.xml +++ b/course/src/main/res/layout/exam_start_screen.xml @@ -42,8 +42,17 @@ android:background="@drawable/testpress_green_curved_edge_background" android:gravity="center" android:text="Download Exam" + android:visibility="gone" android:textColor="@android:color/white" android:textSize="16sp" /> + + + \ No newline at end of file diff --git a/course/src/main/res/layout/item_offline_exam.xml b/course/src/main/res/layout/item_offline_exam.xml index cdc89f25a..205532fd1 100644 --- a/course/src/main/res/layout/item_offline_exam.xml +++ b/course/src/main/res/layout/item_offline_exam.xml @@ -1,6 +1,44 @@ - + - \ No newline at end of file + + + + + + + + + + + + + + \ No newline at end of file diff --git a/exam/src/main/java/in/testpress/exam/network/NetworkLanguage.kt b/exam/src/main/java/in/testpress/exam/network/NetworkLanguage.kt index 7dc5b6898..b84fdfbeb 100644 --- a/exam/src/main/java/in/testpress/exam/network/NetworkLanguage.kt +++ b/exam/src/main/java/in/testpress/exam/network/NetworkLanguage.kt @@ -25,4 +25,19 @@ fun List.asGreenDaoModels(): List { return this.map { createGreenDaoModel(it) } +} + +fun List.asRoomModels(examId: Long): List<`in`.testpress.database.entities.Language>{ + return this.map { + it.asRoomModel(examId) + } +} + +fun NetworkLanguage.asRoomModel(examId: Long): `in`.testpress.database.entities.Language{ + return `in`.testpress.database.entities.Language( + id = this.id, + code = this.code, + title = this.title, + examId = examId + ) } \ No newline at end of file diff --git a/samples/src/main/java/in/testpress/samples/course/CourseSampleActivity.java b/samples/src/main/java/in/testpress/samples/course/CourseSampleActivity.java index 8163619e7..4810b11cd 100644 --- a/samples/src/main/java/in/testpress/samples/course/CourseSampleActivity.java +++ b/samples/src/main/java/in/testpress/samples/course/CourseSampleActivity.java @@ -9,6 +9,7 @@ import in.testpress.core.TestpressSession; import in.testpress.course.TestpressCourse; import in.testpress.course.ui.CustomTestGenerationActivity; +import in.testpress.course.ui.OfflineExamListActivity; import in.testpress.samples.BaseToolBarActivity; import in.testpress.samples.R; import in.testpress.samples.core.TestpressCoreSampleActivity; @@ -167,6 +168,13 @@ public void onClick(View view) { launchCustomTestGenerationActivity(); } }); + + findViewById(R.id.offline_exam).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + launchOfflineExamActivity(); + } + }); } @SuppressWarnings("ConstantConditions") @@ -282,6 +290,11 @@ public Unit invoke() { }); } + private void launchOfflineExamActivity() { + Intent intent = new Intent(this, OfflineExamListActivity.class); + startActivity(intent); + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); diff --git a/samples/src/main/res/layout/activity_open_in.xml b/samples/src/main/res/layout/activity_open_in.xml index 84343952b..eeb70502c 100644 --- a/samples/src/main/res/layout/activity_open_in.xml +++ b/samples/src/main/res/layout/activity_open_in.xml @@ -86,6 +86,11 @@ android:text="Custom Test" android:id="@+id/custom_test_generation" /> + + From c1b622c6f09dca8788f5ecdd70ab05695674c976 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Fri, 21 Jun 2024 09:09:42 +0530 Subject: [PATCH 11/15] refcator --- .../testpress/database/dao/OfflineExamDao.kt | 4 + .../repository/OfflineExamRepository.kt | 5 ++ .../course/ui/OfflineExamListActivity.kt | 87 +++++++++++-------- .../course/viewmodels/OfflineExamViewModel.kt | 4 + .../ic_baseline_delete_forever_24.xml | 5 ++ .../res/layout/activity_offline_exam_list.xml | 14 ++- .../src/main/res/layout/item_offline_exam.xml | 68 +++++++++------ 7 files changed, 123 insertions(+), 64 deletions(-) create mode 100644 course/src/main/res/drawable/ic_baseline_delete_forever_24.xml diff --git a/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt b/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt index 69856c99b..4c5ece5ee 100644 --- a/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt +++ b/core/src/main/java/in/testpress/database/dao/OfflineExamDao.kt @@ -5,6 +5,7 @@ import `in`.testpress.database.entities.CategoryEntity import `in`.testpress.database.entities.OfflineExam import androidx.lifecycle.LiveData import androidx.room.Dao +import androidx.room.Delete import androidx.room.Query @Dao @@ -16,4 +17,7 @@ interface OfflineExamDao: BaseDao { @Query("SELECT * FROM OfflineExam WHERE id = :examId") fun get(examId: Long): OfflineExam? + @Query("DELETE FROM OfflineExam WHERE id = :examId") + fun deleteById(examId: Long) + } \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt index 9554e76c0..e2ac5adb6 100644 --- a/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt +++ b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt @@ -107,4 +107,9 @@ class OfflineExamRepository(val context: Context) { return offlineExamDao.getAll() } + fun deleteExam(examId: Long) { + CoroutineScope(Dispatchers.IO).launch { + offlineExamDao.deleteById(examId) + } + } } \ No newline at end of file diff --git a/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt index 022dced4e..88d2e621d 100644 --- a/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt +++ b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt @@ -1,76 +1,89 @@ package `in`.testpress.course.ui -import `in`.testpress.course.R import `in`.testpress.course.repository.OfflineExamRepository import `in`.testpress.course.viewmodels.OfflineExamViewModel import `in`.testpress.database.entities.OfflineExam import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView +import `in`.testpress.course.databinding.ActivityOfflineExamListBinding +import `in`.testpress.course.databinding.ItemOfflineExamBinding +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup class OfflineExamListActivity : AppCompatActivity() { - private lateinit var recyclerView: RecyclerView - private lateinit var adapter: OfflineExamAdapter + private lateinit var binding: ActivityOfflineExamListBinding private lateinit var offlineExamViewModel: OfflineExamViewModel + private lateinit var offlineExamAdapter: OfflineExamAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_offline_exam_list) + binding = ActivityOfflineExamListBinding.inflate(layoutInflater) + setContentView(binding.root) + initializeViewModel() + offlineExamAdapter = OfflineExamAdapter() + binding.recyclerView.adapter = offlineExamAdapter + + offlineExamViewModel.getAllOfflineExams().observe(this) { exams -> + offlineExamAdapter.submitList(exams) + binding.noDataTextView.visibility = if (exams.isEmpty()) View.VISIBLE else View.GONE + } + } + + private fun initializeViewModel() { offlineExamViewModel = ViewModelProvider(this, object : ViewModelProvider.Factory { override fun create(modelClass: Class): T { return OfflineExamViewModel( OfflineExamRepository(this@OfflineExamListActivity) ) as T } - }).get(OfflineExamViewModel::class.java) + })[OfflineExamViewModel::class.java] + } - recyclerView = findViewById(R.id.recyclerView) - recyclerView.layoutManager = LinearLayoutManager(this) - adapter = OfflineExamAdapter(emptyList()) - recyclerView.adapter = adapter + inner class OfflineExamAdapter : + ListAdapter(EXAM_COMPARATOR) { - offlineExamViewModel.getAllOfflineExams().observe(this) { exams -> - adapter = OfflineExamAdapter(exams) - recyclerView.adapter = adapter - } - } + inner class ExamViewHolder(private val binding: ItemOfflineExamBinding) : + RecyclerView.ViewHolder(binding.root) { - inner class OfflineExamAdapter(private val exams: List) : RecyclerView.Adapter() { + fun bind(exam: OfflineExam) { + binding.titleTextView.text = "${exam.title} Qs" + binding.totalTime.text = exam.duration + binding.numberOfQuestions.text = exam.numberOfQuestions.toString() + binding.deleteButton.setOnClickListener { + offlineExamViewModel.deleteExam(exam.id!!) + } + } + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExamViewHolder { - val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_offline_exam, parent, false) - return ExamViewHolder(itemView) + val binding = + ItemOfflineExamBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ExamViewHolder(binding) } override fun onBindViewHolder(holder: ExamViewHolder, position: Int) { - val exam = exams[position] + val exam = getItem(position) holder.bind(exam) } + } - override fun getItemCount(): Int { - return exams.size - } - - inner class ExamViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val titleTextView: TextView = itemView.findViewById(R.id.titleTextView) - private val totalTime: TextView = itemView.findViewById(R.id.total_time) - private val totalQuestion: TextView = itemView.findViewById(R.id.number_of_questions) + companion object { + private val EXAM_COMPARATOR = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: OfflineExam, newItem: OfflineExam): Boolean { + return oldItem.id == newItem.id + } - fun bind(exam: OfflineExam) { - titleTextView.text = exam.title - totalTime.text = exam.duration - totalQuestion.text = exam.numberOfQuestions.toString() - // Bind other properties of OfflineExam as needed + override fun areContentsTheSame(oldItem: OfflineExam, newItem: OfflineExam): Boolean { + return oldItem == newItem } } } -} \ No newline at end of file +} diff --git a/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt b/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt index 2da513c9e..aa0e66862 100644 --- a/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt +++ b/course/src/main/java/in/testpress/course/viewmodels/OfflineExamViewModel.kt @@ -74,4 +74,8 @@ class OfflineExamViewModel(private val repository: OfflineExamRepository) : View fun getAllOfflineExams(): LiveData> { return repository.getAllOfflineExams() } + + fun deleteExam(examId: Long) { + repository.deleteExam(examId) + } } \ No newline at end of file diff --git a/course/src/main/res/drawable/ic_baseline_delete_forever_24.xml b/course/src/main/res/drawable/ic_baseline_delete_forever_24.xml new file mode 100644 index 000000000..a0c03a9ee --- /dev/null +++ b/course/src/main/res/drawable/ic_baseline_delete_forever_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/course/src/main/res/layout/activity_offline_exam_list.xml b/course/src/main/res/layout/activity_offline_exam_list.xml index c45694095..966d37074 100644 --- a/course/src/main/res/layout/activity_offline_exam_list.xml +++ b/course/src/main/res/layout/activity_offline_exam_list.xml @@ -14,4 +14,16 @@ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:listitem="@layout/item_offline_exam" /> - \ No newline at end of file + + + diff --git a/course/src/main/res/layout/item_offline_exam.xml b/course/src/main/res/layout/item_offline_exam.xml index 205532fd1..ff0b4e922 100644 --- a/course/src/main/res/layout/item_offline_exam.xml +++ b/course/src/main/res/layout/item_offline_exam.xml @@ -1,44 +1,60 @@ - - - + android:layout_height="wrap_content" + android:layout_margin="8dp" + card_view:cardCornerRadius="8dp" + card_view:cardElevation="4dp"> + android:orientation="vertical" + android:padding="8dp"> - - + android:orientation="horizontal" + android:gravity="center_vertical"> + + + + + + + + - - - \ No newline at end of file + From 3aedad7e52947872bd8a070f6c991515f6cf2f10 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Fri, 21 Jun 2024 09:11:38 +0530 Subject: [PATCH 12/15] refcator --- commonlib/commonlib.aar | 3 --- mobilertc/mobilertc.aar | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 commonlib/commonlib.aar delete mode 100644 mobilertc/mobilertc.aar diff --git a/commonlib/commonlib.aar b/commonlib/commonlib.aar deleted file mode 100644 index 31e82d6de..000000000 --- a/commonlib/commonlib.aar +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0f01ce2466a88f245ce7e9ddd9d9e806ae8a2c0e7ada3b84ff1809936860b8c2 -size 4093070 diff --git a/mobilertc/mobilertc.aar b/mobilertc/mobilertc.aar deleted file mode 100644 index 0a443ccdc..000000000 --- a/mobilertc/mobilertc.aar +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7ce42b087a71eef490699a7fa682d0a7875b0b516ea94a1792db5f1a88fd3e86 -size 241348514 From 9e90d0bda1b24fcea71a875dab28ea9af68ea826 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Fri, 21 Jun 2024 09:35:41 +0530 Subject: [PATCH 13/15] fix empty message --- .../fragments/BaseExamWidgetFragment.kt | 6 +++- .../course/ui/OfflineExamListActivity.kt | 8 +++-- .../res/layout/activity_offline_exam_list.xml | 31 +++++++++++-------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt index e42f6b81c..2cc2edf7c 100644 --- a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt +++ b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt @@ -92,7 +92,11 @@ open class BaseExamWidgetFragment : Fragment() { observeViewModelLoading() observeDownloadComplete() downloadExamButton.setOnClickListener { - offlineExamViewModel.downloadExam(contentId, content.exam?.id!!, content.exam?.slug!!) + if (downloadExamButton.text == "Start Exam in Offline"){ + Toast.makeText(requireContext(),"Exam already downloaded", Toast.LENGTH_SHORT).show() + } else { + offlineExamViewModel.downloadExam(contentId, content.exam?.id!!, content.exam?.slug!!) + } } } else -> {} diff --git a/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt index 88d2e621d..c7ac0e071 100644 --- a/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt +++ b/course/src/main/java/in/testpress/course/ui/OfflineExamListActivity.kt @@ -4,7 +4,6 @@ import `in`.testpress.course.repository.OfflineExamRepository import `in`.testpress.course.viewmodels.OfflineExamViewModel import `in`.testpress.database.entities.OfflineExam import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DiffUtil @@ -12,11 +11,12 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import `in`.testpress.course.databinding.ActivityOfflineExamListBinding import `in`.testpress.course.databinding.ItemOfflineExamBinding +import `in`.testpress.ui.BaseToolBarActivity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -class OfflineExamListActivity : AppCompatActivity() { +class OfflineExamListActivity : BaseToolBarActivity() { private lateinit var binding: ActivityOfflineExamListBinding private lateinit var offlineExamViewModel: OfflineExamViewModel @@ -27,13 +27,15 @@ class OfflineExamListActivity : AppCompatActivity() { binding = ActivityOfflineExamListBinding.inflate(layoutInflater) setContentView(binding.root) initializeViewModel() + setActionBarTitle("Offline Exam") offlineExamAdapter = OfflineExamAdapter() binding.recyclerView.adapter = offlineExamAdapter offlineExamViewModel.getAllOfflineExams().observe(this) { exams -> offlineExamAdapter.submitList(exams) - binding.noDataTextView.visibility = if (exams.isEmpty()) View.VISIBLE else View.GONE + binding.recyclerView.visibility = if (exams.isEmpty()) View.GONE else View.VISIBLE + binding.noDataLayout.visibility = if (exams.isEmpty()) View.VISIBLE else View.GONE } } diff --git a/course/src/main/res/layout/activity_offline_exam_list.xml b/course/src/main/res/layout/activity_offline_exam_list.xml index 966d37074..e56af985f 100644 --- a/course/src/main/res/layout/activity_offline_exam_list.xml +++ b/course/src/main/res/layout/activity_offline_exam_list.xml @@ -1,11 +1,16 @@ - + + - - - + android:gravity="center"> + + + From 2a5908aee0a9ca7f83a40be2da4bfefca1a6555a Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Fri, 21 Jun 2024 10:03:57 +0530 Subject: [PATCH 14/15] refcator --- .../fragments/BaseExamWidgetFragment.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt index 2cc2edf7c..f1396a2fc 100644 --- a/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt +++ b/course/src/main/java/in/testpress/course/fragments/BaseExamWidgetFragment.kt @@ -88,16 +88,7 @@ open class BaseExamWidgetFragment : Fragment() { Status.SUCCESS -> { content = it.data!! loadAttemptsAndUpdateStartButton() - checkExamIsDownloaded() - observeViewModelLoading() - observeDownloadComplete() - downloadExamButton.setOnClickListener { - if (downloadExamButton.text == "Start Exam in Offline"){ - Toast.makeText(requireContext(),"Exam already downloaded", Toast.LENGTH_SHORT).show() - } else { - offlineExamViewModel.downloadExam(contentId, content.exam?.id!!, content.exam?.slug!!) - } - } + } else -> {} } @@ -188,6 +179,19 @@ open class BaseExamWidgetFragment : Fragment() { updateStartButtonTextAndVisibility(exam, pausedAttempt) updateStartButtonListener(exam, pausedAttempt) + + + checkExamIsDownloaded() + observeViewModelLoading() + observeDownloadComplete() + downloadExamButton.setOnClickListener { + if (downloadExamButton.text == "Start Exam in Offline"){ + Toast.makeText(requireContext(),"Exam already downloaded", Toast.LENGTH_SHORT).show() + } else { + offlineExamViewModel.downloadExam(contentId, content.exam?.id!!, content.exam?.slug!!) + } + } + } private fun updateStartButtonTextAndVisibility(exam: DomainExamContent, pausedAttempt: DomainContentAttempt?) { From 48306ad11c2b1e63fc860f1d5b1bbcb10eef5c73 Mon Sep 17 00:00:00 2001 From: PruthiviRaj27 Date: Fri, 21 Jun 2024 12:31:47 +0530 Subject: [PATCH 15/15] refcator --- .../main/java/in/testpress/course/network/CourseService.kt | 7 ++++++- .../testpress/course/repository/OfflineExamRepository.kt | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/course/src/main/java/in/testpress/course/network/CourseService.kt b/course/src/main/java/in/testpress/course/network/CourseService.kt index 0d133107a..166627bce 100644 --- a/course/src/main/java/in/testpress/course/network/CourseService.kt +++ b/course/src/main/java/in/testpress/course/network/CourseService.kt @@ -86,6 +86,11 @@ interface CourseService { fun getLanguages( @Path(value = "exam_slug", encoded = true) examSlug: String? ): RetrofitCall> + + @GET("/api/v2.4/contents/{content_id}/") + fun getNetworkContentWithId( + @Path(value = "content_id", encoded = true) contentId: Long + ): RetrofitCall } @@ -145,7 +150,7 @@ class CourseNetwork(context: Context) : TestpressApiClient(context, TestpressSdk } fun getNetworkContentWithId(contentId: Long): RetrofitCall { - return getCourseService().getNetworkContent("https://lmsdemo.testpress.in/api/v2.4/contents/$contentId/") + return getCourseService().getNetworkContentWithId(contentId) } fun getQuestions( diff --git a/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt index e2ac5adb6..d2faea1c1 100644 --- a/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt +++ b/course/src/main/java/in/testpress/course/repository/OfflineExamRepository.kt @@ -2,6 +2,8 @@ package `in`.testpress.course.repository import `in`.testpress.core.TestpressCallback import `in`.testpress.core.TestpressException +import `in`.testpress.core.TestpressSdk +import `in`.testpress.core.TestpressSession import `in`.testpress.course.network.CourseNetwork import `in`.testpress.course.network.NetworkContent import `in`.testpress.course.network.NetworkOfflineQuestionResponse @@ -10,6 +12,7 @@ import `in`.testpress.database.TestpressDatabase import `in`.testpress.database.entities.OfflineExam import `in`.testpress.exam.network.NetworkLanguage import `in`.testpress.exam.network.asRoomModels +import `in`.testpress.models.InstituteSettings import `in`.testpress.models.TestpressApiResponse import `in`.testpress.network.Resource import `in`.testpress.v2_4.models.ApiResponse