Initial Commit

This commit is contained in:
nabeel
2026-09-18 15:56:54 +10:00
commit dd59dcb605
598 changed files with 49076 additions and 0 deletions

86
README.md Normal file
View File

@@ -0,0 +1,86 @@
# 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<BudgetItem>` 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<SizeF, RemoteViews>)` 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.