diff --git a/README.md b/README.md
index 7651dc89..e6541e6b 100644
--- a/README.md
+++ b/README.md
@@ -177,3 +177,8 @@ If you find ShowCase useful and would like to support its development, please co
+
+## Team Members
+* Mehmet Eren Tutas
+* Doga Celebi
+* Gaye Gulmez
diff --git a/app/src/main/java/com/wirelessalien/android/moviedb/activity/CastActivity.kt b/app/src/main/java/com/wirelessalien/android/moviedb/activity/CastActivity.kt
index 254a079a..fd1448f0 100644
--- a/app/src/main/java/com/wirelessalien/android/moviedb/activity/CastActivity.kt
+++ b/app/src/main/java/com/wirelessalien/android/moviedb/activity/CastActivity.kt
@@ -663,7 +663,15 @@ class CastActivity : BaseActivity() {
castMovieArrayList.add(actorMovies)
}
}
-
+ castMovieArrayList.sortWith(
+ compareByDescending {
+ it.optDouble("vote_average", 0.0)
+ }.thenByDescending {
+ it.optDouble("vote_count", 0.0)
+ }.thenByDescending {
+ it.optDouble("popularity", 0.0)
+ }
+ )
castMovieAdapter = ShowBaseAdapter(context, castMovieArrayList, mShowGenreList!!, preferences.getBoolean(SHOWS_LIST_PREFERENCE, true))
binding.castMovieRecyclerView.adapter = castMovieAdapter
}
@@ -685,6 +693,15 @@ class CastActivity : BaseActivity() {
crewMovieArrayList.add(crewMovies)
}
}
+ crewMovieArrayList.sortWith(
+ compareByDescending {
+ it.optDouble("vote_average", 0.0)
+ }.thenByDescending {
+ it.optDouble("vote_count", 0.0)
+ }.thenByDescending {
+ it.optDouble("popularity", 0.0)
+ }
+ )
crewMovieAdapter = ShowBaseAdapter(context, crewMovieArrayList, mShowGenreList!!, preferences.getBoolean(SHOWS_LIST_PREFERENCE, true))
binding.crewMovieRecyclerView.adapter = crewMovieAdapter
diff --git a/app/src/main/java/com/wirelessalien/android/moviedb/activity/DetailActivity.kt b/app/src/main/java/com/wirelessalien/android/moviedb/activity/DetailActivity.kt
index 66b2f001..08502259 100644
--- a/app/src/main/java/com/wirelessalien/android/moviedb/activity/DetailActivity.kt
+++ b/app/src/main/java/com/wirelessalien/android/moviedb/activity/DetailActivity.kt
@@ -787,25 +787,25 @@ class DetailActivity : BaseActivity(), ListTmdbBottomSheetFragment.OnListCreated
}
val shareText = """
- *${title}*
+ 🎬 $title
- *Overview:*
- $overview
+ ${if (isMovie) "Movie" else "TV Show"}
+ ⭐ TMDB: ${binding.rating.text}
+ IMDb: ${binding.imdbRatingChip.text.toString().replace("IMDb ", "")}
+ Metacritic: $metacriticRating
+ Rotten Tomatoes: $rottenTomatoRating
- *TMDB Link:*
- $tmdbLink
+ Overview:
+ $overview
- *Ratings:*
- - TMDB: ${binding.rating.text}
- - IMDb: ${binding.imdbRatingChip.text.toString().replace("IMDb ", "")}
- - Metacritic: $metacriticRating
- - Rotten Tomatoes: $rottenTomatoRating
+ My MovieDB Notes:
+ • My Rating: $userRatingString
+ • My Review: ${reviewString.ifBlank { getString(R.string.rating_na) }}
+ • Watched: $timesWatchedString time(s)
- - My Review: $reviewString
- - I watched: $timesWatchedString times
- - My $userRatingString
-
- """.trimIndent()
+ Open on TMDB:
+ $tmdbLink
+""".trimIndent()
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.type = "text/plain"
@@ -4374,10 +4374,26 @@ class DetailActivity : BaseActivity(), ListTmdbBottomSheetFragment.OnListCreated
val reader = JSONObject(response)
val similarMovieArray = reader.getJSONArray("results")
similarMovieArrayList.clear()
+
for (i in 0 until similarMovieArray.length()) {
val movieData = similarMovieArray.getJSONObject(i)
- similarMovieArrayList.add(movieData)
+
+ val isAdult = movieData.optBoolean("adult", false)
+ val posterPath = movieData.optString("poster_path", "")
+
+ if (!isAdult && posterPath.isNotBlank() && posterPath != "null") {
+ similarMovieArrayList.add(movieData)
+ }
}
+
+ similarMovieArrayList.sortWith(
+ compareByDescending {
+ it.optDouble("vote_average", 0.0)
+ }.thenByDescending {
+ it.optDouble("popularity", 0.0)
+ }
+ )
+
similarMovieAdapter = SimilarMovieBaseAdapter(
similarMovieArrayList, applicationContext
)
@@ -4387,6 +4403,7 @@ class DetailActivity : BaseActivity(), ListTmdbBottomSheetFragment.OnListCreated
je.printStackTrace()
}
}
+
hideEmptyRecyclerView(binding.movieRecyclerView, binding.similarMovieTitle)
}
@@ -4511,12 +4528,42 @@ class DetailActivity : BaseActivity(), ListTmdbBottomSheetFragment.OnListCreated
val reviewsObject = movieData.getJSONObject("reviews")
val resultsArray = reviewsObject.getJSONArray("results")
- // Extract the first three reviews
+ // Filter and prioritize reviews before showing them on the detail screen
+ val spoilerKeywords = listOf(
+ "spoiler", "ending", "final scene", "dies", "death", "killed", "killer", "reveals"
+ )
+
val reviewList = mutableListOf()
- for (i in 0 until minOf(3, resultsArray.length())) {
- reviewList.add(resultsArray.getJSONObject(i))
+
+ for (i in 0 until resultsArray.length()) {
+ val review = resultsArray.getJSONObject(i)
+ val content = review.optString("content", "").trim()
+
+ if (content.isBlank() || content.length < 50) {
+ continue
+ }
+
+ val containsSpoiler = spoilerKeywords.any { keyword ->
+ content.contains(keyword, ignoreCase = true)
+ }
+
+ if (containsSpoiler) {
+ review.put("content", "⚠️ Possible spoiler\n\n$content")
+ }
+
+ reviewList.add(review)
}
+ reviewList.sortWith(
+ compareByDescending {
+ it.optJSONObject("author_details")?.optDouble("rating", 0.0) ?: 0.0
+ }.thenByDescending {
+ it.optString("content", "").length
+ }
+ )
+
+ val limitedReviewList = reviewList.take(3)
+
// Set up the RecyclerView
val reviewAdapter = object : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReviewAdapter.ReviewViewHolder {
@@ -4525,10 +4572,10 @@ class DetailActivity : BaseActivity(), ListTmdbBottomSheetFragment.OnListCreated
}
override fun onBindViewHolder(holder: ReviewAdapter.ReviewViewHolder, position: Int) {
- holder.bind(reviewList[position])
+ holder.bind(limitedReviewList[position])
}
- override fun getItemCount(): Int = reviewList.size
+ override fun getItemCount(): Int = limitedReviewList.size
}
binding.recyclerViewReviews.layoutManager = LinearLayoutManager(this)
diff --git a/app/src/main/java/com/wirelessalien/android/moviedb/adapter/NowPlayingMovieAdapter.kt b/app/src/main/java/com/wirelessalien/android/moviedb/adapter/NowPlayingMovieAdapter.kt
index ca08ce31..70b85bea 100644
--- a/app/src/main/java/com/wirelessalien/android/moviedb/adapter/NowPlayingMovieAdapter.kt
+++ b/app/src/main/java/com/wirelessalien/android/moviedb/adapter/NowPlayingMovieAdapter.kt
@@ -38,6 +38,7 @@ import org.json.JSONObject
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
+import java.util.Date
class NowPlayingMovieAdapter(private val mShowArrayList: ArrayList?) :
RecyclerView.Adapter() {
@@ -73,16 +74,36 @@ class NowPlayingMovieAdapter(private val mShowArrayList: ArrayList?)
if (showData.has(KEY_NAME)) R.drawable.ic_tv_show else R.drawable.ic_movie
)
- var dateString = if (showData.has(KEY_DATE_MOVIE)) showData.getString(KEY_DATE_MOVIE) else showData.getString(KEY_DATE_SERIES)
+ val rawDate = if (showData.has(KEY_DATE_MOVIE)) {
+ showData.optString(KEY_DATE_MOVIE, "")
+ } else {
+ showData.optString(KEY_DATE_SERIES, "")
+ }
+
val originalFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
+ val localFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.getDefault())
+
try {
- val date = originalFormat.parse(dateString)
- val localFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.getDefault())
- dateString = localFormat.format(date)
+ val releaseDate = originalFormat.parse(rawDate)
+ val today = Date()
+
+ if (releaseDate != null) {
+ val diffInMillis = releaseDate.time - today.time
+ val diffInDays = diffInMillis / (1000 * 60 * 60 * 24)
+
+ val formattedDate = localFormat.format(releaseDate)
+
+ holder.binding.date.text = when {
+ diffInDays > 0 -> "Upcoming • $formattedDate"
+ diffInDays in -30..0 -> "New • $formattedDate"
+ else -> formattedDate
+ }
+ } else {
+ holder.binding.date.text = rawDate
+ }
} catch (e: ParseException) {
- e.printStackTrace()
+ holder.binding.date.text = rawDate
}
- holder.binding.date.text = dateString
} catch (e: JSONException) {
e.printStackTrace()
}
diff --git a/app/src/main/java/com/wirelessalien/android/moviedb/adapter/ReviewAdapter.kt b/app/src/main/java/com/wirelessalien/android/moviedb/adapter/ReviewAdapter.kt
index eb5d9b15..a613425e 100644
--- a/app/src/main/java/com/wirelessalien/android/moviedb/adapter/ReviewAdapter.kt
+++ b/app/src/main/java/com/wirelessalien/android/moviedb/adapter/ReviewAdapter.kt
@@ -31,6 +31,7 @@ import com.wirelessalien.android.moviedb.R
import com.wirelessalien.android.moviedb.databinding.ReviewItemBinding
import org.json.JSONObject
import java.util.Locale
+import android.graphics.Typeface
class ReviewAdapter :
PagingDataAdapter(ReviewDiffCallback()) {
@@ -77,18 +78,26 @@ class ReviewAdapter :
} else {
binding.root.context.getString(R.string.rating_na)
}
- // Set content with max lines and click listener
+ // Set content with spoiler warning, max lines and click listener
val content = review.optString("content")
- binding.textViewContent.text = content
- binding.textViewContent.post {
- if (binding.textViewContent.lineCount > 3) {
- binding.textViewContent.maxLines = 3
- isContentExpanded = false
- } else {
- isContentExpanded = true
- }
+ val isSpoiler = content.startsWith("⚠️ Possible spoiler")
+
+ if (isSpoiler) {
+ val cleanedContent = content
+ .replace("⚠️ Possible spoiler", "")
+ .trim()
+
+ binding.textViewContent.text = "⚠️ SPOILER WARNING\n\n$cleanedContent"
+ binding.textViewContent.setTypeface(null, Typeface.BOLD)
+ binding.textViewContent.alpha = 0.9f
+ } else {
+ binding.textViewContent.text = content
+ binding.textViewContent.setTypeface(null, Typeface.NORMAL)
+ binding.textViewContent.alpha = 1.0f
}
+ binding.textViewContent.post {
+
binding.textViewContent.setOnClickListener {
if (binding.textViewContent.lineCount > 3) {
isContentExpanded = !isContentExpanded
@@ -111,6 +120,17 @@ class ReviewAdapter :
return oldItem.getString("id") == newItem.getString("id")
}
+ override fun areContentsTheSame(oldItem: JSONObject, newItem: JSONObject): Boolean {
+ return oldItem.toString() == newItem.toString()
+ }
+ }
+}
+
+ class ReviewDiffCallback : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: JSONObject, newItem: JSONObject): Boolean {
+ return oldItem.optString("id") == newItem.optString("id")
+ }
+
override fun areContentsTheSame(oldItem: JSONObject, newItem: JSONObject): Boolean {
return oldItem.toString() == newItem.toString()
}
diff --git a/app/src/main/java/com/wirelessalien/android/moviedb/fragment/HomeFragment.kt b/app/src/main/java/com/wirelessalien/android/moviedb/fragment/HomeFragment.kt
index 30a7210b..80f2cd8e 100644
--- a/app/src/main/java/com/wirelessalien/android/moviedb/fragment/HomeFragment.kt
+++ b/app/src/main/java/com/wirelessalien/android/moviedb/fragment/HomeFragment.kt
@@ -75,6 +75,8 @@ class HomeFragment : BaseFragment() {
private lateinit var mTVShowAdapter: NowPlayingMovieAdapter
private lateinit var mUpcomingMovieAdapter: NowPlayingMovieAdapter
private lateinit var mUpcomingTVAdapter: NowPlayingMovieAdapter
+ private lateinit var mTopRatedMovieArrayList: ArrayList
+ private lateinit var mTopRatedMovieAdapter: NowPlayingMovieAdapter
private lateinit var binding: FragmentHomeBinding
private lateinit var activityBinding: ActivityMainBinding
private lateinit var menuProvider: MenuProvider
@@ -101,6 +103,7 @@ class HomeFragment : BaseFragment() {
fetchTrendingList()
fetchUpcomingMovies()
fetchUpcomingTVShows()
+
}
}
}
@@ -117,6 +120,7 @@ class HomeFragment : BaseFragment() {
showTrendingList()
showUpcomingMovieList()
showUpcomingTVShowList()
+ // showTopRatedMovieList()
activityBinding.fab2.visibility = View.GONE
activityBinding.fab.visibility = View.GONE
activityBinding.searchView.setupWithSearchBar(binding.searchbar)
@@ -227,11 +231,13 @@ class HomeFragment : BaseFragment() {
mUpcomingTVAdapter = NowPlayingMovieAdapter(mUpcomingTVShowArrayList)
mUpcomingMovieArrayList = ArrayList()
mUpcomingMovieAdapter = NowPlayingMovieAdapter(mUpcomingMovieArrayList)
+ mTopRatedMovieArrayList = ArrayList()
+ mTopRatedMovieAdapter = NowPlayingMovieAdapter(mTopRatedMovieArrayList)
(requireActivity() as BaseActivity).checkNetwork()
}
private fun setupRecyclerView(
- recyclerView: RecyclerView?,
+ recyclerView: RecyclerView,
layoutManager: LinearLayoutManager,
adapter: RecyclerView.Adapter<*>?
) {
@@ -258,7 +264,10 @@ class HomeFragment : BaseFragment() {
val layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
setupRecyclerView(binding.upcomingMovieRecyclerView, layoutManager, mUpcomingMovieAdapter)
}
-
+ private fun showTopRatedMovieList() {
+ val layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
+ setupRecyclerView(binding.upcomingMovieRecyclerView, layoutManager, mTopRatedMovieAdapter)
+ }
private suspend fun fetchUpcomingTVShows() {
withContext(Dispatchers.Main) {
binding.shimmerFrameLayout5.visibility = View.VISIBLE
@@ -272,7 +281,7 @@ class HomeFragment : BaseFragment() {
val response = fetchData(url)
withContext(Dispatchers.Main) {
if (isAdded && !response.isNullOrEmpty()) {
- handleUpcomingTVResponse(response)
+ handleMovieResponse(response)
} else {
binding.shimmerFrameLayout5.visibility = View.GONE
binding.shimmerFrameLayout5.stopShimmer()
@@ -323,7 +332,7 @@ class HomeFragment : BaseFragment() {
val response = fetchData(url)
withContext(Dispatchers.Main) {
if (isAdded && !response.isNullOrEmpty()) {
- handleMovieResponse(response)
+ //SDFKLNHGJKSHKDJFGHSJKLGHDFJKFDGHKJFDHJKFGDHJGIDFK
} else {
binding.shimmerFrameLayout2.visibility = View.GONE
binding.shimmerFrameLayout2.stopShimmer()
@@ -374,10 +383,12 @@ class HomeFragment : BaseFragment() {
val reader = JSONObject(response)
val arrayData = reader.getJSONArray("results")
mHomeShowArrayList.clear()
+
for (i in 0 until arrayData.length()) {
val websiteData = arrayData.getJSONObject(i)
mHomeShowArrayList.add(websiteData)
}
+
binding.nowPlayingRecyclerView.adapter = mHomeShowAdapter
mShowListLoaded = true
binding.shimmerFrameLayout2.visibility = View.GONE