6.2 KiB
6.2 KiB
Architecture
This repository is a native macOS 26 SwiftPM internet radio app.
The app is split into a small app target and a larger shared core target.
Top-Level Structure
Package.swiftDefines:BearWaveCoreBearWaveBearWaveChecks
Sources/BearWaveAppApp entrypoint and scene wiringSources/BearWaveCoreApplication logic, models, services, stores, views, and resources
Main Runtime Objects
BearWaveApp
File:
Responsibilities:
- create the root
AppModel - host the main
WindowGroup - host
MenuBarExtra - host
Settings - manage window sizing and mini-player mode
- define app commands such as play/pause and
Cmd+M
This file should stay thin. It is scene setup, not business logic.
AppModel
File:
Responsibilities:
- own the major runtime subsystems
- coordinate radio, playback, settings, and artwork
- restore launch state
- route user actions like
play(_:),setVolume(_:), andquit()
Owned objects:
SettingsStoreStationLibraryPlaybackControllerStationArtworkLoaderNowPlayingArtworkResolver
AppModel is the top-level coordinator. It should not become a dumping ground for unrelated view logic.
Domain Store
StationLibrary
File:
Responsibilities:
- load and store browse pages
- manage global search
- manage favorites
- manage recents
- manage manual stations
- manage station folders
- persist radio-related state
Important behaviors:
- search is global, not page-local
- search results live on a dedicated
Search Resultspage - search ranking is stricter than raw Radio Browser substring matching
- folders are persisted entities and not just transient UI state
Playback and Metadata
PlaybackController
File:
Responsibilities:
- own the shared
AVPlayer - manage playback state transitions
- play radio streams
- expose explicit playback states
- read timed metadata through
AVPlayerItemMetadataOutput - update
MPNowPlayingInfoCenter - handle artwork updates
Important invariants:
- do not collapse playback state to only
isPlaying - metadata handling must tolerate streams that provide nothing useful
Network Services
RadioBrowserClient
File:
Responsibilities:
- call Radio Browser endpoints
- decode station payloads
- provide search support
- cache API responses on disk
Artwork Services
Files:
- Sources/BearWaveCore/Services/StationArtworkLoader.swift
- Sources/BearWaveCore/Services/NowPlayingArtworkResolver.swift
Responsibilities:
- load and cache station favicons
- resolve playback artwork for Now Playing
- fall back through available artwork sources when metadata is incomplete
Persistence
PersistenceStore
File:
Responsibilities:
- JSON persistence for:
- favorites
- manual stations
- groups
- playback state
- manage application support and cache directories
- import legacy Linux config files on first run where applicable
UI Structure
Main views:
- Sources/BearWaveCore/Views/ContentView.swift
- Sources/BearWaveCore/Views/SidebarView.swift
- Sources/BearWaveCore/Views/StationListView.swift
- Sources/BearWaveCore/Views/StationDetailView.swift
- Sources/BearWaveCore/Views/PlayerBarView.swift
- Sources/BearWaveCore/Views/MiniPlayerView.swift
- Sources/BearWaveCore/Views/MenuBarContentView.swift
- Sources/BearWaveCore/Views/SettingsView.swift
High-level behavior:
ContentViewswitches between full app UI and mini-player mode- sidebar chooses radio pages and folders
- station list and station detail cover browse, search, favorites, recents, manual stations, and folders
PlayerBarViewstays focused on radio playback controls
Data Flow
- User selects a page or search query
StationLibraryloads data throughRadioBrowserClient- UI renders visible stations
- User starts playback
AppModelrecords playback and forwards toPlaybackControllerPlaybackControllerupdates playback state, metadata, artwork, and Now Playing
Build and Packaging Notes
- The current app bundle is staged by
script/build_and_run.sh - SwiftPM resource bundles are copied manually into
dist/BearWave.app - Localization directories are copied manually as part of staging
- This is good enough for local development but not yet a polished release pipeline
Architectural Guardrails
- Keep the app native-first for macOS
- Keep search global and independently modeled
- Keep explicit playback states
- Keep
BearWaveAppthin - Do not move product behavior into ad hoc view code when it belongs in a store or service