Structure & Architecture
Math Mantra is an Android app organized with clear separation of concerns, strong accessibility, and content-driven gameplay sourced from localized Excel files.
- Presentation layer: Fragments/UI and feature orchestration
- Domain layer: Use cases, models, repository interfaces
- Data layer: Excel-backed content loader and in-memory cache
- Core utilities: TTS, dialogs, grading, accessibility helpers
- DI: Hilt modules for wiring repositories and use cases
- Startup: Splash preload + background caching
Repository Layout
- App code:
app/src/main/java/com/zendalona/zmantra/ - Assets:
app/src/main/assets/ - Questions Excel:
assets/questions/{lang}.xlsx(e.g.,en.xlsx,ml.xlsx, etc.) - User guide HTML:
assets/userguide/{lang}.html - Resources:
app/src/main/res/
Presentation Layer
- Game hub
- presentation/features/game/GameFragment.kt
-
Hosts buttons to navigate to game mode fragments via
FragmentNavigation. -
Base game foundation
- core/base/BaseGameFragment.kt
- Responsibilities:
- Reads
langfromLocaleHelperanddifficultyfromDifficultyPreferences. - Manages
TTSUtilitylifecycle. - Sets up hint menu (setupHintMenu) and opens
HintFragment. - Loads questions: try QuestionCache.getQuestions(...); fallback to ExcelQuestionLoader.loadQuestionsFromExcel(...); then cache with QuestionCache.putQuestions(...).
- Accessibility announcements (announce, announceNextQuestion).
- Unified validation flow via handleAnswerSubmission(...) using
GradingUtilsandDialogUtils. - Optional GIF support with Glide (loadGifIfDefined).
- Reads
-
Child fragments must implement:
- getModeName(): String that matches Excel Mode column.
- onQuestionsLoaded(questions: List
) : Render and handle gameplay.
-
Example feature fragments
-
Under
presentation/features/game/:shake/ShakeFragment.kt,tap/TapFragment.kt,angle/AngleFragment.kt,compass/CompassFragment.kt,numberline/NumberLineFragment.kt,drawing/DrawingFragment.kt,touchscreen/TouchScreenFragment.kt, etc. -
Settings and User Guide
- Locale and difficulty:
- User guide:
presentation/features/userguide/UserGuideFragment.kt- presentation/features/userguide/UserGuideViewModel.kt
Domain Layer
- Models
- domain/model/GameQuestion.kt
expression: Stringanswer: InttimeLimit: Int = 20celebration: Boolean = false
- domain/model/Hintable.kt
-
Repository interfaces
- domain/repository/QuestionRepository.kt
-
Use cases
- domain/usecase/LoadQuestionsUseCase.kt
- domain/usecase/userguide/GetUserGuideHtmlUseCase.kt
Note: Question loading currently uses BaseGameFragment + ExcelQuestionLoader + QuestionCache directly. QuestionRepository/LoadQuestionsUseCase exists for future alignment with a repository abstraction.
Data Layer
- Excel loader
- core/utility/excel/ExcelQuestionLoader.kt
- Reads from
assets/questions/{lang}.xlsxvia Apache POI. - Filters by
modeanddifficultycolumns. - Renders variableized templates and evaluates answers via exp4j (numeric modes).
-
Columns per row:
- C0: Question template (supports
{a},{b}, ...) - C1: Mode (e.g.,
shake,tap,angle, ...) - C2: Operand spec (grammar below)
- C3: Difficulty (string
"1".."5") - C4: Answer expression template (uses same variables)
- C5: Time limit (int; default 20)
- C0: Question template (supports
-
Operand grammar
- Comma list:
1,2,5โ pick one randomly - Range:
5:10โ inclusive random - Multiplicative pair:
2,3;3:5โ pick left and right, multiply -
For non-numeric modes like
directionanddrawing, operands map to literal options; answers default to0and are handled by UI logic. -
Cache
- core/utility/excel/QuestionCache.kt
- Key:
"$lang-$mode-$difficulty" -
APIs:
-
User guide repository
- data/repository/userguide/UserGuideRepositoryImpl.kt
- Reads
assets/userguide/{lang}.html.
Dependency Injection (Hilt)
- App init
- ZMantra.kt annotated with
@HiltAndroidApp. -
On startup:
- LocaleHelper.onAttach(this) applies saved locale.
- Contrast mode applied via
AppCompatDelegate.setDefaultNightMode(...).
-
Modules
- di/UserGuideModule.kt
- Provides UserGuideRepository and GetUserGuideHtmlUseCase.
- Future: Provide a concrete QuestionRepository when adopted app-wide.
Startup Flow
- SplashScreen.kt
- Shows welcome GIF via Glide.
- If accessibility enabled, periodically announces โLoading questionsโ.
- Preloads current-difficulty questions via QuestionCache.preloadCurrentDifficultyModes.
- Navigates to
MainActivityon completion. - Background-preloads other difficulties afterward.
Accessibility & TTS
- Accessibility service
- core/utility/accessibility/MathsManthraAccessibilityService.java
-
A11y-first: fragments announce next-question transitions and key events.
-
TTS
- core/utility/common/TTSUtility.java
-
Created in BaseGameFragment.onCreate, shut down in onDestroyView.
-
Dialogs and grading
- core/utility/common/DialogUtils.kt
- core/utility/common/GradingUtils.kt
Localization & Difficulty
- Localization
- LocaleHelper.kt manages language.
- Excel per language in
assets/questions/{lang}.xlsx. -
User guide per language in
assets/userguide/{lang}.html. -
Difficulty
- core/Enum/Diffculty.kt โ
object Difficulty { SIMPLE=1, EASY=2, MEDIUM=3, HARD=4, CHALLENGING=5 } - DifficultyPreferences.kt persists selection.
- Excel filtering uses difficulty strings (
"1".."5").
Adding a New Game Mode
- Create fragment under
presentation/features/game/<mode>/<Mode>Fragment.ktextending BaseGameFragment. - Implement:
override fun getModeName() = "<mode>"(must match Excel Mode column).override fun onQuestionsLoaded(questions: List<GameQuestion>)to render and handle logic.- Use handleAnswerSubmission(...) for validation, and
DialogUtilsto show results/retry/correct-answer dialogs. - Provide optional GIF via getGifImageView() and getGifResource().
- Add navigation from GameFragment.
- Add content rows into
assets/questions/{lang}.xlsxwith correct Mode and Difficulty. - Verify splash preloading logs and cache hits.
Assets & Resources
- Excel questions:
app/src/main/assets/questions/{lang}.xlsx - User guide HTML:
app/src/main/assets/userguide/{lang}.html - Drawables/GIFs:
app/src/main/res/drawable*
Key Dependencies
- Hilt: DI
- Apache POI: Excel parsing
- exp4j: Expression evaluation
- Glide: GIF loading
- AndroidX: Fragments, Lifecycle, Preferences