179 lines
6.2 KiB
Markdown
179 lines
6.2 KiB
Markdown
# 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.swift`
|
|
Defines:
|
|
- `BearWaveCore`
|
|
- `BearWave`
|
|
- `BearWaveChecks`
|
|
- `Sources/BearWaveApp`
|
|
App entrypoint and scene wiring
|
|
- `Sources/BearWaveCore`
|
|
Application logic, models, services, stores, views, and resources
|
|
|
|
## Main Runtime Objects
|
|
|
|
### `BearWaveApp`
|
|
|
|
File:
|
|
- [Sources/BearWaveApp/BearWaveApp.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveApp/BearWaveApp.swift)
|
|
|
|
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:
|
|
- [Sources/BearWaveCore/App/AppModel.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/App/AppModel.swift)
|
|
|
|
Responsibilities:
|
|
- own the major runtime subsystems
|
|
- coordinate radio, playback, settings, and artwork
|
|
- restore launch state
|
|
- route user actions like `play(_:)`, `setVolume(_:)`, and `quit()`
|
|
|
|
Owned objects:
|
|
- `SettingsStore`
|
|
- `StationLibrary`
|
|
- `PlaybackController`
|
|
- `StationArtworkLoader`
|
|
- `NowPlayingArtworkResolver`
|
|
|
|
`AppModel` is the top-level coordinator. It should not become a dumping ground for unrelated view logic.
|
|
|
|
## Domain Store
|
|
|
|
### `StationLibrary`
|
|
|
|
File:
|
|
- [Sources/BearWaveCore/Stores/StationLibrary.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Stores/StationLibrary.swift)
|
|
|
|
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 Results` page
|
|
- 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:
|
|
- [Sources/BearWaveCore/Services/PlaybackController.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Services/PlaybackController.swift)
|
|
|
|
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:
|
|
- [Sources/BearWaveCore/Services/RadioBrowserClient.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Services/RadioBrowserClient.swift)
|
|
|
|
Responsibilities:
|
|
- call Radio Browser endpoints
|
|
- decode station payloads
|
|
- provide search support
|
|
- cache API responses on disk
|
|
|
|
### Artwork Services
|
|
|
|
Files:
|
|
- [Sources/BearWaveCore/Services/StationArtworkLoader.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Services/StationArtworkLoader.swift)
|
|
- [Sources/BearWaveCore/Services/NowPlayingArtworkResolver.swift](/Users/sebastian/Development/radioappmac/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:
|
|
- [Sources/BearWaveCore/Stores/PersistenceStore.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Stores/PersistenceStore.swift)
|
|
|
|
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](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/ContentView.swift)
|
|
- [Sources/BearWaveCore/Views/SidebarView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/SidebarView.swift)
|
|
- [Sources/BearWaveCore/Views/StationListView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/StationListView.swift)
|
|
- [Sources/BearWaveCore/Views/StationDetailView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/StationDetailView.swift)
|
|
- [Sources/BearWaveCore/Views/PlayerBarView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/PlayerBarView.swift)
|
|
- [Sources/BearWaveCore/Views/MiniPlayerView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/MiniPlayerView.swift)
|
|
- [Sources/BearWaveCore/Views/MenuBarContentView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/MenuBarContentView.swift)
|
|
- [Sources/BearWaveCore/Views/SettingsView.swift](/Users/sebastian/Development/radioappmac/Sources/BearWaveCore/Views/SettingsView.swift)
|
|
|
|
High-level behavior:
|
|
- `ContentView` switches 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
|
|
- `PlayerBarView` stays focused on radio playback controls
|
|
|
|
## Data Flow
|
|
|
|
1. User selects a page or search query
|
|
2. `StationLibrary` loads data through `RadioBrowserClient`
|
|
3. UI renders visible stations
|
|
4. User starts playback
|
|
5. `AppModel` records playback and forwards to `PlaybackController`
|
|
6. `PlaybackController` updates 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 `BearWaveApp` thin
|
|
- Do not move product behavior into ad hoc view code when it belongs in a store or service
|