|
| 1 | +# MaterialComponents Theme Migration |
| 2 | + |
| 3 | +## Status: Planning |
| 4 | +## Related: [#15 - Upgrade the UI](https://github.com/williscool/CalendarNotification/issues/15), [#225 - Filter pills bottom sheet dark theme](https://github.com/williscool/CalendarNotification/issues/225) |
| 5 | + |
| 6 | +## Overview |
| 7 | + |
| 8 | +The app currently uses `Theme.AppCompat.DayNight` as its base theme. While this provides basic dark mode support, Material Components (bottom sheets, dialogs, etc.) don't automatically inherit the dark theme styling. |
| 9 | + |
| 10 | +This document outlines the migration path to `Theme.MaterialComponents.DayNight` for full Material Design support with automatic dark mode. |
| 11 | + |
| 12 | +## Background |
| 13 | + |
| 14 | +### Current State |
| 15 | +- Base theme: `Theme.AppCompat.DayNight.DarkActionBar` |
| 16 | +- Material library version: `com.google.android.material:material:1.12.0` |
| 17 | +- Bottom sheets use `BottomSheetDialogFragment` from Material library |
| 18 | +- Dialogs use `AlertDialog.Builder` from AppCompat |
| 19 | + |
| 20 | +### Problem |
| 21 | +Material Components don't inherit dark mode styling from AppCompat themes. This causes: |
| 22 | +- Bottom sheets with light backgrounds in dark mode |
| 23 | +- Inconsistent dialog styling |
| 24 | +- Manual theme overrides needed for each component |
| 25 | + |
| 26 | +### Solution Options |
| 27 | + |
| 28 | +| Option | Approach | Scope | Risk | |
| 29 | +|--------|----------|-------|------| |
| 30 | +| **A** | Add `bottomSheetDialogTheme` attribute | Targeted fix for bottom sheets only | Low | |
| 31 | +| **B** | Switch to `Theme.MaterialComponents.DayNight` | App-wide Material styling | Medium | |
| 32 | + |
| 33 | +**Option A** was merged for the immediate bottom sheet fix. |
| 34 | +**Option B** is tracked here for the broader UI upgrade. |
| 35 | + |
| 36 | +## Option B: Full MaterialComponents Migration |
| 37 | + |
| 38 | +### Changes Required |
| 39 | + |
| 40 | +#### 1. Theme Parent Change (DONE in test branch) |
| 41 | + |
| 42 | +**`values/styles.xml`:** |
| 43 | +```xml |
| 44 | +<!-- Before --> |
| 45 | +<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar"> |
| 46 | + |
| 47 | +<!-- After --> |
| 48 | +<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> |
| 49 | + <item name="colorSecondary">@color/accent</item> <!-- For FAB, etc. --> |
| 50 | +``` |
| 51 | + |
| 52 | +**`values-night/styles.xml`:** |
| 53 | +```xml |
| 54 | +<!-- Update overlays to MaterialComponents equivalents --> |
| 55 | +<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.MaterialComponents.Dark"> |
| 56 | +``` |
| 57 | + |
| 58 | +--- |
| 59 | + |
| 60 | +#### 2. AlertDialog → MaterialAlertDialogBuilder |
| 61 | + |
| 62 | +**Impact:** 52 usages across 14 files |
| 63 | +**Effort:** Medium (2-3 hours) |
| 64 | +**Visual Impact:** High (Material dialogs have rounded corners, different button styling) |
| 65 | + |
| 66 | +**Files to update:** |
| 67 | +- `MainActivityModern.kt` (3 usages) |
| 68 | +- `MainActivityLegacy.kt` (4 usages) |
| 69 | +- `MainActivityBase.kt` (4 usages) |
| 70 | +- `ViewEventActivityNoRecents.kt` (7 usages) |
| 71 | +- `SnoozeAllActivity.kt` (7 usages) |
| 72 | +- `PreActionActivity.kt` (2 usages) |
| 73 | +- `EditEventActivity.kt` (9 usages) |
| 74 | +- `DismissedEventsActivity.kt` (2 usages) |
| 75 | +- `CalendarsActivity.kt` (2 usages) |
| 76 | +- `DismissedEventsFragment.kt` (2 usages) |
| 77 | +- `NavigationSettingsFragmentX.kt` (3 usages) |
| 78 | +- `MiscSettingsFragmentX.kt` (3 usages) |
| 79 | +- `SnoozePresetPreferenceX.kt` (2 usages) |
| 80 | +- `ListPreference.kt` (2 usages) |
| 81 | + |
| 82 | +**Change pattern:** |
| 83 | +```kotlin |
| 84 | +// Before |
| 85 | +import androidx.appcompat.app.AlertDialog |
| 86 | + |
| 87 | +AlertDialog.Builder(context) |
| 88 | + .setTitle("Title") |
| 89 | + .setMessage("Message") |
| 90 | + .setPositiveButton("OK") { _, _ -> } |
| 91 | + .show() |
| 92 | + |
| 93 | +// After |
| 94 | +import com.google.android.material.dialog.MaterialAlertDialogBuilder |
| 95 | + |
| 96 | +MaterialAlertDialogBuilder(context) |
| 97 | + .setTitle("Title") |
| 98 | + .setMessage("Message") |
| 99 | + .setPositiveButton("OK") { _, _ -> } |
| 100 | + .show() |
| 101 | +``` |
| 102 | + |
| 103 | +--- |
| 104 | + |
| 105 | +#### 3. Material Color Attributes |
| 106 | + |
| 107 | +**Impact:** Improves theme consistency |
| 108 | +**Effort:** Low (30 minutes) |
| 109 | + |
| 110 | +Add to `values/colors.xml`: |
| 111 | +```xml |
| 112 | +<!-- Material Design color attributes --> |
| 113 | +<color name="colorSurface">@color/cardview_light_background</color> |
| 114 | +<color name="colorOnSurface">@color/primary_text</color> |
| 115 | +<color name="colorOnPrimary">@color/icons</color> |
| 116 | +<color name="colorPrimaryVariant">@color/primary_dark</color> |
| 117 | +<color name="colorSecondaryVariant">@color/accent</color> |
| 118 | +``` |
| 119 | + |
| 120 | +Add to `values-night/colors.xml`: |
| 121 | +```xml |
| 122 | +<!-- Dark mode surface colors --> |
| 123 | +<color name="colorSurface">@color/cardview_light_background</color> <!-- #1E1E1E --> |
| 124 | +<color name="colorOnSurface">@color/primary_text</color> <!-- #E1E1E1 --> |
| 125 | +<color name="colorOnPrimary">@color/icons</color> |
| 126 | +<color name="colorPrimaryVariant">@color/primary_dark</color> |
| 127 | +<color name="colorSecondaryVariant">@color/accent</color> |
| 128 | +``` |
| 129 | + |
| 130 | +Add to `values/styles.xml` AppTheme: |
| 131 | +```xml |
| 132 | +<item name="colorSurface">@color/colorSurface</item> |
| 133 | +<item name="colorOnSurface">@color/colorOnSurface</item> |
| 134 | +<item name="colorOnPrimary">@color/colorOnPrimary</item> |
| 135 | +<item name="colorPrimaryVariant">@color/colorPrimaryVariant</item> |
| 136 | +<item name="colorSecondaryVariant">@color/colorSecondaryVariant</item> |
| 137 | +``` |
| 138 | + |
| 139 | +--- |
| 140 | + |
| 141 | +#### 4. Fix EditText Styling |
| 142 | + |
| 143 | +**Impact:** Bottom sheet search box |
| 144 | +**Effort:** Low (15 minutes) |
| 145 | + |
| 146 | +**File:** `bottom_sheet_calendar_filter.xml` |
| 147 | + |
| 148 | +```xml |
| 149 | +<!-- Before --> |
| 150 | +<EditText |
| 151 | + android:background="@android:drawable/editbox_background" |
| 152 | + ... /> |
| 153 | + |
| 154 | +<!-- After - Option 1: Simple fix --> |
| 155 | +<EditText |
| 156 | + android:background="?android:attr/editTextBackground" |
| 157 | + ... /> |
| 158 | + |
| 159 | +<!-- After - Option 2: Full Material (more work) --> |
| 160 | +<com.google.android.material.textfield.TextInputLayout |
| 161 | + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" |
| 162 | + android:layout_width="match_parent" |
| 163 | + android:layout_height="wrap_content"> |
| 164 | + <com.google.android.material.textfield.TextInputEditText |
| 165 | + android:id="@+id/search_calendars" |
| 166 | + android:layout_width="match_parent" |
| 167 | + android:layout_height="wrap_content" |
| 168 | + android:hint="@string/calendar_filter_search_hint" /> |
| 169 | +</com.google.android.material.textfield.TextInputLayout> |
| 170 | +``` |
| 171 | + |
| 172 | +--- |
| 173 | + |
| 174 | +#### 5. CardView → MaterialCardView (Optional) |
| 175 | + |
| 176 | +**Impact:** Consistent card styling |
| 177 | +**Effort:** Low (15 minutes) |
| 178 | + |
| 179 | +**File:** `content_main.xml` |
| 180 | + |
| 181 | +```xml |
| 182 | +<!-- Before --> |
| 183 | +<androidx.cardview.widget.CardView ... > |
| 184 | + |
| 185 | +<!-- After --> |
| 186 | +<com.google.android.material.card.MaterialCardView ... > |
| 187 | +``` |
| 188 | + |
| 189 | +MaterialCardView provides: |
| 190 | +- Consistent corner radius |
| 191 | +- Better elevation handling in dark mode |
| 192 | +- Ripple effects |
| 193 | + |
| 194 | +--- |
| 195 | + |
| 196 | +#### 6. Button Styling (If Needed) |
| 197 | + |
| 198 | +MaterialComponents buttons default to **filled** style. If you want text or outlined buttons: |
| 199 | + |
| 200 | +```xml |
| 201 | +<!-- Text button (like a link) --> |
| 202 | +<Button |
| 203 | + style="@style/Widget.MaterialComponents.Button.TextButton" |
| 204 | + ... /> |
| 205 | + |
| 206 | +<!-- Outlined button --> |
| 207 | +<Button |
| 208 | + style="@style/Widget.MaterialComponents.Button.OutlinedButton" |
| 209 | + ... /> |
| 210 | + |
| 211 | +<!-- Filled button (default in MaterialComponents) --> |
| 212 | +<Button |
| 213 | + style="@style/Widget.MaterialComponents.Button" |
| 214 | + ... /> |
| 215 | +``` |
| 216 | + |
| 217 | +--- |
| 218 | + |
| 219 | +## Implementation Priority |
| 220 | + |
| 221 | +| Priority | Task | Effort | Visual Impact | |
| 222 | +|----------|------|--------|---------------| |
| 223 | +| 1 | Material color attributes | 30 min | Medium | |
| 224 | +| 2 | AlertDialog → MaterialAlertDialogBuilder | 2-3 hours | **High** | |
| 225 | +| 3 | Fix EditText in bottom sheet | 15 min | Medium | |
| 226 | +| 4 | CardView → MaterialCardView | 15 min | Low | |
| 227 | +| 5 | Button style audit | 1 hour | Medium | |
| 228 | +| 6 | TextInputLayout migration (optional) | 2-3 hours | Medium | |
| 229 | + |
| 230 | +**Total estimated effort:** 4-6 hours for cohesive Material look |
| 231 | + |
| 232 | +--- |
| 233 | + |
| 234 | +## Visual Differences Summary |
| 235 | + |
| 236 | +| Component | AppCompat | MaterialComponents | |
| 237 | +|-----------|-----------|-------------------| |
| 238 | +| Dialogs | Sharp corners, standard buttons | Rounded corners, Material buttons | |
| 239 | +| Bottom sheets | Needs manual theming | Auto dark mode | |
| 240 | +| Buttons | Borderless/text style | Filled by default | |
| 241 | +| Cards | Standard elevation | Better dark mode elevation | |
| 242 | +| Text fields | Platform default | Outlined/Filled with labels | |
| 243 | +| Checkboxes | Platform style | Material ripple + animation | |
| 244 | +| Radio buttons | Platform style | Material ripple + animation | |
| 245 | + |
| 246 | +--- |
| 247 | + |
| 248 | +## Testing Checklist |
| 249 | + |
| 250 | +After migration, test these in both light and dark mode: |
| 251 | + |
| 252 | +- [ ] Main activity (Modern UI) |
| 253 | +- [ ] Main activity (Legacy UI) |
| 254 | +- [ ] Settings screens |
| 255 | +- [ ] Handled Calendars page |
| 256 | +- [ ] View Event screen |
| 257 | +- [ ] Snooze All dialog |
| 258 | +- [ ] All AlertDialog confirmations |
| 259 | +- [ ] Filter bottom sheets (Time, Calendar) |
| 260 | +- [ ] Edit Event screen |
| 261 | +- [ ] About screen |
| 262 | + |
| 263 | +--- |
| 264 | + |
| 265 | +## References |
| 266 | + |
| 267 | +- [Material Components Android - Getting Started](https://material.io/develop/android/docs/getting-started) |
| 268 | +- [Migrating to Material Components](https://material.io/blog/migrate-android-material-components) |
| 269 | +- [Material Theming](https://material.io/design/material-theming/overview.html) |
0 commit comments