@ -278,59 +278,61 @@ class ResultsBottomDrawer(private val context: Context)
}
}
}
}
private fun createExpandedContent ( result : DetectionResult ) : LinearLayout
private fun createExpandedContent ( result : DetectionResult ) : ScrollView
{
{
return LinearLayout ( context ) . apply {
return ScrollView ( context ) . apply {
orientation = LinearLayout . VERTICAL
visibility = View . GONE // Initially hidden
visibility = View . GONE // Initially hidden
tag = " expanded_content " // For easy finding
tag = " expanded_content " // For easy finding
// Add some spacing
// Create the scrollable content container
setPadding ( 0 , dpToPx ( 8 ) , 0 , 0 )
val contentContainer = LinearLayout ( context ) . apply {
orientation = LinearLayout . VERTICAL
setPadding ( 0 , dpToPx ( 8 ) , 0 , dpToPx ( 16 ) ) // Add bottom padding for scroll
}
if ( result . success && result . pokemonInfo != null )
if ( result . success && result . pokemonInfo != null )
{
{
val pokemonInfo = result . pokemonInfo
val pokemonInfo = result . pokemonInfo
// Basic Pokemon Info Section
// Basic Pokemon Info Section
addView ( createSectionHeader ( " Pokemon Info " ) )
contentContainer . addView ( createSectionHeader ( " Pokemon Info " ) )
addView ( createTwoColumnRow (
contentContainer . addView ( createTwoColumnRow (
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 "
) )
) )
addView ( createTwoColumnRow (
contentContainer . addView ( createTwoColumnRow (
leftLabel = " Nickname " , leftValue = pokemonInfo . nickname ?: " None " ,
leftLabel = " Nickname " , leftValue = pokemonInfo . nickname ?: " None " ,
rightLabel = " Gender " , rightValue = pokemonInfo . gender ?: " Unknown "
rightLabel = " Gender " , rightValue = pokemonInfo . gender ?: " Unknown "
) )
) )
addView ( createTwoColumnRow (
contentContainer . addView ( createTwoColumnRow (
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 "
) )
) )
// Types Section
// Types Section
addView ( createSectionHeader ( " Types " ) )
contentContainer . addView ( createSectionHeader ( " Types " ) )
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 "
}
}
addView ( createTwoColumnRow (
contentContainer . addView ( createTwoColumnRow (
leftLabel = " Type " , leftValue = typeDisplay ,
leftLabel = " Type " , leftValue = typeDisplay ,
rightLabel = " Tera " , rightValue = pokemonInfo . teraType ?: " N/A "
rightLabel = " Tera " , rightValue = pokemonInfo . teraType ?: " N/A "
) )
) )
// Stats Section (if available)
// Stats Section (if available)
pokemonInfo . stats ?. let { stats ->
pokemonInfo . stats ?. let { stats ->
addView ( createSectionHeader ( " Base Stats " ) )
contentContainer . addView ( createSectionHeader ( " Base Stats " ) )
addView ( createThreeColumnRow (
contentContainer . addView ( createThreeColumnRow (
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 ( ) ?: " ? "
) )
) )
addView ( createThreeColumnRow (
contentContainer . addView ( createThreeColumnRow (
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 ( ) ?: " ? "
@ -338,25 +340,25 @@ class ResultsBottomDrawer(private val context: Context)
}
}
// Special Properties Section
// Special Properties Section
addView ( createSectionHeader ( " Properties " ) )
contentContainer . addView ( createSectionHeader ( " Properties " ) )
addView ( createCheckboxRow (
contentContainer . addView ( createCheckboxRow (
leftLabel = " Shiny " , leftChecked = pokemonInfo . isShiny ,
leftLabel = " Shiny " , leftChecked = pokemonInfo . isShiny ,
rightLabel = " Alpha " , rightChecked = pokemonInfo . isAlpha
rightLabel = " Alpha " , rightChecked = pokemonInfo . isAlpha
) )
) )
addView ( createMixedRow (
contentContainer . addView ( createMixedRow (
leftLabel = " Favorited " , leftChecked = pokemonInfo . isFavorited ,
leftLabel = " Favorited " , leftChecked = pokemonInfo . isFavorited ,
rightLabel = " Pokeball " , rightValue = pokemonInfo . pokeballType ?: " Unknown "
rightLabel = " Pokeball " , rightValue = pokemonInfo . pokeballType ?: " Unknown "
) )
) )
// Game Origin Section
// Game Origin Section
addView ( createSectionHeader ( " Origin " ) )
contentContainer . addView ( createSectionHeader ( " Origin " ) )
addView ( createTwoColumnRow (
contentContainer . addView ( createTwoColumnRow (
leftLabel = " Game " , leftValue = pokemonInfo . gameSource ?: " Unknown " ,
leftLabel = " Game " , leftValue = pokemonInfo . gameSource ?: " Unknown " ,
rightLabel = " Language " , rightValue = pokemonInfo . language ?: " Unknown "
rightLabel = " Language " , rightValue = pokemonInfo . language ?: " Unknown "
) )
) )
pokemonInfo . originalTrainerName ?. let { trainerName ->
pokemonInfo . originalTrainerName ?. let { trainerName ->
addView ( createTwoColumnRow (
contentContainer . addView ( createTwoColumnRow (
leftLabel = " OT Name " , leftValue = trainerName ,
leftLabel = " OT Name " , leftValue = trainerName ,
rightLabel = " OT ID " , rightValue = pokemonInfo . originalTrainerId ?: " Unknown "
rightLabel = " OT ID " , rightValue = pokemonInfo . originalTrainerId ?: " Unknown "
) )
) )
@ -364,45 +366,48 @@ class ResultsBottomDrawer(private val context: Context)
// Ability & Moves
// Ability & Moves
pokemonInfo . ability ?. let { ability ->
pokemonInfo . ability ?. let { ability ->
addView ( createSectionHeader ( " Ability & Moves " ) )
contentContainer . addView ( createSectionHeader ( " Ability & Moves " ) )
addView ( createDetailRow ( " Ability " , ability ) )
contentContainer . addView ( createDetailRow ( " Ability " , ability ) )
}
}
if ( pokemonInfo . moves . isNotEmpty ( ) ) {
if ( pokemonInfo . moves . isNotEmpty ( ) ) {
addView ( createDetailRow ( " Moves " , pokemonInfo . moves . take ( 4 ) . joinToString ( " , " ) ) )
contentContainer . addView ( createDetailRow ( " Moves " , pokemonInfo . moves . take ( 4 ) . joinToString ( " , " ) ) )
}
}
// Additional Data
// Additional Data
if ( pokemonInfo . stamps . isNotEmpty ( ) || pokemonInfo . labels . isNotEmpty ( ) || pokemonInfo . marks . isNotEmpty ( ) ) {
if ( pokemonInfo . stamps . isNotEmpty ( ) || pokemonInfo . labels . isNotEmpty ( ) || pokemonInfo . marks . isNotEmpty ( ) ) {
addView ( createSectionHeader ( " Additional " ) )
contentContainer . addView ( createSectionHeader ( " Additional " ) )
if ( pokemonInfo . stamps . isNotEmpty ( ) ) {
if ( pokemonInfo . stamps . isNotEmpty ( ) ) {
addView ( createDetailRow ( " Stamps " , pokemonInfo . stamps . joinToString ( " , " ) ) )
contentContainer . addView ( createDetailRow ( " Stamps " , pokemonInfo . stamps . joinToString ( " , " ) ) )
}
}
if ( pokemonInfo . labels . isNotEmpty ( ) ) {
if ( pokemonInfo . labels . isNotEmpty ( ) ) {
addView ( createDetailRow ( " Labels " , pokemonInfo . labels . joinToString ( " , " ) ) )
contentContainer . addView ( createDetailRow ( " Labels " , pokemonInfo . labels . joinToString ( " , " ) ) )
}
}
if ( pokemonInfo . marks . isNotEmpty ( ) ) {
if ( pokemonInfo . marks . isNotEmpty ( ) ) {
addView ( createDetailRow ( " Marks " , pokemonInfo . marks . joinToString ( " , " ) ) )
contentContainer . addView ( createDetailRow ( " Marks " , pokemonInfo . marks . joinToString ( " , " ) ) )
}
}
}
}
}
}
else
else
{
{
// Show error details
// Show error details
addView ( createSectionHeader ( " Detection Failed " ) )
contentContainer . addView ( createSectionHeader ( " Detection Failed " ) )
addView ( createDetailRow ( " Status " , if ( result . success ) " No Pokemon detected " else " Detection failed " ) )
contentContainer . addView ( createDetailRow ( " Status " , if ( result . success ) " No Pokemon detected " else " Detection failed " ) )
result . errorMessage ?. let { error ->
result . errorMessage ?. let { error ->
addView ( createDetailRow ( " Error " , error ) )
contentContainer . addView ( createDetailRow ( " Error " , error ) )
}
}
}
}
// Technical Info Section
// Technical Info Section
addView ( createSectionHeader ( " Technical Info " ) )
contentContainer . addView ( createSectionHeader ( " Technical Info " ) )
addView ( createTwoColumnRow (
contentContainer . addView ( createTwoColumnRow (
leftLabel = " Processing " , leftValue = " ${result.processingTimeMs} ms " ,
leftLabel = " Processing " , leftValue = " ${result.processingTimeMs} ms " ,
rightLabel = " Detected " , rightValue = " ${result.detections.size} items "
rightLabel = " Detected " , rightValue = " ${result.detections.size} items "
) )
) )
addView ( createDetailRow ( " Timestamp " , result . timestamp . format ( DateTimeFormatter . ofPattern ( " HH:mm:ss " ) ) ) )
contentContainer . addView ( createDetailRow ( " Timestamp " , result . timestamp . format ( DateTimeFormatter . ofPattern ( " HH:mm:ss " ) ) ) )
// Add the content container to the ScrollView
addView ( contentContainer )
}
}
}
}
@ -755,10 +760,15 @@ class ResultsBottomDrawer(private val context: Context)
{
{
val deltaY = event . rawY - initialTouchY
val deltaY = event . rawY - initialTouchY
if ( deltaY > SWIPE_THRESHOLD )
if ( deltaY > SWIPE_THRESHOLD && isExpanded )
{
{
// Dismiss if swiped down enough
// Only collapse to minimal state if expanded, never fully dismiss
hide ( )
collapseDrawer ( )
ObjectAnimator . ofFloat ( view , " translationY " , view . translationY , initialTranslationY ) . apply {
duration = 200L
interpolator = AccelerateDecelerateInterpolator ( )
start ( )
}
}
}
else if ( deltaY < EXPAND_THRESHOLD && !is Expanded )
else if ( deltaY < EXPAND_THRESHOLD && !is Expanded )
{
{
@ -809,7 +819,7 @@ class ResultsBottomDrawer(private val context: Context)
isExpanded = true
isExpanded = true
// Show expanded content
// Show expanded content
drawerContainer ?. findViewWithTag < LinearLayout > ( " expanded_content " ) ?. let { expandedContent ->
drawerContainer ?. findViewWithTag < ScrollView > ( " expanded_content " ) ?. let { expandedContent ->
expandedContent . visibility = View . VISIBLE
expandedContent . visibility = View . VISIBLE
expandedContent . alpha = 0f
expandedContent . alpha = 0f
@ -837,7 +847,7 @@ class ResultsBottomDrawer(private val context: Context)
isExpanded = false
isExpanded = false
// Hide expanded content
// Hide expanded content
drawerContainer ?. findViewWithTag < LinearLayout > ( " expanded_content " ) ?. let { expandedContent ->
drawerContainer ?. findViewWithTag < ScrollView > ( " expanded_content " ) ?. let { expandedContent ->
ObjectAnimator . ofFloat ( expandedContent , " alpha " , 1f , 0f ) . apply {
ObjectAnimator . ofFloat ( expandedContent , " alpha " , 1f , 0f ) . apply {
duration = SLIDE_ANIMATION_DURATION
duration = SLIDE_ANIMATION_DURATION
addListener ( object : AnimatorListenerAdapter ( ) {
addListener ( object : AnimatorListenerAdapter ( ) {