# Budget Tracker Widget An Android home-screen widget that shows actual spend vs. budget: an overall progress bar (color-coded green/amber/red) plus a per-category breakdown chart, rendered for 7 sample budget items. ## Opening the project 1. Open Android Studio → **Open** → select the `BudgetTrackerWidget` folder. 2. Let Gradle sync (Android Studio will fetch Gradle 8.7 per `gradle/wrapper/gradle-wrapper.properties` — no wrapper jar is bundled, so the first sync needs an internet connection). 3. Run the `app` module on an emulator or device (API 26+). 4. Long-press the home screen → **Widgets** → find **Budget Tracker** → drag it onto the home screen. ## How it's wired together - **`BudgetItem.kt`** — data model for one budget line (category, budgeted, spent). - **`BudgetRepository.kt`** — the single data source. `fetchBudgetData()` is a placeholder that simulates a network call and returns 7 sample categories (Rent, Groceries, Dining Out, Transport, Utilities, Entertainment, Savings) mixing under-, at-, and over-budget items. A commented-out `parseBudgetJson()` shows how to parse a real API response — swap the body of `fetchBudgetData()` for an OkHttp/Retrofit/Ktor call when you have a real endpoint, and nothing else in the app needs to change. - **`BudgetColors.kt`** — the single green/amber/red threshold definition, shared by the chart renderer, the widget's progress bar, and the app's progress bar, so status colors are always consistent. - **`BudgetChartRenderer.kt`** — draws the category bar chart onto a `Bitmap` using `Canvas`. Widgets can't host arbitrary custom Views (RemoteViews only supports a fixed set of native widgets), so this is the standard way to get a custom visualization into a widget: draw it yourself, then push the bitmap into an `ImageView`. The **app screen reuses this exact same renderer**, so the in-app view and the widget are pixel-identical, just at different sizes. - **`WidgetLayoutPlanner.kt`** — pure logic that turns a widget's current width/height (dp) into a display plan: whether to show the percent label, whether there's room for the chart at all, how many category rows fit, and whether text should shrink for narrow widths. - **`BudgetWidgetProvider.kt`** — the `AppWidgetProvider`. Reads the widget's live size from `onAppWidgetOptionsChanged()` (fired whenever the user drags the resize handles) as well as `onUpdate()`, feeds it through `WidgetLayoutPlanner`, and builds `RemoteViews` accordingly — hiding the chart entirely at very small sizes, showing only the most over-budget categories (with a "+N more" footer) when space is tight, and sizing the rendered bitmap to match. - **`widget_budget.xml`** — the widget layout: title, total, percent label, three stacked (mutually-exclusive-visibility) `ProgressBar`s for the green/amber/red states, an `ImageView` for the chart bitmap, and a "+N more" footer. - **`MainActivity.kt`** / **`activity_main.xml`** — a full-screen version of the same card: same background, same title/total/percent, a single `ProgressBar` tinted at runtime via `BudgetColors`, and the same chart bitmap (rendered larger, showing every category since there's no space constraint). ## Flexible widget sizing The widget can be resized from a small ~2×1 cell (just title, total, and progress bar) up to a full card with the complete chart: - `minWidth`/`minHeight` in `budget_widget_info.xml` set the default placed size; `minResizeWidth`/`minResizeHeight` set how small it can be dragged. - At runtime, `onAppWidgetOptionsChanged()` reports the new size, and `WidgetLayoutPlanner` decides what fits — hiding the percent label and chart below certain heights, shrinking text below a certain width, and showing the categories closest to (or over) budget first when not all 7 fit. - Try dragging the widget to different sizes on the home screen to see it adapt live. ## Extending it - **Real data**: replace `BudgetRepository.fetchBudgetData()`'s body with an actual HTTP call; keep the return type `List` and everything downstream (widget + activity) keeps working unchanged. - **Refresh cadence**: `updatePeriodMillis` in `budget_widget_info.xml` is set to 30 minutes (Android's minimum useful floor is ~30 min for this mechanism). For more frequent updates, trigger `ACTION_APPWIDGET_UPDATE` yourself from a `WorkManager` periodic job. - **Tap-to-open categories**: `setOnClickPendingIntent` is only wired to the whole widget right now; you could add per-row click targets if you split the chart into individual `ImageView`/`TextView` rows instead of one bitmap. - **Android 12+ responsive layouts**: for an even smoother resize experience on API 31+, you could additionally supply a size-keyed `RemoteViews(Map)` so the system switches layouts instantly during a drag, rather than waiting for the `onAppWidgetOptionsChanged()` callback. The current approach already covers all API levels (26+) and updates immediately once the drag ends.