diff --git a/.idea/misc.xml b/.idea/misc.xml
index a210768..2bb228a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,33 +4,37 @@
diff --git a/README.md b/README.md
index 673e87e..efcd314 100644
--- a/README.md
+++ b/README.md
@@ -7,3 +7,6 @@ Native Android Application to show the data on https://islamqa.org/.
+
+Islamic graphic vector created by
+rawpixel.com - www.freepik.com
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index aae6a32..dccada3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -99,4 +99,7 @@ dependencies {
implementation 'androidx.preference:preference:1.2.0'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2"
+
+ implementation 'com.github.bumptech.glide:glide:4.13.2'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 481bb43..a8c234f 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -18,4 +18,16 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
+#-renamesourcefileattribute SourceFile
+
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep class * extends com.bumptech.glide.module.AppGlideModule {
+ (...);
+}
+-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
+ **[] $VALUES;
+ public *;
+}
+-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
+ *** rewind();
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1b0b5e5..e40c787 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,14 +13,14 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
- android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:targetApi="31">
+ android:exported="true"
+ android:theme="@style/StartTheme">
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/common/utility/ktx/View.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/common/utility/ktx/View.kt
index 8af0a89..5b84c57 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/common/utility/ktx/View.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/common/utility/ktx/View.kt
@@ -1,6 +1,9 @@
package io.github.kabirnayeem99.islamqaorg.common.utility.ktx
import android.view.View
+import android.view.animation.AccelerateDecelerateInterpolator
+import android.view.animation.Animation
+import android.view.animation.RotateAnimation
import com.google.android.material.snackbar.Snackbar
fun View.showUserMessage(userMessage: String) {
@@ -16,4 +19,18 @@ fun View.showUserMessage(userMessage: String) {
*/
fun View.viewVisibility(visibility: Int) {
this.visibility = visibility
+}
+
+fun View.rotateViewOneEighty(duration: Long = 5000L) {
+ val rotate = RotateAnimation(
+ 0F,
+ 180F,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f,
+ Animation.RELATIVE_TO_SELF,
+ 0.5f
+ )
+ rotate.duration = duration
+ rotate.interpolator = AccelerateDecelerateInterpolator()
+ startAnimation(rotate)
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaLocalDataSource.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaLocalDataSource.kt
index 781bf00..ec312ce 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaLocalDataSource.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaLocalDataSource.kt
@@ -79,19 +79,22 @@ class IslamQaLocalDataSource @Inject constructor(
return withContext(Dispatchers.IO) {
try {
- val dto = questionDetailDao.getQuestionByLink(url)
+ var detail: QuestionDetail? = null
- val detail = QuestionDetail(
- questionTitle = dto.questionTitle,
- detailedQuestion = dto.detailedQuestion,
- detailedAnswer = dto.detailedAnswer,
- fiqh = dto.fiqh,
- source = dto.source,
- originalLink = dto.originalLink,
- nextQuestionLink = dto.nextQuestionLink,
- previousQuestionLink = dto.previousQuestionLink,
- relevantQuestions = getQuestionList(),
- )
+ questionDetailDao.getQuestionByLink(url)?.let { dto ->
+
+ detail = QuestionDetail(
+ questionTitle = dto.questionTitle,
+ detailedQuestion = dto.detailedQuestion,
+ detailedAnswer = dto.detailedAnswer,
+ fiqh = dto.fiqh,
+ source = dto.source,
+ originalLink = dto.originalLink,
+ nextQuestionLink = dto.nextQuestionLink,
+ previousQuestionLink = dto.previousQuestionLink,
+ relevantQuestions = getQuestionList(),
+ )
+ }
Timber.d(detail.toString())
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaRemoteDataSource.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaRemoteDataSource.kt
index 84d5767..62586c9 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaRemoteDataSource.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/IslamQaRemoteDataSource.kt
@@ -64,7 +64,7 @@ class IslamQaRemoteDataSource @Inject constructor(private val scrapingService: S
val questionAnswer = mutableListOf()
qList.questions.forEachIndexed { index, question ->
val answerLink = qList.questionLinks[index]
- questionAnswer.add(Question(index, question, answerLink))
+ questionAnswer.add(Question(index, question, answerLink, fiqh.displayName))
}
questionAnswer.ifEmpty { throw Exception("Failed to parse links of the questions") }
}
@@ -96,7 +96,7 @@ class IslamQaRemoteDataSource @Inject constructor(private val scrapingService: S
relevantQuestions = dto.relevantQuestions,
)
- Timber.d(detail.toString())
+ Timber.d("getDetailedQuestionAndAnswer -> $detail")
detail
}
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/localDb/QuestionDetailDao.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/localDb/QuestionDetailDao.kt
index 0df6c84..ca48626 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/localDb/QuestionDetailDao.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/localDb/QuestionDetailDao.kt
@@ -23,6 +23,6 @@ interface QuestionDetailDao {
* @param link String
*/
@Query("SELECT * FROM questiondetailentity WHERE originalLink=:link")
- suspend fun getQuestionByLink(link: String): QuestionDetailEntity
+ suspend fun getQuestionByLink(link: String): QuestionDetailEntity?
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/service/ScrapingService.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/service/ScrapingService.kt
index 1ea1616..8bb00ef 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/service/ScrapingService.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dataSource/service/ScrapingService.kt
@@ -5,8 +5,6 @@ import io.github.kabirnayeem99.islamqaorg.data.dto.islamQa.QuestionDetailScreenD
import io.github.kabirnayeem99.islamqaorg.data.dto.islamQa.RandomQuestionListDto
import io.github.kabirnayeem99.islamqaorg.domain.entity.Fiqh
import io.github.kabirnayeem99.islamqaorg.domain.entity.Question
-import io.github.serpro69.kfaker.Faker
-import io.github.serpro69.kfaker.faker
import it.skrape.core.document
import it.skrape.fetcher.HttpFetcher
import it.skrape.fetcher.Result
@@ -35,7 +33,7 @@ class ScrapingService {
val islamQaHomeDto = skrape(HttpFetcher) {
request { url = homeScreenUrl }
- response { getIslamQaHomeDtoOutOfResponse() }
+ response { getRandomQuestionListDtoOutOfResponse() }
}
Timber.d(islamQaHomeDto.toString())
@@ -47,7 +45,7 @@ class ScrapingService {
/**
* Parses the HTML response and returns [RandomQuestionListDto] class.
*/
- private fun Result.getIslamQaHomeDtoOutOfResponse() = RandomQuestionListDto(
+ private fun Result.getRandomQuestionListDtoOutOfResponse() = RandomQuestionListDto(
httpStatusCode = status { code },
httpStatusMessage = status { message },
questions = document.findAll("li")
@@ -55,6 +53,7 @@ class ScrapingService {
questionLinks = document.li { a { findAll { filter { it.className == "arpw-title" }.eachHref } } }
)
+
/**
* Fetches the details of a specific question from islamqa.org, parses it, and converts it to a
* [QuestionDetailScreenDto] object.
@@ -91,12 +90,17 @@ class ScrapingService {
/**
* Parses the detailed answer from IslamQA.org, if it exists
*/
- private fun Result.getDetailedAnswer() = document.div {
- findAll {
- filter { it.className == "ddb-answer" }.eachText.joinToString(
- "\n"
- )
+ private fun Result.getDetailedAnswer() = try {
+ document.div {
+ findAll {
+ filter { it.className == "ddb-answer" }.eachText.joinToString(
+ "\n"
+ )
+ }
}
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to get detailed answer")
+ ""
}
/**
@@ -107,11 +111,16 @@ class ScrapingService {
* @receiver Result
* @return String
*/
- private fun Result.getDetailedQuestionAsHtmlText() = document.div {
- findAll {
- "" + filter { it.id == "qna_only" }.html.removePrefix("")
- .removeSuffix("
") + ""
+ private fun Result.getDetailedQuestionAsHtmlText() = try {
+ document.div {
+ findAll {
+ "" + filter { it.id == "qna_only" }.html.removePrefix("")
+ .removeSuffix("
") + ""
+ }
}
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to parse the detailed question -> ${e.message}")
+ "No Questions found.
"
}
enum class Page {
@@ -130,21 +139,26 @@ class ScrapingService {
*/
private fun Result.getPrevOrNextLink(prevOrNext: Page): String {
- val classNameForPrevOrNext = when (prevOrNext) {
- Page.PREV -> "nav-previous"
- Page.NEXT -> "nav-next"
- }
+ try {
+ val classNameForPrevOrNext = when (prevOrNext) {
+ Page.PREV -> "nav-previous"
+ Page.NEXT -> "nav-next"
+ }
- return document.div {
- findAll {
- span {
- findAll {
- first { it.className == classNameForPrevOrNext }.a {
- findAll { eachHref.firstOrNull() ?: "" }
+ return document.div {
+ findAll {
+ span {
+ findAll {
+ first { it.className == classNameForPrevOrNext }.a {
+ findAll { eachHref.firstOrNull() ?: "" }
+ }
}
}
}
}
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to get $prevOrNext url -> ${e.message}.")
+ return ""
}
}
@@ -155,50 +169,102 @@ class ScrapingService {
* `li` elements within the `ul` element and then map the `li` elements to a `Question` object
*/
private fun Result.getRelevantQuestionsFromQuestionDetails(): List {
- return document.div {
- findAll {
- first { it.className == "crp_related_widget" }.ul {
- li {
- findAll {
- map {
- Question(
- id = Random.nextInt(50),
- question = it.text,
- url = it.eachHref.firstOrNull() ?: ""
- )
+ return try {
+ document.div {
+ findAll {
+ first { it.className == "crp_related_widget" }.ul {
+ li {
+ findAll {
+ map {
+ Question(
+ id = Random.nextInt(50),
+ question = it.text,
+ url = it.eachHref.firstOrNull() ?: ""
+ )
+ }
}
}
}
}
}
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to get relevant questions from $this -> ${e.message}")
+ emptyList()
}
}
- private val faker: Faker by lazy {
- faker {}
- }
+ /**
+ * Makes a network call to the IslamQa.org, gets the html response, parses it
+ * and converts it into a [FiqhBasedQuestionListDto]
+ *
+ * @param fiqh Fiqh - The Fiqh for which the questions are to be fetched.
+ * @param pageNumber The page number of the questions list.
+ * @return A list of questions.
+ */
+ suspend fun parseFiqhBasedQuestionsList(fiqh: Fiqh, pageNumber: Int): FiqhBasedQuestionListDto {
+
+ return withContext(Dispatchers.IO) {
+
+ val fiqhParamName = if (fiqh == Fiqh.UNKNOWN) Fiqh.HANAFI.paramName else fiqh.paramName
- fun parseFiqhBasedQuestionsList(fiqh: Fiqh, pageNumber: Int): FiqhBasedQuestionListDto {
+ Timber.d("Getting question for $fiqhParamName of page $pageNumber.")
- val listOfQuestions = mutableListOf()
- val listOfQuestionLinks = mutableListOf()
+ val fiqhBasedQuestionUrl = "https://islamqa.org/category/${fiqhParamName}/"
- Timber.d("Getting list of $fiqh based questions with page $pageNumber")
+ Timber.d("URL is $fiqhBasedQuestionUrl")
- for (index in 1..18) {
- val question = "Ulema of Deoband $index"
- val questionLink = "https://islamqa.org/hanafi/muftionline/95119/ulema-of-deoband/"
- listOfQuestions.add(question)
- listOfQuestionLinks.add(questionLink)
+ val fiqhBasedQuestionListDto = skrape(HttpFetcher) {
+ request { url = fiqhBasedQuestionUrl }
+ response { getFiqhBasedQuestionListDtoOutOfResponse(fiqh) }
+ }
+
+ Timber.d(fiqhBasedQuestionListDto.toString())
+
+ fiqhBasedQuestionListDto
}
+ }
- return FiqhBasedQuestionListDto(
- 200,
- "No problem",
- listOfQuestions,
- listOfQuestionLinks,
+ /**
+ * Parses the HTML response and returns [FiqhBasedQuestionListDto] class.
+ */
+ private fun Result.getFiqhBasedQuestionListDtoOutOfResponse(fiqh: Fiqh): FiqhBasedQuestionListDto {
+ val dto = FiqhBasedQuestionListDto(
+ httpStatusCode = status { code },
+ httpStatusMessage = status { message },
+ questions = getFiqhBasedQuestionsFromResult(),
+ questionLinks = getQuestionLinksForFiqhBasedQuestions(),
+ fiqh = fiqh
)
+
+ Timber.d("FiqhBasedQuestionListDto -> $dto")
+ return dto
+ }
+
+ private fun Result.getFiqhBasedQuestionsFromResult() = try {
+ document.h1 {
+ findAll {
+ filter { it.className == "entry-title" }.eachText
+ .filterIndexed { index, _ -> index != 0 }
+ }
+ }
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to get questions -> ${e.message}.")
+ emptyList()
+ }
+
+ private fun Result.getQuestionLinksForFiqhBasedQuestions() = try {
+ document.h1 {
+ findAll {
+ filter { it.className == "entry-title" }.map {
+ it.eachHref.joinToString(",")
+ }.filterIndexed { index, _ -> index != 0 }
+
+ }
+ }
+ } catch (e: Exception) {
+ Timber.e(e, "Failed to get question links -> ${e.message}.")
+ emptyList()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dto/islamQa/FiqhBasedQuestionListDto.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dto/islamQa/FiqhBasedQuestionListDto.kt
index f6b2cea..36c7ede 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dto/islamQa/FiqhBasedQuestionListDto.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/dto/islamQa/FiqhBasedQuestionListDto.kt
@@ -1,9 +1,13 @@
package io.github.kabirnayeem99.islamqaorg.data.dto.islamQa
+import io.github.kabirnayeem99.islamqaorg.domain.entity.Fiqh
+
data class FiqhBasedQuestionListDto(
val httpStatusCode: Int,
val httpStatusMessage: String,
- val questions: List,
- val questionLinks: List
+ val questions
+ : List,
+ val questionLinks: List,
+ val fiqh: Fiqh = Fiqh.HANAFI,
)
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/repository/QuestionAnswerRepositoryImpl.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/repository/QuestionAnswerRepositoryImpl.kt
index 2d4f282..a7b40f1 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/repository/QuestionAnswerRepositoryImpl.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/data/repository/QuestionAnswerRepositoryImpl.kt
@@ -91,7 +91,6 @@ class QuestionAnswerRepositoryImpl
}
}
- private var inMemoryQuestionDetail = QuestionDetail()
/**
* Fetches the question details based on the URL
@@ -107,37 +106,46 @@ class QuestionAnswerRepositoryImpl
* @return A flow of resources.
*/
override suspend fun getQuestionDetails(url: String): Flow> {
- val questionDetail = inMemoryMutex.withLock { inMemoryQuestionDetail }
return flow {
try {
+ emit(Resource.Loading())
val questionDetailLocal = localDataSource.getDetailedQuestionAndAnswer(url)
questionDetailLocal?.let {
- inMemoryMutex.withLock { inMemoryQuestionDetail = it }
+ kotlinx.coroutines.delay(1600)
emit(Resource.Success(it))
}
if (isNetworkAvailable) {
val questionDetailed = remoteDataSource.getDetailedQuestionAndAnswer(url)
- inMemoryMutex.withLock { inMemoryQuestionDetail = questionDetailed }
- localDataSource.cacheQuestionDetail(questionDetail)
+ localDataSource.cacheQuestionDetail(questionDetailed)
emit(Resource.Success(questionDetailed))
}
} catch (e: Exception) {
+ Timber.e(e, "Failed to get the detailed question -> ${e.message}.")
emit(Resource.Error(e.localizedMessage ?: "Failed to get the detailed question."))
}
- }.onStart {
- if (questionDetail.originalLink == url) emit(Resource.Success(questionDetail))
- else emit(Resource.Loading())
}.flowOn(Dispatchers.IO)
}
private suspend fun getCurrentlySelectedFiqh(): Fiqh {
- return preferenceDataSource.getPreferredFiqh()
+ val preferredFiqh = preferenceDataSource.getPreferredFiqh()
+ if (preferredFiqh == Fiqh.UNKNOWN) {
+ preferenceDataSource.savePreferredFiqh(Fiqh.HANAFI)
+ return Fiqh.HANAFI
+ }
+ return preferredFiqh
}
private var inMemoryFiqhBasedQuestionList = emptyList()
+ /**
+ * Gets questions list based on the preferred [Fiqh] of the user
+ *
+ * @param pageNumber Int - the page number from which the questions will be loaded.
+ * @param shouldRefresh Boolean - whether the data should be fetched from website or from local cache
+ * @return a flow of the [Question] list wrapped in a [Resource] class.
+ */
override suspend fun getFiqhBasedQuestionList(
pageNumber: Int,
shouldRefresh: Boolean,
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Fiqh.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Fiqh.kt
index 5fc4a1f..39be47c 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Fiqh.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Fiqh.kt
@@ -1,10 +1,16 @@
package io.github.kabirnayeem99.islamqaorg.domain.entity
-enum class Fiqh(val paramName: String) {
- HANAFI("hanafi"),
- MALIKI("maliki"),
- SHAFII("shafii"),
- HANBALI("hanbali"),
- UNKNOWN(""),
-
+/**
+ * Fiqh is Islamic jurisprudence. Fiqh is often described as the human understanding and practices
+ * of the sharia, that is human understanding of the divine Islamic law as revealed in the Quran
+ * and the Sunnah.
+ *
+ * @property paramName String - the name of the Fiqh to pass to IslamQA
+ */
+enum class Fiqh(val paramName: String, val displayName: String) {
+ HANAFI("hanafi", "Hanafi"),
+ MALIKI("maliki", "Maliki"),
+ SHAFII("shafii", "Shafii"),
+ HANBALI("hanbali", "Hanbali"),
+ UNKNOWN("", ""),
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Question.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Question.kt
index 7917bbf..16b4a6c 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Question.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/domain/entity/Question.kt
@@ -12,4 +12,5 @@ data class Question(
val id: Int = 0,
val question: String = "",
val url: String = "",
+ val fiqh: String = "",
)
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/HomeFragment.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/HomeFragment.kt
index ed04f1a..a86c6bf 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/HomeFragment.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/HomeFragment.kt
@@ -7,18 +7,20 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
+import com.bumptech.glide.request.transition.DrawableCrossFadeFactory
import dagger.hilt.android.AndroidEntryPoint
import io.github.kabirnayeem99.islamqaorg.R
import io.github.kabirnayeem99.islamqaorg.common.base.BaseFragment
+import io.github.kabirnayeem99.islamqaorg.common.utility.ktx.rotateViewOneEighty
import io.github.kabirnayeem99.islamqaorg.common.utility.ktx.showUserMessage
import io.github.kabirnayeem99.islamqaorg.common.utility.ktx.viewVisibility
import io.github.kabirnayeem99.islamqaorg.databinding.FragmentHomeBinding
import io.github.kabirnayeem99.islamqaorg.domain.entity.Question
import io.github.kabirnayeem99.islamqaorg.ui.MainActivity
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.*
import javax.inject.Inject
+
@AndroidEntryPoint
class HomeFragment : BaseFragment() {
@@ -51,20 +53,51 @@ class HomeFragment : BaseFragment() {
@Inject
lateinit var questionSliderAdapter: QuestionSliderAdapter
+
private fun handleUiState(uiState: HomeScreenUiState) {
uiState.apply {
+
questionAdapter.submitQuestionList(fiqhBasedQuestions)
questionSliderAdapter.submitQuestionList(randomQuestions)
+
+ if (!isRandomQuestionLoading && !isFiqhBasedQuestionsLoading) {
+ showRotatingGeometryForever()
+ }
+
messages.firstOrNull()?.let { userMessage ->
binding.root.showUserMessage(userMessage.message)
homeViewModel.userMessageShown(userMessage.id)
}
binding.apply {
- sflRandomQuestionLoading.viewVisibility(if (isRandomQuestionLoading) View.VISIBLE else View.GONE)
- rvQuestions.viewVisibility(if (isRandomQuestionLoading) View.GONE else View.VISIBLE)
- sflFiqhBasedQuestionLoading.viewVisibility(if (isFiqhBasedQuestionsLoading) View.VISIBLE else View.GONE)
- rvLatestQuestions.viewVisibility(if (isFiqhBasedQuestionsLoading) View.GONE else View.VISIBLE)
+ sflRandomQuestionLoading.viewVisibility(if (isRandomQuestionLoading) View.VISIBLE else View.INVISIBLE)
+ rvQuestions.viewVisibility(if (isRandomQuestionLoading) View.INVISIBLE else View.VISIBLE)
+ sflFiqhBasedQuestionLoading.viewVisibility(if (isFiqhBasedQuestionsLoading) View.VISIBLE else View.INVISIBLE)
+ rvLatestQuestions.viewVisibility(if (isFiqhBasedQuestionsLoading) View.INVISIBLE else View.VISIBLE)
+ }
+
+ slideShowRandomQuestionList(randomQuestions)
+ }
+ }
+
+
+ private val factory by lazy {
+ DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build()
+ }
+
+ private var adapterScrollingJob: Job? = null
+
+ /**
+ * Smooth scrolls through recyclerview items, to give a feeling of slide show
+ *
+ * @param randomQuestions List
+ */
+ private fun slideShowRandomQuestionList(randomQuestions: List) {
+ adapterScrollingJob?.cancel()
+ adapterScrollingJob = viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
+ randomQuestions.forEachIndexed { index, _ ->
+ binding.rvQuestions.smoothScrollToPosition(index)
+ delay(5000)
}
}
}
@@ -92,20 +125,22 @@ class HomeFragment : BaseFragment() {
questionSliderAdapter.setOnClickListener { navigateToQuestionDetailsScreen(it) }
(activity as MainActivity).setOnSyncButtonClickListener {
- showLoadingForAShortTimePeriod()
+ showRotatingGeometryForever()
homeViewModel.getRandomQuestions(true)
}
(activity as MainActivity).setOnSettingButtonClickListener {
navController.navigate(R.id.action_HomeFragment_to_settingsFragment)
}
+
}
- private fun showLoadingForAShortTimePeriod() {
- viewLifecycleOwner.lifecycleScope.launch {
- loading.show()
- delay(2000)
- loading.dismiss()
+ private fun showRotatingGeometryForever() {
+ viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
+ while (viewLifecycleOwner.lifecycleScope.isActive) {
+ binding.ivDesignGeometry.rotateViewOneEighty(4000)
+ delay(4000)
+ }
}
}
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionAdapter.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionAdapter.kt
index 38354ae..9e7b1da 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionAdapter.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionAdapter.kt
@@ -3,11 +3,10 @@ package io.github.kabirnayeem99.islamqaorg.ui.home
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.animation.Animation
-import android.view.animation.ScaleAnimation
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
+import io.github.kabirnayeem99.islamqaorg.common.utility.ktx.viewVisibility
import io.github.kabirnayeem99.islamqaorg.databinding.ListQuestionBinding
import io.github.kabirnayeem99.islamqaorg.domain.entity.Question
@@ -50,38 +49,25 @@ class QuestionAdapter : RecyclerView.Adapter
override fun getItemCount(): Int = differ.currentList.size
override fun onBindViewHolder(holder: QuestionViewHolder, position: Int) {
+
val currentQuestion = getQuestionAtIndex(position)
+
holder.binding.apply {
+
question = currentQuestion
executePendingBindings()
- if (onClick != null) root.setOnClickListener {
- animate(holder.binding.root, position)
- onClick!!(currentQuestion)
- }
- animate(holder.binding.root, position)
- }
- }
- private fun getQuestionAtIndex(index: Int): Question = differ.currentList[index] ?: Question()
+ if (onClick != null) root.setOnClickListener { onClick!!(currentQuestion) }
+
+
+ val fiqhVisibilityBasedOnFiqhAvailability =
+ if (currentQuestion.fiqh.isBlank()) View.GONE
+ else View.VISIBLE
- private var lastPosition = -1
-
- private fun animate(view: View, position: Int) {
- if (position > lastPosition) {
- val animation = ScaleAnimation(
- 0.0f,
- 1.0f,
- 0.0f,
- 1.0f,
- Animation.RELATIVE_TO_SELF,
- 0.5f,
- Animation.RELATIVE_TO_SELF,
- 0.5f
- )
- animation.duration = if (lastPosition != -1) (100L * (lastPosition / 2)) else 90
- view.startAnimation(animation)
- lastPosition = position
+ tvSelectedFiqh.viewVisibility(fiqhVisibilityBasedOnFiqhAvailability)
}
}
+ private fun getQuestionAtIndex(index: Int): Question = differ.currentList[index] ?: Question()
+
}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionSliderAdapter.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionSliderAdapter.kt
index f529eca..0b75207 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionSliderAdapter.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/home/QuestionSliderAdapter.kt
@@ -5,6 +5,8 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import io.github.kabirnayeem99.islamqaorg.R
import io.github.kabirnayeem99.islamqaorg.databinding.SlideQuestionBinding
import io.github.kabirnayeem99.islamqaorg.domain.entity.Question
@@ -51,6 +53,7 @@ class QuestionSliderAdapter : RecyclerView.Adapter() {
private fun handleUiState(uiState: QuestionDetailsUiState) {
uiState.apply {
- if (isLoading) loading.show()
- else {
- loading.dismiss()
- binding.nsvRoot.smoothScrollTo(0, 0)
- }
+
+ binding.sflLoading.viewVisibility(if (isLoading) View.VISIBLE else View.GONE)
+ binding.llContent.viewVisibility(if (isLoading) View.GONE else View.VISIBLE)
binding.questionDetail = uiState.questionDetails
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/settings/SettingsFragment.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/settings/SettingsFragment.kt
index ce7753d..6b2ff53 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/settings/SettingsFragment.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/settings/SettingsFragment.kt
@@ -3,6 +3,7 @@ package io.github.kabirnayeem99.islamqaorg.ui.settings
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
+import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@@ -30,6 +31,12 @@ class SettingsFragment : BaseFragment() {
navController.navigate(R.id.action_settingsFragment_to_aboutFragment)
}
spinFiqh.prompt = getString(R.string.hint_fiqh)
+ spinFiqh.setPopupBackgroundDrawable(
+ ContextCompat.getDrawable(
+ requireContext(),
+ R.drawable.bg_tappable_rounded
+ )
+ )
val fiqhAdapter = ArrayAdapter.createFromResource(
requireContext(),
R.array.fiqh_array,
diff --git a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/start/StartActivity.kt b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/start/StartActivity.kt
index 48c4693..3dec239 100644
--- a/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/start/StartActivity.kt
+++ b/app/src/main/java/io/github/kabirnayeem99/islamqaorg/ui/start/StartActivity.kt
@@ -6,11 +6,14 @@ import io.github.kabirnayeem99.islamqaorg.BuildConfig
import io.github.kabirnayeem99.islamqaorg.R
import io.github.kabirnayeem99.islamqaorg.common.base.BaseActivity
import io.github.kabirnayeem99.islamqaorg.common.utility.ktx.gotoActivity
+import io.github.kabirnayeem99.islamqaorg.common.utility.ktx.rotateViewOneEighty
import io.github.kabirnayeem99.islamqaorg.databinding.ActivityStartBinding
import io.github.kabirnayeem99.islamqaorg.ui.MainActivity
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
+const val SPLASH_SCREEN_DURATION: Long = 3000L
+
class StartActivity : BaseActivity() {
override val layout: Int
get() = R.layout.activity_start
@@ -21,13 +24,17 @@ class StartActivity : BaseActivity() {
}
private fun initViews() {
- binding.tvAppVersionName.text = BuildConfig.VERSION_NAME
+ binding.apply {
+ tvAppVersionName.text = BuildConfig.VERSION_NAME
+ ivBackgroundGeometry.rotateViewOneEighty(SPLASH_SCREEN_DURATION)
+ }
navigateToOtherScreen()
}
+
private fun navigateToOtherScreen() {
lifecycleScope.launch {
- delay(3000)
+ delay(SPLASH_SCREEN_DURATION)
gotoActivity(MainActivity::class.java, true)
}
}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index 1a76d15..0000000
--- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/bg_banner.jpg b/app/src/main/res/drawable/bg_banner.jpg
new file mode 100644
index 0000000..5b4142b
Binary files /dev/null and b/app/src/main/res/drawable/bg_banner.jpg differ
diff --git a/app/src/main/res/drawable/bg_home.xml b/app/src/main/res/drawable/bg_home.xml
new file mode 100644
index 0000000..a8b409b
--- /dev/null
+++ b/app/src/main/res/drawable/bg_home.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_shimmer_placeholder.xml b/app/src/main/res/drawable/bg_shimmer_placeholder.xml
new file mode 100644
index 0000000..c962cb9
--- /dev/null
+++ b/app/src/main/res/drawable/bg_shimmer_placeholder.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_tappable_rounded.xml b/app/src/main/res/drawable/bg_tappable_rounded.xml
index edf79ad..62e31ba 100644
--- a/app/src/main/res/drawable/bg_tappable_rounded.xml
+++ b/app/src/main/res/drawable/bg_tappable_rounded.xml
@@ -2,13 +2,13 @@
-
+
+ android:bottom="0.5dp"
+ android:left="8dp"
+ android:right="8dp"
+ android:top="0.5dp" />
diff --git a/app/src/main/res/drawable/ic_islamic_geometric.xml b/app/src/main/res/drawable/ic_islamic_geometric.xml
new file mode 100644
index 0000000..f58a664
--- /dev/null
+++ b/app/src/main/res/drawable/ic_islamic_geometric.xml
@@ -0,0 +1,7030 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
index 5b67963..6a617a7 100644
--- a/app/src/main/res/drawable/ic_launcher_background.xml
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -1,10 +1,10 @@
+ android:width="200dp"
+ android:height="200dp"
+ android:viewportWidth="200"
+ android:viewportHeight="200">
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 867f858..de2483c 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -21,7 +21,8 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="center">
+ android:layout_gravity="center"
+ android:background="@color/transparent">
+ android:background="@color/md_theme_light_primary">
+
+
+ app:layout_constraintTop_toTopOf="parent">
+ app:tint="@color/md_theme_light_onSurface" />
+ app:cardCornerRadius="40dp"
+ app:cardElevation="4dp"
+ app:layout_constraintEnd_toEndOf="@id/cv_logo"
+ app:layout_constraintTop_toBottomOf="@id/cv_logo"
+ app:layout_constraintTop_toTopOf="@id/cv_logo">
diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml
index 9462289..674c631 100644
--- a/app/src/main/res/layout/fragment_about.xml
+++ b/app/src/main/res/layout/fragment_about.xml
@@ -27,8 +27,8 @@
-
+ android:orientation="vertical">
+
+
+ android:textSize="46sp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/tv_title" />
@@ -60,13 +77,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
+ android:layout_marginTop="14dp"
android:orientation="vertical"
android:visibility="visible"
- app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/tv_title"
- app:shimmer_base_alpha="0.3">
+ app:layout_constraintTop_toBottomOf="@id/tv_relevant_q_n_a_label"
+ app:shimmer_base_alpha="0.6"
+ app:shimmer_base_color="@color/md_theme_light_surface">
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/sfl_random_question_loading" />
@@ -112,10 +133,10 @@
android:id="@+id/sfl_fiqh_based_question_loading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/tv_title">
+ app:layout_constraintTop_toBottomOf="@id/tv_fiqh_label">
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_question_details.xml b/app/src/main/res/layout/fragment_question_details.xml
index 82c9b8d..0f02df1 100644
--- a/app/src/main/res/layout/fragment_question_details.xml
+++ b/app/src/main/res/layout/fragment_question_details.xml
@@ -1,5 +1,6 @@
@@ -14,73 +15,139 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
-
-
-
-
-
-
+ android:layout_height="wrap_content">
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_margin="12dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
index 432b752..ef73ea2 100644
--- a/app/src/main/res/layout/fragment_settings.xml
+++ b/app/src/main/res/layout/fragment_settings.xml
@@ -59,7 +59,7 @@
app:layout_constraintBottom_toBottomOf="@id/tv_about_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_about_label"
- app:tint="?android:textColorPrimary" />
+ app:tint="?android:colorPrimary" />
+ app:tint="?android:colorPrimary" />
+
+
@@ -41,14 +40,30 @@
android:layout_height="22dp"
android:layout_marginEnd="6dp"
android:background="@drawable/bg_icon_rounded"
- android:backgroundTint="#11aaaaaa"
+ android:backgroundTint="@color/trans_primary"
android:contentDescription="@string/content_desc_go_to_details"
android:padding="5dp"
android:src="@drawable/ic_arrow_forward"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
- app:tint="#aaaaaaaa" />
+ app:tint="@color/md_theme_light_primary" />
+
+
+
diff --git a/app/src/main/res/layout/slide_question.xml b/app/src/main/res/layout/slide_question.xml
index 98b1d6d..0c5838b 100644
--- a/app/src/main/res/layout/slide_question.xml
+++ b/app/src/main/res/layout/slide_question.xml
@@ -12,29 +12,38 @@
+ app:cardElevation="0.8dp"
+ app:strokeColor="#e7b386">
+ android:layout_gravity="center">
+
+
+ app:tint="@color/md_theme_light_onSurface" />
diff --git a/app/src/main/res/layout/slide_question_placeholder.xml b/app/src/main/res/layout/slide_question_placeholder.xml
index cb8817a..ffa0e9e 100644
--- a/app/src/main/res/layout/slide_question_placeholder.xml
+++ b/app/src/main/res/layout/slide_question_placeholder.xml
@@ -12,25 +12,33 @@
+ android:layout_gravity="center">
+
+
+ app:tint="#e7b386" />
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index eca70cf..90f9580 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
deleted file mode 100644
index eca70cf..0000000
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b0cb592
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
deleted file mode 100644
index c209e78..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_back.png
new file mode 100644
index 0000000..80fd7c9
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_back.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png
new file mode 100644
index 0000000..21525bd
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
deleted file mode 100644
index b2dfe3d..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f4c6bed
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
deleted file mode 100644
index 4f0f1d6..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_back.png
new file mode 100644
index 0000000..b51a72e
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_back.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png
new file mode 100644
index 0000000..4cb70a9
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
deleted file mode 100644
index 62b611d..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6c9e4cf
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
deleted file mode 100644
index 948a307..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_back.png
new file mode 100644
index 0000000..90118c3
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_back.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png
new file mode 100644
index 0000000..931ce23
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
deleted file mode 100644
index 1b9a695..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..5a8e8fa
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
deleted file mode 100644
index 28d4b77..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png
new file mode 100644
index 0000000..31a7fe4
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png
new file mode 100644
index 0000000..328157c
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9287f50..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..7298760
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
deleted file mode 100644
index aa7d642..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png
new file mode 100644
index 0000000..871cf92
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png
new file mode 100644
index 0000000..11a7ffe
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9126ae3..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml
deleted file mode 100644
index 22d7f00..0000000
--- a/app/src/main/res/values-land/dimens.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- 48dp
-
\ No newline at end of file
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
index 7613b84..1a8d332 100644
--- a/app/src/main/res/values-night/themes.xml
+++ b/app/src/main/res/values-night/themes.xml
@@ -3,6 +3,7 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/values-v31/themes.xml b/app/src/main/res/values-v31/themes.xml
new file mode 100644
index 0000000..70bfcaf
--- /dev/null
+++ b/app/src/main/res/values-v31/themes.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-w1240dp/dimens.xml b/app/src/main/res/values-w1240dp/dimens.xml
deleted file mode 100644
index d73f4a3..0000000
--- a/app/src/main/res/values-w1240dp/dimens.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- 200dp
-
\ No newline at end of file
diff --git a/app/src/main/res/values-w600dp/dimens.xml b/app/src/main/res/values-w600dp/dimens.xml
deleted file mode 100644
index 22d7f00..0000000
--- a/app/src/main/res/values-w600dp/dimens.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
- 48dp
-
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 662f281..8868b80 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,5 +1,6 @@
#933C87
+ #66933C87
#FFFFFF
#FFD7F2
#390034
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3548982..4995f48 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -21,10 +21,11 @@
Go to GitHub App Source Code
-
+
Fiqh
- Select your preferred Fiqh
+ Select your preferred madhab.
Learn more about this application
Info
Preferences
+ Madhab
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 9ee98e3..2cede77 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -2,6 +2,8 @@
+
+
+
+
diff --git a/doc/images/demo_details_page.png b/doc/images/demo_details_page.png
index a509380..034d07d 100644
Binary files a/doc/images/demo_details_page.png and b/doc/images/demo_details_page.png differ
diff --git a/doc/images/demo_home_screen.png b/doc/images/demo_home_screen.png
index 3d44140..0518e32 100644
Binary files a/doc/images/demo_home_screen.png and b/doc/images/demo_home_screen.png differ