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
lang
fromLocaleHelper
anddifficulty
fromDifficultyPreferences
. - Manages
TTSUtility
lifecycle. - 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
GradingUtils
andDialogUtils
. - 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: String
answer: Int
timeLimit: Int = 20
celebration: 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}.xlsx
via Apache POI. - Filters by
mode
anddifficulty
columns. - 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
direction
anddrawing
, operands map to literal options; answers default to0
and 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
MainActivity
on 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.kt
extending 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
DialogUtils
to show results/retry/correct-answer dialogs. - Provide optional GIF via getGifImageView() and getGifResource().
- Add navigation from GameFragment.
- Add content rows into
assets/questions/{lang}.xlsx
with 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