Browse Source

feat: add spinning FAB animation and disable default overlay

- Added spinning animation to EnhancedFloatingFAB during detection processing
- Integrated animation start/stop calls throughout ScreenCaptureService detection flow
- Changed default overlay visibility to false for cleaner UX
- Updated CLAUDE.md with comprehensive JIRA management guidelines

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

Co-Authored-By: Claude <noreply@anthropic.com>
feature/pgh-1-results-display-history
Quildra 5 months ago
parent
commit
fb2e481e87
  1. 59
      CLAUDE.md
  2. 21
      app/src/main/java/com/quillstudios/pokegoalshelper/ScreenCaptureService.kt
  3. 46
      app/src/main/java/com/quillstudios/pokegoalshelper/ui/EnhancedFloatingFAB.kt

59
CLAUDE.md

@ -297,4 +297,61 @@ When working on this project:
6. Test changes incrementally 6. Test changes incrementally
7. Update documentation when architecture changes 7. Update documentation when architecture changes
8. Use the build commands above for compilation testing 8. Use the build commands above for compilation testing
9. When asked about Jira/Confluence, use the Atlassian resources defined above 9. When asked about Jira/Confluence, use the Atlassian resources defined above
## JIRA Management Guidelines
### Task Status Updates
- **NEVER edit task descriptions** to update status or progress
- **ALWAYS use comments** to provide status updates instead
- **Preserve original task descriptions** - they document the original intent and requirements
- **Comments should include**: current progress, blockers, next steps, implementation notes
### Task Completion Rules
- **NEVER mark tasks as "Done"** without explicit user approval
- **Code compilation ≠ task completion** - must be tested on actual device
- **Implementation complete ≠ task complete** - requires validation and testing
- **Always check with user** before transitioning tasks to "Done" status
- **Use "In Progress"** for actively worked tasks, even if implementation is complete
### Progress Documentation
- **Use comments for progress updates**:
```
Progress Update:
✅ Implementation complete - added close functionality to drawer
✅ Compilation successful
🔄 Next steps: Device testing required before marking complete
📋 Files modified: ResultsBottomDrawer.kt, enhanced swipe-to-dismiss
```
### Status Workflow
1. **To Do** → Start working
2. **In Progress** → Implementation and testing in progress
3. **Ready for Review** → Implementation complete, needs device testing/validation
4. **Done** → Only after user confirmation that feature works as expected
### Implementation vs Completion
- **Implementation Complete**: Code written, compiles, logic appears correct
- **Task Complete**: Feature tested on device, user validated, works as intended
- **Always distinguish** between these two states in updates
### Example Comment Format
```
**Implementation Progress:**
- ✅ Added swipe-to-dismiss functionality
- ✅ Enhanced close buttons in both states
- ✅ Build compilation successful
- 🔄 **Pending**: Device testing to validate gesture behavior
- 🔄 **Pending**: User validation of close functionality
**Technical Details:**
- Modified touch handling in ResultsBottomDrawer.kt
- Enhanced gesture detection for full dismiss vs collapse
- Added header close button for expanded state
**Next Steps:**
- Device testing required
- User validation needed before marking Done
```
This preserves original task intent while providing clear progress visibility.

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

@ -134,7 +134,7 @@ class ScreenCaptureService : Service() {
private lateinit var screenCaptureManager: ScreenCaptureManager private lateinit var screenCaptureManager: ScreenCaptureManager
private var detectionOverlay: DetectionOverlay? = null private var detectionOverlay: DetectionOverlay? = null
private var overlayEnabled = true // Track overlay visibility state private var overlayEnabled = false // Track overlay visibility state
private var lastDetections: List<MLDetection> = emptyList() // Cache last detections for toggle private var lastDetections: List<MLDetection> = emptyList() // Cache last detections for toggle
// MVC Components // MVC Components
@ -558,6 +558,9 @@ class ScreenCaptureService : Service() {
pokemonInfo = pokemonInfo, pokemonInfo = pokemonInfo,
processingTimeMs = duration processingTimeMs = duration
) )
// Stop spinning animation - detection complete
enhancedFloatingFAB?.stopDetectionAnimation()
} else { } else {
PGHLog.i(TAG, "❌ Could not extract complete Pokemon info") PGHLog.i(TAG, "❌ Could not extract complete Pokemon info")
@ -566,6 +569,9 @@ class ScreenCaptureService : Service() {
detections = extractorDetections, detections = extractorDetections,
processingTimeMs = duration processingTimeMs = duration
) )
// Stop spinning animation - detection complete (no results)
enhancedFloatingFAB?.stopDetectionAnimation()
} }
} finally { } finally {
// Analysis cycle complete, allow next one // Analysis cycle complete, allow next one
@ -603,6 +609,9 @@ class ScreenCaptureService : Service() {
errorMessage = "Processing error: ${e.message}", errorMessage = "Processing error: ${e.message}",
processingTimeMs = duration processingTimeMs = duration
) )
// Stop spinning animation - detection failed
enhancedFloatingFAB?.stopDetectionAnimation()
} }
// Clear flag on error too // Clear flag on error too
@ -1185,6 +1194,9 @@ class ScreenCaptureService : Service() {
private fun triggerManualDetection() { private fun triggerManualDetection() {
PGHLog.d(TAG, "🔍 Manual detection triggered via MVC!") PGHLog.d(TAG, "🔍 Manual detection triggered via MVC!")
// Start spinning animation to show detection is in progress
enhancedFloatingFAB?.startDetectionAnimation()
latestImage?.let { image -> latestImage?.let { image ->
try { try {
// Convert image to Mat for processing // Convert image to Mat for processing
@ -1210,11 +1222,16 @@ class ScreenCaptureService : Service() {
// Extract Pokemon info using YOLO detections with OCR // Extract Pokemon info using YOLO detections with OCR
extractPokemonInfoFromYOLOAsync(mat, detections) extractPokemonInfoFromYOLOAsync(mat, detections)
} else {
// No detections found - stop animation
PGHLog.i(TAG, "No detections found")
enhancedFloatingFAB?.stopDetectionAnimation()
} }
mat.release() mat.release()
} else { } else {
PGHLog.e(TAG, "❌ Failed to convert image to Mat") PGHLog.e(TAG, "❌ Failed to convert image to Mat")
enhancedFloatingFAB?.stopDetectionAnimation()
} }
// Close the image after processing to free the buffer // Close the image after processing to free the buffer
@ -1223,9 +1240,11 @@ class ScreenCaptureService : Service() {
} catch (e: Exception) { } catch (e: Exception) {
PGHLog.e(TAG, "❌ Error in manual detection", e) PGHLog.e(TAG, "❌ Error in manual detection", e)
enhancedFloatingFAB?.stopDetectionAnimation()
} }
} ?: run { } ?: run {
PGHLog.w(TAG, "⚠️ No image available for detection") PGHLog.w(TAG, "⚠️ No image available for detection")
enhancedFloatingFAB?.stopDetectionAnimation()
} }
} }

46
app/src/main/java/com/quillstudios/pokegoalshelper/ui/EnhancedFloatingFAB.kt

@ -53,6 +53,8 @@ class EnhancedFloatingFAB(
private var isShowing = false private var isShowing = false
private var isMenuExpanded = false private var isMenuExpanded = false
private var isDragging = false private var isDragging = false
private var isDetecting = false
private var spinAnimator: ObjectAnimator? = null
// Animation and positioning // Animation and positioning
private var currentX = 0 private var currentX = 0
@ -565,6 +567,50 @@ class EnhancedFloatingFAB(
).toInt() ).toInt()
} }
/**
* Start spinning animation to indicate detection is in progress
*/
fun startDetectionAnimation() {
if (isDetecting) return // Already spinning
isDetecting = true
mainFAB?.let { fab ->
spinAnimator = ObjectAnimator.ofFloat(fab, "rotation", 0f, 360f).apply {
duration = 1000L // 1 second per rotation
repeatCount = ObjectAnimator.INFINITE
repeatMode = ObjectAnimator.RESTART
interpolator = AccelerateDecelerateInterpolator()
start()
}
}
}
/**
* Stop spinning animation when detection completes
*/
fun stopDetectionAnimation() {
if (!isDetecting) return // Not spinning
isDetecting = false
spinAnimator?.let { animator ->
animator.cancel()
// Smoothly return to 0 rotation
mainFAB?.let { fab ->
ObjectAnimator.ofFloat(fab, "rotation", fab.rotation, 0f).apply {
duration = 200L
interpolator = AccelerateDecelerateInterpolator()
start()
}
}
}
spinAnimator = null
}
/**
* Check if detection animation is currently running
*/
fun isDetectionAnimationRunning(): Boolean = isDetecting
private data class MenuItemData( private data class MenuItemData(
val label: String, val label: String,
val iconRes: Int, val iconRes: Int,

Loading…
Cancel
Save