diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..f11c6eb25 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,63 @@ +name: Release + +# Pushing a tag like v3.1.0 builds the app, packages an unsigned .ipa, +# and creates a GitHub release with generated notes. No signing identity +# or Apple developer account is required: the .ipa is unsigned and meant +# for sideloading (AltStore, Sideloadly), where the installer tool +# re-signs it with the user's own Apple ID. + +on: + push: + tags: ["v*"] + +permissions: + contents: write + +jobs: + release: + runs-on: macos-26 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Select latest Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + # Tags must be vMAJOR.MINOR.PATCH. Build number packs the tag into a + # monotonically increasing integer: v3.1.0 -> 30100. + - name: Derive version from tag + run: | + VERSION_NAME="${GITHUB_REF_NAME#v}" + IFS=. read -r MAJOR MINOR PATCH <<< "$VERSION_NAME" + BUILD_NUMBER=$((MAJOR * 10000 + MINOR * 100 + ${PATCH:-0})) + echo "VERSION_NAME=$VERSION_NAME" >> "$GITHUB_ENV" + echo "BUILD_NUMBER=$BUILD_NUMBER" >> "$GITHUB_ENV" + + - name: Build unsigned archive + run: | + xcodebuild archive \ + -project SwiftRadio.xcodeproj \ + -scheme SwiftRadio \ + -destination 'generic/platform=iOS' \ + -archivePath build/SwiftRadio.xcarchive \ + CODE_SIGNING_ALLOWED=NO \ + MARKETING_VERSION="$VERSION_NAME" \ + CURRENT_PROJECT_VERSION="$BUILD_NUMBER" + + - name: Package unsigned IPA + run: | + mkdir -p Payload + cp -R "build/SwiftRadio.xcarchive/Products/Applications/SwiftRadio.app" Payload/ + zip -qr "swift-radio-$GITHUB_REF_NAME-unsigned.ipa" Payload + + - name: Create GitHub release + run: | + gh release create "$GITHUB_REF_NAME" "swift-radio-$GITHUB_REF_NAME-unsigned.ipa" \ + --title "Swift Radio $GITHUB_REF_NAME" \ + --generate-notes \ + --notes "The attached \`.ipa\` is unsigned. Install it by sideloading with [AltStore](https://altstore.io) or [Sideloadly](https://sideloadly.io), which re-sign it with your own Apple ID. Or clone the repo and run it from Xcode with your personal team." + env: + GH_TOKEN: ${{ github.token }} diff --git a/SwiftRadio/CarPlay/CarPlaySceneDelegate.swift b/SwiftRadio/CarPlay/CarPlaySceneDelegate.swift index 56781e752..6b91c8606 100644 --- a/SwiftRadio/CarPlay/CarPlaySceneDelegate.swift +++ b/SwiftRadio/CarPlay/CarPlaySceneDelegate.swift @@ -96,8 +96,13 @@ extension CarPlaySceneDelegate: StationsManagerObserver { } func stationsManager(_ manager: StationsManager, stationDidChange station: RadioStation?) { - if let station { - print("Station changed to: \(station.name)") + guard let listTemplate = interfaceController?.rootTemplate as? CPListTemplate else { return } + let items = listTemplate.sections.flatMap { $0.items }.compactMap { $0 as? CPListItem } + let stations = manager.stations + + for (index, item) in items.enumerated() { + guard index < stations.count else { break } + item.isPlaying = (stations[index] == station) } } } diff --git a/SwiftRadio/Images.xcassets/AppIcon.appiconset/AppIcon.png b/SwiftRadio/Images.xcassets/AppIcon.appiconset/AppIcon.png index df9dc2e46..50a87b4a7 100644 Binary files a/SwiftRadio/Images.xcassets/AppIcon.appiconset/AppIcon.png and b/SwiftRadio/Images.xcassets/AppIcon.appiconset/AppIcon.png differ diff --git a/SwiftRadio/Images.xcassets/logo.imageset/logo.png b/SwiftRadio/Images.xcassets/logo.imageset/logo.png index 2e735fcbb..63e8b678d 100644 Binary files a/SwiftRadio/Images.xcassets/logo.imageset/logo.png and b/SwiftRadio/Images.xcassets/logo.imageset/logo.png differ diff --git a/SwiftRadio/Images.xcassets/logo.imageset/logo@2x.png b/SwiftRadio/Images.xcassets/logo.imageset/logo@2x.png index 423e7d6f8..4cf44f044 100644 Binary files a/SwiftRadio/Images.xcassets/logo.imageset/logo@2x.png and b/SwiftRadio/Images.xcassets/logo.imageset/logo@2x.png differ diff --git a/SwiftRadio/Images.xcassets/logo.imageset/logo@3x.png b/SwiftRadio/Images.xcassets/logo.imageset/logo@3x.png index 19b326cc7..fe2b03184 100644 Binary files a/SwiftRadio/Images.xcassets/logo.imageset/logo@3x.png and b/SwiftRadio/Images.xcassets/logo.imageset/logo@3x.png differ diff --git a/SwiftRadio/Model/StationsManager.swift b/SwiftRadio/Model/StationsManager.swift index ad915db85..6ad6e917d 100755 --- a/SwiftRadio/Model/StationsManager.swift +++ b/SwiftRadio/Model/StationsManager.swift @@ -192,7 +192,15 @@ extension StationsManager { // MARK: - FRadioPlayerObserver extension StationsManager: FRadioPlayerObserver { - + + func radioPlayer(_ player: FRadioPlayer, playerStateDidChange state: FRadioPlayer.State) { + // Update lock screen when player finishes loading so duration is accurate + // (fixes live indicator sticking when switching from live to MP3) + if state == .readyToPlay || state == .loadingFinished { + resetArtwork(with: currentStation) + } + } + func radioPlayer(_ player: FRadioPlayer, metadataDidChange metadata: FRadioPlayer.Metadata?) { resetArtwork(with: currentStation) }