OpenFlip is a Braun-inspired flip clock for Android, focusing on mechanical animation fidelity, visual precision, and maintainable architecture.
Tip
If you like this project, please give it a star! ⭐
Key features:
- Custom rendering engine: Physics-based flip animations using
Canvas+ 3D transforms - Pixel-perfect layout: Precise text positioning and light-overlay compensation across all screen densities
- Modular architecture: Hilt DI + multi-module layering for performance and extensibility
- Realistic card-flip animation with custom
Canvas+ 3D transform pipeline — each flip simulates paper weight, shadow, and perspective. - Simulated bulb light: Warm light overlay recreates the glow of a real desk lamp illuminating the clock face. Toggle on/off with satisfying haptic feedback.
- Rotary knob time control: Drag the knob to fast-flip through digits at variable speed, simulating a mechanical adjustment dial with momentum.
- Hourly chime: Plays a configurable chime sound on the hour. Volume and enable/disable are adjustable from Settings.
- Sleep timer: Set a countdown to automatically close the app — perfect for bedside use without draining battery overnight.
- Zero-drain background behavior: Stops all rendering and activity when not visible.
- Hybrid UI stack:
- Jetpack Compose for settings screens.
- Custom Views for high-performance clock rendering.
- OLED burn-in protection with subtle pixel shifting.
- Light overlay effect with translation compensation (no edge gaps during burn-in shift).
- Hilt-based dependency injection with compile-time graph validation.
- Screenshots
- Project Structure
- Tech Stack
- Quick Start
- Build and Development Commands
- Architecture
- Dependency Injection (Hilt)
- Key Runtime Components
- Testing and Verification
- Performance Notes
- Recent Maintenance (2026-02)
- Contributing
- License
Captured from a real connected Android device via ADB.
OpenFlip/
├── app/ # Android app entry, DI modules, resources
├── core/ # Shared contracts/models/utilities
├── data/ # Repository implementations and persistence
├── domain/ # Use cases and repository interfaces
├── feature-clock/ # Clock runtime, custom view engine, activity/controllers
├── feature-settings/ # Settings UI (Compose), settings ViewModel/controllers
├── feature-chime/ # Hourly chime feature
└── docs/ # Architecture notes, ADRs, regression baseline
- Language: Kotlin
- UI:
- Jetpack Compose (settings and modern UI components)
- Custom Views (clock rendering, interactive 3D controls)
- Architecture: MVVM + reactive
StateFlow+ Hilt DI - Major dependencies:
- Hilt
2.55 - Material Components / Material 3
- Cloudy (liquid-glass blur effects)
- Hilt
- JDK 17+
- Android Studio Ladybug or newer
- Android SDK configured locally
# Replace with your actual repository URL
git clone https://github.com/<your-username>/fliqlo_android.git
cd fliqlo_android
./gradlew installDebugIf dependencies or DI setup changed, run a clean build once:
./gradlew clean build# Install debug APK to connected device/emulator
./gradlew installDebug
# Run unit tests
./gradlew test
# Static analysis
./gradlew lint
# Validate full compile graph (including Hilt)
./gradlew buildOpenFlip uses modular clean boundaries with feature-focused runtime orchestration.
:app: Android entry points, DI composition, resources.:core: Common contracts, models, shared utilities.:domain: Use cases and repository contracts.:data: Repository implementations andAppSettingsManagerpersistence.:feature-clock: Fullscreen clock runtime, rendering, interaction controllers.:feature-settings: Settings UI and settings state flow.:feature-chime: Hourly chime behavior.
UI -> ViewModel -> Repository -> SettingsStore(AppSettingsManager)
Clock runtime (feature-clock) observes settings flow and applies UI/runtime diffs reactively.
- Baseline:
docs/architecture-baseline.md - ADRs:
docs/adr/
Hilt replaced manual wiring for compile-time safety and cleaner lifecycle scoping.
app/src/main/java/com/bokehforu/openflip/
├── OpenFlipApplication.kt # @HiltAndroidApp
└── di/module/
├── CoreModule.kt # Context, CoroutineScope, time utilities
├── ManagerModule.kt # Manager/interface bindings
└── ControllerModule.kt # Activity-scoped bindings
AppSettingsManager(@Singleton)HapticFeedbackManager(@Singleton)FeedbackSoundManager(@Singleton)TimeProvider(@Singleton)FullscreenClockViewModel(@HiltViewModel)SettingsViewModel(@HiltViewModel)LightToggleController(AssistedInject + Factory)
feature-clock/src/main/java/com/bokehforu/openflip/feature/clock/view/FullscreenFlipClockView.kt- Main custom view for card flip rendering.
feature-clock/src/main/java/com/bokehforu/openflip/feature/clock/view/renderer/LightOverlayRenderer.kt- Light overlay rendering with full-coverage compensation.
feature-clock/src/main/java/com/bokehforu/openflip/feature/clock/manager/DisplayBurnInProtectionManager.kt- OLED shift manager with custom shift applier callback.
feature-clock/src/main/java/com/bokehforu/openflip/feature/clock/ui/FullscreenClockActivity.ktfeature-clock/src/main/java/com/bokehforu/openflip/feature/clock/ui/controller/LightToggleController.kt
feature-settings/src/main/java/com/bokehforu/openflip/feature/settings/viewmodel/SettingsViewModel.ktdata/src/main/java/com/bokehforu/openflip/data/settings/AppSettingsManager.kt
- Unit tests:
app/src/test - Build-time DI graph verification:
./gradlew build - Custom Gradle verification tasks (run automatically during
check):checkModuleBoundaries— Enforces allowed module dependency graph.checkSharedPreferencesIsolation— EnsuresSharedPreferencesusage is confined to:data.checkResourceOwnershipBoundaries— Detects duplicate resource paths between:appand:feature-settings.checkResourceSymbolBoundaries— Detects duplicate resource symbols across modules.checkAppResourceReferenceBoundaries— Prevents:appfrom referencing:feature-settings-owned resources.checkNoFeatureSettingsRUsageInApp— Blocks direct:feature-settingsR imports in:app.
- Recommended local gate before PR:
./gradlew test lint build- Verify flip animations across portrait/landscape.
- Verify dark/light theme transitions in settings.
- Verify OLED protection subtle shifts while keeping visual continuity.
- Verify light overlay with OLED protection enabled (no edge gaps).
- Verify haptic feedback on all buttons.
- Verify only the Light button triggers sound effect.
- Clock rendering path is optimized for smooth 60fps behavior.
- Avoid allocations inside
onDrawhot paths. - Cache expensive text/theme/noise rendering resources where possible.
- Keep Compose and custom rendering concerns separated to minimize regressions.
- Settings Sheet refinement:
- Improved gesture handling (drag-to-dismiss, scroll synchronization).
- Power optimization:
- Zero background activity when screen off or app hidden.
- App Shortcuts:
- Fixed shortcuts for Dark/Light mode and Settings.
- Documentation:
- Added Chinese (Simplified) README (
README.zh-CN.md).
- Added Chinese (Simplified) README (
- Replaced
app/src/main/res/raw/flip_sound.mp3. - Rebalanced audio levels (flip softer, chime slightly louder).
- Cached theme background color in
FullscreenFlipClockView. - Accessibility updates:
- Clock announces current time.
- Light button announces on/off and is clickable.
- Text rendering optimization:
- Added LRU cache for ink-center calculations (digits + AM/PM).
- Flip renderer optimization:
- Noise shader caching in
FlipCardRendererto reduce GC during theme changes.
- Noise shader caching in
- Gesture safety update:
- Brightness dim only on single-finger scroll.
- Multi-finger pinch no longer triggers dim.
- Light overlay rendering:
- Removed PorterDuff
ADDto avoid GPU-to-software fallback.
- Removed PorterDuff
- Bug Fixes:
- Resolved Sleep Timer crash.
- Fixed Invert button sound feedback.
- Use feature branches from
main. - Keep each PR scoped to one behavior or refactor goal.
- Keep module boundaries intact (
docs/architecture-baseline.md). - Include tests or rationale for test gaps.
- Run local quality gates:
./gradlew test lint build installDebug- Update docs when changing architecture, behavior, or user-facing settings.
- Follow Conventional Commits (
feat:,fix:,refactor:,docs:,chore:, etc.). - Prefer small, reviewable, atomic commits.
- Use clear commit subjects describing behavioral impact.
This project is licensed under the GNU General Public License v3.0.
See the LICENSE file for the full license text.









