@ -178,6 +178,19 @@ class HistoryAdapter(
}
}
private fun createExpandedContent ( context : Context ) : View
private fun createExpandedContent ( context : Context ) : View
{
// Create placeholder that will be replaced when content is needed
return android . widget . FrameLayout ( context ) . apply {
layoutParams = LinearLayout . LayoutParams (
LinearLayout . LayoutParams . MATCH_PARENT ,
LinearLayout . LayoutParams . WRAP_CONTENT
)
tag = " expanded_content "
visibility = View . GONE
}
}
private fun createPopulatedExpandedContent ( context : Context , result : DetectionResult ) : View
{
{
return androidx . core . widget . NestedScrollView ( context ) . apply {
return androidx . core . widget . NestedScrollView ( context ) . apply {
// Set a reasonable fixed height for the scrollable area
// Set a reasonable fixed height for the scrollable area
@ -189,6 +202,7 @@ class HistoryAdapter(
// Configure scrolling behavior optimized for nested scrolling
// Configure scrolling behavior optimized for nested scrolling
isFillViewport = false
isFillViewport = false
isNestedScrollingEnabled = true
isNestedScrollingEnabled = true
tag = " expanded_content "
val contentContainer = LinearLayout ( context ) . apply {
val contentContainer = LinearLayout ( context ) . apply {
orientation = LinearLayout . VERTICAL
orientation = LinearLayout . VERTICAL
@ -200,6 +214,16 @@ class HistoryAdapter(
tag = " expanded_container "
tag = " expanded_container "
}
}
// Populate content immediately - this is the key fix!
if ( result . success && result . pokemonInfo != null ) {
populatePokemonInfoViewsForContainer ( result . pokemonInfo , contentContainer , context )
} else {
populateErrorInfoViewsForContainer ( result , contentContainer , context )
}
// Technical info
populateTechnicalInfoViewsForContainer ( result , contentContainer , context )
addView ( contentContainer )
addView ( contentContainer )
}
}
}
}
@ -223,232 +247,144 @@ class HistoryAdapter(
) . toInt ( )
) . toInt ( )
}
}
inner class HistoryViewHolder ( itemView : View ) : RecyclerView . ViewHolder ( itemView )
private fun populatePokemonInfoViewsForContainer ( pokemonInfo : com . quillstudios . pokegoalshelper . PokemonInfo , container : LinearLayout , context : Context )
{
private val cardContainer = itemView as LinearLayout
private val collapsedContent = itemView . findViewWithTag < LinearLayout > ( " collapsed_content " )
private val expandedContent = itemView . findViewWithTag < androidx . core . widget . NestedScrollView > ( " expanded_content " )
private val expandedContainer = expandedContent . findViewWithTag < LinearLayout > ( " expanded_container " )
// Collapsed content views
private val statusIcon = collapsedContent . findViewWithTag < ImageView > ( " status_icon " )
private val titleText = collapsedContent . findViewWithTag < TextView > ( " title_text " )
private val subtitleText = collapsedContent . findViewWithTag < TextView > ( " subtitle_text " )
private val chevronIcon = collapsedContent . findViewWithTag < TextView > ( " chevron_icon " )
fun bind ( item : HistoryItem , position : Int )
{
val result = item . result
val context = itemView . context
// Update collapsed content
updateCollapsedContent ( result , context )
// Update expanded content if needed
if ( item . isExpanded ) {
updateExpandedContent ( result , context )
showExpandedContent ( )
} else {
hideExpandedContent ( )
}
// Set click listeners
collapsedContent . setOnClickListener {
onItemClick ( result , position )
}
// Add delete button in expanded state
if ( item . isExpanded ) {
addDeleteButton ( result , position , context )
}
}
private fun updateCollapsedContent ( result : DetectionResult , context : Context )
{
// Status icon
statusIcon . setImageResource (
if ( result . success ) android . R . drawable . ic_menu_myplaces
else android . R . drawable . ic_dialog_alert
)
statusIcon . setColorFilter (
ContextCompat . getColor (
context ,
if ( result . success ) android . R . color . holo_green_light
else android . R . color . holo_red_light
)
)
// Title (Pokemon name or status)
titleText . text = when {
result . success && result . pokemonInfo ?. species != null -> {
result . pokemonInfo . species +
( result . pokemonInfo . nationalDexNumber ?. let { " (# $it ) " } ?: " " )
}
result . success -> " Pokemon Detected "
else -> " Detection Failed "
}
// Subtitle (timestamp and processing time)
val formatter = DateTimeFormatter . ofPattern ( " MMM dd, HH:mm " )
subtitleText . text = " ${result.timestamp.format(formatter)} • ${result.processingTimeMs} ms "
// Chevron rotation based on expansion state
val rotation = if ( expandedContent . visibility == View . VISIBLE ) 180f else 0f
chevronIcon . rotation = rotation
}
private fun updateExpandedContent ( result : DetectionResult , context : Context )
{
expandedContainer . removeAllViews ( )
if ( result . success && result . pokemonInfo != null ) {
addPokemonInfoViews ( result . pokemonInfo , context )
} else {
addErrorInfoViews ( result , context )
}
// Technical info
addTechnicalInfoViews ( result , context )
}
private fun addPokemonInfoViews ( pokemonInfo : com . quillstudios . pokegoalshelper . PokemonInfo , context : Context )
{
{
// Basic Pokemon Info Section
// Basic Pokemon Info Section
addSectionHead er ( " Pokemon Info " , context )
container . addView ( createSectionHeaderForContainer ( " Pokemon Info " , context ) )
addTwoColumnRow (
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Species " , leftValue = pokemonInfo . species ?: " Unknown " ,
leftLabel = " Species " , leftValue = pokemonInfo . species ?: " Unknown " ,
rightLabel = " Dex # " , rightValue = pokemonInfo . nationalDexNumber ?. let { " # $it " } ?: " N/A " ,
rightLabel = " Dex # " , rightValue = pokemonInfo . nationalDexNumber ?. let { " # $it " } ?: " N/A " ,
context = context
context = context
)
) )
addTwoColumnRow (
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Nickname " , leftValue = pokemonInfo . nickname ?: " None " ,
leftLabel = " Nickname " , leftValue = pokemonInfo . nickname ?: " None " ,
rightLabel = " Gender " , rightValue = pokemonInfo . gender ?: " Unknown " ,
rightLabel = " Gender " , rightValue = pokemonInfo . gender ?: " Unknown " ,
context = context
context = context
)
) )
addTwoColumnRow (
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Level " , leftValue = pokemonInfo . level ?. toString ( ) ?: " N/A " ,
leftLabel = " Level " , leftValue = pokemonInfo . level ?. toString ( ) ?: " N/A " ,
rightLabel = " Nature " , rightValue = pokemonInfo . nature ?: " Unknown " ,
rightLabel = " Nature " , rightValue = pokemonInfo . nature ?: " Unknown " ,
context = context
context = context
)
) )
// Types Section
// Types Section
addSectionHead er ( " Types " , context )
container . addView ( createSectionHeaderForContainer ( " Types " , context ) )
val typeDisplay = when {
val typeDisplay = when {
pokemonInfo . primaryType != null && pokemonInfo . secondaryType != null ->
pokemonInfo . primaryType != null && pokemonInfo . secondaryType != null ->
" ${pokemonInfo.primaryType} / ${pokemonInfo.secondaryType} "
" ${pokemonInfo.primaryType} / ${pokemonInfo.secondaryType} "
pokemonInfo . primaryType != null -> pokemonInfo . primaryType
pokemonInfo . primaryType != null -> pokemonInfo . primaryType
else -> " Unknown "
else -> " Unknown "
}
}
addTwoColumnRow (
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Type " , leftValue = typeDisplay ,
leftLabel = " Type " , leftValue = typeDisplay ,
rightLabel = " Tera " , rightValue = pokemonInfo . teraType ?: " N/A " ,
rightLabel = " Tera " , rightValue = pokemonInfo . teraType ?: " N/A " ,
context = context
context = context
)
) )
// Stats Section (if available)
// Stats Section (if available)
pokemonInfo . stats ?. let { stats ->
pokemonInfo . stats ?. let { stats ->
addSectionHead er ( " Base Stats " , context )
container . addView ( createSectionHeaderForContainer ( " Base Stats " , context ) )
addThreeColumnRow (
container . addView ( createThreeColumnRowForContainer (
leftLabel = " HP " , leftValue = stats . hp ?. toString ( ) ?: " ? " ,
leftLabel = " HP " , leftValue = stats . hp ?. toString ( ) ?: " ? " ,
middleLabel = " ATK " , middleValue = stats . attack ?. toString ( ) ?: " ? " ,
middleLabel = " ATK " , middleValue = stats . attack ?. toString ( ) ?: " ? " ,
rightLabel = " DEF " , rightValue = stats . defense ?. toString ( ) ?: " ? " ,
rightLabel = " DEF " , rightValue = stats . defense ?. toString ( ) ?: " ? " ,
context = context
context = context
)
) )
addThreeColumnRow (
container . addView ( createThreeColumnRowForContainer (
leftLabel = " SP.ATK " , leftValue = stats . spAttack ?. toString ( ) ?: " ? " ,
leftLabel = " SP.ATK " , leftValue = stats . spAttack ?. toString ( ) ?: " ? " ,
middleLabel = " SP.DEF " , middleValue = stats . spDefense ?. toString ( ) ?: " ? " ,
middleLabel = " SP.DEF " , middleValue = stats . spDefense ?. toString ( ) ?: " ? " ,
rightLabel = " SPEED " , rightValue = stats . speed ?. toString ( ) ?: " ? " ,
rightLabel = " SPEED " , rightValue = stats . speed ?. toString ( ) ?: " ? " ,
context = context
context = context
)
) )
}
}
// Special Properties Section
// Special Properties Section
addSectionHead er ( " Properties " , context )
container . addView ( createSectionHeaderForContainer ( " Properties " , context ) )
addCheckboxRow (
container . addView ( createCheckboxRowForContainer (
leftLabel = " Shiny " , leftChecked = pokemonInfo . isShiny ,
leftLabel = " Shiny " , leftChecked = pokemonInfo . isShiny ,
rightLabel = " Alpha " , rightChecked = pokemonInfo . isAlpha ,
rightLabel = " Alpha " , rightChecked = pokemonInfo . isAlpha ,
context = context
context = context
)
) )
addMixedRow (
container . addView ( createMixedRowForContainer (
leftLabel = " Favorited " , leftChecked = pokemonInfo . isFavorited ,
leftLabel = " Favorited " , leftChecked = pokemonInfo . isFavorited ,
rightLabel = " Pokeball " , rightValue = pokemonInfo . pokeballType ?: " Unknown " ,
rightLabel = " Pokeball " , rightValue = pokemonInfo . pokeballType ?: " Unknown " ,
context = context
context = context
)
) )
// Game Origin Section
// Game Origin Section
addSectionHead er ( " Origin " , context )
container . addView ( createSectionHeaderForContainer ( " Origin " , context ) )
addTwoColumnRow (
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Game " , leftValue = pokemonInfo . gameSource ?: " Unknown " ,
leftLabel = " Game " , leftValue = pokemonInfo . gameSource ?: " Unknown " ,
rightLabel = " Language " , rightValue = pokemonInfo . language ?: " Unknown " ,
rightLabel = " Language " , rightValue = pokemonInfo . language ?: " Unknown " ,
context = context
context = context
)
) )
pokemonInfo . originalTrainerName ?. let { trainerName ->
pokemonInfo . originalTrainerName ?. let { trainerName ->
addTwoColumnRow (
container . addView ( createTwoColumnRowForContainer (
leftLabel = " OT Name " , leftValue = trainerName ,
leftLabel = " OT Name " , leftValue = trainerName ,
rightLabel = " OT ID " , rightValue = pokemonInfo . originalTrainerId ?: " Unknown " ,
rightLabel = " OT ID " , rightValue = pokemonInfo . originalTrainerId ?: " Unknown " ,
context = context
context = context
)
) )
}
}
// Ability & Moves
// Ability & Moves
pokemonInfo . ability ?. let { ability ->
pokemonInfo . ability ?. let { ability ->
addSectionHead er ( " Ability & Moves " , context )
container . addView ( createSectionHeaderForContainer ( " Ability & Moves " , context ) )
addInfoRow ( " Ability " , ability , context )
container . addView ( createInfoRowForContainer ( " Ability " , ability , context ) )
}
}
if ( pokemonInfo . moves . isNotEmpty ( ) ) {
if ( pokemonInfo . moves . isNotEmpty ( ) ) {
if ( pokemonInfo . ability == null ) {
if ( pokemonInfo . ability == null ) {
addSectionHead er ( " Moves " , context )
container . addView ( createSectionHeaderForContain er( " Moves " , context ) )
}
}
addInfoRow ( " Moves " , pokemonInfo . moves . take ( 4 ) . joinToString ( " , " ) , context )
container . addView ( createInfoRowForContainer ( " Moves " , pokemonInfo . moves . take ( 4 ) . joinToString ( " , " ) , context ) )
}
}
// Additional Data
// Additional Data
if ( pokemonInfo . stamps . isNotEmpty ( ) || pokemonInfo . labels . isNotEmpty ( ) || pokemonInfo . marks . isNotEmpty ( ) ) {
if ( pokemonInfo . stamps . isNotEmpty ( ) || pokemonInfo . labels . isNotEmpty ( ) || pokemonInfo . marks . isNotEmpty ( ) ) {
addSectionHead er ( " Additional " , context )
container . addView ( createSectionHeaderForContain er( " Additional " , context ) )
if ( pokemonInfo . stamps . isNotEmpty ( ) ) {
if ( pokemonInfo . stamps . isNotEmpty ( ) ) {
addInfoRow ( " Stamps " , pokemonInfo . stamps . joinToString ( " , " ) , context )
container . addView ( createInfoRowForContainer ( " Stamps " , pokemonInfo . stamps . joinToString ( " , " ) , context ) )
}
}
if ( pokemonInfo . labels . isNotEmpty ( ) ) {
if ( pokemonInfo . labels . isNotEmpty ( ) ) {
addInfoRow ( " Labels " , pokemonInfo . labels . joinToString ( " , " ) , context )
container . addView ( createInfoRowForContainer ( " Labels " , pokemonInfo . labels . joinToString ( " , " ) , context ) )
}
}
if ( pokemonInfo . marks . isNotEmpty ( ) ) {
if ( pokemonInfo . marks . isNotEmpty ( ) ) {
addInfoRow ( " Marks " , pokemonInfo . marks . joinToString ( " , " ) , context )
container . addView ( createInfoRowForContainer ( " Marks " , pokemonInfo . marks . joinToString ( " , " ) , context ) )
}
}
}
}
}
}
private fun addErrorInfoViews ( result : DetectionResult , context : Context )
private fun populateErrorInfoViewsForContainer ( result : DetectionResult , container : LinearLayou t , context : Context )
{
{
addSectionHead er ( " Error Details " , context )
container . addView ( createSectionHeaderForContain er( " Error Details " , context ) )
addInfoRow ( " Status " , if ( result . success ) " No Pokemon found " else " Detection failed " , context )
container . addView ( createInfoRowForContainer ( " Status " , if ( result . success ) " No Pokemon found " else " Detection failed " , context ) )
result . errorMessage ?. let { addInfoRow ( " Error " , it , context ) }
result . errorMessage ?. let { container . addView ( create InfoRowForContainer ( " Error " , it , context ) ) }
}
}
private fun addTechnicalInfoViews ( result : DetectionResult , context : Context )
private fun populateTechnicalInfoViewsForContainer ( result : DetectionResult , container : LinearLayou t , context : Context )
{
{
addSectionHead er ( " Technical Info " , context )
container . addView ( createSectionHeaderForContain er( " Technical Info " , context ) )
addInfoRow ( " Processing Time " , " ${result.processingTimeMs} ms " , context )
container . addView ( createInfoRowForContainer ( " Processing Time " , " ${result.processingTimeMs} ms " , context ) )
addInfoRow ( " Detections Found " , result . detections . size . toString ( ) , context )
container . addView ( createInfoRowForContainer ( " Detections Found " , result . detections . size . toString ( ) , context ) )
addInfoRow ( " Timestamp " , result . timestamp . format ( DateTimeFormatter . ofPattern ( " yyyy-MM-dd HH:mm:ss " ) ) , context )
container . addView ( createInfoRowForContainer ( " Timestamp " , result . timestamp . format ( DateTimeFormatter . ofPattern ( " yyyy-MM-dd HH:mm:ss " ) ) , context ) )
}
}
private fun addSectionHeader ( title : String , context : Context )
// Helper methods for container population - using the methods from the inner class
private fun createSectionHeaderForContainer ( title : String , context : Context ) : TextView
{
{
val header = TextView ( context ) . apply {
return TextView ( context ) . apply {
text = title
text = title
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 14f )
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 14f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . holo_blue_light ) )
setTextColor ( ContextCompat . getColor ( context , android . R . color . holo_blue_light ) )
typeface = android . graphics . Typeface . DEFAULT_BOLD
typeface = android . graphics . Typeface . DEFAULT_BOLD
setPadding ( 0 , dpToPx ( context , 8 ) , 0 , dpToPx ( context , 4 ) )
setPadding ( 0 , dpToPx ( context , 8 ) , 0 , dpToPx ( context , 4 ) )
}
}
expandedContainer . addView ( header )
}
}
private fun addInfoRow ( label : String , value : String , context : Context )
private fun createInfoRowForContainer ( label : String , value : String , context : Context ) : LinearLayout
{
{
val row = LinearLayout ( context ) . apply {
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
orientation = LinearLayout . HORIZONTAL
@ -478,14 +414,10 @@ class HistoryAdapter(
row . addView ( labelView )
row . addView ( labelView )
row . addView ( valueView )
row . addView ( valueView )
expandedContainer . addView ( row )
return row
}
}
private fun addTwoColumnRow (
private fun createTwoColumnRowForContainer ( leftLabel : String , leftValue : String , rightLabel : String , rightValue : String , context : Context ) : LinearLayout
leftLabel : String , leftValue : String ,
rightLabel : String , rightValue : String ,
context : Context
)
{
{
val row = LinearLayout ( context ) . apply {
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
orientation = LinearLayout . HORIZONTAL
@ -493,7 +425,7 @@ class HistoryAdapter(
}
}
// Left column
// Left column
val leftColumn = createColumnItem ( leftLabel , leftValue , context )
val leftColumn = createColumnItemForContainer ( leftLabel , leftValue , context )
leftColumn . layoutParams = LinearLayout . LayoutParams (
leftColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -501,7 +433,7 @@ class HistoryAdapter(
)
)
// Right column
// Right column
val rightColumn = createColumnItem ( rightLabel , rightValue , context )
val rightColumn = createColumnItemForContainer ( rightLabel , rightValue , context )
rightColumn . layoutParams = LinearLayout . LayoutParams (
rightColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -512,15 +444,10 @@ class HistoryAdapter(
row . addView ( leftColumn )
row . addView ( leftColumn )
row . addView ( rightColumn )
row . addView ( rightColumn )
expandedContainer . addView ( row )
return row
}
}
private fun addThreeColumnRow (
private fun createThreeColumnRowForContainer ( leftLabel : String , leftValue : String , middleLabel : String , middleValue : String , rightLabel : String , rightValue : String , context : Context ) : LinearLayout
leftLabel : String , leftValue : String ,
middleLabel : String , middleValue : String ,
rightLabel : String , rightValue : String ,
context : Context
)
{
{
val row = LinearLayout ( context ) . apply {
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
orientation = LinearLayout . HORIZONTAL
@ -528,7 +455,7 @@ class HistoryAdapter(
}
}
// Left column
// Left column
val leftColumn = createColumnItem ( leftLabel , leftValue , context )
val leftColumn = createColumnItemForContainer ( leftLabel , leftValue , context )
leftColumn . layoutParams = LinearLayout . LayoutParams (
leftColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -536,7 +463,7 @@ class HistoryAdapter(
)
)
// Middle column
// Middle column
val middleColumn = createColumnItem ( middleLabel , middleValue , context )
val middleColumn = createColumnItemForContainer ( middleLabel , middleValue , context )
middleColumn . layoutParams = LinearLayout . LayoutParams (
middleColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -546,7 +473,7 @@ class HistoryAdapter(
}
}
// Right column
// Right column
val rightColumn = createColumnItem ( rightLabel , rightValue , context )
val rightColumn = createColumnItemForContainer ( rightLabel , rightValue , context )
rightColumn . layoutParams = LinearLayout . LayoutParams (
rightColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -556,38 +483,10 @@ class HistoryAdapter(
row . addView ( leftColumn )
row . addView ( leftColumn )
row . addView ( middleColumn )
row . addView ( middleColumn )
row . addView ( rightColumn )
row . addView ( rightColumn )
expandedContainer . addView ( row )
return row
}
}
private fun createColumnItem ( label : String , value : String , context : Context ) : LinearLayout
private fun createCheckboxRowForContainer ( leftLabel : String , leftChecked : Boolean , rightLabel : String , rightChecked : Boolean , context : Context ) : LinearLayout
{
return LinearLayout ( context ) . apply {
orientation = LinearLayout . VERTICAL
gravity = android . view . Gravity . START
val labelView = TextView ( context ) . apply {
text = " $label : "
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 9f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . darker_gray ) )
}
val valueView = TextView ( context ) . apply {
text = value
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 11f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
typeface = android . graphics . Typeface . DEFAULT_BOLD
}
addView ( labelView )
addView ( valueView )
}
}
private fun addCheckboxRow (
leftLabel : String , leftChecked : Boolean ,
rightLabel : String , rightChecked : Boolean ,
context : Context
)
{
{
val row = LinearLayout ( context ) . apply {
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
orientation = LinearLayout . HORIZONTAL
@ -595,7 +494,7 @@ class HistoryAdapter(
}
}
// Left checkbox
// Left checkbox
val leftCheckbox = createCheckboxItem ( leftLabel , leftChecked , context )
val leftCheckbox = createCheckboxItemForContainer ( leftLabel , leftChecked , context )
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -603,7 +502,7 @@ class HistoryAdapter(
)
)
// Right checkbox
// Right checkbox
val rightCheckbox = createCheckboxItem ( rightLabel , rightChecked , context )
val rightCheckbox = createCheckboxItemForContainer ( rightLabel , rightChecked , context )
rightCheckbox . layoutParams = LinearLayout . LayoutParams (
rightCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -614,14 +513,10 @@ class HistoryAdapter(
row . addView ( leftCheckbox )
row . addView ( leftCheckbox )
row . addView ( rightCheckbox )
row . addView ( rightCheckbox )
expandedContainer . addView ( row )
return row
}
}
private fun addMixedRow (
private fun createMixedRowForContainer ( leftLabel : String , leftChecked : Boolean , rightLabel : String , rightValue : String , context : Context ) : LinearLayout
leftLabel : String , leftChecked : Boolean ,
rightLabel : String , rightValue : String ,
context : Context
)
{
{
val row = LinearLayout ( context ) . apply {
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
orientation = LinearLayout . HORIZONTAL
@ -629,7 +524,7 @@ class HistoryAdapter(
}
}
// Left checkbox
// Left checkbox
val leftCheckbox = createCheckboxItem ( leftLabel , leftChecked , context )
val leftCheckbox = createCheckboxItemForContainer ( leftLabel , leftChecked , context )
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -637,7 +532,7 @@ class HistoryAdapter(
)
)
// Right text item
// Right text item
val rightItem = createColumnItem ( rightLabel , rightValue , context )
val rightItem = createColumnItemForContainer ( rightLabel , rightValue , context )
rightItem . layoutParams = LinearLayout . LayoutParams (
rightItem . layoutParams = LinearLayout . LayoutParams (
0 ,
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
@ -648,10 +543,34 @@ class HistoryAdapter(
row . addView ( leftCheckbox )
row . addView ( leftCheckbox )
row . addView ( rightItem )
row . addView ( rightItem )
expandedContainer . addView ( row )
return row
}
}
private fun createCheckboxItem ( label : String , checked : Boolean , context : Context ) : LinearLayout
private fun createColumnItemForContainer ( label : String , value : String , context : Context ) : LinearLayout
{
return LinearLayout ( context ) . apply {
orientation = LinearLayout . VERTICAL
gravity = android . view . Gravity . START
val labelView = TextView ( context ) . apply {
text = " $label : "
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 9f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . darker_gray ) )
}
val valueView = TextView ( context ) . apply {
text = value
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 11f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
typeface = android . graphics . Typeface . DEFAULT_BOLD
}
addView ( labelView )
addView ( valueView )
}
}
private fun createCheckboxItemForContainer ( label : String , checked : Boolean , context : Context ) : LinearLayout
{
{
return LinearLayout ( context ) . apply {
return LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
orientation = LinearLayout . HORIZONTAL
@ -685,35 +604,101 @@ class HistoryAdapter(
}
}
}
}
private fun addDeleteButton ( result : DetectionResult , position : Int , context : Context )
inner class HistoryViewHolder ( itemView : View ) : RecyclerView . ViewHolder ( itemView )
{
{
val deleteButton = Button ( context ) . apply {
private val cardContainer = itemView as LinearLayout
text = " Delete "
private val collapsedContent = itemView . findViewWithTag < LinearLayout > ( " collapsed_content " )
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
private var expandedContent : View ? = null // Will be created when needed
background = GradientDrawable ( ) . apply {
setColor ( ContextCompat . getColor ( context , android . R . color . holo_red_light ) )
// Collapsed content views
cornerRadius = dpToPx ( context , 4 ) . toFloat ( )
private val statusIcon = collapsedContent . findViewWithTag < ImageView > ( " status_icon " )
private val titleText = collapsedContent . findViewWithTag < TextView > ( " title_text " )
private val subtitleText = collapsedContent . findViewWithTag < TextView > ( " subtitle_text " )
private val chevronIcon = collapsedContent . findViewWithTag < TextView > ( " chevron_icon " )
fun bind ( item : HistoryItem , position : Int )
{
val result = item . result
val context = itemView . context
// Update collapsed content
updateCollapsedContent ( result , context )
// Handle expanded content
if ( item . isExpanded ) {
ensureExpandedContent ( result , context )
showExpandedContent ( )
} else {
hideExpandedContent ( )
}
}
setPadding ( dpToPx ( context , 16 ) , dpToPx ( context , 8 ) , dpToPx ( context , 16 ) , dpToPx ( context , 8 ) )
setOnClickListener {
// Set click listeners
onDeleteClick ( result , position )
collapsedContent . setOnClickListener {
onItemClick ( result , position )
}
}
}
layoutParams = LinearLayout . LayoutParams (
private fun ensureExpandedContent ( result : DetectionResult , context : Context )
ViewGroup . LayoutParams . WRAP_CONTENT ,
{
ViewGroup . LayoutParams . WRAP_CONTENT
// Remove existing expanded content if any
) . apply {
expandedContent ?. let { existing ->
setMargins ( 0 , dpToPx ( context , 8 ) , 0 , 0 )
if ( existing . parent == cardContainer ) {
cardContainer . removeView ( existing )
}
}
// Create new expanded content with actual data
expandedContent = createPopulatedExpandedContent ( context , result ) . apply {
// Add delete button to the content
val scrollView = this as androidx . core . widget . NestedScrollView
val container = scrollView . findViewWithTag < LinearLayout > ( " expanded_container " )
container ?. let {
addDeleteButton ( result , adapterPosition , context , it )
}
}
}
}
expandedContainer . addView ( deleteButton )
// Add to card container
expandedContent ?. let { cardContainer . addView ( it ) }
}
private fun updateCollapsedContent ( result : DetectionResult , context : Context )
{
// Status icon
statusIcon . setImageResource (
if ( result . success ) android . R . drawable . ic_menu_myplaces
else android . R . drawable . ic_dialog_alert
)
statusIcon . setColorFilter (
ContextCompat . getColor (
context ,
if ( result . success ) android . R . color . holo_green_light
else android . R . color . holo_red_light
)
)
// Title (Pokemon name or status)
titleText . text = when {
result . success && result . pokemonInfo ?. species != null -> {
result . pokemonInfo . species +
( result . pokemonInfo . nationalDexNumber ?. let { " (# $it ) " } ?: " " )
}
result . success -> " Pokemon Detected "
else -> " Detection Failed "
}
}
// Subtitle (timestamp and processing time)
val formatter = DateTimeFormatter . ofPattern ( " MMM dd, HH:mm " )
subtitleText . text = " ${result.timestamp.format(formatter)} • ${result.processingTimeMs} ms "
// Chevron rotation based on expansion state
val rotation = if ( expandedContent ?. visibility == View . VISIBLE ) 180f else 0f
chevronIcon . rotation = rotation
}
private fun showExpandedContent ( )
private fun showExpandedContent ( )
{
{
expandedContent . visibility = View . VISIBLE
expandedContent ? .visibility = View . VISIBLE
// Animate chevron rotation
// Animate chevron rotation
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 0f , 180f ) . apply {
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 0f , 180f ) . apply {
@ -724,7 +709,7 @@ class HistoryAdapter(
private fun hideExpandedContent ( )
private fun hideExpandedContent ( )
{
{
expandedContent . visibility = View . GONE
expandedContent ? .visibility = View . GONE
// Animate chevron rotation
// Animate chevron rotation
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 180f , 0f ) . apply {
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 180f , 0f ) . apply {
@ -732,5 +717,31 @@ class HistoryAdapter(
start ( )
start ( )
}
}
}
}
private fun addDeleteButton ( result : DetectionResult , position : Int , context : Context , container : LinearLayout )
{
val deleteButton = Button ( context ) . apply {
text = " Delete "
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
background = GradientDrawable ( ) . apply {
setColor ( ContextCompat . getColor ( context , android . R . color . holo_red_light ) )
cornerRadius = dpToPx ( context , 4 ) . toFloat ( )
}
setPadding ( dpToPx ( context , 16 ) , dpToPx ( context , 8 ) , dpToPx ( context , 16 ) , dpToPx ( context , 8 ) )
setOnClickListener {
onDeleteClick ( result , position )
}
layoutParams = LinearLayout . LayoutParams (
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT
) . apply {
setMargins ( 0 , dpToPx ( context , 8 ) , 0 , 0 )
}
}
container . addView ( deleteButton )
}
}
}
}
}