FAQ activity

FAq rv and adapter

Woka support Activity for both kind of user
Viewmodel architecture for activity

Integration of woka support both apis
This commit is contained in:
2024-06-05 21:08:33 +05:30
parent 2bf884ed56
commit 84a8f11f5a
32 changed files with 927 additions and 62 deletions

View File

@@ -16,18 +16,14 @@ import android.view.HapticFeedbackConstants
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.WindowManager
import android.view.animation.Animation
import androidx.activity.enableEdgeToEdge
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.GravityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.bumptech.glide.Glide
import com.google.android.exoplayer2.ExoPlayer
import com.jwplayer.pub.api.license.LicenseUtil
import com.woka.BuildConfig
import com.woka.R
@@ -39,7 +35,9 @@ import com.woka.home.BottomNavigation.Companion.MY_LIST
import com.woka.home.fragments.Home1Fragment
import com.woka.home.fragments.Home2Fragment
import com.woka.home.fragments.MyListFragment
import com.woka.home.sidebar.AboutActivity
import com.woka.home.sidebar.aboutwoka.AboutActivity
import com.woka.home.sidebar.faqs.FaqActivity
import com.woka.home.sidebar.support.SupportActivity
import com.woka.mvvm.userDataModels.UserDataResponse
import com.woka.networking.ApiResult
import com.woka.onboard.OnboardActivity
@@ -268,6 +266,16 @@ class HomeActivity : WokaBaseActivity(),
startActivity(Intent(this@HomeActivity, AboutActivity::class.java),
ActivityOptions.makeSceneTransitionAnimation(this@HomeActivity).toBundle())
}
sbFaqCard.setOnClickListener {
startActivity(Intent(this@HomeActivity, FaqActivity::class.java),
ActivityOptions.makeSceneTransitionAnimation(this@HomeActivity).toBundle())
}
sbWokaSupportCard.setOnClickListener {
startActivity(Intent(this@HomeActivity, SupportActivity::class.java),
ActivityOptions.makeSceneTransitionAnimation(this@HomeActivity).toBundle())
}
}
}

View File

@@ -9,6 +9,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.woka.R
import com.woka.databinding.ActivityMoreHomeBinding
import com.woka.modules.blogs.BlogsAdapter
import com.woka.modules.blogs.BlogsRepository
import com.woka.networking.ApiResult
import com.woka.utils.WokaBaseActivity

View File

@@ -1,21 +0,0 @@
package com.woka.home.sidebar
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.woka.R
class FaqActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_faq)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
}
}

View File

@@ -1,4 +1,4 @@
package com.woka.home.sidebar
package com.woka.home.sidebar.aboutwoka
import android.os.Bundle
import android.transition.Slide

View File

@@ -0,0 +1,80 @@
package com.woka.home.sidebar.faqs
import android.os.Bundle
import android.transition.Slide
import android.view.Gravity
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.woka.R
import com.woka.databinding.ActivityFaqBinding
import com.woka.modules.faqs.FAQsRepository
import com.woka.networking.ApiResult
import com.woka.utils.ProgressView
import com.woka.utils.toast
class FaqActivity : AppCompatActivity() {
private lateinit var binding: ActivityFaqBinding
private var adapter: FaqsAdapter? = null
private lateinit var progressView: ProgressView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.enterTransition = Slide().apply {
slideEdge = Gravity.END
}
enableEdgeToEdge()
binding = ActivityFaqBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
progressView = ProgressView(this, getString(R.string.please_wait))
initViews()
clickEvents()
setObservers()
}
private fun setObservers() {
FAQsRepository.faqLiveData.observe(this){
when(it){
is ApiResult.Error -> {
toast(it.errorMessage)
progressView.hide()
}
is ApiResult.Loading -> progressView.show()
is ApiResult.Success -> {
progressView.hide()
it.data?.result?.let {faqs ->
adapter?.submitList(faqs)
}
}
null -> {}
}
}
}
private fun initViews() {
binding.apply {
adapter = FaqsAdapter()
rvFaq.adapter = adapter
}
}
private fun clickEvents() {
binding.apply {
backBtn.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
}
}

View File

@@ -0,0 +1,90 @@
package com.woka.home.sidebar.faqs
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.woka.R
import com.woka.databinding.FaqViewHolderBinding
import com.woka.modules.faqs.models.Faq
import com.woka.utils.hide
import com.woka.utils.show
import java.util.concurrent.Executors
class FaqsAdapter(config: AsyncDifferConfig<Faq>) :
ListAdapter<Faq, FaqsAdapter.FaqViewHolder>(config) {
inner class FaqViewHolder(val binding: FaqViewHolderBinding): ViewHolder(binding.root)
private var openedFaq = -1
companion object{
private val DIFF_UTILS = object : DiffUtil.ItemCallback<Faq>(){
override fun areItemsTheSame(oldItem: Faq, newItem: Faq): Boolean =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Faq, newItem: Faq): Boolean =
oldItem == newItem
}
private val ASYNC_DIFF_CONFIG = AsyncDifferConfig.Builder(DIFF_UTILS)
.setBackgroundThreadExecutor(Executors.newSingleThreadExecutor())
.build()
}
constructor(): this(ASYNC_DIFF_CONFIG)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FaqViewHolder {
return FaqViewHolder(FaqViewHolderBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: FaqViewHolder, position: Int) {
val faq = getItem(position)
holder.binding.apply {
title.text = faq.english_question
description.text = faq.english_answer
val arrowUp = ResourcesCompat.getDrawable(card.context.resources, R.drawable.ic_half_arrow_up, null)
val arrowRight = ResourcesCompat.getDrawable(card.context.resources, R.drawable.ic_half_arrow_right, null)
if (position == openedFaq){
// showing
descriptionView.show()
title.setCompoundDrawablesWithIntrinsicBounds(null, null, arrowUp, null)
}else{
// not showing
descriptionView.hide()
title.setCompoundDrawablesWithIntrinsicBounds(null, null, arrowRight, null)
}
card.setOnClickListener {
if (descriptionView.isVisible){
// closing the faq
descriptionView.hide()
title.setCompoundDrawablesWithIntrinsicBounds(null, null, arrowRight, null)
}else{
// closing previous faq
if (openedFaq != -1){
try {
notifyItemChanged(openedFaq)
} catch (e: Exception) {
// do nothing
}
}
// opening the faq
descriptionView.show()
title.setCompoundDrawablesWithIntrinsicBounds(null, null, arrowUp, null)
openedFaq = position
}
}
}
}
}

View File

@@ -0,0 +1,162 @@
package com.woka.home.sidebar.support
import android.os.Bundle
import android.transition.Slide
import android.util.Patterns
import android.view.Gravity
import android.widget.ArrayAdapter
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.ViewModelProvider
import com.woka.R
import com.woka.WokaApp.Companion.userPrefs
import com.woka.databinding.ActivitySupportBinding
import com.woka.networking.ApiResult
import com.woka.utils.ProgressView
import com.woka.utils.UserType
import com.woka.utils.WokaBaseActivity
import com.woka.utils.hide
import com.woka.utils.toast
class SupportActivity : WokaBaseActivity() {
private lateinit var binding: ActivitySupportBinding
private lateinit var viewModel: SupportViewModel
private lateinit var progressView: ProgressView
private val subjects = arrayOf(
"Select a subject", "Query",
"Complaint", "Suggestion", "Other"
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.enterTransition = Slide().apply {
slideEdge = Gravity.END
}
enableEdgeToEdge()
binding = ActivitySupportBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
viewModel = ViewModelProvider(this)[SupportViewModel::class.java]
progressView = ProgressView(this, getString(R.string.please_wait))
initViews()
clickEvents()
setObservers()
}
private fun setObservers() {
viewModel.supportLiveData.observe(this){
when(it){
is ApiResult.Error -> {
progressView.hide()
toast(it.errorMessage)
}
is ApiResult.Loading -> progressView.show()
is ApiResult.Success -> {
progressView.hide()
toast(it.message)
}
null -> {}
}
}
}
private fun initViews() {
binding.apply {
if (userPrefs?.userType != UserType.GUEST){
// user is logged in
nameView.hide()
emailView.hide()
}
val adapter: ArrayAdapter<*> = ArrayAdapter(
this@SupportActivity,
android.R.layout.simple_spinner_item,
subjects.toList()
)
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item
)
subjectSpinner.setAdapter(adapter)
}
}
private fun clickEvents() {
binding.apply {
backBtn.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
submit.setOnClickListener {
if (allOkay()){
binding.apply {
if (userPrefs?.userType == UserType.GUEST){
viewModel.supportForGuest(
email.text.toString(),
name.text.toString(),
subjectSpinner.selectedItem.toString(),
message.text.toString()
)
}else{
viewModel.supportForUser(
userPrefs?.userData?.id.toString(),
subjectSpinner.selectedItem.toString(),
message.text.toString()
)
}
}
}
}
}
}
private fun allOkay(): Boolean {
var allOkay = true
binding.apply {
name.error = null
email.error = null
message.error = null
if (userPrefs?.userType == UserType.GUEST){
if (name.text.isEmpty()){
name.error = getString(R.string.required)
allOkay = false
}
if (!Patterns.EMAIL_ADDRESS.matcher(email.text).matches()){
email.error = getString(R.string.invalid_email)
allOkay = false
}
}
if (subjectSpinner.selectedItemId == 0L){
toast("Please select a subject")
allOkay = false
}
if (message.text.isEmpty()){
message.error = getString(R.string.required)
allOkay = false
}
}
return allOkay
}
}

View File

@@ -0,0 +1,40 @@
package com.woka.home.sidebar.support
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.woka.modules.ModuleRepository
import com.woka.networking.ApiResult
import kotlinx.coroutines.launch
class SupportViewModel: ViewModel() {
private val _supportLiveData = MutableLiveData<ApiResult<Any>?>()
val supportLiveData: LiveData<ApiResult<Any>?>
get() = _supportLiveData
fun supportForGuest(email: String, name: String, subject: String, message: String) {
viewModelScope.launch {
_supportLiveData.postValue(ApiResult.Loading())
_supportLiveData.postValue(ModuleRepository.supportForGuest(
email,
name,
subject,
message
))
}
}
fun supportForUser(userId: String, subject: String, message: String) {
viewModelScope.launch {
_supportLiveData.postValue(ApiResult.Loading())
_supportLiveData.postValue(ModuleRepository.supportForUser(
userId,
subject,
message
))
}
}
}

View File

@@ -3,7 +3,9 @@ package com.woka.modules
import com.woka.modules.blogs.models.BlogsResponse
import com.woka.modules.faqs.models.FaqResponse
import com.woka.networking.ApiResponse
import okhttp3.FormBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
@@ -13,5 +15,11 @@ interface ModuleApiService {
suspend fun getBlogs(): Response<ApiResponse<BlogsResponse>>
@POST("faq_listing")
suspend fun getFaqs(): Response<ApiResponse<FaqResponse>>
suspend fun getFaqs(@Body formBody: FormBody): Response<ApiResponse<FaqResponse>>
@POST("guest_queries_store")
suspend fun supportForGuest(@Body body: FormBody): Response<ApiResponse<Any>>
@POST("guest_queries_store")
suspend fun supportForUser(@Body body: FormBody): Response<ApiResponse<Any>>
}

View File

@@ -0,0 +1,36 @@
package com.woka.modules
import com.woka.networking.ApiResult
import com.woka.networking.RetrofitHelper
import okhttp3.FormBody
object ModuleRepository {
private val moduleApiService = RetrofitHelper.getRetrofit().create(ModuleApiService::class.java)
suspend fun supportForGuest(email: String, name: String, subject: String, message: String): ApiResult<Any> {
return RetrofitHelper.handleApiCall {
moduleApiService.supportForGuest(
FormBody.Builder()
.add("name", name)
.add("email_id", email)
.add("subject", subject)
.add("message", message)
.build()
)
}
}
suspend fun supportForUser(userId: String, subject: String, message: String): ApiResult<Any> {
return RetrofitHelper.handleApiCall {
moduleApiService.supportForGuest(
FormBody.Builder()
.add("user_id", userId)
.add("subject", subject)
.add("message", message)
.build()
)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.woka.home
package com.woka.modules.blogs
import android.view.LayoutInflater
import android.view.ViewGroup

View File

@@ -9,6 +9,7 @@ import com.woka.networking.RetrofitHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.FormBody
object FAQsRepository {
@@ -24,7 +25,11 @@ object FAQsRepository {
private suspend fun getBlogs(): ApiResult<FaqResponse> {
return RetrofitHelper.handleApiCall {
apiService.getFaqs()
apiService.getFaqs(
FormBody.Builder()
.add("faq_category_key", "watch")
.build()
)
}
}

View File

@@ -1,6 +1,6 @@
package com.woka.modules.faqs.models
data class Result(
data class Faq(
val category_master_id: Int?,
val english_answer: String?,
val english_question: String?,

View File

@@ -1,6 +1,6 @@
package com.woka.modules.faqs.models
data class FaqResponse(
val result: List<Result?>?,
val result: List<Faq?>?,
val total_records: Int?
)

View File

@@ -37,6 +37,8 @@ class UserPreference(context: Context) {
@SuppressLint("HardwareIds")
val deviceId: String = Secure.getString(context.contentResolver, Secure.ANDROID_ID)
var userData: UserData? = null
var appLanguage: String
get() = userPrefs.getString(APP_LANGUAGE, "en") ?: "en"
set(value) = userPrefs.edit().putString(APP_LANGUAGE, value).apply()
@@ -66,7 +68,15 @@ class UserPreference(context: Context) {
fun loadUserData() {
CoroutineScope(Dispatchers.IO).launch {
_userLiveData.postValue(ApiResult.Loading())
_userLiveData.postValue(userRepository.getUserData())
val result = userRepository.getUserData()
when (result){
is ApiResult.Error -> {}
is ApiResult.Loading -> {}
is ApiResult.Success -> userData = result.data?.result
}
_userLiveData.postValue(result)
}
}