Skip to content

Instantly share code, notes, and snippets.

@PollyGlot
Created January 3, 2020 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PollyGlot/576806af99492a865d9de5cefd85ce11 to your computer and use it in GitHub Desktop.
Save PollyGlot/576806af99492a865d9de5cefd85ce11 to your computer and use it in GitHub Desktop.
RecyclerView adapter to show several recyclerviews with different orientations and types of headers
package com.kinomap.trainingapps.helper
import android.content.Intent
import android.os.Bundle
import android.preference.PreferenceManager
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.navigation.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.request.RequestOptions
import com.kinomap.api.helper.GlideApp
import com.kinomap.api.helper.constants.PreferencesConstants
import com.kinomap.api.helper.model.VideoCoaching
import com.kinomap.api.helper.model.VideoObject
import com.kinomap.api.helper.model.VideoSection
import com.kinomap.api.helper.util.UnitHelper
import com.kinomap.kinomapcommon.util.setSafeOnClickListener
import com.kinomap.trainingapps.equipment.helper.Util
import com.kinomap.trainingapps.helper.FilterActivity.Companion.VIDEOS_FILTER
import kotlinx.android.synthetic.main.header_filter.view.*
class VideosListAdapter(
val hasHeader: Boolean
) : RecyclerView.Adapter<VideosListAdapter.ViewHolder>() {
val videosList: MutableList<VideoObject> = mutableListOf()
private lateinit var linearItemDecoration: LinearItemHorizontalOffsetDecoration
val recommendedVideosAdapter = VideosAdapter(
VideosAdapter.From.LIST_VIDEOS,
hasHeader = false,
headerType = null,
isRecommended = true,
isGrid = false
)
override fun getItemViewType(position: Int): Int {
return when (hasHeader) {
position == 0 -> HEADER_TITLE_SUBTITLE
position == 1 -> LIST_RECOMMENDED
position == 2 -> HEADER_FILTER
position >= 3 -> {
when (videosList[position - 3]) {
is VideoSection -> VIDEO_ITEM_DYNAMIC
is VideoCoaching -> VIDEO_COACHING_DYNAMIC
else -> 0
}
}
else -> 0
}
}
fun hasHeader(position: Int) = position <= 2
override fun getItemCount() = videosList.size + 3
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
var view: View? = null
when (viewType) {
HEADER_FILTER -> view = LayoutInflater.from(parent.context).inflate(R.layout.header_filter, parent, false)
LIST_RECOMMENDED -> view = LayoutInflater.from(parent.context).inflate(R.layout.list_recommended, parent, false)
VIDEO_ITEM_DYNAMIC -> view = LayoutInflater.from(parent.context).inflate(R.layout.item_video_dynamic, parent, false)
HEADER_TITLE_SUBTITLE -> view = LayoutInflater.from(parent.context).inflate(R.layout.header_title_subtitle, parent, false)
VIDEO_COACHING_DYNAMIC -> view = LayoutInflater.from(parent.context).inflate(R.layout.item_video_coaching, parent, false)
}
val holder = ViewHolder(view!!)
when (viewType) {
LIST_RECOMMENDED -> {
linearItemDecoration = when (holder.itemView.context.resources.getBoolean(R.bool.isTablet)) {
true -> LinearItemHorizontalOffsetDecoration(holder.itemView.context, R.dimen.item_offset_24)
false -> LinearItemHorizontalOffsetDecoration(holder.itemView.context, R.dimen.item_offset_16)
}
holder.listRecommendedRecyclerView.addItemDecoration(linearItemDecoration)
}
HEADER_FILTER -> {
view.headerFilterBtn.setSafeOnClickListener {
val intent = Intent(view.context, FilterActivity::class.java)
intent.putExtra(FilterActivity.ARGS_TYPE_FILTER, VIDEOS_FILTER)
(view.context as BottomNavigationActivity).startActivityForResult(intent, FilterActivity.REQUEST_CODE)
}
}
}
return ViewHolder(view)
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val image = itemView.findViewById<ImageView>(R.id.videoImage)
val authorImage = itemView.findViewById<ImageView>(R.id.videoAuthorAvatar)
val authorUsername = itemView.findViewById<TextView>(R.id.videoAuthorUsername)
val title = itemView.findViewById<TextView>(R.id.videoTitle)
val sport = itemView.findViewById<ImageView>(R.id.videoSportIcon)
val country = itemView.findViewById<ImageView>(R.id.videoStartCountry)
val languageCoaching = itemView.findViewById<TextView>(R.id.videoCoachingLanguage)
val distance = itemView.findViewById<TextView>(R.id.distance)
val distanceUnit = itemView.findViewById<TextView>(R.id.distanceUnit)
val duration = itemView.findViewById<TextView>(R.id.duration)
val durationCoaching = itemView.findViewById<TextView>(R.id.videoCoachingStatisticsDuration)
val durationUnit = itemView.findViewById<TextView>(R.id.durationUnit)
var durationCoachingUnit = itemView.findViewById<TextView>(R.id.videoCoachingStatisticsDurationUnit)
val elevation = itemView.findViewById<TextView>(R.id.elevationAscent)
val elevationUnit = itemView.findViewById<TextView>(R.id.elevationUnit)
val averageInfo = itemView.findViewById<TextView>(R.id.averageInfoData)
val averageInfoUnit = itemView.findViewById<TextView>(R.id.averageInfoUnit)
val averageInfoIcon = itemView.findViewById<ImageView>(R.id.averageInfoIcon)
val difficulty = itemView.findViewById<ImageView>(R.id.difficulty)
val quality = itemView.findViewById<ImageView>(R.id.quality)
val progress: ProgressBar? = itemView.findViewById(R.id.videoProgressBar)
/* Headers */
val headerTitleSubtitleTitle = itemView.findViewById<TextView>(R.id.headerTitleSubtitleTitle)
val headerTitleSubtitleSubtitle = itemView.findViewById<TextView>(R.id.headerTitleSubtitleSubtitle)
var headerFilterTitle = itemView.findViewById<TextView>(R.id.headerFilterTitle)
var headerFilterButton = itemView.findViewById<TextView>(R.id.headerFilterBtn)
val listRecommendedRecyclerView = itemView.findViewById<RecyclerView>(R.id.listRecommendedRecyclerView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (holder.itemViewType) {
HEADER_TITLE_SUBTITLE -> {
holder.headerTitleSubtitleTitle.text = holder.itemView.resources.getString(R.string.menu_recommended_for_you)
holder.headerTitleSubtitleSubtitle.text = holder.itemView.resources.getString(R.string.train_recommended_videos_description)
}
LIST_RECOMMENDED -> {
val recommendedVideosLayoutManager = LinearLayoutManager(holder.itemView.context, LinearLayoutManager.HORIZONTAL, false)
holder.listRecommendedRecyclerView.layoutManager = recommendedVideosLayoutManager
holder.listRecommendedRecyclerView.adapter = recommendedVideosAdapter
}
HEADER_FILTER -> {
val preferences = PreferenceManager.getDefaultSharedPreferences(holder.itemView.context)
holder.headerFilterTitle.text = holder.itemView.resources.getString(R.string.videosList_all_videos_title)
holder.headerFilterButton.setBackgroundResource(
when (preferences.getBoolean(PreferencesConstants.FILTER_VIDEOS_BUTTON_FILTERED, false)) {
true -> R.drawable.btn_circle_filtered_yellow
false -> R.drawable.btn_circle_filter_default
}
)
}
VIDEO_ITEM_DYNAMIC -> {
val videoSectionList = videosList[position - 3] as VideoSection
// Image
GlideApp.with(holder.image.context)
.load(videoSectionList.thumbnailLarge)
.apply(RequestOptions().placeholder(R.drawable.ic_placeholder_flux))
.into(holder.image)
// Profile image
GlideApp.with(holder.authorImage.context)
.load(videoSectionList.user.avatarUrl)
.apply(RequestOptions().circleCrop())
.apply(RequestOptions().placeholder(R.drawable.ic_profile_placeholder))
.into(holder.authorImage)
// Author name
when (videoSectionList.user.username.isNotEmpty()) {
true -> holder.authorUsername.text = videoSectionList.user.username
false -> holder.authorUsername.text = holder.itemView.context.getString(R.string.dash_long)
}
// Video title
when (videoSectionList.name.isNotEmpty()) {
true -> holder.title.text = videoSectionList.name
false -> holder.title.text = holder.itemView.context.getString(R.string.dash)
}
// Sport type
GlideApp.with(holder.itemView.context)
.load(Util.getIconSportType(videoSectionList.sport))
.into(holder.sport)
// Country star
try {
val appPackage = holder.itemView.context.applicationContext.packageName
val resources = holder.itemView.resources
val flagCode = resources.getIdentifier(videoSectionList.countryStart.code, "drawable", appPackage)
Log.d("COUNTRY_CODE", videoSectionList.countryStart.code)
GlideApp.with(holder.country.context)
.load(flagCode)
.into(holder.country)
} catch (e: Exception) {
e.printStackTrace()
}
// Distance
val distance = UnitHelper.getInstance().getDistanceString(videoSectionList.distance, true)
val distanceUnit = UnitHelper.getInstance().getDistanceUnit(videoSectionList.distance)
holder.distance.text = distance.toString()
holder.distanceUnit.text = distanceUnit
// Duration
holder.duration.text = UnitHelper.getInstance().getDurationString(videoSectionList.duration)
holder.durationUnit.text = UnitHelper.getInstance().getDurationUnit(videoSectionList.duration)
// Elevation
val elevation = UnitHelper.getInstance().getElevationString(videoSectionList.elevationAscent.toInt())
val elevationUnit = UnitHelper.getInstance().elevationUnit
holder.elevation.text = elevation
holder.elevationUnit.text = elevationUnit
// Average Info
when (videoSectionList.sport) {
FeedAdapter.ActivityType.CYCLING.activityType -> {
if (UnitHelper.unitModeCycling == UnitHelper.UNIT_MODE_CYCLING.REGULAR_MODE) {
holder.averageInfo.text = UnitHelper.getInstance().getSpeedString(videoSectionList.avgSpeed.toFloat(), true)
holder.averageInfoUnit.text = UnitHelper.getInstance().getUnit(UnitHelper.UNIT_STRING.SPEED)
holder.averageInfoIcon.setImageResource(R.drawable.ic_speed_avg)
} else {
holder.averageInfo.text = videoSectionList.avgPower.toString()
holder.averageInfoUnit.text = holder.itemView.resources.getString(R.string.misc_watts)
holder.averageInfoIcon.setImageResource(R.drawable.ic_watts)
}
}
FeedAdapter.ActivityType.RUNNING.activityType -> {
if (UnitHelper.unitModeRunning == UnitHelper.UNIT_MODE_RUNNING.REGULAR_MODE) {
holder.averageInfo.text = UnitHelper.getInstance().getSpeedString(videoSectionList.avgSpeed.toFloat(), true)
holder.averageInfoUnit.text = UnitHelper.getInstance().getUnit(UnitHelper.UNIT_STRING.SPEED)
holder.averageInfoIcon.setImageResource(R.drawable.ic_speed_avg)
} else {
holder.averageInfo.text = UnitHelper.getRunningAverageSpeedString(videoSectionList.avgSpeed.toFloat())
holder.averageInfoUnit.text = "/${UnitHelper.getInstance().getUnit(UnitHelper.UNIT_STRING.DISTANCE_K)}"
holder.averageInfoIcon.setImageResource(R.drawable.ic_speed_avg)
}
}
FeedAdapter.ActivityType.ROWING.activityType -> {
holder.averageInfo.text = UnitHelper.getRowingAverageSpeedString(videoSectionList.avgSpeed.toFloat())
holder.averageInfoUnit.text = UnitHelper.getInstance().getUnit(UnitHelper.UNIT_STRING.SPEED_ROWING)
holder.averageInfoIcon.setImageResource(R.drawable.ic_speed_avg)
}
}
// Difficulty
GlideApp.with(holder.itemView.context)
.load(Util.getDifficultBanner(videoSectionList.difficultyLevel))
.into(holder.difficulty)
GlideApp.with(holder.itemView.context)
.load(Util.getQualityIcon(videoSectionList.quality))
.into(holder.quality!!)
if (videoSectionList.completionPercent > 0) {
holder.progress?.progress = videoSectionList.completionPercent
holder.progress?.visibility = View.VISIBLE
}
// Click listener
holder.itemView.setOnClickListener {
val data = Bundle()
data.putInt(Constants.VIDEO_ID_KEY, videosList[holder.adapterPosition - 3].id)
data.putString(Constants.VIDEO_TYPE_KEY, Constants.VIDEO_TYPE_SECTION)
holder.itemView.findNavController().navigate(R.id.action_list_video_playlist_fragment_to_video_details_fragment, data)
}
}
VIDEO_COACHING_DYNAMIC -> {
val videoCoachingList = videosList[position - 3] as VideoCoaching
// Image
GlideApp.with(holder.image.context)
.load(videoCoachingList.thumbnailLarge)
.apply(RequestOptions().placeholder(R.drawable.ic_placeholder_flux))
.into(holder.image)
// Profile image
GlideApp.with(holder.authorImage.context)
.load(videoCoachingList.user.avatarUrl)
.apply(RequestOptions().circleCrop())
.apply(RequestOptions().placeholder(R.drawable.ic_profile_placeholder))
.into(holder.authorImage)
// Author name
when (videoCoachingList.user.username.isNotEmpty()) {
true -> holder.authorUsername.text = videoCoachingList.user.username
false -> holder.authorUsername.text = holder.itemView.context.getString(R.string.dash_long)
}
// Video title
when (videoCoachingList.name.isNotEmpty()) {
true -> holder.title.text = videoCoachingList.name
false -> holder.title.text = holder.itemView.context.getString(R.string.dash)
}
// Sport type
GlideApp.with(holder.itemView.context)
.load(Util.getBlackIconEquipmentType(videoCoachingList.equipmentType))
.into(holder.sport)
// Duration
holder.durationCoaching.text = UnitHelper.getInstance().getDurationString(videoCoachingList.duration)
holder.durationCoachingUnit.text = UnitHelper.getInstance().getDurationUnit(videoCoachingList.duration)
// Difficulty
GlideApp.with(holder.itemView.context)
.load(Util.getDifficultBanner(videoCoachingList.difficultyLevel))
.into(holder.difficulty)
GlideApp.with(holder.itemView.context)
.load(Util.getQualityIcon(videoCoachingList.quality))
.into(holder.quality)
// Language
holder.languageCoaching.text = videoCoachingList.langNativeName
if (videoCoachingList.completionPercent > 0) {
holder.progress?.progress = videoCoachingList.completionPercent
holder.progress?.visibility = View.VISIBLE
}
// Click listener
holder.itemView.setOnClickListener {
val data = Bundle()
data.putInt(Constants.VIDEO_ID_KEY, videosList[holder.adapterPosition - 3].id)
data.putString(Constants.VIDEO_TYPE_KEY, Constants.VIDEO_TYPE_COACHING)
holder.itemView.findNavController().navigate(R.id.action_list_video_playlist_fragment_to_video_details_fragment, data)
}
}
}
}
companion object {
const val LIST_RECOMMENDED = 0
const val LIST_ALL_VIDEOS = 1
const val HEADER_TITLE = 2
const val HEADER_TITLE_SUBTITLE = 3
const val HEADER_FILTER = 4
const val VIDEO_ITEM = 5
const val VIDEO_ITEM_DYNAMIC = 6
const val VIDEO_COACHING = 6
const val VIDEO_COACHING_DYNAMIC = 7
const val PLACEHOLDER = 8
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment