Browse Source

Fix detection overlay rendering in MVC architecture

- Update DetectionController.processDetection() to return Detection objects
- Add Detection import to controller
- Update ScreenCaptureService to show overlay using returned detections
- Improve FloatingOrbUI button text visibility with larger font and padding

The MVC refactor is now complete with fully working detection overlay.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
refactor/mvc-architecture
Quildra 5 months ago
parent
commit
99c0e1d3ad
  1. 289
      app/src/main/java/com/quillstudios/pokegoalshelper/ScreenCaptureService.kt
  2. 7
      app/src/main/java/com/quillstudios/pokegoalshelper/controllers/DetectionController.kt
  3. 3
      app/src/main/java/com/quillstudios/pokegoalshelper/ui/FloatingOrbUI.kt

289
app/src/main/java/com/quillstudios/pokegoalshelper/ScreenCaptureService.kt

@ -1062,287 +1062,6 @@ class ScreenCaptureService : Service() {
Log.i(TAG, "====================================")
}
private fun createFloatingButton() {
try {
if (overlayButton != null) return // Already created
windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
createFloatingOrb()
// Main detect button
val detectButton = Button(this).apply {
text = "🔍 DETECT"
textSize = 10f
setBackgroundColor(0xFF4CAF50.toInt()) // Green
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(140, 80)
setOnClickListener { triggerManualDetection() }
}
// Coordinate transform test buttons
val directButton = Button(this).apply {
text = "DIRECT"
textSize = 9f
setBackgroundColor(0xFF2196F3.toInt()) // Blue
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(140, 60)
setOnClickListener {
YOLOOnnxDetector.setCoordinateMode("DIRECT")
triggerManualDetection()
}
}
val letterboxButton = Button(this).apply {
text = "LETTERBOX"
textSize = 9f
setBackgroundColor(0xFFFF9800.toInt()) // Orange
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(140, 60)
setOnClickListener {
YOLOOnnxDetector.setCoordinateMode("LETTERBOX")
triggerManualDetection()
}
}
val hybridButton = Button(this).apply {
text = "HYBRID"
textSize = 9f
setBackgroundColor(0xFF9C27B0.toInt()) // Purple
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(140, 60)
setOnClickListener {
YOLOOnnxDetector.setCoordinateMode("HYBRID")
triggerManualDetection()
}
}
// Class filter buttons for debugging
val shinyFilterButton = Button(this).apply {
text = "SHINY"
textSize = 8f
setBackgroundColor(0xFFFFD700.toInt()) // Gold
setTextColor(0xFF000000.toInt())
layoutParams = LinearLayout.LayoutParams(140, 60)
setOnClickListener {
YOLOOnnxDetector.setClassFilter("shiny_icon")
triggerManualDetection()
}
}
val pokeballFilterButton = Button(this).apply {
text = "POKEBALL"
textSize = 8f
setBackgroundColor(0xFFE91E63.toInt()) // Pink
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(140, 60)
setOnClickListener {
YOLOOnnxDetector.setClassFilter("ball_icon_cherishball")
triggerManualDetection()
}
}
val allClassesButton = Button(this).apply {
text = "ALL"
textSize = 8f
setBackgroundColor(0xFF607D8B.toInt()) // Blue Grey
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(140, 60)
setOnClickListener {
YOLOOnnxDetector.setClassFilter(null) // Show all classes
triggerManualDetection()
}
}
val debugModeButton = Button(this).apply {
text = "DEBUG"
textSize = 8f
setBackgroundColor(0xFFFF5722.toInt()) // Deep Orange
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(140, 60)
setOnClickListener {
YOLOOnnxDetector.toggleShowAllConfidences()
triggerManualDetection()
}
}
buttonContainer.addView(detectButton)
buttonContainer.addView(directButton)
buttonContainer.addView(letterboxButton)
buttonContainer.addView(hybridButton)
buttonContainer.addView(shinyFilterButton)
buttonContainer.addView(pokeballFilterButton)
buttonContainer.addView(allClassesButton)
buttonContainer.addView(debugModeButton)
overlayButton = buttonContainer
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
@Suppress("DEPRECATION")
WindowManager.LayoutParams.TYPE_PHONE
},
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
).apply {
gravity = Gravity.TOP or Gravity.START
x = 100
y = 200
}
windowManager?.addView(overlayButton, params)
Log.d(TAG, "✅ Floating detection button created")
} catch (e: Exception) {
Log.e(TAG, "❌ Error creating floating button", e)
}
}
private fun createFloatingOrb() {
// Create the main floating orb button
val orbButton = Button(this).apply {
text = "🎯"
textSize = 20f
setBackgroundResource(android.R.drawable.btn_default)
background.setTint(0xFF4CAF50.toInt()) // Green
setTextColor(0xFFFFFFFF.toInt())
// Make it circular
width = 120
height = 120
layoutParams = ViewGroup.LayoutParams(120, 120)
setOnClickListener {
if (isMenuExpanded) {
collapseMenu()
} else {
expandMenu()
}
}
}
overlayButton = orbButton
val params = WindowManager.LayoutParams(
120, 120,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
@Suppress("DEPRECATION")
WindowManager.LayoutParams.TYPE_PHONE
},
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
).apply {
gravity = Gravity.TOP or Gravity.START
x = 50
y = 200
}
windowManager?.addView(overlayButton, params)
}
private fun expandMenu() {
if (isMenuExpanded) return
// Create the expanded menu
val menuContainer = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setBackgroundColor(0xE0000000.toInt()) // Semi-transparent black
setPadding(16, 16, 16, 16)
}
// Add menu buttons
val buttons = listOf(
Triple("🔍 DETECT", 0xFF4CAF50.toInt()) { triggerManualDetection() },
Triple("SHINY", 0xFFFFD700.toInt()) { YOLOOnnxDetector.setClassFilter("shiny_icon"); triggerManualDetection() },
Triple("POKEBALL", 0xFFE91E63.toInt()) { YOLOOnnxDetector.setClassFilter("ball_icon_cherishball"); triggerManualDetection() },
Triple("ALL", 0xFF607D8B.toInt()) { YOLOOnnxDetector.setClassFilter(null); triggerManualDetection() },
Triple("DEBUG", 0xFFFF5722.toInt()) { YOLOOnnxDetector.toggleShowAllConfidences(); triggerManualDetection() }
)
buttons.forEach { (text, color, action) ->
val button = Button(this).apply {
this.text = text
textSize = 12f
setBackgroundColor(color)
setTextColor(0xFFFFFFFF.toInt())
layoutParams = LinearLayout.LayoutParams(160, 60).apply {
setMargins(0, 0, 0, 8)
}
setOnClickListener {
action()
collapseMenu()
}
}
menuContainer.addView(button)
}
expandedMenu = menuContainer
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
@Suppress("DEPRECATION")
WindowManager.LayoutParams.TYPE_PHONE
},
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
).apply {
gravity = Gravity.TOP or Gravity.START
x = 180 // Position next to the orb
y = 200
}
windowManager?.addView(expandedMenu, params)
isMenuExpanded = true
// Change orb appearance
(overlayButton as? Button)?.apply {
text = ""
background.setTint(0xFFFF5722.toInt()) // Orange-red
}
}
private fun collapseMenu() {
if (!isMenuExpanded) return
expandedMenu?.let { windowManager?.removeView(it) }
expandedMenu = null
isMenuExpanded = false
// Reset orb appearance
(overlayButton as? Button)?.apply {
text = "🎯"
background.setTint(0xFF4CAF50.toInt()) // Green
}
}
private fun removeFloatingButton() {
try {
// Collapse menu first if expanded
if (isMenuExpanded) {
collapseMenu()
}
overlayButton?.let { button ->
windowManager?.removeView(button)
overlayButton = null
}
windowManager = null
Log.d(TAG, "🗑️ Floating button removed")
} catch (e: Exception) {
Log.e(TAG, "❌ Error removing floating button", e)
}
}
private fun convertImageToMat(image: Image): Mat? {
return try {
val planes = image.planes
@ -1388,7 +1107,13 @@ class ScreenCaptureService : Service() {
if (mat != null) {
// Use controller to process detection (this will notify UI via callbacks)
detectionController.processDetection(mat)
val detections = detectionController.processDetection(mat)
// Show detection overlay with results
if (detections.isNotEmpty()) {
showYOLODetectionOverlay(detections)
}
mat.release()
} else {
Log.e(TAG, "❌ Failed to convert image to Mat")

7
app/src/main/java/com/quillstudios/pokegoalshelper/controllers/DetectionController.kt

@ -2,6 +2,7 @@ package com.quillstudios.pokegoalshelper.controllers
import android.util.Log
import com.quillstudios.pokegoalshelper.YOLOOnnxDetector
import com.quillstudios.pokegoalshelper.Detection
import com.quillstudios.pokegoalshelper.ui.interfaces.DetectionUIEvents
import com.quillstudios.pokegoalshelper.ui.interfaces.DetectionUICallbacks
import org.opencv.core.Mat
@ -107,7 +108,7 @@ class DetectionController(
* Process detection on the given image
* This will be called by the service layer
*/
fun processDetection(inputMat: Mat): Int {
fun processDetection(inputMat: Mat): List<Detection> {
return try {
uiCallbacks?.onDetectionStarted()
@ -117,11 +118,11 @@ class DetectionController(
Log.i(TAG, "✅ Detection completed: $detectionCount objects found")
uiCallbacks?.onDetectionCompleted(detectionCount)
detectionCount
detections
} catch (e: Exception) {
Log.e(TAG, "❌ Detection failed", e)
uiCallbacks?.onDetectionFailed(e.message ?: "Unknown error")
0
emptyList()
}
}

3
app/src/main/java/com/quillstudios/pokegoalshelper/ui/FloatingOrbUI.kt

@ -226,9 +226,10 @@ class FloatingOrbUI(
private fun createMenuButton(option: MenuOption): Button {
return Button(context).apply {
text = option.text
textSize = 12f
textSize = 14f // Increased text size
setBackgroundColor(option.color)
setTextColor(0xFFFFFFFF.toInt())
setPadding(8, 4, 8, 4) // Add padding for better text spacing
layoutParams = LinearLayout.LayoutParams(MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT).apply {
setMargins(0, 0, 0, 8)
}

Loading…
Cancel
Save