Gemini Near Me
Senior Android Engineer · Tapforce · 2023–present
- Kotlin
- Jetpack Compose
- Hilt
- Navigation 3
- Firebase
- Media3
- CameraX
View on Google Play: open play://com.tapforce.gemininearme
Context
Gemini Near Me is a consumer astrology and self-development app. It brings together the things people reach for in that practice — natal charts, horoscopes, compatibility readings, numerology, journaling, meditation, dream interpretation — and a community feed around them, in one place. It is built for people who keep up an astrology and self-reflection habit, and it runs on a subscription.
Approach
Gemini Near Me is a single-module app organized as a layer-based spine — data, domain, presentation — with the presentation layer grouped by feature beneath it. It is the oldest app I work on, which makes it the real test of two different things: whether the early boundaries held (they did), and whether an aging codebase can be modernized in place without a rewrite. It can: the Compose migration is essentially complete — one XML layout remains — the app runs Navigation 3 in production with type-safe @Serializable routes rendered by NavDisplay, and the screens are migrating to MVI one at a time.
That migration is ratcheted, not hoped for: a Konsist test carries the known violations as an explicit set with a standing rule that the set may never grow. Every screen that converts shrinks it; nothing new can sneak in behind it.
Technical decisions
Astrology has a fixed vocabulary — ten classical planets, twelve signs, the houses — and Gemini Near Me models that vocabulary as typed enums instead of passing raw strings between the chart math and the UI. ZodiacPlanets pairs each celestial body with the glyph the natal chart draws for it, so rendering a chart is a lookup over a closed set rather than string-matching that can quietly miss.
enum class ZodiacPlanets(val value: String, val iconRes: Int) {
Sun("Sun", R.drawable.sun),
Moon("Moon", R.drawable.moon),
Mercury("Mercury", R.drawable.mercury),
Venus("Venus", R.drawable.venus),
Mars("Mars", R.drawable.mars),
Jupiter("Jupiter", R.drawable.jupiter),
Saturn("Saturn", R.drawable.saturn),
Uranus("Uranus", R.drawable.uranus),
Neptune("Neptune", R.drawable.neptune),
Pluto("Pluto", R.drawable.pluto);
companion object Companion {
fun fromValue(value: String): ZodiacPlanets? =
entries.find { it.value.equals(value, ignoreCase = true) }
fun iconForPlanetName(planetName: String): Int? = when (planetName.lowercase()) {
"ascendant" -> R.drawable.rising
else -> fromValue(planetName)?.iconRes
}
}
}Outcome
Gemini Near Me is a mature, shipped product — version 2.3 across one hundred and fifty-nine builds, developed continuously for three years. Features have kept landing — an AI avatar built on CameraX with on-device face detection, PDF reports, video via Media3, a community feed — without the codebase getting harder to move through. The proof isn't that it looked clean on day one; it's that a three-year-old app is currently the easiest of the four to modernize, because the boundaries were drawn early and the ratchets only turn one way.