Skip to content

feat: auto-trim schedule, TrimNow preview, settings rewrite with segmented tabs - #20

Merged
ricardoleal merged 1 commit into
mainfrom
6-auto-trim-scheduled-background-deletion-of-old-backups
Jun 13, 2026
Merged

feat: auto-trim schedule, TrimNow preview, settings rewrite with segmented tabs#20
ricardoleal merged 1 commit into
mainfrom
6-auto-trim-scheduled-background-deletion-of-old-backups

Conversation

@ricardoleal

@ricardoleal ricardoleal commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Description

Completes the auto-trim feature with daily schedule, adds a preview phase to TrimNow, rewrites Settings with a native macOS segmented tab layout, and fixes the window launch visibility bug.

  • AutoTrimService — new service with daily timer (86400s), immediate eligibility check on start, Run Now bypasses toggle, cooldown uses autoTrimLastRun
  • TrimUnit — extracted enum (days/weeks/months) with cutoffDate(byAdding:to:) and displayName(count:)
  • SettingsStore — all 11 props converted from @ObservationIgnored+computed to stored var+didSet for proper @Observable tracking
  • SettingsView — replaced TabView with custom segmented picker (Trim/Auto Trim/Helper/General tabs), card-based layout, removed all section header Labels and Picker "Unit" labels
  • TrimNowSheetconfigure → scanning → preview → deleting → done flow, user sees backup count before confirming deletion
  • WindowSetuporderOut(nil) when showWindowOnLaunch = false (fix: SwiftUI creates window before AppDelegate fires)
  • BackupViewModelprepareTrimNow() / confirmedTrimNow() split for preview flow; trimThresholdValue/Unit replaces ageThresholdMonths
  • HelperClientnonisolated isInstalled + uninstall() via osascript with admin privileges
  • TrimByAgeView — unit picker, dynamic slider bounds per selected unit

Related Issue

#6

Type of Change

  • Bug fix
  • New feature
  • Enhancement/improvement
  • Documentation update
  • Other (please describe):

How Has This Been Tested?

==> Compiling test sources...

==> Running tests...
TimeMachineTrimmer Tests
================================================

## ResumptionFlag
  ✓ first call returns true
  ✓ second call returns false
  ✓ third call returns false
  ✓ only one succeeds from 100 concurrent calls

## Date Part Extraction
  ✓ full TM snapshot name
  ✓ non-TM string unchanged
  ✓ empty date part

## Backup Dict Validation
  ✓ valid dict returns nil
  ✓ empty snapshot returns error
  ✓ error mentions snapshotName
  ✓ empty volume returns error
  ✓ error mentions volumePath
  ✓ empty dict returns error

## HelperClient Backup Dict
  ✓ dict contains key 'id'
  ✓ dict contains key 'volumePath'
  ✓ dict contains key 'path'
  ✓ dict contains key 'snapshotName'
  ✓ Optional("my-id") == Optional("my-id")
  ✓ Optional("/path with/spaces") == Optional("/path with/spaces")
  ✓ Optional("snap") == Optional("snap")
  ✓ Optional("/Volumes/My Disk") == Optional("/Volumes/My Disk")
  ✓ empty id ok
  ✓ 4 keys even with empty values

## XPC Reply Format
  ✓ empty string means success
  ✓ non-empty string means error
  ✓ success = empty
  ✓ failure = error message


================================================
Integration Tests
================================================

-- Build verification --
  ✓ binary is Mach-O format
  ✓ binary is arm64 architecture
  ✓ code signature present

-- XPC communication --
  ✓ ping: helper is alive
  ✓ version: XPC response received

-- Delete operations --
  ✓ delete: returned (no hang)
  ✓ delete: produced a result line
  ✓ delete (bad volume): returned (no hang)

──────────────────────────────
35 passed, 0 failed
──────────────────────────────

Checklist

  • My code follows the existing code style
  • I've tested the changes on macOS 26 (Tahoe)
  • I've updated the README if necessary
  • I've added comments for complex logic
  • My changes don't break existing functionality

Screenshots (if applicable)

image ## Additional Notes

…ented tabs

- Add AutoTrimService with daily timer (86400s) and 24h cooldown
- Extract TrimUnit enum; replace months-only with days/weeks/months
- Rewrite SettingsStore from @ObservationIgnored backing vars to stored + didSet
- Rewrite SettingsView from TabView to 4-tab segmented picker (Trim, Auto Trim, Helper, General)
- TrimNowSheet: add preview phase (configure → scan → preview → delete → done)
- WindowSetup: hide main window on launch when showWindowOnLaunch = false
- BackupViewModel: add prepareTrimNow() scanning + confirmedTrimNow() deletion split
- TrimByAgeView: add unit picker, dynamic slider bounds
- HelperClient: nonisolated isInstalled + uninstall() via osascript

Signed-off-by: Ricardo Leal <ricardo.martins-leal@siemens.com>
@ricardoleal ricardoleal linked an issue Jun 13, 2026 that may be closed by this pull request
@ricardoleal ricardoleal self-assigned this Jun 13, 2026
@ricardoleal ricardoleal added the enhancement New feature or request label Jun 13, 2026
@ricardoleal
ricardoleal merged commit 1a3c618 into main Jun 13, 2026
2 checks passed
@ricardoleal
ricardoleal deleted the 6-auto-trim-scheduled-background-deletion-of-old-backups branch June 13, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto-trim: scheduled background deletion of old backups

1 participant