Created BlogsActivity and integrated blogs api.

Image loading in Home1Fragment, Home2Fragment and HomeActivity.

Created and shared build with testers.

Integrated navigation component for web series.

Research for problem related to save state of WebSeriesFragment of collapsing toolbar.
Solved it.

Integrated room database dependency with ksp and started working on on creating database for click events.

Created models, dao, database (singleton).

Issue related to app-inspection.
This commit is contained in:
2024-08-05 20:53:29 +05:30
parent 719e8e4441
commit 84fe475951
36 changed files with 821 additions and 179 deletions

1
.idea/gradle.xml generated
View File

@@ -15,5 +15,6 @@
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
<option name="offlineMode" value="true" />
</component>
</project>

2
.idea/kotlinc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.0" />
<option name="version" value="2.0.0" />
</component>
</project>

View File

@@ -3,6 +3,7 @@ plugins {
alias(libs.plugins.jetbrainsKotlinAndroid)
id("kotlin-parcelize")
alias(libs.plugins.navigationSafeArgs)
alias(libs.plugins.ksp)
}
android {
@@ -114,6 +115,14 @@ dependencies {
// audio mixer for karaoke
implementation("com.github.ZeroOneZeroR:android_audio_mixer:v1.1")
// room-database
def room_version = "2.6.1"
implementation(libs.androidx.room.runtime)
ksp("androidx.room:room-compiler:$room_version")
// optional - Kotlin Extensions and Coroutines support for Room
implementation(libs.room.ktx)
implementation libs.androidx.core.ktx
implementation libs.androidx.appcompat
implementation libs.material

View File

@@ -17,11 +17,14 @@
android:supportsRtl="true"
android:theme="@style/Theme.Woka"
tools:targetApi="31">
<activity
android:name=".modules.blogs.view.BlogsActivity"
android:exported="false" />
<activity
android:name=".shop.views.AddressActivity"
android:exported="false"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan" />
android:windowSoftInputMode="adjustPan" />
<activity
android:name=".shop.views.PaymentActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode|fontScale|fontWeightAdjustment|screenLayout"
@@ -76,7 +79,9 @@
android:theme="@style/FullScreenTheme" />
<activity
android:name=".home.views.FMActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode|fontScale|fontWeightAdjustment|screenLayout"
android:exported="false"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/TransparentActivity" />
<activity

View File

@@ -3,6 +3,7 @@ package com.woka
import android.annotation.SuppressLint
import android.app.Application
import com.jwplayer.pub.api.license.LicenseUtil
import com.woka.database.AppDatabase
import com.woka.userPreference.UserPreference
class WokaApp: Application() {
@@ -10,11 +11,14 @@ class WokaApp: Application() {
companion object{
@SuppressLint("StaticFieldLeak")
var userPrefs: UserPreference? = null
var appDatabase: AppDatabase? = null
}
override fun onCreate() {
super.onCreate()
userPrefs = UserPreference(applicationContext)
LicenseUtil().setLicenseKey(this, "LkYoNusv+gSIVJIrXa5Bf59iBNlUMxeg82PM/l8JWk+cD4BE")
appDatabase = AppDatabase.getInstance(applicationContext)
}
}

View File

@@ -0,0 +1,32 @@
package com.woka.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.woka.database.dao.ClicksDao
import com.woka.database.models.clicks.ClickEvent
private const val DATABASE_NAME = "woka_local_db"
@Database(entities = [ClickEvent::class], version = 1)
abstract class AppDatabase : RoomDatabase(){
companion object{
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, DATABASE_NAME
).build()
}
abstract fun clicksDao(): ClicksDao
}

View File

@@ -0,0 +1,12 @@
package com.woka.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import com.woka.database.models.clicks.ClickEvent
@Dao
interface ClicksDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun addClickEvent(vararg clickEvent: ClickEvent)
}

View File

@@ -0,0 +1,17 @@
package com.woka.database.models.clicks
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
private const val DB_TABLE_NAME = "click_events"
@Entity(tableName = DB_TABLE_NAME)
data class ClickEvent(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id") val clickId: Int = 0,
@ColumnInfo(name = "post_id") val postId: String,
@ColumnInfo(name = "post_type") val postType: String,
@ColumnInfo(name = "categoryId") val categoryId: String?,
@ColumnInfo(name = "clicks_count") val clickCount: Int,
)

View File

@@ -16,26 +16,34 @@ import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.Player.Listener
import com.bumptech.glide.Glide
import com.woka.R
import com.woka.WokaApp
import com.woka.WokaApp.Companion.appDatabase
import com.woka.WokaApp.Companion.userPrefs
import com.woka.audiobooks.views.AudioBooksActivity
import com.woka.database.models.clicks.ClickEvent
import com.woka.databinding.FragmentHome1Binding
import com.woka.home.views.FMActivity
import com.woka.home.viewmodels.HomeViewModel
import com.woka.home.views.MoreHomeActivity
import com.woka.home.models.TimePeriod
import com.woka.home.viewmodels.HomeViewModel
import com.woka.home.views.FMActivity
import com.woka.home.views.MoreHomeActivity
import com.woka.karaoke.views.KaraokeActivity
import com.woka.userdata.userDataModels.UserDataResponse
import com.woka.networking.ApiResult
import com.woka.players.views.LiveStreamPlayerActivity
import com.woka.shop.views.ShopActivity
import com.woka.userPreference.UserType
import com.woka.userdata.userDataModels.UserDataResponse
import com.woka.utils.hide
import com.woka.utils.scaleAnimate
import com.woka.utils.show
import com.woka.webseries.views.WebSeriesActivity
import com.woka.wokagames.views.GamesActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class Home1Fragment : Fragment(), Listener {
@@ -181,6 +189,18 @@ class Home1Fragment : Fragment(), Listener {
webSeries.setOnClickListener {
activity?.let {
startActivity(Intent(it, WebSeriesActivity::class.java))
lifecycleScope.launch {
CoroutineScope(Dispatchers.IO).launch {
appDatabase?.clicksDao()?.addClickEvent(
ClickEvent(
postId = "2",
postType = "3",
categoryId = "1",
clickCount = 1
)
)
}
}
}
}
@@ -218,6 +238,15 @@ class Home1Fragment : Fragment(), Listener {
private fun updateUserData(data: UserDataResponse?) {
binding.apply {
data?.result?.avtar_url?.let {
Glide.with(binding.root.context)
.load(it)
.error(R.drawable.profile_placeholder)
.placeholder(R.drawable.profile_placeholder)
.into(profileImage)
}
val name = if (userPrefs?.userType == UserType.GUEST) userPrefs?.guestUserName
else data?.result?.fullname

View File

@@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.bumptech.glide.Glide
import com.jwplayer.pub.api.media.playlists.PlaylistItem
import com.woka.R
import com.woka.WokaApp
@@ -184,6 +185,14 @@ class Home2Fragment : Fragment() {
private fun updateUserData(data: UserDataResponse?) {
binding.apply {
data?.result?.avtar_url?.let {
Glide.with(binding.root.context)
.load(it)
.error(R.drawable.profile_placeholder)
.placeholder(R.drawable.profile_placeholder)
.into(profileImage)
}
val name = if (WokaApp.userPrefs?.userType == UserType.GUEST) WokaApp.userPrefs?.guestUserName
else data?.result?.fullname

View File

@@ -246,7 +246,7 @@ class MyListFragment : Fragment() {
if (engList.isNotEmpty()){
webSeriesEnglishView.show()
dataLoaded = true
webSeriesEAdapter.submitList(engList)
webSeriesEAdapter.submitList(engList.reversed())
}else{
webSeriesEnglishView.hide()
}
@@ -254,7 +254,7 @@ class MyListFragment : Fragment() {
if (hinList.isNotEmpty()){
webSeriesHindiView.show()
dataLoaded = true
webSeriesHAdapter.submitList(hinList)
webSeriesHAdapter.submitList(hinList.reversed())
}else{
webSeriesHindiView.hide()
}
@@ -271,7 +271,7 @@ class MyListFragment : Fragment() {
audioBooksView.show()
dataLoaded = true
audioBooksAdapter.submitList(audioData)
audioBooksAdapter.submitList(audioData.reversed())
}else{
audioBooksView.hide()
}
@@ -283,7 +283,7 @@ class MyListFragment : Fragment() {
karaokeView.show()
dataLoaded = true
karaokeAdapter.submitList(singKaraokeData)
karaokeAdapter.submitList(singKaraokeData.reversed())
}else{
karaokeView.hide()
}
@@ -294,7 +294,7 @@ class MyListFragment : Fragment() {
gamesView.show()
dataLoaded = true
gamesAdapter.submitList(gamesData)
gamesAdapter.submitList(gamesData.reversed())
}else{
gamesView.hide()
}

View File

@@ -13,7 +13,7 @@ import java.util.Calendar
import java.util.Locale
import java.util.concurrent.Executors
class NotificationAdapter(config: AsyncDifferConfig<NotificationData>): ListAdapter<NotificationData, NotificationAdapter.NotificationViewHolder>(config) {
class NotificationAdapter: ListAdapter<NotificationData, NotificationAdapter.NotificationViewHolder>(DIFF_CONFIG) {
companion object{
private val DIFF_UTIL = object : DiffUtil.ItemCallback<NotificationData>(){
@@ -33,10 +33,10 @@ class NotificationAdapter(config: AsyncDifferConfig<NotificationData>): ListAdap
.build()
}
constructor(): this(DIFF_CONFIG)
inner class NotificationViewHolder(val binding: NotificationViewHolderBinding): ViewHolder(binding.root)
var clickListener: ((Int) -> Unit)? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationViewHolder {
return NotificationViewHolder(
NotificationViewHolderBinding.inflate(
@@ -65,5 +65,11 @@ class NotificationAdapter(config: AsyncDifferConfig<NotificationData>): ListAdap
}
holder.binding.bodyTxt.text = notification.title
holder.binding.root.setOnClickListener {
notification.post_type?.let {
clickListener?.invoke(it)
}
}
}
}

View File

@@ -1,15 +1,21 @@
package com.woka.home.notifications
import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.woka.R
import com.woka.audiobooks.views.AudioBooksActivity
import com.woka.databinding.ActivityNotificationsBinding
import com.woka.karaoke.views.KaraokeActivity
import com.woka.networking.ApiResult
import com.woka.shop.views.ShopActivity
import com.woka.utils.WokaBaseActivity
import com.woka.utils.hide
import com.woka.utils.show
import com.woka.webseries.views.WebSeriesActivity
import com.woka.wokagames.views.GamesActivity
class NotificationsActivity : WokaBaseActivity() {
@@ -55,6 +61,23 @@ class NotificationsActivity : WokaBaseActivity() {
backBtn.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
adapter.clickListener = {
when (it){
in 1..4 -> {
WebSeriesActivity::class.java
}
in 6..6 -> GamesActivity::class.java
in 7..7 -> AudioBooksActivity::class.java
in 8..8 -> KaraokeActivity::class.java
in 9..9 -> ShopActivity::class.java
else -> {null}
}?.let {destination ->
startActivity(Intent(
this@NotificationsActivity, destination
))
}
}
}
}

View File

@@ -1,8 +0,0 @@
package com.woka.home.viewmodels
import androidx.lifecycle.ViewModel
class FMViewModel: ViewModel() {
}

View File

@@ -13,7 +13,9 @@ import com.woka.R
import com.woka.audiobooks.views.AudioBooksActivity
import com.woka.databinding.ActivityExploreWokaBinding
import com.woka.karaoke.views.KaraokeActivity
import com.woka.modules.blogs.view.BlogsActivity
import com.woka.players.views.LiveStreamPlayerActivity
import com.woka.shop.views.ShopActivity
import com.woka.utils.WokaBaseActivity
import com.woka.utils.lightStatusBar
import com.woka.webseries.views.WebSeriesActivity
@@ -81,6 +83,14 @@ class ExploreWokaActivity : WokaBaseActivity() {
startActivity(Intent(this@ExploreWokaActivity, KaraokeActivity::class.java))
}
blogs.setOnClickListener {
startActivity(Intent(this@ExploreWokaActivity, BlogsActivity::class.java))
}
shop.setOnClickListener {
startActivity(Intent(this@ExploreWokaActivity, ShopActivity::class.java))
}
}
}
}

View File

@@ -562,7 +562,7 @@ class HomeActivity : WokaBaseActivity(),
value.data?.result?.let {
binding.apply {
it.avtar?.let {
it.avtar_url?.let {
Glide.with(this@HomeActivity)
.load(it)
.placeholder(R.drawable.profile_placeholder)

View File

@@ -13,7 +13,6 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.media3.common.MediaItem
import androidx.recyclerview.widget.SimpleItemAnimator
import com.bumptech.glide.Glide
import com.woka.R
import com.woka.WokaApp.Companion.userPrefs
import com.woka.databinding.ActivityMoreHomeBinding
@@ -216,11 +215,7 @@ class MoreHomeActivity : WokaBaseActivity() {
scrollView.smoothScrollTo(0, 0)
blog.thumbnail_path?.let {
Glide.with(this@MoreHomeActivity)
.load(it)
.placeholder(android.R.color.darker_gray)
.error(android.R.color.darker_gray)
.into(blogImage)
blogImage.loadImage(it)
}
var titleTxt = blog.title

View File

@@ -12,8 +12,8 @@ import com.woka.modules.blogs.models.Blog
import java.util.concurrent.Executors
import kotlin.reflect.KFunction1
class BlogsAdapter(private val onBlogClicked: KFunction1<Blog, Unit>, config: AsyncDifferConfig<Blog>) :
ListAdapter<Blog, BlogsAdapter.BlogViewHolder>(config) {
class BlogsAdapter(private val onBlogClicked: KFunction1<Blog, Unit>, isGridView: Boolean = false) :
ListAdapter<Blog, BlogsAdapter.BlogViewHolder>(ASYNC_DIFF_CONFIG) {
inner class BlogViewHolder(val binding: BlogViewHolderBinding): ViewHolder(binding.root)
@@ -31,8 +31,6 @@ class BlogsAdapter(private val onBlogClicked: KFunction1<Blog, Unit>, config: As
.build()
}
constructor(onBlogClicked: KFunction1<Blog, Unit>): this(onBlogClicked, ASYNC_DIFF_CONFIG)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlogViewHolder {
return BlogViewHolder(BlogViewHolderBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}

View File

@@ -0,0 +1,67 @@
package com.woka.modules.blogs
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.woka.WokaApp
import com.woka.databinding.BlogViewHolderBinding
import com.woka.databinding.BlogViewHolderGridBinding
import com.woka.modules.blogs.models.Blog
import java.util.concurrent.Executors
import kotlin.reflect.KFunction1
class BlogsGridAdapter(private val onBlogClicked: KFunction1<Blog, Unit>, isGridView: Boolean = false) :
ListAdapter<Blog, BlogsGridAdapter.BlogViewHolder>(ASYNC_DIFF_CONFIG) {
inner class BlogViewHolder(val binding: BlogViewHolderGridBinding): ViewHolder(binding.root)
companion object{
private val DIFF_UTILS = object : DiffUtil.ItemCallback<Blog>(){
override fun areItemsTheSame(oldItem: Blog, newItem: Blog): Boolean =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Blog, newItem: Blog): Boolean =
oldItem == newItem
}
private val ASYNC_DIFF_CONFIG = AsyncDifferConfig.Builder(DIFF_UTILS)
.setBackgroundThreadExecutor(Executors.newSingleThreadExecutor())
.build()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlogViewHolder {
return BlogViewHolder(BlogViewHolderGridBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: BlogViewHolder, position: Int) {
val blog = getItem(holder.absoluteAdapterPosition)
holder.binding.apply {
blog.thumbnail_path?.let {
image.loadImage(it)
}
card.setOnClickListener {
onBlogClicked(blog)
}
var titleTxt = blog.title
blog.content_more_details?.let {
if (it.isNotEmpty()){
titleTxt = it[0]?.title
if (it.size > 1 && WokaApp.userPrefs?.appLanguage == "hi"){
titleTxt = it[1]?.title
}
}
}
title.text = titleTxt
}
}
}

View File

@@ -29,7 +29,7 @@ object BlogsRepository{
}
}
private fun loadBlogs(){
fun loadBlogs(){
CoroutineScope(Dispatchers.IO).launch {
_blogsLiveData.postValue(ApiResult.Loading())
_blogsLiveData.postValue(getBlogs())

View File

@@ -0,0 +1,162 @@
package com.woka.modules.blogs.view
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.InsetDrawable
import android.os.Bundle
import android.text.Html
import android.view.WindowManager
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.WokaApp
import com.woka.databinding.ActivityBlogsBinding
import com.woka.databinding.DialogBlogsBinding
import com.woka.modules.blogs.BlogsGridAdapter
import com.woka.modules.blogs.BlogsRepository
import com.woka.modules.blogs.models.Blog
import com.woka.networking.ApiResult
import com.woka.utils.hide
import com.woka.utils.show
class BlogsActivity : AppCompatActivity() {
private lateinit var binding: ActivityBlogsBinding
private lateinit var adapter: BlogsGridAdapter
private lateinit var blogBinding: DialogBlogsBinding
private lateinit var blogDialog: Dialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
binding = ActivityBlogsBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
window.navigationBarColor = getColor(R.color.color_primary)
adapter = BlogsGridAdapter(::obBlogClicked)
initViews()
clickEvents()
initBlogDialog()
setObservers()
}
private fun initViews(){
binding.apply {
toolbar.title.text = getString(R.string.blogs)
rvBlogs.adapter = adapter
}
}
private fun clickEvents(){
binding.apply {
retryBtn.setOnClickListener {
BlogsRepository.loadBlogs()
}
toolbar.backBtn.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
}
private fun initBlogDialog(){
blogBinding = DialogBlogsBinding.inflate(layoutInflater)
blogDialog = Dialog(this)
blogDialog.setContentView(blogBinding.root)
try {
val back = ColorDrawable(Color.TRANSPARENT)
val inset = InsetDrawable(back, 50)
blogDialog.window!!.setBackgroundDrawable(inset)
} catch (e: Exception) {
// do nothing
}
try {
val layoutParams = blogDialog.window!!.attributes
layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT
blogDialog.window!!.setAttributes(layoutParams)
} catch (e: Exception) {
// do nothing
}
blogBinding.close.setOnClickListener { blogDialog.dismiss() }
}
private fun obBlogClicked(blog: Blog){
blogBinding.apply {
scrollView.smoothScrollTo(0, 0)
blog.thumbnail_path?.let {
blogImage.loadImage(it)
}
var titleTxt = blog.title
var descriptionTxt = blog.description
blog.content_more_details?.let {
if (it.isNotEmpty()){
titleTxt = it[0]?.title
descriptionTxt = it[0]?.article
if (it.size > 1 && WokaApp.userPrefs?.appLanguage == "hi"){
titleTxt = it[1]?.title
descriptionTxt = it[1]?.article
}
}
}
blogTitle.text = titleTxt
blogDescription.text = Html.fromHtml(descriptionTxt, Html.FROM_HTML_MODE_LEGACY)
}
blogDialog.show()
}
private fun setObservers(){
BlogsRepository.blogsLiveData.observe(this){
binding.apply {
when (it){
is ApiResult.Error -> {
shimmer.hide()
rvBlogs.hide()
noData.show()
}
is ApiResult.Loading -> {
shimmer.show()
rvBlogs.hide()
noData.hide()
}
is ApiResult.Success -> {
it.data?.blogs?.filterNotNull()?.let {
adapter.submitList(it){
shimmer.hide()
noData.hide()
rvBlogs.show()
}
}
}
null -> {}
}
}
}
}
}

View File

@@ -4,11 +4,12 @@ data class UserData(
val already_logged_in: Boolean,
val is_deactive: Boolean,
val avtar: String?,
val avtar_url: String?,
val gender_data: Gender?,
val birthdate: String?,
val child_detail: ChildDetail?,
val email: String?,
val fullname: String?,
// val gender: Gender?,
val id: Int?,
val is_active: String?,
val language: Language?,

View File

@@ -18,9 +18,13 @@ import com.woka.webseries.models.teaserdata.TeaserData
import kotlinx.coroutines.launch
class WebSeriesViewModel : ViewModel() {
private val repository = WebSeriesRepository
// callbacks
var onShowDataChanged: ((ShowData, String) -> Unit)? = null
var isTrailerExpanded: Boolean = true
var selectedCategoryPos: Int = 0
// categories listing
private val _showCategoryLiveData = MutableLiveData<ApiResult<CategoriesResponse>>()

View File

@@ -4,12 +4,13 @@ import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.navigation.NavOptions
import androidx.navigation.fragment.NavHostFragment
import com.woka.R
import com.woka.databinding.ActivityWebSeriesBinding
import com.woka.utils.WokaBaseActivity
import com.woka.webseries.models.ShowData
import com.woka.webseries.views.fragments.WebSeriesFragment
import com.woka.webseries.views.fragments.WebShowFragment
import com.woka.webseries.views.fragments.WebSeriesFragmentDirections
class WebSeriesActivity : WokaBaseActivity() {
@@ -38,14 +39,11 @@ class WebSeriesActivity : WokaBaseActivity() {
val showData = intent.getParcelableExtra<ShowData>(EXTRA_SHOW_DATA)
val categoryId = intent.getStringExtra(EXTRA_SHOW_CATEGORY)
supportFragmentManager.beginTransaction()
.add(
R.id.fcv_web_series, if (showData != null && categoryId != null) {
WebShowFragment.newInstance(showData, categoryId)
} else {
WebSeriesFragment.newInstance()
}
)
.commit()
if (showData != null && categoryId != null) {
val navHost = supportFragmentManager.findFragmentById(R.id.fc_web_series) as NavHostFragment
navHost.navController.navigate(WebSeriesFragmentDirections.actionWebSeriesFragment2ToWebShowFragment(
showData, categoryId
), NavOptions.Builder().setPopUpTo(R.id.webSeriesFragment2, true).build())
}
}
}

View File

@@ -15,6 +15,7 @@ import android.widget.AdapterView
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.appbar.CollapsingToolbarLayout
import com.jwplayer.pub.api.media.playlists.PlaylistItem
@@ -41,16 +42,14 @@ import com.woka.webseries.models.ContinueEpisodeData
import com.woka.webseries.models.ShowData
import com.woka.webseries.viewmodel.WebSeriesViewModel
class WebSeriesFragment private constructor(): Fragment() {
class WebSeriesFragment : Fragment() {
private lateinit var binding: FragmentWebSeriesBinding
private var viewModel: WebSeriesViewModel? = null
private lateinit var viewModel: WebSeriesViewModel
private lateinit var showAdapter: WebSeriesShowAdapter
private lateinit var continueWatchAdapter: ContinueEpisodeAdapter
private var catSpinnerAdapter: SpinnerAdapter? = null
private lateinit var catSpinnerAdapter: SpinnerAdapter
private lateinit var episodeDialogBinding: DialogContinueEpisodeBinding
private lateinit var episodeDialog: Dialog
@@ -59,20 +58,21 @@ class WebSeriesFragment private constructor(): Fragment() {
private lateinit var noSignInDialog: NoSignInDialog
companion object {
fun newInstance() = WebSeriesFragment()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentWebSeriesBinding.inflate(inflater, container, false)
viewModel = ViewModelProvider(requireActivity())[WebSeriesViewModel::class.java]
activity?.let {
it.window.setBackgroundDrawable(AppCompatResources.getDrawable(it, R.drawable.gradient_web_series))
it.window.setBackgroundDrawable(
AppCompatResources.getDrawable(
it,
R.drawable.gradient_web_series
)
)
it.window.statusBarColor = 0
it.window.lightStatusBar(false)
viewModel = ViewModelProvider(it)[WebSeriesViewModel::class.java]
}
return binding.root
}
@@ -82,6 +82,11 @@ class WebSeriesFragment private constructor(): Fragment() {
noSignInDialog = NoSignInDialog(requireContext())
showAdapter = WebSeriesShowAdapter(requireContext(), ::onShowClicked, ::onShowCommonDataChange) {
noSignInDialog.show()
}
continueWatchAdapter = ContinueEpisodeAdapter(requireContext())
initViews()
initEpisodeDialog()
@@ -90,8 +95,8 @@ class WebSeriesFragment private constructor(): Fragment() {
setObservers()
if (viewModel?.showCategoryLiveData?.isInitialized == false){
viewModel?.loadCategories()
if (!viewModel.showCategoryLiveData.isInitialized) {
viewModel.loadCategories()
}
}
@@ -105,19 +110,19 @@ class WebSeriesFragment private constructor(): Fragment() {
binding.shimmer.show()
binding.errorView.hide()
viewModel?.loadCategories()
viewModel.loadCategories()
}
loadMoreBtn.setOnClickListener {
catSpinnerAdapter?.selectedCategoryType?.let {
catSpinnerAdapter.selectedCategoryType?.let {
loadingMore = true
viewModel?.loadMoreWebSeries(it)
viewModel.loadMoreWebSeries(it)
}
}
trailerBtn.setOnClickListener {
activity?.let {
it.startActivity(Intent(it, PlayerActivity::class.java).apply {
activity.let {
it?.startActivity(Intent(it, PlayerActivity::class.java).apply {
putExtra(
EXTRA_PLAY_LIST,
VideoPlayList(
@@ -139,19 +144,17 @@ class WebSeriesFragment private constructor(): Fragment() {
}
}
}
private fun initViews(){
// adapters
activity?.let {
showAdapter = WebSeriesShowAdapter(it, ::onShowClicked, ::onShowCommonDataChange){
noSignInDialog.show()
}
continueWatchAdapter = ContinueEpisodeAdapter(it)
}
private fun initViews() {
// receiving callbacks
viewModel.onShowDataChanged = ::onShowDataChanged
binding.apply {
adjustMasilaImage()
binding.trailerView.setExpanded(viewModel.isTrailerExpanded)
toolbar.title.text = getString(R.string.web_series)
rvWebSeries.adapter = showAdapter
@@ -175,7 +178,7 @@ class WebSeriesFragment private constructor(): Fragment() {
}
}
private fun initEpisodeDialog(){
private fun initEpisodeDialog() {
episodeDialogBinding = DialogContinueEpisodeBinding.inflate(layoutInflater)
episodeDialog = Dialog(requireContext())
@@ -202,23 +205,24 @@ class WebSeriesFragment private constructor(): Fragment() {
episodeDialogBinding.close.setOnClickListener { episodeDialog.dismiss() }
}
private fun loadShowData(){
catSpinnerAdapter?.selectedCategoryType?.let {
private fun loadShowData() {
catSpinnerAdapter.selectedCategoryType?.let {
loadingMore = false
viewModel?.loadWebSeries(it)
viewModel.loadWebSeries(it)
}
}
private fun setObservers(){
viewModel?.showCategoryLiveData?.observe(viewLifecycleOwner){
when(it){
private fun setObservers() {
viewModel.showCategoryLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
binding.errorView.show()
binding.shimmer.hide()
}
is ApiResult.Loading -> {}
is ApiResult.Success -> {
it.data?.result?.let {catList ->
it.data?.result?.let { catList ->
binding.shimmer.hide()
binding.trailerView.show()
@@ -228,34 +232,34 @@ class WebSeriesFragment private constructor(): Fragment() {
binding.spinnerCard.show()
binding.selectLangTxt.show()
activity?.let {activity ->
catSpinnerAdapter = SpinnerAdapter(activity, catList.filterNotNull())
binding.categorySpinner.setAdapter(catSpinnerAdapter)
catSpinnerAdapter = SpinnerAdapter(requireContext(), catList.filterNotNull())
binding.categorySpinner.setAdapter(catSpinnerAdapter)
binding.categorySpinner.setSelection(viewModel.selectedCategoryPos)
loadShowData()
if (userPrefs?.userType != UserType.GUEST && viewModel?.continueWatchLiveData?.isInitialized == false){
viewModel?.loadContinueWatching()
}
loadShowData()
if (userPrefs?.userType != UserType.GUEST && !viewModel.continueWatchLiveData.isInitialized) {
viewModel.loadContinueWatching()
}
}
}
}
}
viewModel?.continueWatchLiveData?.observe(viewLifecycleOwner){
when (it){
viewModel.continueWatchLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
binding.rvContinueWatch.hide()
binding.continueWatchTxt.hide()
}
is ApiResult.Loading -> {}
is ApiResult.Success -> {
it.data?.result?.let {continueWatchList ->
if (continueWatchList.isNotEmpty()){
it.data?.result?.let { continueWatchList ->
if (continueWatchList.isNotEmpty()) {
binding.rvContinueWatch.show()
binding.continueWatchTxt.show()
continueWatchAdapter.submitList(continueWatchList.asReversed())
}else{
continueWatchAdapter.submitList(continueWatchList.reversed())
} else {
binding.rvContinueWatch.hide()
binding.continueWatchTxt.hide()
}
@@ -264,43 +268,47 @@ class WebSeriesFragment private constructor(): Fragment() {
}
}
viewModel?.webSeriesLiveData?.observe(viewLifecycleOwner){
when (it){
viewModel.webSeriesLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
binding.shimmerShowData.hide()
if (loadingMore){
if (loadingMore) {
// load more
binding.loadMoreBtn.text = getString(R.string.retry)
binding.loadMoreBtn.show()
}else{
} else {
// first time load
binding.rvWebSeries.hide()
binding.shimmerShowData.hide()
binding.loadMoreBtn.hide()
}
}
is ApiResult.Loading -> {
binding.shimmerShowData.show()
binding.loadMoreBtn.hide()
binding.rvWebSeries.setVisibility(loadingMore)
}
is ApiResult.Success -> {
catSpinnerAdapter?.selectedCategoryType?.let { categoryType ->
it.data?.let {showList ->
catSpinnerAdapter.selectedCategoryType?.let { categoryType ->
it.data?.let { showList ->
binding.rvWebSeries.show()
binding.shimmerShowData.hide()
binding.loadMoreBtn.text = getString(R.string.load_more)
binding.loadMoreBtn.setVisibility(viewModel?.categoryPagingData?.get(categoryType)?.lastPage == false)
binding.loadMoreBtn.setVisibility(
viewModel.categoryPagingData[categoryType]?.lastPage == false
)
if (loadingMore){
if (loadingMore) {
// loaded more data
showAdapter.notifyItemRangeInserted(
showAdapter.showList.size,
showList.size
)
}else{
} else {
// new category data load
showAdapter.submitListShowList(showList, categoryType)
}
@@ -318,36 +326,42 @@ class WebSeriesFragment private constructor(): Fragment() {
position: Int,
id: Long
) {
if (position != catSpinnerAdapter?.currentSelection){
catSpinnerAdapter?.let {
if (position != catSpinnerAdapter.currentSelection) {
catSpinnerAdapter.let {
it.selectPosition(position)
loadShowData()
}
}
viewModel.selectedCategoryPos = position
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
binding.trailerView.addOnOffsetChangedListener { _, offset ->
viewModel.isTrailerExpanded = offset == 0
}
}
private fun onShowClicked(showData: ShowData, categoryId: String){
parentFragmentManager.beginTransaction()
.add(R.id.fcv_web_series, WebShowFragment.newInstance(showData, categoryId, ::onShowDataChanged))
.hide(this)
.addToBackStack(null)
.commit()
private fun onShowClicked(showData: ShowData, categoryId: String) {
findNavController().navigate(
WebSeriesFragmentDirections.actionWebSeriesFragment2ToWebShowFragment(
showData, categoryId
)
)
}
// updating common data of shows across all category show list
private fun onShowCommonDataChange(showData: ShowData, categoryId: String){
private fun onShowCommonDataChange(showData: ShowData, categoryId: String) {
// changing in viewmodel data
viewModel?.showCommonDataChanged(showData, categoryId)
viewModel.showCommonDataChanged(showData, categoryId)
}
private fun onShowDataChanged(showData: ShowData, categoryId: String) {
viewModel?.showCommonDataChanged(showData, categoryId)
viewModel.showCommonDataChanged(showData, categoryId)
val position = showAdapter.showList.indexOfFirst { it.id == showData.id }
if (position >= 0 && position < showAdapter.showList.size){
if (position >= 0 && position < showAdapter.showList.size) {
val currData = showAdapter.showList[position]
currData.is_liked = showData.is_liked
@@ -358,18 +372,18 @@ class WebSeriesFragment private constructor(): Fragment() {
}
}
private fun onContinueEpisodeClicked(episodeData: ContinueEpisodeData){
private fun onContinueEpisodeClicked(episodeData: ContinueEpisodeData) {
episodeDialogBinding.apply {
episodeData.content_more_details?.let {moreDetailsList ->
episodeData.content_more_details?.let { moreDetailsList ->
episodeData.thumbnail_path?.let {
episodeData.thumbnail_path.let {
image.loadImage(it)
}
if (moreDetailsList.isNotEmpty()){
if (moreDetailsList.isNotEmpty()) {
if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1){
moreDetailsList[1].let {data ->
if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1) {
moreDetailsList[1].let { data ->
title.text = data.title
description.text = Html.fromHtml(
data.description?.replace(
@@ -378,8 +392,8 @@ class WebSeriesFragment private constructor(): Fragment() {
), Html.FROM_HTML_MODE_LEGACY
)
}
}else{
moreDetailsList[0].let {data ->
} else {
moreDetailsList[0].let { data ->
title.text = data.title
description.text = Html.fromHtml(
data.description?.replace(
@@ -389,7 +403,7 @@ class WebSeriesFragment private constructor(): Fragment() {
)
}
}
}else{
} else {
title.text = episodeData.episode_title
description.text = Html.fromHtml(
episodeData.episode_description?.replace(
@@ -400,11 +414,11 @@ class WebSeriesFragment private constructor(): Fragment() {
}
watchCard.setOnClickListener {
episodeData.content_more_details.let {moreDetailsList ->
episodeData.content_more_details.let { moreDetailsList ->
val videoPlayList = VideoPlayList(ArrayList(), ArrayList())
if (moreDetailsList.isNotEmpty()){
if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1){
if (moreDetailsList.isNotEmpty()) {
if (userPrefs?.appLanguage == "hi" && moreDetailsList.size > 1) {
videoPlayList.playlist.add(
PlaylistItem.Builder()
.file(moreDetailsList[1].content_hd_url)
@@ -421,7 +435,7 @@ class WebSeriesFragment private constructor(): Fragment() {
category_id = "18"
)
)
}else{
} else {
videoPlayList.playlist.add(
PlaylistItem.Builder()
.file(moreDetailsList[0].content_hd_url)
@@ -441,13 +455,11 @@ class WebSeriesFragment private constructor(): Fragment() {
}
}
activity?.let {
startActivity(Intent(it, PlayerActivity::class.java)
.apply {
putExtra(EXTRA_PLAY_LIST, videoPlayList)
putExtra(EXTRA_PLAY_INDEX, 0)
})
}
startActivity(Intent(activity, PlayerActivity::class.java)
.apply {
putExtra(EXTRA_PLAY_LIST, videoPlayList)
putExtra(EXTRA_PLAY_INDEX, 0)
})
}
}

View File

@@ -16,6 +16,7 @@ import android.view.WindowManager
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.navArgs
import com.google.android.material.tabs.TabLayout
import com.jwplayer.pub.api.media.playlists.PlaylistItem
import com.woka.R
@@ -43,23 +44,16 @@ import com.woka.webseries.viewmodel.WebSeriesViewModel
import com.woka.webseries.views.WebSeriesActivity.Companion.EXTRA_SHOW_ID
import kotlin.math.max
class WebShowFragment private constructor(
private var showData: ShowData,
private val categoryId: String,
private val onShowDataChange: ((ShowData, String) -> Unit)? = null
) : Fragment(), TabLayout.OnTabSelectedListener {
companion object {
fun newInstance(
showData: ShowData,
categoryId: String,
onShowDataChange: ((ShowData, String) -> Unit)? = null
) =
WebShowFragment(showData, categoryId, onShowDataChange)
}
class WebShowFragment: Fragment(), TabLayout.OnTabSelectedListener {
private lateinit var binding: FragmentWebShowBinding
private var viewModel: WebSeriesViewModel? = null
private lateinit var viewModel: WebSeriesViewModel
// args
private val args by navArgs<WebShowFragmentArgs>()
private val showData: ShowData by lazy { args.showData }
private val categoryId: String by lazy { args.categoryId }
// variables
@@ -89,11 +83,10 @@ class WebShowFragment private constructor(
savedInstanceState: Bundle?
): View {
binding = FragmentWebShowBinding.inflate(inflater, container, false)
viewModel = ViewModelProvider(this)[WebSeriesViewModel::class.java]
viewModel = ViewModelProvider(requireActivity())[WebSeriesViewModel::class.java]
activity?.let {
it.window.setBackgroundDrawableResource(R.color.web_show_bg)
it.window.lightStatusBar(true)
viewModel = ViewModelProvider(it)[WebSeriesViewModel::class.java]
}
return binding.root
}
@@ -112,7 +105,7 @@ class WebShowFragment private constructor(
setObservers()
binding.seasonProgressView.show()
viewModel?.seasonListing("${showData.id}", categoryId)
viewModel.seasonListing("${showData.id}", categoryId)
}
override fun onDestroyView() {
@@ -128,12 +121,12 @@ class WebShowFragment private constructor(
it.window.lightStatusBar(false)
}
viewModel?.clearSeasonLiveData()
viewModel?.clearEpisodeListingLiveData()
viewModel?.clearTeaserListingLiveData()
viewModel.clearSeasonLiveData()
viewModel.clearEpisodeListingLiveData()
viewModel.clearTeaserListingLiveData()
if (showDataChanged) {
onShowDataChange?.invoke(showData, categoryId)
viewModel.onShowDataChanged?.invoke(showData, categoryId)
}
}
@@ -171,7 +164,7 @@ class WebShowFragment private constructor(
epLoadMoreBtn.setOnClickListener {
loadMoreEpisodes = true
viewModel?.loadMoreEpisodes("${showData.id}", selectedSeasonId)
viewModel.loadMoreEpisodes("${showData.id}", selectedSeasonId)
}
likeSeason.setOnClickListener {
@@ -243,7 +236,7 @@ class WebShowFragment private constructor(
playTrailer.setOnClickListener {
if (seasonsTab.selectedTabPosition >= 0) {
viewModel?.seasonListingMap?.get("${showData.id}_${categoryId}")
viewModel.seasonListingMap["${showData.id}_${categoryId}"]
?.let { seasonList ->
if (seasonsTab.selectedTabPosition < seasonList.size) {
seasonList[seasonsTab.selectedTabPosition].let { seasonData ->
@@ -318,7 +311,7 @@ class WebShowFragment private constructor(
// callbacks
private fun setObservers() {
viewModel?.seasonListingLiveData?.observe(viewLifecycleOwner) {
viewModel.seasonListingLiveData.observe(viewLifecycleOwner) {
binding.seasonsTab.removeAllTabs()
when (it) {
is ApiResult.Error -> {
@@ -342,7 +335,7 @@ class WebShowFragment private constructor(
}
}
viewModel?.episodeListingLiveData?.observe(viewLifecycleOwner) {
viewModel.episodeListingLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
binding.epShimmer.hide()
@@ -373,7 +366,7 @@ class WebShowFragment private constructor(
binding.epShimmer.hide()
binding.epLoadMoreBtn.text = getString(R.string.load_more)
binding.epLoadMoreBtn.setVisibility(viewModel?.episodePagingData?.get("${showData.id}_$selectedSeasonId")?.lastPage == false)
binding.epLoadMoreBtn.setVisibility(viewModel.episodePagingData["${showData.id}_$selectedSeasonId"]?.lastPage == false)
if (loadMoreEpisodes) {
// loaded more data
@@ -390,7 +383,7 @@ class WebShowFragment private constructor(
}
}
viewModel?.teaserListingLiveData?.observe(viewLifecycleOwner) {
viewModel.teaserListingLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
binding.rvTeaser.hide()
@@ -490,7 +483,7 @@ class WebShowFragment private constructor(
startActivity(Intent(it, PlayerActivity::class.java).apply {
putExtra(
PlayerActivity.EXTRA_PLAY_LIST,
viewModel?.episodesPlaylistMap?.get("${showData.id}_${selectedSeasonId}_$categoryId")
viewModel.episodesPlaylistMap["${showData.id}_${selectedSeasonId}_$categoryId"]
)
putExtra(PlayerActivity.EXTRA_PLAY_INDEX, position)
})
@@ -565,7 +558,7 @@ class WebShowFragment private constructor(
private fun loadSeasonData() {
binding.apply {
if (seasonsTab.selectedTabPosition >= 0) {
viewModel?.seasonListingMap?.get("${showData.id}_${categoryId}")
viewModel.seasonListingMap["${showData.id}_${categoryId}"]
?.let { seasonList ->
if (seasonsTab.selectedTabPosition < seasonList.size) {
seasonList[seasonsTab.selectedTabPosition].let { seasonData ->
@@ -579,8 +572,8 @@ class WebShowFragment private constructor(
selectedSeasonId = it
loadMoreEpisodes = false
viewModel?.loadEpisodes("${showData.id}", it)
viewModel?.loadTeasers("${showData.id}", it)
viewModel.loadEpisodes("${showData.id}", it)
viewModel.loadTeasers("${showData.id}", it)
}
seasonYear.text = "${seasonData.release_year}"
@@ -631,7 +624,7 @@ class WebShowFragment private constructor(
startActivity(Intent(it, PlayerActivity::class.java).apply {
putExtra(
PlayerActivity.EXTRA_PLAY_LIST,
viewModel?.teaserPlaylistMap?.get("${showData.id}_${selectedSeasonId}_$categoryId")
viewModel.teaserPlaylistMap["${showData.id}_${selectedSeasonId}_$categoryId"]
)
putExtra(PlayerActivity.EXTRA_PLAY_INDEX, position)
})

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_web_series"
tools:context=".modules.blogs.view.BlogsActivity">
<include android:id="@+id/toolbar"
layout="@layout/layout_toolbar"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/color_primary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:contentDescription="@string/image"
android:src="@drawable/primary_bg"
android:scaleType="fitXY"
app:layout_constraintTop_toBottomOf="@id/g2"
app:layout_constraintBottom_toBottomOf="parent"
/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/g2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.55"/>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="@+id/shimmer"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:shimmer_auto_start="true"
app:shimmer_duration="1500"
app:shimmer_highlight_alpha="0.5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:baselineAligned="false"
android:weightSum="2">
<include layout="@layout/blog_view_holder_grid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<include layout="@layout/blog_view_holder_grid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"
android:baselineAligned="false"
android:weightSum="2">
<include layout="@layout/blog_view_holder_grid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<include layout="@layout/blog_view_holder_grid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
</com.facebook.shimmer.ShimmerFrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_blogs"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/blog_view_holder_grid"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="2"
tools:itemCount="6"
android:layout_marginTop="10dp"
/>
<LinearLayout
android:id="@+id/no_data"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:contentDescription="@string/image"
android:src="@drawable/img_support"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/something_went_wrong"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/white"
android:textSize="@dimen/_14ssp"
android:layout_marginTop="10dp"
/>
<TextView
android:id="@+id/retry_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/retry_underline"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/white"
android:textSize="@dimen/_12ssp"
android:padding="5dp"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fcv_web_series"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fc_web_series"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".webseries.views.WebSeriesActivity"/>
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph_web_series"
tools:context=".webseries.views.WebSeriesActivity" />

View File

@@ -4,7 +4,6 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/_130sdp"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/round_bg_5"
android:backgroundTint="@color/white"
android:layout_marginStart="15dp"

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<com.woka.utils.PressableCard xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="@dimen/_130sdp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/round_bg_5"
android:backgroundTint="@color/white"
android:layout_marginHorizontal="5dp"
android:layout_marginBottom="10dp"
app:pressType="scale"
app:scaleFrom="0.95"
app:scaleTo="1"
android:elevation="3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.woka.utils.AdiImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="@dimen/_70sdp"
app:imageCornerRadius="5dp"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="10dp"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/exo_2_bold"
android:textColor="@color/color_primary"
android:textSize="12sp"
android:layout_marginTop="10dp"
android:layout_marginStart="10dp"
android:layout_marginBottom="10dp"
android:ems="9"
android:maxLines="3"
android:ellipsize="end"
/>
</LinearLayout>
</com.woka.utils.PressableCard>

View File

@@ -37,13 +37,10 @@
app:cardCornerRadius="15dp"
>
<ImageView
<com.woka.utils.AdiImageView
android:id="@+id/blog_image"
android:layout_width="match_parent"
android:layout_height="@dimen/_150sdp"
android:src="@android:color/darker_gray"
android:contentDescription="@string/image"
android:scaleType="fitXY"
/>
</androidx.cardview.widget.CardView>

View File

@@ -7,7 +7,7 @@
android:layout_height="match_parent"
android:background="@drawable/gradient_web_series"
android:orientation="vertical"
tools:context=".webseries.views.WebSeriesActivity">
tools:context="com.woka.webseries.views.fragments.WebSeriesFragment">
<include android:id="@+id/toolbar"
layout="@layout/layout_toolbar"/>

View File

@@ -5,7 +5,9 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_primary">
android:background="@color/color_primary"
tools:context=".webseries.views.fragments.WebShowFragment"
>
<LinearLayout
android:layout_width="match_parent"

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph_web_series"
app:startDestination="@id/webSeriesFragment2">
<fragment
android:id="@+id/webSeriesFragment2"
android:name="com.woka.webseries.views.fragments.WebSeriesFragment"
android:label="fragment_web_series"
tools:layout="@layout/fragment_web_series" >
<action
android:id="@+id/action_webSeriesFragment2_to_webShowFragment"
app:destination="@id/webShowFragment"
/>
</fragment>
<fragment
android:id="@+id/webShowFragment"
android:name="com.woka.webseries.views.fragments.WebShowFragment"
android:label="fragment_web_show"
tools:layout="@layout/fragment_web_show" >
<argument
android:name="showData"
app:argType="com.woka.webseries.models.ShowData" />
<argument
android:name="categoryId"
app:argType="string" />
</fragment>
</navigation>

View File

@@ -3,4 +3,5 @@ plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
alias(libs.plugins.navigationSafeArgs) apply false
alias(libs.plugins.ksp) apply false
}

View File

@@ -1,6 +1,6 @@
[versions]
agp = "8.3.0"
kotlin = "1.9.0"
kotlin = "2.0.0"
coreKtx = "1.12.0"
junit = "4.13.2"
junitVersion = "1.1.5"
@@ -12,9 +12,13 @@ constraintlayout = "2.1.4"
navigationFragmentKtx = "2.7.7"
navigationUiKtx = "2.7.7"
navigationSafeArgs = "2.7.7"
roomKtx = "2.6.1"
roomRuntime = "2.6.1"
ksp = "2.0.0-1.0.24"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomRuntime" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
@@ -24,8 +28,10 @@ androidx-activity = { group = "androidx.activity", name = "activity", version.re
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomKtx" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
navigationSafeArgs = {id = "androidx.navigation.safeargs.kotlin", version.ref = "navigationSafeArgs"}
navigationSafeArgs = {id = "androidx.navigation.safeargs.kotlin", version.ref = "navigationSafeArgs"}
ksp = {id = "com.google.devtools.ksp", version.ref = "ksp"}