# AestheticDialogs 1.x — architecture audit The audit that preceded the 2.0 rebuild. It records what 1.3.8 actually did, what was wrong with it, and what each piece became. Kept in the repository because "why is it like this now" is a question that outlives everyone who was in the room. ## 1. What 1.x was One file, 717 lines: `AestheticDialog.kt`. Inside it, a `Builder` class with a `show()` method containing a single `when (dialogStyle)` over eight branches. Each branch inflated an XML layout, bound it with ViewBinding, applied colours with `ContextCompat.getColor`, created an `AlertDialog`, and then reached into `alertDialog.window` to set gravity, background and size. Supporting cast: | Kind | Count | Notes | |---|---|---| | Public Kotlin types | 6 | `AestheticDialog`, `Builder`, `DialogStyle`, `DialogType`, `DialogAnimation`, `OnDialogClickListener` | | XML layouts | 10 | one per style, two for the styles that split success/error | | Drawables | 44 | 34 XML shapes/selectors, 10 PNG bitmaps | | Animation XML | 30 | 15 enter/exit pairs for 16 animation values | | Styles | 16 | one window-animation style per animation | | Colour resources | 13 | including four unused `*_darker` variants | | Dimension resources | 16 | fixed dialog widths and heights in `dp` | | Tests | 2 | the Android Studio templates, asserting `2 + 2 == 4` | Dependencies: `appcompat`, `cardview`, `core-ktx`. `minSdk 19`, `compileSdk 34`, Groovy Gradle, no version catalog, no publishing configuration in the repository (distribution was JitPack), no CI, no lint configuration, no ProGuard rules beyond the template comments. ## 2. Component-by-component ### 2.1 `DialogStyle.FLAT` | | | |---|---| | **Responsibility** | Modal status card with an icon, title, message and one button. | | **Public API** | `AestheticDialog.Builder(activity, FLAT, type)` + eight setters. | | **State** | None. Everything is passed at construction and never changes. | | **Visual implementation** | `dialog_flat.xml` (fixed 300×290dp) + four `rounded_rect_*` drawables + four button selectors, chosen by a `when (dialogType)`. | | **Dependencies** | `Activity`, `AlertDialog`, ViewBinding, `ContextCompat`. | | **Problems** | Fixed 300×290dp: content longer than three lines is silently ellipsized, and the dialog is the same size on a phone and a tablet. Dark mode is a boolean that repaints four views by hand — and repeats the `setText`/`setOnClickListener` calls already made ten lines above. Button colour is duplicated across four drawable files that differ only in a colour reference. Title colour comes from the status hue on white, which fails contrast for warning. | | **2.0** | `FeedbackDialogUiModel.Flat` → `FeedbackDialogFlat` variant → `DialogFramePrimitive` + `StatusBadgePrimitive` + `DialogActionRow`. Size is adaptive, dark mode is a theme, the four drawables are one `Tone` token lookup. | ### 2.2 `DialogStyle.FLASH` | | | |---|---| | **Responsibility** | Modal status card on a gradient, with an outlined button. | | **Public API** | Same builder. | | **Visual implementation** | `dialog_flash.xml` + two gradient drawables (success and error only). | | **Problems** | Only two of the four `DialogType` values have a gradient; passing `WARNING` silently rendered the error gradient (the branch was `if (type == SUCCESS) … else …`). Gradients are hard-coded hexes unrelated to the colour resources, so rebranding means editing XML. | | **2.0** | `FeedbackDialogUiModel.Flash`. The gradient is derived from the tone accent, so all five tones work and a rebranded theme stays consistent. | ### 2.3 `DialogStyle.TOASTER` | | | |---|---| | **Responsibility** | Edge-anchored banner: accent bar, icon, title, message, close. | | **Visual implementation** | `dialog_toaster.xml`, fixed 100dp height, shown as an `AlertDialog` with `Gravity.TOP`. | | **Problems** | It is not a dialog. Rendering it as one means it dims the screen, takes focus, blocks touches on the content behind it and consumes the back gesture — for an informational toast. The title size is `18dp`, not `sp`, so it ignores the user's font size setting entirely. | | **2.0** | `NotificationUiModel.Toaster`, rendered by `BannerPrimitive` inside `AestheticNotificationHost`. Not modal, announced as a live region, type in `sp`. | ### 2.4 `DialogStyle.CONNECTIFY` | | | |---|---| | **Responsibility** | Connectivity banner with a gradient strip. | | **Visual implementation** | Two near-identical layouts (`dialog_connectify_success.xml`, `..._error.xml`) differing only in gradient and text colour, plus a manual `AppCompatImageView`/`AppCompatTextView` variable dance in `show()` to unify them. | | **Problems** | The clearest duplication in the library: two layouts, two gradient drawables and fifteen lines of glue to paper over a single colour difference. Only success and error exist. | | **2.0** | `NotificationUiModel.Connectify`, one variant, gradient from the tone. | ### 2.5 `DialogStyle.RAINBOW` | | | |---|---| | **Responsibility** | Solid tone-filled banner. | | **Problems** | Same modality problem as Toaster. Fixed 100dp height with two-line messages. | | **2.0** | `NotificationUiModel.Rainbow`. | ### 2.6 `DialogStyle.EMOJI` | | | |---|---| | **Responsibility** | Banner with a large emoji. | | **Visual implementation** | `thumbs_up_sign.png` and `man_shrugging.png`, shipped at a single density. | | **Problems** | Bitmaps for glyphs the platform already renders as text: they blur when scaled, add weight to every consumer's APK, cannot follow the system emoji style and cannot be changed by the caller. Only two emoji exist, hard-wired to success and error. | | **2.0** | `NotificationUiModel.Emoji` takes the character. The library supplies a tone default; the caller can pass any emoji. Zero assets. | ### 2.7 `DialogStyle.EMOTION` | | | |---|---| | **Responsibility** | Wide card with an avatar, title, message and a timestamp. | | **Visual implementation** | `dialog_emotion.xml` inside a `CardView`, with `background_emotion_success.png` / `background_emotion_error.png` as background bitmaps. | | **Problems** | The dialog called `SimpleDateFormat("HH:mm")` on `Calendar.getInstance()` **inside the view code**. That ignores the user's 12/24-hour preference, ignores their locale, uses the default time zone, allocates a formatter on every show, and makes the component impossible to screenshot-test because its output changes every minute. Background bitmaps mean the card cannot resize cleanly. | | **2.0** | `NotificationUiModel.Emotion` takes a preformatted `timestamp: String?`. Formatting a time is a product decision. Background is a derived gradient. | ### 2.8 `DialogStyle.DRAKE` | | | |---|---| | **Responsibility** | Meme dialog: a two-panel Drake reaction image with success/error text. | | **Visual implementation** | `drake_success.png`, `drake_error.png`. | | **Problems** | The images are frames from a copyrighted music video redistributed inside an Apache-2.0 library. Beyond licensing: the text is baked into the bitmap, so it cannot be localised, cannot be read by a screen reader, and cannot honour the `setTitle`/`setMessage` the builder accepted (this style ignored both). | | **2.0** | **Removed.** Documented in `MIGRATION.md`. `FeedbackDialogUiModel.Flat` is the suggested replacement. | ### 2.9 `DialogAnimation` (16 values) | | | |---|---| | **Implementation** | 30 `res/anim` XML files and 16 `