An iOS app for recording tennis videos and getting AI-powered analysis using Google Gemini.
- Video Recording: Record tennis practice/match videos with 60fps support
- AI Analysis: Get professional-level tennis technique analysis powered by Gemini
- Interactive Chat: Ask follow-up questions about your technique
- Video Management: Browse and manage recorded videos
- Secure API Key Storage: API keys stored securely in iOS Keychain
- In-App Video Player: Play recorded videos directly within the app
- Full-Screen Playback: Tap to expand videos to full screen with native controls
- Save to Photos: Export videos to iPhone Photos Library for backup and sharing
- Auto-Save Option: Videos automatically saved to Photos Library after recording
- Lens Switching: 0.5x (ultra-wide), 1x (standard), 2x (telephoto/digital zoom)
- Tap-to-Focus: Tap anywhere on preview to focus with visual indicator
- Recording Time Limits: 30s@60fps / 45s@30fps based on 100MB Gemini limit
- Auto-Stop with Warning: Orange indicator 10 seconds before limit
- Smart Initialization: Loading indicator during camera setup
- Session Management: Camera automatically resumes when returning to Recording tab
- State Indicators: Clear visual feedback for camera status (initializing, ready, recording, error)
- Error Recovery: Retry button when camera initialization fails
- Developer Contact: Email link for support
- GitHub Repository: Direct link to source code
- Contribution Info: Open source contribution invitation
- iOS 17.0+
- Xcode 15.0+
- Google AI Studio API Key (Gemini)
git clone https://github.com/leemingee/TennisCoach.git
cd TennisCoachopen TennisCoach.xcodeproj- Select your target device or simulator
- Press
Cmd + Rto build and run - On first launch, the app will prompt you to enter your Gemini API key
- Visit Google AI Studio
- Create a new API key
- Enter it in the app's Settings tab
- Tap "Test Connection" to verify
TennisCoach/
├── TennisCoachApp.swift # App entry point
├── ContentView.swift # Main TabView with Settings
├── Models/
│ ├── Video.swift # Video entity (SwiftData)
│ ├── Conversation.swift # Chat conversation entity
│ └── Message.swift # Chat message entity
├── Services/
│ ├── GeminiService.swift # Gemini API integration with retry logic
│ ├── VideoRecorder.swift # AVFoundation video recording
│ ├── VideoCompressor.swift # Video compression for upload
│ └── Prompts.swift # AI analysis prompts (Chinese)
├── Views/
│ ├── Recording/
│ │ ├── RecordView.swift # Camera preview and controls
│ │ └── RecordViewModel.swift # Recording state management
│ ├── VideoList/
│ │ └── VideoListView.swift # Video gallery grid
│ ├── VideoPlayer/
│ │ └── VideoPlayerView.swift # Video playback components
│ └── Chat/
│ ├── ChatView.swift # AI chat interface
│ └── ChatViewModel.swift # Chat state and API calls
└── Utilities/
├── Constants.swift # App constants & API config
├── SecureKeyManager.swift # Keychain API key storage
├── APIKeySetupView.swift # API key configuration UI
├── APIKeyValidator.swift # API key validation
├── RetryPolicy.swift # Network retry logic
└── AppLogger.swift # Structured logging (OSLog)
TennisCoachTests/
├── RecordViewModelTests.swift
├── VideoRecorderTests.swift
├── GeminiServiceTests.swift
├── SecureKeyManagerTests.swift
├── RetryPolicyTests.swift
└── ...
- MVVM Pattern: Clear separation of Views, ViewModels, and Models
- Protocol-Oriented: Services use protocols for testability and dependency injection
- Async/Await: Modern Swift concurrency throughout (no completion handlers)
- Combine: Reactive state management with @Published properties
- SwiftData: Conversation history, messages, video metadata
- Photos Library: Video files (optional, user-controlled export)
- Keychain: Secure API key storage (encrypted, device-only)
- FileManager: Video files in app Documents directory
- VideoRecorder: AVFoundation-based recording with 60fps, session state management
- GeminiService: Streaming API integration with exponential backoff retry
- VideoCompressor: H.264 compression for efficient uploads
- Uses AVFoundation for high-quality 60fps video capture
- Automatic thumbnail generation from first frame
- Camera state machine: initializing → ready → recording → processing
- Session pause/resume for tab switching
- AVKit-based VideoPlayer with native controls
- Full-screen expansion with dismiss gesture
- Photos Library integration via PHPhotoLibrary
- Thumbnail caching for smooth scrolling
- Streaming responses via AsyncThrowingStream for real-time feedback
- Exponential backoff retry logic (up to 5 attempts)
- Progress tracking for video uploads (0-100%)
- Conversation history maintained per video
- API keys stored in iOS Keychain (not in code or UserDefaults)
- Keys are device-only, not backed up to iCloud
- Connection validation before use
- No sensitive data logged
The app requests the following iOS permissions:
- Purpose: Record tennis practice and match videos
- When Requested: First time opening Recording tab
- If Denied: Camera preview shows error with instructions
- Purpose: Capture audio during video recording
- When Requested: First time opening Recording tab
- If Denied: Videos record without audio
- Purpose: Save recorded videos to Photos app
- Permission Type: "Add Photos Only" (limited access)
- When Requested: When tapping "Save to Photos" button
- If Denied: Videos remain in app, viewable within TennisCoach
If you need to change permissions:
- Open iOS Settings app
- Scroll to TennisCoach
- Toggle permissions as needed
- Return to app and retry the action
Run tests using Cmd + U or via Product → Test.
# Run tests from command line
xcodebuild test -scheme TennisCoach -destination 'platform=iOS Simulator,name=iPhone 15'docs/PRODUCT_VISION.md- Product roadmap and feature prioritiesDESIGN.md- Detailed design document (Chinese)ARCHITECTURE_REVIEW.md- Storage architecture recommendationsTROUBLESHOOTING.md- Common issues and solutionsworking_docs/- Iteration planning and code review findingsbest-practice/- iOS development guidelines
- Check camera permission in Settings → TennisCoach
- Close and reopen the app
- Tap "Retry" button if shown
- Verify your API key at Google AI Studio
- Re-enter the key in Settings tab
- Tap "Test Connection" to verify
- Check internet connection
- Ensure video file is under 100MB
- Try again - the app has automatic retry logic
- Tap the video thumbnail in ChatView
- Tap "Save to Photos" button
- Grant photo library permission if prompted
Contributions welcome!
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please read the design document and code review findings before submitting PRs.
- Email: leemingee1995@gmail.com
- GitHub: TennisCoach Repository
This project is for personal/educational use.