Skip to content

Releases: slavins-co/keep-in-touch

v0.5.0 - Siri Shortcuts, Insights, Accessory Widgets & a Big Internals Cleanup

Choose a tag to compare

@slavins-co slavins-co released this 29 May 04:18
5d93b91

🎉 v0.5.0 is our biggest release yet. Keeping in touch just got effortless - ask Siri to log a call, glance at a Lock Screen widget to see who's overdue, and check the new Insights dashboard to see how your habits stack up against your intentions. Add a guided tutorial, group-hangout logging, and a major under-the-hood cleanup, and this is the most capable, polished build to date.

✨ Features

  • App Intents v1 - Log Touch, Get Overdue / Due-Soon, Open, Shortcuts provider (#304)
  • Stats & Insights v1 - Performance vs Intent + Method Breakdown (#138)
  • Lock Screen + StandBy accessory widgets (#279)
  • Upcoming birthdays in the widget family (#329)
  • Self-guided tutorial - anchored walkthroughs + TipKit tips (#10)
  • Bulk log touch for group hangouts (#293)
  • Snoozed Contacts management view (#334)
  • Flexible messenger routing + FaceTime on Call button (#233)
  • Streamlined Log Connection picker - medium-only TouchMethod (#299)
  • Screenshot blur protection on app background - privacy (#105)

🔧 Engineering / performance (the #302 tech-debt audit)

  • Repository CRUD base, shared helpers, DI/layering cleanup (#308, #307, #314)
  • Cold-launch wins: formatter caching, dedupe fetch (#309)
  • Batch saves + list-render efficiency (#316, #317)
  • Status-drift fix - unify Home buckets through PersonStatusService (#310)
  • PersonDetailVM in-place edits + notification debounce (#311)
  • View component extraction, ViewModelErrorHandling helper, stringly/magic-number cleanup (#313, #315, #312)
  • Person initializer to nested config structs (#318)
  • Swift 6 strict-concurrency Sendable hotfix (#326)

Build: 0.5.0 (14) · TestFlight: https://testflight.apple.com/join/UY7Pgusg

Full changelog: v0.4.0...v0.5.0

v0.4.0 — iOS Widget Family + Home Polish

Choose a tag to compare

@slavins-co slavins-co released this 23 Apr 13:00
b0d877f

10 PRs closing 12 issues. The flagship is a new iOS Home Screen widget family. Supporting work tightens the home screen and contact display, fixes a search-bar bug, and consolidates multi-target infra.

New Features

  • #60 iOS Home Screen widgets — small (overdue count + most-overdue avatar) and medium (3-row list with interactive Log Touch, no app launch) (#282)
    • keepintouch:// deep-link scheme routes taps to the overdue list or a specific person
    • Empty and all-caught-up states mirror the in-app affordances
  • #283 Add "all caught up" celebratory banner on Home when no one is overdue or due soon — matches the widget's copy (#289)
  • #278 Display nickname in contact detail and list views, with case-insensitive dedupe against displayName (#287)
  • #275 Nickname search from contact info — search matches nickname in addition to name (#277)
  • #274 Auto-expand collapsed Home sections while a search is active; restore state when cleared (#277)

Bug Fixes

  • #272 Search bar no longer disappears when search returns no results on Contacts tab — users can clear/edit without force-quitting the view (#273)
  • #271 Remove tab content .accessibilityLabel that was overriding all child labels and breaking UI-test element discovery

Internal Improvements

  • #60 Move Core Data store to an App Group container so the widget extension can read it (#280)
  • #284 Share FrequencyCalculator between app and widget via narrow protocols in Shared/ — widget and app now agree on customDueDate + grace-period rules; 3 documented divergences removed (#288)
  • #286 Add widget orchestration tests — WidgetDataProvider testable core moved to Shared/; 12 new tests covering snapshot ordering, filtering, and FrequencyCalculator parity (#288)
  • #285 Extract brand color tokens into Shared/BrandColors.swift — single source of truth for the hero accent green previously duplicated across the widget and DesignSystem (#290)
  • #281 Consolidate CLAUDE.md and lessons.md per the 250-line policy

Metrics

Metric v0.3.6 v0.4.0 Change
Swift source lines 13,131 14,489 +1,358
Test lines 6,827 8,026 +1,199
Tests 333 397 +19%
Source:test ratio 1.9:1 1.8:1

Issues Closed

#60, #271, #272, #274, #275, #278, #281, #283, #284, #285, #286

v0.3.6 — Accessibility, CSV Export & Terminology Cleanup

Choose a tag to compare

@slavins-co slavins-co released this 20 Mar 16:59
838d278

5 PRs closing 5 issues. Accessibility improvements, CSV export, terminology cleanup, and a status filtering fix.

Accessibility

  • #197 Add VoiceOver accessibility labels to all picker and editor sheets (#266)
  • #202 Replace hardcoded font sizes with Dynamic Type text styles throughout the app (#264)

New Features

  • #134 Add CSV export option for spreadsheet use (#265)

Internal Improvements

  • #241 Rename "Groups" → "Cadences" and "Tags" → "Groups" throughout the codebase — aligns terminology with how users think about contact organization (#267)
    • Export format updated to v3 with full backward compatibility for v2 imports

Bug Fixes

  • #268 Fix Due Soon contacts missing from Home View — removed redundant dueSoonWindowDays filter from PersonStatusService (#269)

Metrics

Metric v0.3.5 v0.3.6 Change
Swift source lines 12,911 13,126 +215
Test lines 6,368 6,743 +375
Tests 309 330 +7%
Source:test ratio 2.0:1 1.9:1

Issues Closed

#134, #197, #202, #241, #268

v0.3.5

Choose a tag to compare

@slavins-co slavins-co released this 15 Mar 13:33

Patch release — fixes stale status indicator colors after bulk updates (#263).

No other changes from v0.3.4.

v0.3.4 — Notifications, Polish & Architecture

Choose a tag to compare

@slavins-co slavins-co released this 10 Mar 20:25
6f8da96

8 PRs closing 13 issues. Notification UX improvements, birthday polish, a new DI container, and Swift 6 concurrency cleanup.

New Features

  • #253 Birthday today indicator on contact cards (#254)
  • #247 Combine multiple birthday notifications into a single grouped alert (#252)
  • #232 Pull-to-refresh re-syncs full contact info from Contacts app (#255)
  • #248 Extract notification settings into a dedicated sub-screen (#256)

Notification Improvements

  • #246 Deliver notifications when the app is in the foreground (#257)
  • #230 Suppress weekly digest when only 1 person is overdue — avoids a redundant notification alongside the daily breach alert (#259)

Bug Fixes

  • #249 Fix blank import screen on first JSON file selection (#251)

Architecture & Code Quality

  • #215 AppDependencies DI container — eliminates direct CoreDataStack.shared references in views; all 8 ViewModels gain convenience init(dependencies:) (#258)
  • #216 Domain error types — RepositoryError and ImportError replace untyped throws across all 4 repositories and 5 ViewModels (#258)
  • #214 Logged assertions in entity mappings — silent ?? UUID() / ?? "" fallbacks replaced with AppLogger.logWarning calls that surface data corruption at runtime (#258)
  • #168 Consolidate contact import logic — OnboardingViewModel delegates to ContactImportService, removing ~60 lines of duplicated Person/TouchEvent construction (#259)
  • #250 Fix Swift 6 actor-isolation warnings in OnboardingViewModel (#259)
  • #260 Thread coreDataStack through ContactImportService — completes DI wiring so injected repos and background context use the same store (#259)

Metrics

Metric v0.3.3 v0.3.4 Change
Swift source lines 12,506 12,911 +405
Test lines 5,929 6,368 +439
Tests 288 309 +7%
Source:test ratio 2.1:1 2.0:1

Issues Closed

#168, #214, #215, #216, #230, #232, #246, #247, #248, #249, #250, #253, #260

v0.3.3 — Professional Grade Upgrade

Choose a tag to compare

@slavins-co slavins-co released this 10 Mar 00:23
85d5cc0

Systematic codebase upgrade from B/B+ to A- through 9 professional-grade issues, 5 new features, and 364% test coverage growth (62 → 288 tests).

New Features

  • #231 Birthday push notifications with per-person toggle and customizable settings (#245)
  • #106 Notification privacy mode — hide contact names on lock screen (#244)
  • #236 Display multiple groups on contact cards (#242)
  • #235 "Link to Contact" recovery for unavailable contacts (#243)
  • #137 Fresh Start auto-prompt for inactive or overwhelmed users (#227)

Code Quality — Tier 0 (Safety)

  • #205 Remove all force-unwraps and unsafe array indexing (#217)

Code Quality — Tier 1 (Structure)

  • #209 Add loading states to ViewModels with guard+defer cancellation (#218)
  • #206 Decompose PersonDetailView from 1,168 → 433 lines into 7 focused files (#219)
  • #207 Extract SettingsViewModel into 3 dedicated services (DataImport/Export/ContactImport) (#220)
  • #208 Replace onChange modal chains with navigation state enum (#221)

Code Quality — Tier 2 (Testing)

  • #210 NotificationScheduler test coverage with protocol injection (#223)
  • #211 Import integration tests with context-injectable DataImportService (#224)
  • #212 ViewModel edge-case tests (#225)
  • #213 Repository error path tests (#225)

Accessibility & Polish

  • Fix accessibility labels, WCAG AA contrast compliance, and double-tap guard (#222)
  • #204 Replace UITabBar.appearance() with SwiftUI .toolbarBackground modifier (#226)
  • #237 Fix concurrency and redundant modifier warnings — Swift 6 prep (#239)
  • #229 Fix incorrect app version displayed in Settings (#238)
  • #228 Audit and update TelemetryDeck events after refactors (#240)

Metrics

Metric v0.3.2 v0.3.3 Change
Swift source lines 11,609 12,506 +897
Test lines 3,393 5,929 +2,536
Tests 62 288 +364%
Source:test ratio 3.4:1 2.1:1
Overall grade B/B+ A-

Issues Closed

#106, #137, #204, #205, #206, #207, #208, #209, #210, #211, #212, #213, #228, #229, #231, #235, #236, #237

v0.3.2 — UX Redesign

Choose a tag to compare

@slavins-co slavins-co released this 05 Mar 00:44
e779764

v0.3.2 — UX Redesign

Complete visual refresh with new navigation, redesigned screens, and polished interactions.

Navigation

  • #172 Tab bar navigation — Home, Contacts, and Settings tabs replace the previous single-screen layout
  • #183 Contact detail opens as full-screen cover instead of push navigation

Home Screen

  • #174 Redesigned header with status summary cards (Overdue, Due Soon, All Good counts)
  • #175 Sticky section headers, floating search bar, and redesigned contact cards

Contact Detail

  • #177 Redesigned notes card, history timeline with TimelineEntryView, and contact settings section
  • #186 New hero section with action buttons and fixed bottom CTA
  • #192 Delete option in Edit Connection modal with confirmation alert
  • #193 Half-height picker sheets with titles for birthday, reminder time, snooze, due date, frequency, groups, and digest day

Contacts Tab

  • New alphabetical A-Z contact list with section index sidebar and search
  • Uniform row dividers throughout the list

Design System

  • #171 Centralized design tokens — colors, typography, spacing, and radius constants in DesignSystem.swift
  • #195 Restored random avatar colors (stored per contact) replacing the fixed accent green

Visual Polish

  • #178 Dark mode audit — structural fixes for adaptive colors across all screens
  • #179 Design token propagation through Settings and Onboarding screens
  • #194 iPhone locked to portrait orientation
  • Weekly Digest settings row color matched to Daily Reminders
  • Groups row icon updated to person.2 to match Settings

Accessibility

  • #180 VoiceOver labels, hints, and interaction polish across all screens

Bug Fixes

  • Paused contacts no longer leak into Home "All Good" section or inflate summary card count
  • Fixed double .padding(.leading) stacking to 32pt on contact list dividers

Issues Closed

#150, #171, #172, #174, #175, #177, #178, #179, #180, #183, #186, #191, #192, #193, #194, #195

v0.3.1 — Rename, Custom Due Dates & Import Fixes

Choose a tag to compare

@slavins-co slavins-co released this 04 Mar 04:01
36ef252

v0.3.1 — Rename, Custom Due Dates & Import Fixes

App Rename

  • #139 Renamed from "Stay in Touch" to Keep In Touch — new bundle ID, background task ID, display name, all user-facing strings, and documentation updated. Internal directory/target/module names preserved for stability.

New Features

  • #9 Custom due dates per contact — set a specific "reach out by" date that overrides the group frequency; auto-clears when a touch is logged
  • #146 Frequency member management — tap a frequency in Settings to view/add/remove members, with swipe-to-remove reassigning to default
  • #132 Last-connected date seeding — new onboarding/import step lets users pick "when did you last connect?" so home screen shows meaningful status from day one
  • #141 Birthday display — cake icon + M/DD in contact header, auto-pulled from address book with manual override via editor sheet

Import/Export Improvements

  • #114 Remove cnIdentifier from JSON export (privacy)
  • #145 Export now includes frequencies and groups for complete backups, with case-insensitive merge on re-import
  • #149 Post-import auto-matching to device address book by display name, with manual linking for unmatched contacts
  • #162 Fix .limited contacts auth excluded from CN dedup, Dictionary(uniqueKeysWithValues:) crash on duplicate identifiers, and synchronous enumerateContacts blocking main thread
  • Import deduplicates contacts (4-tier matching: UUID → CN → name → new) and touch events (content-based dedup)
  • Imported touch events now correctly populate lastTouchAt/lastTouchMethod/lastTouchNotes

Bug Fixes

  • #152 Use calendar days instead of 24-hour periods in FrequencyCalculator — fixes "yesterday late evening" showing as "Today"
  • #148 Default theme to System instead of Light for new installs
  • #133 Fix notes truncation in touch history — dynamic row height replaces fixed 52pt
  • #111 Add character limits: 500 chars for notes, 100 chars for search
  • #140 Remove "Last connected Nd ago" badge that caused layout issues in detail header

Performance

  • #112 Replace N+1 loop saves with batchSave in tag/group deletion — deleting a tag used by 50 people now triggers 1 Core Data save instead of 50

Code Quality & Accessibility

  • #113 Standardize @MainActor usage, remove all DispatchQueue.main.async calls
  • #144 Add VoiceOver accessibility label to TagPill
  • #147 Reorganize Settings view into 6 logical sections: Appearance, People, Notifications, Data, About, Danger Zone

15 PRs merged · 16 commits · All tests passing

v0.3.0 — Features, Security & Accessibility

Choose a tag to compare

@slavins-co slavins-co released this 01 Mar 18:33
6984e50

What's New in v0.3.0

New Features

  • #72 Contact photos — display iOS Contacts thumbnails with initials fallback and NSCache for scroll performance
  • #73 JSON import — file picker, preview screen, conflict resolution by UUID matching
  • #74 Enriched data export — includes groupName, tagNames, and full touchEvents history
  • #59 "Reset All Frequencies" — emergency button in Settings resets all contacts to today
  • #51 Multi-value contact picker — choose between multiple phone numbers/emails with labeled options
  • #52 Badge settings — configure badge count to show overdue only, or overdue + due soon
  • #67 TelemetryDeck analytics — privacy-first, anonymous, opt-out toggle in Settings

Accessibility & UX

  • #39 VoiceOver labels on home screen — ContactCard, StatusIndicator, section headers
  • #43 "Last connected Xd ago" timestamp on PersonDetailView hero
  • #71 Notification tap navigates via push (not modal sheet)
  • #58 Onboarding back navigation with progress indicator
  • #42 Animated section count transitions on home screen
  • #44 Touch method icon grid replaces Picker dropdown

Security & Privacy (12 fixes)

  • #126 Sanitize JSON import — regenerate UUIDs, clear cnIdentifier, remove cnIdentifier matching
  • #125 AnalyticsService thread safety — NSLock, cached enabled state
  • #109 Sanitize notification userInfo before deep link forwarding
  • #104 Clean up temp export files after share sheet dismissal
  • #99 Remove PII from log statements
  • #100 Fix demo mode data isolation with isDemoData flag
  • #101 Cascade deletes for Person→TouchEvent and Group/Tag cleanup
  • #102 Fix notification handler thread safety (background context)
  • #103 Verify and reorder PrivacyInfo.xcprivacy declarations
  • #108 Replace silent try? with proper error handling (14 sites, 5 files)
  • #98 Add NSContactsUsageDescription to Info.plist
  • #107 Fix background contact sync race condition

Performance

  • #81 Predicate-based contact fetching with fetchBatchSize = 50

27 PRs merged · 12 security fixes · All tests passing

v0.2.2 — Performance, UX & Polish

Choose a tag to compare

@slavins-co slavins-co released this 27 Feb 05:27
8808a86

What's New in v0.2.2

⚡ Performance

  • #62 FrequencyCalculator optimized — single instance per render instead of multiple per card
  • #63 Batch CoreData saves during contact import — single context.save() instead of per-contact, reducing I/O for large imports

🤝 Auto-Log & Undo UX

  • #54 Auto-log touch after quick action — tap Call/Message/Email, the app logs the connection automatically. On return, an undo banner appears for 5 seconds: "Logged call. Didn't connect?"
  • #36 Undo for person deletion — 5-second red banner with "Undo" button before deletion commits, following the same pattern as auto-log undo

🔔 Notifications

  • #61 Improved notification reliability — repeating triggers + foreground rescheduling ensure reminders fire even when background refresh is throttled
  • #75 Quick-log from notification — "Log Connection" action button on person reminders logs a touch without opening the app

✨ Accessibility & Polish

  • #53 Limited contact access handling — shows "grant full access" alert instead of misleading "up to date" when all selected contacts are imported
  • #33 Design system typography token — DS.Typography.heroTitle replaces hardcoded font in PersonDetailView
  • #38 Proper FlowLayout — filter chips and tag pills now wrap correctly using the Layout protocol, replacing the WrapLayout stub
  • #41 Haptic feedback — tactile responses on touch logging (success), deletions (medium), quick action auto-log and undo (light)

🧹 Code Quality

  • #76 48 new ViewModel unit tests — PersonDetailViewModel, SettingsViewModel, OnboardingViewModel with shared mock infrastructure
  • #82 Dead code removal — 3 unused methods deleted (ExportPerson helpers, digitsOnly)
  • #83 Sort switch cleanup — removed misleading identical branches in HomeViewModel
  • Bug fix: undo-wrong-touch and double-delete bugs in PersonDetailView

24 files changed · 1,415 additions · 152 deletions · Build 8 · All tests passing

Closes #62, #54, #53, #61, #76, #33, #63, #36, #75, #38, #82, #83, #41