Pattern · Settings

New

Storage SwiftUI Block

The Storage page of Settings: what the app takes in a split bar, Clear cache that confirms and counts down, removable downloads and options.

Where people see and reclaim the room an app takes. A summary card shows the total, the device's free space and a bar split into downloads, cache, photos and other; Clear cache confirms, works and shrinks its segment as the figures count down. Downloads remove from Edit or a long press, and the options cover cellular, quality and when finished downloads go.

  • SwiftUI
  • iOS 17.0+
  • storage-settings
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • The total in the brand's face, with the device's free space beside it
  • A bar and legend for downloads, cache, photos and other
  • Clear cache confirms, then shrinks its segment as the figures count down
  • Downloads that remove from Edit, a long press or VoiceOver
  • Cellular, quality and auto-remove options bound to your settings

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

A summary card leads with "Used by this app" and the total in the brand's display face, the free space left on the device beside it, and a bar split into Downloads, Cache, Photos and Other, with a legend of each part's size under it. Clear cache asks first in a confirmation that names the size; once confirmed the button shows a spinner while your closure runs, then a checkmark and "Cleared 1.2 GB."; hand the block the new usage and the cache segment shrinks out of the bar while the total and legend count down, leaving the empty track behind. With no cache left the button reads "Cache is empty" and dims. A thrown error shows under the button. The Downloads card lists each download with its symbol, title, detail and size. Edit puts a remove control in front of every row, and a long press offers Remove download; either runs your closure with a spinner in the row, and the row leaves when your usage drops it. With nothing downloaded the card says "No downloads". Options hold Download over cellular as a switch, then Download quality and Remove finished as menus showing the current choice, all bound to your settings. Pass nil for the usage while you measure and the block shows grey shapes in its own layout.

Notes

  • StorageSettings(usage:options:showsFreeSpace:onClearCache:onRemove:). It is a section: no navigation stack, background, padding or scroll view of its own, so place it in your own column, such as a ScrollView with .padding(.horizontal, 20).
  • usage is a StorageSettings.Usage in bytes: the downloads list, cache (what downloads again when needed), photos (kept for offline use) and other (database, settings, logs). downloadBytes and total are computed. Usage.sample is three downloads, 1.2 GB of cache and 4.8 GB in all. Measure it off the main actor, for example with FileManager and URLResourceValues.totalFileAllocatedSize, and pass the new value after each change.
  • A Download has an id, title, optional detail ("Audio · 52 min"), an SF Symbol for its kind and its bytes.
  • options is a Binding<StorageSettings.Options>: cellular (off by default), quality (.dataSaver, .standard, .high) and autoRemove (.never, .day, .week, .month). The block only writes the binding; apply the options where your downloads run.
  • onClearCache is async throws and runs after the person confirms. Empty URLCache, your image cache and temporary files there, then set the new usage. Done holds for a few seconds before the button settles. Throw to show a LocalizedError's errorDescription, or "The cache wasn't cleared. Try again." A CancellationError goes back to rest quietly.
  • onRemove receives the Download; delete its files and drop it from your usage. Several can run at once. A thrown error shows under the card. Nil hides Edit and the remove actions. Edit turns to Done and closes itself when the last download goes.
  • showsFreeSpace reads volumeAvailableCapacityForImportantUsage for the home directory, which needs no permission. Pass false to hide it.
  • The bar's full width is the largest total the block has seen, so a cleared cache leaves room on the track instead of stretching the other parts.
  • Haptics: success when the cache clears and an error when it fails; a selection tick on the cellular switch.
  • VoiceOver reads the summary as one element ("Used by this app, 4.8 GB. 41.2 GB free on this device"), each legend entry with its size, each download with its size and a Remove download action, and announces what was cleared or removed and any failure. Every target is at least 44 points tall. At accessibility sizes the legend becomes one column and rows wrap their text.
  • Reduce Motion places the bar at its new value without the shrink, and other changes become short fades.
  • StorageSettingsExample at the end of StorageSettings.swift is the Storage page from the preview: the sample usage, a cache clear that takes a moment and sets the cache to zero, and removals that drop the download. Pass wrapsInNavigationStack: false to push it in your own stack. The States preview shows the loading layout and an empty cache with no downloads.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • Cards are color.surface with radius.lg and 16 point padding (space.lg); rows use SPHairline dividers in separator, inset to the text. Groups sit 24 points apart (space.xl) under type.headline titles.
  • The total is the one display moment: the brand's face (type.face) at 34 points, type.numeralWeight capped at semibold, in type.figureDesign when the face isn't bundled, with monospaced digits. The free space is type.footnote in textSecondary.
  • The bar is a 12 point capsule on a fill track. Downloads are textPrimary, Cache accent, Photos textPrimary at 45% and Other textTertiary, so the accent marks what Clear cache frees. The legend is type.subhead, sizes in textSecondary with monospaced digits.
  • Clear cache is a secondary button: fill with textPrimary in type.headline, radius.md, 52 points. Its note is type.footnote in textSecondary, or danger on a failure. The confirmation is the system's, with Clear cache as the destructive choice.
  • Rows: titles type.body in textPrimary, details type.footnote in textSecondary, symbols textSecondary, sizes and menu values textSecondary, the menu chevrons textTertiary. The remove control is danger with a statusOn bar. Edit and Done are type.subhead semibold in textPrimary.
  • The cellular switch is accent with an accentOn thumb when on and fill with a white thumb when off.
  • The bar and figures move with motion.smooth, states with motion.snappy; both become short fades under Reduce Motion.