Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package com.battlelancer.seriesguide.people

import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.ViewGroup
import androidx.appcompat.widget.SearchView
import com.battlelancer.seriesguide.R
import com.battlelancer.seriesguide.databinding.ActivityPeopleBinding
import com.battlelancer.seriesguide.people.PeopleFragment.OnShowPersonListener
Expand Down Expand Up @@ -105,6 +107,32 @@ class PeopleActivity : BaseActivity(), OnShowPersonListener {
}
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.people_menu, menu)

val peopleType = PeopleType.valueOf(
intent.getStringExtra(InitBundle.PEOPLE_TYPE)!!
)

val searchItem = menu.findItem(R.id.menu_search)
val searchView = searchItem.actionView as SearchView
searchView.queryHint = "${getString(R.string.search)} ${if (peopleType == PeopleType.CAST) getString(R.string.movie_cast) else getString(R.string.movie_crew)}"
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return true
}

override fun onQueryTextChange(newText: String): Boolean {
val peopleFragment =
supportFragmentManager.findFragmentById(R.id.containerPeople) as PeopleFragment
peopleFragment.search(newText)
return true
}
})

return super.onCreateOptionsMenu(menu)
}

override fun showPerson(tmdbId: Int) {
if (isTwoPane) {
// show inline
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2014-2025 Uwe Trottmann
// Apache-2.0
// Copyright © 2026 Uwe Trottmann <uwe@uwetrottmann.com>

package com.battlelancer.seriesguide.people

Expand All @@ -8,31 +8,52 @@ import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import com.battlelancer.seriesguide.R
import com.battlelancer.seriesguide.tmdbapi.TmdbTools
import com.battlelancer.seriesguide.util.CircleTransformation
import com.battlelancer.seriesguide.util.ImageTools
import com.squareup.picasso.Transformation

/**
* Shows a list of people in rows with headshots, name and description.
*/
internal class PeopleAdapter(context: Context) : ArrayAdapter<Person>(context, LAYOUT) {
interface PeopleAdapterHost {
fun searchResultIsEmpty(isEmpty: Boolean)
}

class PeopleAdapter(
private val host: PeopleAdapterHost,
private val placeholderDrawable: Drawable?
) : BaseAdapter() {

private val personImageTransform = CircleTransformation()
private val placeholderDrawable =
AppCompatResources.getDrawable(context, R.drawable.ic_account_circle_black_24dp)!!

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
private var originalData = emptyList<Person>()
private var data = emptyList<Person>()

fun setData(data: List<Person>) {
originalData = data
this.data = originalData
notifyDataSetChanged()
}

override fun getCount() = data.count()

override fun getItem(position: Int) = data.getOrNull(position)

override fun getItemId(position: Int) = position.toLong()

override fun getView(
position: Int,
convertView: View?,
parent: ViewGroup?
): View {
val view: View
val viewHolder: ViewHolder
val context = parent?.context ?: throw IllegalStateException("Context missing")

if (convertView == null) {
view = LayoutInflater.from(parent.context)
.inflate(LAYOUT, parent, false)
view = LayoutInflater.from(context).inflate(R.layout.item_person, parent, false)
viewHolder = ViewHolder(view, placeholderDrawable)
view.tag = viewHolder
} else {
Expand All @@ -45,17 +66,9 @@ internal class PeopleAdapter(context: Context) : ArrayAdapter<Person>(context, L
return view
}

/**
* Replace the data in this [android.widget.ArrayAdapter] with the given list.
*/
fun setData(data: List<Person>) {
clear()
addAll(data)
}

class ViewHolder(
view: View,
private val placeholderDrawable: Drawable
private val placeholderDrawable: Drawable?
) {
private val name: TextView = view.findViewById(R.id.textViewPerson)
private val description: TextView = view.findViewById(R.id.textViewPersonDescription)
Expand All @@ -67,26 +80,31 @@ internal class PeopleAdapter(context: Context) : ArrayAdapter<Person>(context, L
description.text = person?.description ?: ""

// load profile picture
if (person != null) {
if (person != null && placeholderDrawable != null) {
ImageTools.loadWithPicasso(
context,
TmdbTools.buildProfileImageUrl(
context, person.profilePath,
TmdbTools.ProfileImageSize.W185
context, TmdbTools.buildProfileImageUrl(
context, person.profilePath, TmdbTools.ProfileImageSize.W185
)
)
// Note: dimensions should match placeholder drawable, see notes in its file
.resizeDimen(R.dimen.person_headshot_size, R.dimen.person_headshot_size)
.centerCrop()
.transform(personImageTransform)
.centerCrop().transform(personImageTransform)
.placeholder(placeholderDrawable)
.error(placeholderDrawable)
.into(picture)
.error(placeholderDrawable).into(picture)
}
}
}

companion object {
private val LAYOUT = R.layout.item_person
fun filter(query: String) {
data = originalData.filter { person ->
if (person.description != null) {
person.name.contains(query, ignoreCase = true) ||
person.description.contains(query, ignoreCase = true)
} else {
person.name.contains(query, ignoreCase = true)
}
}
host.searchResultIsEmpty(data.isEmpty())
notifyDataSetChanged()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import android.view.animation.AnimationUtils
import android.widget.AdapterView
import android.widget.ListView
import android.widget.ProgressBar
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.battlelancer.seriesguide.R
Expand All @@ -22,7 +23,7 @@ import com.uwetrottmann.androidutils.AndroidUtils
/**
* A fragment loading and showing a list of cast or crew members.
*/
class PeopleFragment : Fragment() {
class PeopleFragment : Fragment(), PeopleAdapterHost {

private lateinit var listView: ListView
private lateinit var emptyView: EmptyView
Expand Down Expand Up @@ -80,7 +81,6 @@ class PeopleFragment : Fragment() {
ListView.CHOICE_MODE_NONE
}


return rootView
}

Expand All @@ -103,7 +103,10 @@ class PeopleFragment : Fragment() {

emptyView.setButtonClickListener { refresh() }

adapter = PeopleAdapter(requireContext())
adapter = PeopleAdapter(
this,
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_account_circle_black_24dp)
)
listView.adapter = adapter

model.credits.observe(viewLifecycleOwner) {
Expand All @@ -126,7 +129,6 @@ class PeopleFragment : Fragment() {

override fun onDetach() {
super.onDetach()

onShowPersonListener = sDummyListener
}

Expand Down Expand Up @@ -183,6 +185,20 @@ class PeopleFragment : Fragment() {
emptyView.setContentVisibility(View.VISIBLE)
}

fun search(query: String) {
adapter.filter(query)
}

override fun searchResultIsEmpty(isEmpty: Boolean) {
if (isEmpty) {
emptyView.setMessage(R.string.empty_no_results)
emptyView.setButtonGone(true)
} else {
emptyView.setButtonGone(false)
setEmptyMessage()
}
}

companion object {
val liftOnScrollTargetViewId = R.id.listViewPeople

Expand Down
13 changes: 13 additions & 0 deletions app/src/main/res/menu/people_menu.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Apache-2.0 -->
<!-- Copyright © 2026 Uwe Trottmann <uwe@uwetrottmann.com> -->

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_search"
android:icon="@drawable/ic_search_white_24dp"
android:title="@string/search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />
</menu>