2026-09-18 18:23:45 +10:00
2026-09-18 15:56:54 +10:00
2026-09-18 18:16:39 +10:00
2026-09-18 18:16:39 +10:00
2026-09-18 15:56:54 +10:00
2026-09-18 18:23:45 +10:00
2026-09-18 15:56:54 +10:00
2026-09-18 15:56:54 +10:00
2026-09-18 15:56:54 +10:00
2026-09-18 15:56:54 +10:00
2026-09-18 15:56:54 +10:00

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) ProgressBars 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.
Description
No description provided
Readme 22 MiB
Languages
Kotlin 100%