Skip to content

Remove storyboard, migrate to SwiftUI layout#608

Open
bjorkert wants to merge 9 commits intodevfrom
remove-storyboard
Open

Remove storyboard, migrate to SwiftUI layout#608
bjorkert wants to merge 9 commits intodevfrom
remove-storyboard

Conversation

@bjorkert
Copy link
Copy Markdown
Contributor

Summary

Removes Main.storyboard and SceneDelegate, replacing the entire UI lifecycle with SwiftUI. The home screen layout (BG display, info table, charts, stats) is now composed in a single SwiftUI view (MainHomeView) with the DGCharts LineChartView instances embedded via UIViewRepresentable.

What changed:

  • Storyboard and SceneDelegate deleted, replaced by LoopFollowApp (SwiftUI App) and MainTabView
  • All five tab view controllers (Alarms, Settings, Snoozer, Remote, More Menu) replaced with SwiftUI views
  • Info table migrated from UITableView to SwiftUI List backed by InfoManager as an ObservableObject
  • Statistics area and pie chart migrated to SwiftUI (pie chart still uses DGCharts PieChartView via UIViewRepresentable since the Charts pod shadows Swift Charts)
  • BG display area (BG value, direction, delta, min ago, loop status, prediction) migrated from UILabels to SwiftUI with pull-to-refresh via .refreshable
  • Main layout rewritten from UIStackView hierarchy to MainHomeView SwiftUI composition — visibility of info table, small graph, and stats is now reactive via Storage observables
  • getMainViewController() hierarchy-walking methods replaced with MainViewController.shared weak reference
  • Cleaned up dead code: unused imports, stale tabBarController references, redundant appearance notification relay, unused UIViewExtension

Net result: −1430 lines, all UIKit view controllers except MainViewController (charts) and NightscoutViewController (web view) are gone.

Replace UIKit storyboard/SceneDelegate architecture with SwiftUI App
entry point (LoopFollowApp.swift) and TabView (MainTabView.swift).
Convert MoreMenuViewController to SwiftUI (MoreMenuView.swift). Add
SwiftUI wrappers for Remote and Nightscout tabs. Remove 6 obsolete
UIKit wrapper view controllers and ~300 lines of tab management code
from MainViewController.
Replace UITableView with SwiftUI InfoTableView hosted in
MainViewController. Make InfoManager an ObservableObject so data
updates trigger SwiftUI rebuilds automatically. Remove
UITableViewDataSource conformance and table delegate methods.
No changes needed to the 10 Nightscout controller files that
populate the table data.
Replace 7 UILabel properties and DGCharts PieChartView with a
StatsDisplayModel ObservableObject and hosted StatsDisplayView.
The pie chart uses a UIViewRepresentable wrapper for DGCharts
since the Charts pod name shadows Swift Charts. Remove ~60 lines
of UIKit stack layout code from MainViewController setupUI().
Replace BGText, DirectionText, DeltaText, MinAgoText, serverText,
LoopStatusLabel, and PredictionLabel with a SwiftUI BGDisplayView.
Add pull-to-refresh via .refreshable modifier. Move loop status and
prediction text updates to Observable values across DeviceStatus,
DeviceStatusLoop, DeviceStatusOpenAPS, and BGData. Remove
UIScrollView overlay and UIScrollViewDelegate conformance.
Replace UIStackView layout with MainHomeView SwiftUI view that composes
BGDisplayView, InfoTableView, LineChartWrapper (UIViewRepresentable for
DGCharts), and StatsDisplayView. MainViewController now hosts a single
UIHostingController instead of managing individual UIView containers.

Visibility of info table, small graph, and stats is now reactive via
Storage observables in SwiftUI, removing several Combine subscriptions.
BG text uses lineLimit + minimumScaleFactor instead of manual font sizing.
- Fix AVSpeechSynthesizer temporary in AppDelegate that would be
  deallocated before speech completes; use stored property instead
- Fix appMovedToBackground tab switching to use Observable instead of
  dead UIKit tabBarController reference
- Remove dead code: rebuildTabsIfNeeded(), updateNightscoutTabState(),
  traitCollectionDidChange notification relay, UIViewExtension.addBorder
- Remove unused imports (Charts, UIKit, Combine) from migrated files
- Remove unused synthesizer from LoopFollowApp
- Remove redundant .appearanceDidChange subscription from NightscoutVC
- Add missing super calls in viewWillAppear/viewDidAppear
The getMainViewController() methods in TreatmentsView, SettingsMenuView,
and BackgroundRefreshManager tried to find MainViewController by casting
rootViewController as UITabBarController, which always fails with the
SwiftUI lifecycle. Add a weak static shared reference set during
viewDidLoad and use it everywhere instead.
@bjorkert bjorkert requested a review from codebymini April 18, 2026 11:03
Pass MainViewController.shared instead of nil when creating
AggregatedStatsContentView in MainTabView and MoreMenuView. Replace
view-hierarchy-walking getMainViewController() in TreatmentsViewModel
with MainViewController.shared.
The storyboard used system 17pt for both title and detail labels.
The SwiftUI migration used .subheadline (~15pt) making text smaller.
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