Skip to content

Modernize app: SwiftUI lifecycle, Swift 6, iOS 18#5

Merged
coffee-cup merged 8 commits into
masterfrom
jr/modernize-swiftui
Jun 11, 2026
Merged

Modernize app: SwiftUI lifecycle, Swift 6, iOS 18#5
coffee-cup merged 8 commits into
masterfrom
jr/modernize-swiftui

Conversation

@coffee-cup

Copy link
Copy Markdown
Owner

Migrates the app from 2016-era storyboard UIKit to a SwiftUI app lifecycle with Swift 6 strict concurrency, keeping only the gesture-driven timeline in UIKit behind a representable. Every step was verified in the simulator against baseline screenshots; the timeline, menu, search, info, and notification flows behave identically, now rendering edge-to-edge behind the dynamic island.

  • Remove the first-run walkthrough (5 view controllers, storyboard scenes, assets, defaults keys, loop-script flags)
  • Raise the deployment target to iOS 18 and drop the widget's iOS 16/17 availability shims
  • Replace dead UILocalNotification scheduling with UNUserNotificationCenter calendar triggers (idempotent per-alert identifiers) and legacy background fetch with BGAppRefreshTask
  • Remove the vendored Spring animation library (~28 files), replacing call sites with UIView.animate
  • Convert SunViewController to programmatic safe-area layout so the gradient runs full-bleed
  • Rewrite location search, info menu, and info detail screens in SwiftUI
  • Move to @main SwiftUI App: RootView owns the slide-out menu, dim overlay, and edge drag; @observable LocationModel/SettingsModel/MenuState replace the Bus NotificationCenter wrapper; Main/LaunchScreen storyboards deleted
  • Adopt Swift 6 language mode with default MainActor isolation on the app target (widget stays nonisolated)

App now always boots into MainViewController. Deletes the 5 walkthrough
view controllers, their storyboard scenes, Walkthrough assets, and the
ShowWalkthrough/ShowTutorial defaults; drops --skip/--show-walkthrough
from the loop scripts and skill docs.
Drops the widget's iOS 16/17 availability shims (containerBackground is
always available now).
…eshTask

NotificationScheduler keeps one pending request per enabled alert type
(identifier = defaults key, so re-adding replaces) which makes
rescheduling idempotent and removes the NotificationCount bookkeeping
suite. Background fetch moves to BGTaskScheduler with the same 3h
cadence; Bus loses the two notification events.
Replaces the ~6 Spring call sites (menu/center button fades, info menu
staggered fade-in-from-left) with UIView.animate equivalents and reverts
the storyboard Spring subclasses to plain UIKit. Drops dead
MomentumScroll.swift and the unused animateButtonsOut.
Rebuilds the timeline view hierarchy in loadView (TouchDownView root,
now marker, labels, center button) with safe-area constraints so the
gradient runs edge-to-edge. Sun construction moves to a layout-time
setupIfNeeded since the gradient maths capture the view height once
and the frame is not final until the first layout pass. MainViewController
embeds the timeline via addChild instead of a storyboard container;
the Sun scene leaves the storyboard. Drops the dead hourSlider outlet.
LocationSearchView (+ LocationSearchModel wrapping MKLocalSearchCompleter),
InfoMenuView, and InfoView replace the three storyboard view controllers,
presented full-screen from the menu via UIHostingController. Rows expose
combined accessibility labels; bell selection still writes the
NotificationPlace string and reschedules on dismiss. Drops BellButton and
the NSMutableAttributedString/UIButton helpers only those screens used.
SolisApp + RootView replace AppDelegate/MainViewController: the slide-out
menu, dim overlay, and edge-drag live in SwiftUI (MenuState), and the
UIKit timeline is hosted via a representable that forwards observable
model changes as diffed tokens (location updates, place changes,
time-format flips, foreground scroll resets). LocationModel/SettingsModel
replace the Bus events; SunLocation splits into shared storage (widget)
and an app-only LocationProvider extension for mutation/geocoding.
Launch screen becomes a UILaunchScreen plist entry. Skill + agent docs
updated for the new selectors.
SWIFT_VERSION = 6.0 everywhere, with default MainActor isolation on the
app target (the widget's timeline provider runs off-main). Burn-down:
Sun and the line/area views lose their redundant main-queue dispatch
wrappers, Sun/SunProtocol/TouchDownProtocol gain explicit @mainactor,
LocationProvider isolates to the main actor with a @preconcurrency
CLLocationManagerDelegate conformance, the shared UserDefaults statics
become nonisolated(unsafe) (UserDefaults is thread-safe), the mutable
DateFormatter caches are dropped, and AttributedString attributes are
set via explicit attribute types instead of Sendable-hostile keypaths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant