@ -178,6 +178,19 @@ class HistoryAdapter(
}
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 {
// Set a reasonable fixed height for the scrollable area
@ -189,6 +202,7 @@ class HistoryAdapter(
// Configure scrolling behavior optimized for nested scrolling
isFillViewport = false
isNestedScrollingEnabled = true
tag = " expanded_content "
val contentContainer = LinearLayout ( context ) . apply {
orientation = LinearLayout . VERTICAL
@ -200,6 +214,16 @@ class HistoryAdapter(
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 )
}
}
@ -223,12 +247,368 @@ class HistoryAdapter(
) . toInt ( )
}
private fun populatePokemonInfoViewsForContainer ( pokemonInfo : com . quillstudios . pokegoalshelper . PokemonInfo , container : LinearLayout , context : Context )
{
// Basic Pokemon Info Section
container . addView ( createSectionHeaderForContainer ( " Pokemon Info " , context ) )
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Species " , leftValue = pokemonInfo . species ?: " Unknown " ,
rightLabel = " Dex # " , rightValue = pokemonInfo . nationalDexNumber ?. let { " # $it " } ?: " N/A " ,
context = context
) )
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Nickname " , leftValue = pokemonInfo . nickname ?: " None " ,
rightLabel = " Gender " , rightValue = pokemonInfo . gender ?: " Unknown " ,
context = context
) )
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Level " , leftValue = pokemonInfo . level ?. toString ( ) ?: " N/A " ,
rightLabel = " Nature " , rightValue = pokemonInfo . nature ?: " Unknown " ,
context = context
) )
// Types Section
container . addView ( createSectionHeaderForContainer ( " Types " , context ) )
val typeDisplay = when {
pokemonInfo . primaryType != null && pokemonInfo . secondaryType != null ->
" ${pokemonInfo.primaryType} / ${pokemonInfo.secondaryType} "
pokemonInfo . primaryType != null -> pokemonInfo . primaryType
else -> " Unknown "
}
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Type " , leftValue = typeDisplay ,
rightLabel = " Tera " , rightValue = pokemonInfo . teraType ?: " N/A " ,
context = context
) )
// Stats Section (if available)
pokemonInfo . stats ?. let { stats ->
container . addView ( createSectionHeaderForContainer ( " Base Stats " , context ) )
container . addView ( createThreeColumnRowForContainer (
leftLabel = " HP " , leftValue = stats . hp ?. toString ( ) ?: " ? " ,
middleLabel = " ATK " , middleValue = stats . attack ?. toString ( ) ?: " ? " ,
rightLabel = " DEF " , rightValue = stats . defense ?. toString ( ) ?: " ? " ,
context = context
) )
container . addView ( createThreeColumnRowForContainer (
leftLabel = " SP.ATK " , leftValue = stats . spAttack ?. toString ( ) ?: " ? " ,
middleLabel = " SP.DEF " , middleValue = stats . spDefense ?. toString ( ) ?: " ? " ,
rightLabel = " SPEED " , rightValue = stats . speed ?. toString ( ) ?: " ? " ,
context = context
) )
}
// Special Properties Section
container . addView ( createSectionHeaderForContainer ( " Properties " , context ) )
container . addView ( createCheckboxRowForContainer (
leftLabel = " Shiny " , leftChecked = pokemonInfo . isShiny ,
rightLabel = " Alpha " , rightChecked = pokemonInfo . isAlpha ,
context = context
) )
container . addView ( createMixedRowForContainer (
leftLabel = " Favorited " , leftChecked = pokemonInfo . isFavorited ,
rightLabel = " Pokeball " , rightValue = pokemonInfo . pokeballType ?: " Unknown " ,
context = context
) )
// Game Origin Section
container . addView ( createSectionHeaderForContainer ( " Origin " , context ) )
container . addView ( createTwoColumnRowForContainer (
leftLabel = " Game " , leftValue = pokemonInfo . gameSource ?: " Unknown " ,
rightLabel = " Language " , rightValue = pokemonInfo . language ?: " Unknown " ,
context = context
) )
pokemonInfo . originalTrainerName ?. let { trainerName ->
container . addView ( createTwoColumnRowForContainer (
leftLabel = " OT Name " , leftValue = trainerName ,
rightLabel = " OT ID " , rightValue = pokemonInfo . originalTrainerId ?: " Unknown " ,
context = context
) )
}
// Ability & Moves
pokemonInfo . ability ?. let { ability ->
container . addView ( createSectionHeaderForContainer ( " Ability & Moves " , context ) )
container . addView ( createInfoRowForContainer ( " Ability " , ability , context ) )
}
if ( pokemonInfo . moves . isNotEmpty ( ) ) {
if ( pokemonInfo . ability == null ) {
container . addView ( createSectionHeaderForContainer ( " Moves " , context ) )
}
container . addView ( createInfoRowForContainer ( " Moves " , pokemonInfo . moves . take ( 4 ) . joinToString ( " , " ) , context ) )
}
// Additional Data
if ( pokemonInfo . stamps . isNotEmpty ( ) || pokemonInfo . labels . isNotEmpty ( ) || pokemonInfo . marks . isNotEmpty ( ) ) {
container . addView ( createSectionHeaderForContainer ( " Additional " , context ) )
if ( pokemonInfo . stamps . isNotEmpty ( ) ) {
container . addView ( createInfoRowForContainer ( " Stamps " , pokemonInfo . stamps . joinToString ( " , " ) , context ) )
}
if ( pokemonInfo . labels . isNotEmpty ( ) ) {
container . addView ( createInfoRowForContainer ( " Labels " , pokemonInfo . labels . joinToString ( " , " ) , context ) )
}
if ( pokemonInfo . marks . isNotEmpty ( ) ) {
container . addView ( createInfoRowForContainer ( " Marks " , pokemonInfo . marks . joinToString ( " , " ) , context ) )
}
}
}
private fun populateErrorInfoViewsForContainer ( result : DetectionResult , container : LinearLayout , context : Context )
{
container . addView ( createSectionHeaderForContainer ( " Error Details " , context ) )
container . addView ( createInfoRowForContainer ( " Status " , if ( result . success ) " No Pokemon found " else " Detection failed " , context ) )
result . errorMessage ?. let { container . addView ( createInfoRowForContainer ( " Error " , it , context ) ) }
}
private fun populateTechnicalInfoViewsForContainer ( result : DetectionResult , container : LinearLayout , context : Context )
{
container . addView ( createSectionHeaderForContainer ( " Technical Info " , context ) )
container . addView ( createInfoRowForContainer ( " Processing Time " , " ${result.processingTimeMs} ms " , context ) )
container . addView ( createInfoRowForContainer ( " Detections Found " , result . detections . size . toString ( ) , context ) )
container . addView ( createInfoRowForContainer ( " Timestamp " , result . timestamp . format ( DateTimeFormatter . ofPattern ( " yyyy-MM-dd HH:mm:ss " ) ) , context ) )
}
// Helper methods for container population - using the methods from the inner class
private fun createSectionHeaderForContainer ( title : String , context : Context ) : TextView
{
return TextView ( context ) . apply {
text = title
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 14f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . holo_blue_light ) )
typeface = android . graphics . Typeface . DEFAULT_BOLD
setPadding ( 0 , dpToPx ( context , 8 ) , 0 , dpToPx ( context , 4 ) )
}
}
private fun createInfoRowForContainer ( label : String , value : String , context : Context ) : LinearLayout
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
val labelView = TextView ( context ) . apply {
text = " $label : "
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 12f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . darker_gray ) )
layoutParams = LinearLayout . LayoutParams (
dpToPx ( context , 100 ) ,
ViewGroup . LayoutParams . WRAP_CONTENT
)
}
val valueView = TextView ( context ) . apply {
text = value
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 12f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
}
row . addView ( labelView )
row . addView ( valueView )
return row
}
private fun createTwoColumnRowForContainer ( leftLabel : String , leftValue : String , rightLabel : String , rightValue : String , context : Context ) : LinearLayout
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
// Left column
val leftColumn = createColumnItemForContainer ( leftLabel , leftValue , context )
leftColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Right column
val rightColumn = createColumnItemForContainer ( rightLabel , rightValue , context )
rightColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 8 ) , 0 , 0 , 0 )
}
row . addView ( leftColumn )
row . addView ( rightColumn )
return row
}
private fun createThreeColumnRowForContainer ( leftLabel : String , leftValue : String , middleLabel : String , middleValue : String , rightLabel : String , rightValue : String , context : Context ) : LinearLayout
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
// Left column
val leftColumn = createColumnItemForContainer ( leftLabel , leftValue , context )
leftColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Middle column
val middleColumn = createColumnItemForContainer ( middleLabel , middleValue , context )
middleColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 4 ) , 0 , dpToPx ( context , 4 ) , 0 )
}
// Right column
val rightColumn = createColumnItemForContainer ( rightLabel , rightValue , context )
rightColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
row . addView ( leftColumn )
row . addView ( middleColumn )
row . addView ( rightColumn )
return row
}
private fun createCheckboxRowForContainer ( leftLabel : String , leftChecked : Boolean , rightLabel : String , rightChecked : Boolean , context : Context ) : LinearLayout
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
// Left checkbox
val leftCheckbox = createCheckboxItemForContainer ( leftLabel , leftChecked , context )
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Right checkbox
val rightCheckbox = createCheckboxItemForContainer ( rightLabel , rightChecked , context )
rightCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 8 ) , 0 , 0 , 0 )
}
row . addView ( leftCheckbox )
row . addView ( rightCheckbox )
return row
}
private fun createMixedRowForContainer ( leftLabel : String , leftChecked : Boolean , rightLabel : String , rightValue : String , context : Context ) : LinearLayout
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
// Left checkbox
val leftCheckbox = createCheckboxItemForContainer ( leftLabel , leftChecked , context )
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Right text item
val rightItem = createColumnItemForContainer ( rightLabel , rightValue , context )
rightItem . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 8 ) , 0 , 0 , 0 )
}
row . addView ( leftCheckbox )
row . addView ( rightItem )
return row
}
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 {
orientation = LinearLayout . HORIZONTAL
gravity = android . view . Gravity . CENTER_VERTICAL
// Checkbox symbol
val checkboxView = TextView ( context ) . apply {
text = if ( checked ) " ☑ " else " ☐ "
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 14f )
setTextColor (
if ( checked ) ContextCompat . getColor ( context , android . R . color . holo_green_light )
else ContextCompat . getColor ( context , android . R . color . darker_gray )
)
layoutParams = LinearLayout . LayoutParams (
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT
) . apply {
setMargins ( 0 , 0 , dpToPx ( context , 6 ) , 0 )
}
}
// Label
val labelView = TextView ( context ) . apply {
text = label
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 11f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
}
addView ( checkboxView )
addView ( labelView )
}
}
inner class HistoryViewHolder ( itemView : View ) : RecyclerView . ViewHolder ( itemView )
{
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 " )
private var expandedContent : View ? = null // Will be created when needed
// Collapsed content views
private val statusIcon = collapsedContent . findViewWithTag < ImageView > ( " status_icon " )
@ -244,9 +624,9 @@ class HistoryAdapter(
// Update collapsed content
updateCollapsedContent ( result , context )
// Update expanded content if needed
// Handle expanded content
if ( item . isExpanded ) {
updat eExpandedContent( result , context )
ensur eExpandedContent( result , context )
showExpandedContent ( )
} else {
hideExpandedContent ( )
@ -256,11 +636,29 @@ class HistoryAdapter(
collapsedContent . setOnClickListener {
onItemClick ( result , position )
}
}
private fun ensureExpandedContent ( result : DetectionResult , context : Context )
{
// Remove existing expanded content if any
expandedContent ?. let { existing ->
if ( existing . parent == cardContainer ) {
cardContainer . removeView ( existing )
}
}
// Add delete button in expanded state
if ( item . isExpanded ) {
addDeleteButton ( result , position , context )
// 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 )
}
}
// Add to card container
expandedContent ?. let { cardContainer . addView ( it ) }
}
private fun updateCollapsedContent ( result : DetectionResult , context : Context )
@ -293,399 +691,34 @@ class HistoryAdapter(
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
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
addSectionHeader ( " Pokemon Info " , context )
addTwoColumnRow (
leftLabel = " Species " , leftValue = pokemonInfo . species ?: " Unknown " ,
rightLabel = " Dex # " , rightValue = pokemonInfo . nationalDexNumber ?. let { " # $it " } ?: " N/A " ,
context = context
)
addTwoColumnRow (
leftLabel = " Nickname " , leftValue = pokemonInfo . nickname ?: " None " ,
rightLabel = " Gender " , rightValue = pokemonInfo . gender ?: " Unknown " ,
context = context
)
addTwoColumnRow (
leftLabel = " Level " , leftValue = pokemonInfo . level ?. toString ( ) ?: " N/A " ,
rightLabel = " Nature " , rightValue = pokemonInfo . nature ?: " Unknown " ,
context = context
)
// Types Section
addSectionHeader ( " Types " , context )
val typeDisplay = when {
pokemonInfo . primaryType != null && pokemonInfo . secondaryType != null ->
" ${pokemonInfo.primaryType} / ${pokemonInfo.secondaryType} "
pokemonInfo . primaryType != null -> pokemonInfo . primaryType
else -> " Unknown "
}
addTwoColumnRow (
leftLabel = " Type " , leftValue = typeDisplay ,
rightLabel = " Tera " , rightValue = pokemonInfo . teraType ?: " N/A " ,
context = context
)
// Stats Section (if available)
pokemonInfo . stats ?. let { stats ->
addSectionHeader ( " Base Stats " , context )
addThreeColumnRow (
leftLabel = " HP " , leftValue = stats . hp ?. toString ( ) ?: " ? " ,
middleLabel = " ATK " , middleValue = stats . attack ?. toString ( ) ?: " ? " ,
rightLabel = " DEF " , rightValue = stats . defense ?. toString ( ) ?: " ? " ,
context = context
)
addThreeColumnRow (
leftLabel = " SP.ATK " , leftValue = stats . spAttack ?. toString ( ) ?: " ? " ,
middleLabel = " SP.DEF " , middleValue = stats . spDefense ?. toString ( ) ?: " ? " ,
rightLabel = " SPEED " , rightValue = stats . speed ?. toString ( ) ?: " ? " ,
context = context
)
}
// Special Properties Section
addSectionHeader ( " Properties " , context )
addCheckboxRow (
leftLabel = " Shiny " , leftChecked = pokemonInfo . isShiny ,
rightLabel = " Alpha " , rightChecked = pokemonInfo . isAlpha ,
context = context
)
addMixedRow (
leftLabel = " Favorited " , leftChecked = pokemonInfo . isFavorited ,
rightLabel = " Pokeball " , rightValue = pokemonInfo . pokeballType ?: " Unknown " ,
context = context
)
// Game Origin Section
addSectionHeader ( " Origin " , context )
addTwoColumnRow (
leftLabel = " Game " , leftValue = pokemonInfo . gameSource ?: " Unknown " ,
rightLabel = " Language " , rightValue = pokemonInfo . language ?: " Unknown " ,
context = context
)
pokemonInfo . originalTrainerName ?. let { trainerName ->
addTwoColumnRow (
leftLabel = " OT Name " , leftValue = trainerName ,
rightLabel = " OT ID " , rightValue = pokemonInfo . originalTrainerId ?: " Unknown " ,
context = context
)
}
// Ability & Moves
pokemonInfo . ability ?. let { ability ->
addSectionHeader ( " Ability & Moves " , context )
addInfoRow ( " Ability " , ability , context )
}
if ( pokemonInfo . moves . isNotEmpty ( ) ) {
if ( pokemonInfo . ability == null ) {
addSectionHeader ( " Moves " , context )
}
addInfoRow ( " Moves " , pokemonInfo . moves . take ( 4 ) . joinToString ( " , " ) , context )
}
// Additional Data
if ( pokemonInfo . stamps . isNotEmpty ( ) || pokemonInfo . labels . isNotEmpty ( ) || pokemonInfo . marks . isNotEmpty ( ) ) {
addSectionHeader ( " Additional " , context )
if ( pokemonInfo . stamps . isNotEmpty ( ) ) {
addInfoRow ( " Stamps " , pokemonInfo . stamps . joinToString ( " , " ) , context )
}
if ( pokemonInfo . labels . isNotEmpty ( ) ) {
addInfoRow ( " Labels " , pokemonInfo . labels . joinToString ( " , " ) , context )
}
if ( pokemonInfo . marks . isNotEmpty ( ) ) {
addInfoRow ( " Marks " , pokemonInfo . marks . joinToString ( " , " ) , context )
}
}
}
private fun addErrorInfoViews ( result : DetectionResult , context : Context )
{
addSectionHeader ( " Error Details " , context )
addInfoRow ( " Status " , if ( result . success ) " No Pokemon found " else " Detection failed " , context )
result . errorMessage ?. let { addInfoRow ( " Error " , it , context ) }
}
private fun addTechnicalInfoViews ( result : DetectionResult , context : Context )
{
addSectionHeader ( " Technical Info " , context )
addInfoRow ( " Processing Time " , " ${result.processingTimeMs} ms " , context )
addInfoRow ( " Detections Found " , result . detections . size . toString ( ) , context )
addInfoRow ( " Timestamp " , result . timestamp . format ( DateTimeFormatter . ofPattern ( " yyyy-MM-dd HH:mm:ss " ) ) , context )
}
private fun addSectionHeader ( title : String , context : Context )
{
val header = TextView ( context ) . apply {
text = title
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 14f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . holo_blue_light ) )
typeface = android . graphics . Typeface . DEFAULT_BOLD
setPadding ( 0 , dpToPx ( context , 8 ) , 0 , dpToPx ( context , 4 ) )
}
expandedContainer . addView ( header )
}
private fun addInfoRow ( label : String , value : String , context : Context )
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
val labelView = TextView ( context ) . apply {
text = " $label : "
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 12f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . darker_gray ) )
layoutParams = LinearLayout . LayoutParams (
dpToPx ( context , 100 ) ,
ViewGroup . LayoutParams . WRAP_CONTENT
)
}
val valueView = TextView ( context ) . apply {
text = value
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 12f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
}
row . addView ( labelView )
row . addView ( valueView )
expandedContainer . addView ( row )
}
private fun addTwoColumnRow (
leftLabel : String , leftValue : String ,
rightLabel : String , rightValue : String ,
context : Context
)
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
// Left column
val leftColumn = createColumnItem ( leftLabel , leftValue , context )
leftColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Right column
val rightColumn = createColumnItem ( rightLabel , rightValue , context )
rightColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 8 ) , 0 , 0 , 0 )
}
row . addView ( leftColumn )
row . addView ( rightColumn )
expandedContainer . addView ( row )
}
private fun addThreeColumnRow (
leftLabel : String , leftValue : String ,
middleLabel : String , middleValue : String ,
rightLabel : String , rightValue : String ,
context : Context
)
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
// Left column
val leftColumn = createColumnItem ( leftLabel , leftValue , context )
leftColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Middle column
val middleColumn = createColumnItem ( middleLabel , middleValue , context )
middleColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 4 ) , 0 , dpToPx ( context , 4 ) , 0 )
}
// Right column
val rightColumn = createColumnItem ( rightLabel , rightValue , context )
rightColumn . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
row . addView ( leftColumn )
row . addView ( middleColumn )
row . addView ( rightColumn )
expandedContainer . addView ( row )
}
private fun createColumnItem ( 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 addCheckboxRow (
leftLabel : String , leftChecked : Boolean ,
rightLabel : String , rightChecked : Boolean ,
context : Context
)
private fun showExpandedContent ( )
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
expandedContent ?. visibility = View . VISIBLE
// Left checkbox
val leftCheckbox = createCheckboxItem ( leftLabel , leftChecked , context )
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Right checkbox
val rightCheckbox = createCheckboxItem ( rightLabel , rightChecked , context )
rightCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 8 ) , 0 , 0 , 0 )
// Animate chevron rotation
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 0f , 180f ) . apply {
duration = 200L
start ( )
}
row . addView ( leftCheckbox )
row . addView ( rightCheckbox )
expandedContainer . addView ( row )
}
private fun addMixedRow (
leftLabel : String , leftChecked : Boolean ,
rightLabel : String , rightValue : String ,
context : Context
)
private fun hideExpandedContent ( )
{
val row = LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
setPadding ( 0 , dpToPx ( context , 2 ) , 0 , dpToPx ( context , 2 ) )
}
expandedContent ?. visibility = View . GONE
// Left checkbox
val leftCheckbox = createCheckboxItem ( leftLabel , leftChecked , context )
leftCheckbox . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
)
// Right text item
val rightItem = createColumnItem ( rightLabel , rightValue , context )
rightItem . layoutParams = LinearLayout . LayoutParams (
0 ,
ViewGroup . LayoutParams . WRAP_CONTENT ,
1f
) . apply {
setMargins ( dpToPx ( context , 8 ) , 0 , 0 , 0 )
}
row . addView ( leftCheckbox )
row . addView ( rightItem )
expandedContainer . addView ( row )
}
private fun createCheckboxItem ( label : String , checked : Boolean , context : Context ) : LinearLayout
{
return LinearLayout ( context ) . apply {
orientation = LinearLayout . HORIZONTAL
gravity = android . view . Gravity . CENTER_VERTICAL
// Checkbox symbol
val checkboxView = TextView ( context ) . apply {
text = if ( checked ) " ☑ " else " ☐ "
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 14f )
setTextColor (
if ( checked ) ContextCompat . getColor ( context , android . R . color . holo_green_light )
else ContextCompat . getColor ( context , android . R . color . darker_gray )
)
layoutParams = LinearLayout . LayoutParams (
ViewGroup . LayoutParams . WRAP_CONTENT ,
ViewGroup . LayoutParams . WRAP_CONTENT
) . apply {
setMargins ( 0 , 0 , dpToPx ( context , 6 ) , 0 )
}
}
// Label
val labelView = TextView ( context ) . apply {
text = label
setTextSize ( TypedValue . COMPLEX_UNIT_SP , 11f )
setTextColor ( ContextCompat . getColor ( context , android . R . color . white ) )
}
addView ( checkboxView )
addView ( labelView )
// Animate chevron rotation
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 180f , 0f ) . apply {
duration = 200L
start ( )
}
}
private fun addDeleteButton ( result : DetectionResult , position : Int , context : Context )
private fun addDeleteButton ( result : DetectionResult , position : Int , context : Context , container : LinearLayout )
{
val deleteButton = Button ( context ) . apply {
text = " Delete "
@ -708,29 +741,7 @@ class HistoryAdapter(
}
}
expandedContainer . addView ( deleteButton )
}
private fun showExpandedContent ( )
{
expandedContent . visibility = View . VISIBLE
// Animate chevron rotation
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 0f , 180f ) . apply {
duration = 200L
start ( )
}
}
private fun hideExpandedContent ( )
{
expandedContent . visibility = View . GONE
// Animate chevron rotation
ObjectAnimator . ofFloat ( chevronIcon , " rotation " , 180f , 0f ) . apply {
duration = 200L
start ( )
}
container . addView ( deleteButton )
}
}
}