Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Integration mp now playing info center #1314

Merged
merged 13 commits into from
Oct 15, 2024
12 changes: 9 additions & 3 deletions kDrive/Resources/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*
* Loco ios export: iOS Localizable.strings
* Loco ios export: Xcode Strings (legacy)
* Project: kDrive
* Locale: de, German
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Fri, 26 Jul 2024 13:09:12 +0200
* Exported by: Matthieu Déglon
* Exported at: Thu, 03 Oct 2024 08:22:20 +0200
*/

/* loco:610a8791fa12ab20713c09e4 */
Expand Down Expand Up @@ -2053,6 +2053,12 @@
/* loco:62344c023cb45e6fcb219b43 */
"trashedFileRestoreFileToOriginalPlaceSuccess-plural" = "%d Elemente am ursprünglichen Ort wiederhergestellt";

/* loco:66fe3560501931dbfb04f0c8 */
"unknownArtist" = "Unbekannter Künstler";

/* loco:66fe3634a0cfdc15cf0c1a94 */
"unknownTitle" = "Unbekannter Titel";

/* loco:6049df4d5c2c3a04bc397a7d */
"updateAvailableDescription" = "Mit Blick auf ein optimales kDrive-Benutzererlebnis empfehlen wir Ihnen, Ihre Anwendung zu aktualisieren.";

Expand Down
6 changes: 6 additions & 0 deletions kDrive/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -2053,6 +2053,12 @@
/* loco:62344c023cb45e6fcb219b43 */
"trashedFileRestoreFileToOriginalPlaceSuccess-plural" = "%d items recovered to their original location";

/* loco:66fe3560501931dbfb04f0c8 */
"unknownArtist" = "Unknown Artist";

/* loco:66fe3634a0cfdc15cf0c1a94 */
"unknownTitle" = "Unknown Title";

/* loco:6049df4d5c2c3a04bc397a7d */
"updateAvailableDescription" = "To get the best out of kDrive, we recommend you update your application.";

Expand Down
12 changes: 9 additions & 3 deletions kDrive/Resources/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*
* Loco ios export: iOS Localizable.strings
* Loco ios export: Xcode Strings (legacy)
* Project: kDrive
* Locale: es, Spanish
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Fri, 26 Jul 2024 13:09:12 +0200
* Exported by: Matthieu Déglon
* Exported at: Thu, 03 Oct 2024 08:22:20 +0200
*/

/* loco:610a8791fa12ab20713c09e4 */
Expand Down Expand Up @@ -2053,6 +2053,12 @@
/* loco:62344c023cb45e6fcb219b43 */
"trashedFileRestoreFileToOriginalPlaceSuccess-plural" = "%d elementos restaurados en el emplazamiento original";

/* loco:66fe3560501931dbfb04f0c8 */
"unknownArtist" = "Artista desconocido";

/* loco:66fe3634a0cfdc15cf0c1a94 */
"unknownTitle" = "Título desconocido";

/* loco:6049df4d5c2c3a04bc397a7d */
"updateAvailableDescription" = "Para disfrutar de una experiencia óptima de kDrive, te aconsejamos que actualices tu aplicación.";

Expand Down
12 changes: 9 additions & 3 deletions kDrive/Resources/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*
* Loco ios export: iOS Localizable.strings
* Loco ios export: Xcode Strings (legacy)
* Project: kDrive
* Locale: fr, French
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Fri, 26 Jul 2024 13:09:12 +0200
* Exported by: Matthieu Déglon
* Exported at: Thu, 03 Oct 2024 08:22:20 +0200
*/

/* loco:610a8791fa12ab20713c09e4 */
Expand Down Expand Up @@ -2053,6 +2053,12 @@
/* loco:62344c023cb45e6fcb219b43 */
"trashedFileRestoreFileToOriginalPlaceSuccess-plural" = "%d éléments restaurés à leur emplacement d’origine";

/* loco:66fe3560501931dbfb04f0c8 */
"unknownArtist" = "Artiste inconnu";

/* loco:66fe3634a0cfdc15cf0c1a94 */
"unknownTitle" = "Titre inconnu";

/* loco:6049df4d5c2c3a04bc397a7d */
"updateAvailableDescription" = "Afin de profiter d’une expérience optimale de kDrive, nous vous conseillons de mettre à jour votre application.";

Expand Down
12 changes: 9 additions & 3 deletions kDrive/Resources/it.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*
* Loco ios export: iOS Localizable.strings
* Loco ios export: Xcode Strings (legacy)
* Project: kDrive
* Locale: it, Italian
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Fri, 26 Jul 2024 13:09:12 +0200
* Exported by: Matthieu Déglon
* Exported at: Thu, 03 Oct 2024 08:22:20 +0200
*/

/* loco:610a8791fa12ab20713c09e4 */
Expand Down Expand Up @@ -2053,6 +2053,12 @@
/* loco:62344c023cb45e6fcb219b43 */
"trashedFileRestoreFileToOriginalPlaceSuccess-plural" = "%d elementi ipristinati nell’ubicazione di origine";

/* loco:66fe3560501931dbfb04f0c8 */
"unknownArtist" = "Artista sconosciuto";

/* loco:66fe3634a0cfdc15cf0c1a94 */
"unknownTitle" = "Titolo sconosciuto";

/* loco:6049df4d5c2c3a04bc397a7d */
"updateAvailableDescription" = "Per vivere la migliore esperienza con kDrive, ti consigliamo di aggiornare la tua applicazione.";

Expand Down
24 changes: 20 additions & 4 deletions kDrive/UI/View/Files/Preview/AudioCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ import MediaPlayer
import UIKit

final class AudioCollectionViewCell: PreviewCollectionViewCell {
@IBOutlet var iconImageView: UIImageView!
@IBOutlet var artworkImageView: UIImageView!
@IBOutlet var elapsedTimeLabel: UILabel!
@IBOutlet var remainingTimeLabel: UILabel!
@IBOutlet var positionSlider: UISlider!
@IBOutlet var playButton: UIButton!
@IBOutlet var landscapePlayButton: UIButton!
@IBOutlet var iconHeightConstraint: NSLayoutConstraint!
@IBOutlet var songTitleLabel: UILabel!
@IBOutlet var artistNameLabel: UILabel!

var driveFileManager: DriveFileManager!

Expand All @@ -49,6 +51,8 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {
ctx.cgContext.addEllipse(in: rect)
ctx.cgContext.drawPath(using: .fill)
}
songTitleLabel.text = ""
artistNameLabel.text = ""
elapsedTimeLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 14, weight: .medium)
remainingTimeLabel.font = UIFont.monospacedDigitSystemFont(ofSize: 14, weight: .medium)
positionSlider.setThumbImage(circleImage, for: .normal)
Expand All @@ -75,14 +79,16 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {
super.prepareForReuse()
setControls(enabled: false)
singleTrackPlayer.reset()
songTitleLabel.text = ""
artistNameLabel.text = ""
artworkImageView.image = KDriveResourcesAsset.music.image
}

override func configureWith(file: File) {
// file should be safe for async work in the player
let frozenFile = file.freezeIfNeeded()
setUpPlayButtons()

Task {
setUpPlayButtons()
Task { @MainActor in
await singleTrackPlayer.setup(with: frozenFile)
setControls(enabled: true)
setupObservation()
Expand Down Expand Up @@ -142,6 +148,16 @@ final class AudioCollectionViewCell: PreviewCollectionViewCell {
self.positionSlider.maximumValue = sliderMaximum
}
.store(in: &cancellables)

singleTrackPlayer
.onCurrentTrackMetadata
.receive(on: DispatchQueue.main)
.sink { metadata in
self.artworkImageView.image = metadata.artwork
self.artistNameLabel.text = metadata.artist
self.songTitleLabel.text = metadata.title
}
.store(in: &cancellables)
}

@MainActor func setUpPlayButtons() {
Expand Down
33 changes: 23 additions & 10 deletions kDrive/UI/View/Files/Preview/AudioCollectionViewCell.xib
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_3" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
Expand All @@ -19,10 +18,10 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="JwS-de-Pn7">
<rect key="frame" x="24" y="246.5" width="458" height="334"/>
<rect key="frame" x="24" y="185.33333333333334" width="458" height="456.66666666666663"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="36" translatesAutoresizingMaskIntoConstraints="NO" id="RQC-MS-Xpl">
<rect key="frame" x="0.0" y="0.0" width="458" height="302"/>
<rect key="frame" x="0.0" y="0.0" width="458" height="424.66666666666669"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="music" translatesAutoresizingMaskIntoConstraints="NO" id="W9a-yf-gb4">
<rect key="frame" x="169" y="0.0" width="120" height="120"/>
Expand All @@ -31,8 +30,20 @@
<constraint firstAttribute="height" constant="120" id="SGq-zm-Qis"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Song title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="l45-mr-rI7" customClass="IKLabel" customModule="kDrive" customModuleProvider="target">
<rect key="frame" x="182.33333333333334" y="155.99999999999997" width="93.666666666666657" height="27.666666666666657"/>
<fontDescription key="fontDescription" type="system" pointSize="23"/>
<color key="textColor" name="backgroundCardView"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Artist" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="I2u-ME-J8U" customClass="IKLabel" customModule="kDrive" customModuleProvider="target">
<rect key="frame" x="206.33333333333334" y="219.66666666666666" width="45.666666666666657" height="23"/>
<fontDescription key="fontDescription" type="system" pointSize="19"/>
<color key="textColor" name="backgroundCardView"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="Stm-WL-vWh">
<rect key="frame" x="5" y="156" width="448" height="40"/>
<rect key="frame" x="5" y="278.66666666666663" width="448" height="40"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q1t-cA-X5f">
<rect key="frame" x="0.0" y="0.0" width="40" height="40"/>
Expand Down Expand Up @@ -78,7 +89,7 @@
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="nEX-wd-Ij8">
<rect key="frame" x="194" y="232" width="70" height="70"/>
<rect key="frame" x="194" y="354.66666666666663" width="70" height="70"/>
<constraints>
<constraint firstAttribute="height" constant="70" id="PVE-gP-cBs"/>
<constraint firstAttribute="width" constant="70" id="cfr-Lz-2Q8"/>
Expand Down Expand Up @@ -113,15 +124,17 @@
</constraints>
<size key="customSize" width="506" height="827"/>
<connections>
<outlet property="artistNameLabel" destination="I2u-ME-J8U" id="SAn-0a-1QQ"/>
<outlet property="artworkImageView" destination="W9a-yf-gb4" id="Pfh-2f-8LB"/>
<outlet property="elapsedTimeLabel" destination="8sR-5A-U2n" id="FNe-ZD-WTw"/>
<outlet property="iconHeightConstraint" destination="SGq-zm-Qis" id="4mQ-eH-uYF"/>
<outlet property="iconImageView" destination="W9a-yf-gb4" id="Pfh-2f-8LB"/>
<outlet property="landscapePlayButton" destination="Q1t-cA-X5f" id="OAx-pH-vod"/>
<outlet property="playButton" destination="nEX-wd-Ij8" id="uAY-1X-0fZ"/>
<outlet property="positionSlider" destination="43x-AW-wg9" id="2gc-jE-Usy"/>
<outlet property="remainingTimeLabel" destination="1Ga-6s-Xxf" id="Pl6-EM-Orh"/>
<outlet property="songTitleLabel" destination="l45-mr-rI7" id="NyL-Lf-eST"/>
</connections>
<point key="canvasLocation" x="421.73913043478262" y="320.42410714285711"/>
<point key="canvasLocation" x="420.8955223880597" y="320.25171624713954"/>
</collectionViewCell>
</objects>
<resources>
Expand Down
57 changes: 54 additions & 3 deletions kDriveCore/AudioPlayer/SingleTrackPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import Combine
import InfomaniakCore
import InfomaniakDI
import kDriveResources
import MediaPlayer

/// Track one file been played
Expand All @@ -39,6 +40,8 @@ public final class SingleTrackPlayer {

private var playableFileName: String?

private var currentTrackMetadata: TrackMetadata?

// MARK: Player Observation

private var interruptionObserver: NSObjectProtocol?
Expand All @@ -55,6 +58,7 @@ public final class SingleTrackPlayer {
public let onRemainingTimeChange = PassthroughSubject<String, Never>()
public let onPositionChange = PassthroughSubject<Float, Never>()
public let onPositionMaximumChange = PassthroughSubject<Float, Never>()
public let onCurrentTrackMetadata = PassthroughSubject<TrackMetadata, Never>()

var player: AVPlayer?

Expand Down Expand Up @@ -87,6 +91,33 @@ public final class SingleTrackPlayer {
reset()
}

private func extractTrackMetadata(from asset: AVAsset) async -> TrackMetadata {
var title = playableFileName ?? KDriveResourcesStrings.Localizable.unknownTitle
var artist = KDriveResourcesStrings.Localizable.unknownArtist
var artwork: UIImage?

let metadata = asset.commonMetadata

for item in metadata {
guard let commonKey = item.commonKey else { continue }

switch commonKey {
case .commonKeyTitle:
title = item.value as? String ?? title
case .commonKeyArtist:
artist = item.value as? String ?? artist
case .commonKeyArtwork:
if let data = item.value as? Data {
artwork = UIImage(data: data)
}
default:
break
}
}

return TrackMetadata(title: title, artist: artist, artwork: artwork)
}

// MARK: - Load

/// Load internal structures to play a single track
Expand All @@ -96,15 +127,20 @@ public final class SingleTrackPlayer {
playableFileName = playableFile.name

if !playableFile.isLocalVersionOlderThanRemote {
let asset = AVAsset(url: playableFile.localUrl)
player = AVPlayer(url: playableFile.localUrl)
Task { @MainActor in
await onCurrentTrackMetadata.send(extractTrackMetadata(from: asset))
}
setUpObservers()
} else if let token = driveFileManager.apiFetcher.currentToken {
driveFileManager.apiFetcher.performAuthenticatedRequest(token: token) { token, _ in
if let token {
let url = Endpoint.download(file: playableFile).url
let headers = ["Authorization": "Bearer \(token.accessToken)"]
let asset = AVURLAsset(url: url, options: ["AVURLAssetHTTPHeaderFieldsKey": headers])
Task {
Task { @MainActor in
await self.onCurrentTrackMetadata.send(self.extractTrackMetadata(from: asset))
self.player = AVPlayer(playerItem: AVPlayerItem(asset: asset))
self.setUpObservers()
}
Expand All @@ -130,7 +166,17 @@ public final class SingleTrackPlayer {
var nowPlayingInfo = [String: Any]()
nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = MPNowPlayingInfoMediaType.audio.rawValue
nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = false
nowPlayingInfo[MPMediaItemPropertyTitle] = playableFileName ?? ""

if let currentTrackMetadata {
nowPlayingInfo[MPMediaItemPropertyTitle] = currentTrackMetadata.title
nowPlayingInfo[MPMediaItemPropertyArtist] = currentTrackMetadata.artist
if let artwork = currentTrackMetadata.artwork {
let artworkItem = MPMediaItemArtwork(boundsSize: artwork.size) { _ in artwork }
nowPlayingInfo[MPMediaItemPropertyArtwork] = artworkItem
}
} else {
nowPlayingInfo[MPMediaItemPropertyTitle] = playableFileName ?? ""
}

MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
Expand All @@ -151,12 +197,12 @@ public final class SingleTrackPlayer {
var nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [String: Any]()
if let position = player?.currentItem?.currentTime() {
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = Float(position.seconds)

let remainingTime = position.formattedText
onRemainingTimeChange.send(remainingTime)
let positionSlider = Float(position.seconds)
onPositionChange.send(positionSlider)
}

if let rate = player?.rate {
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = rate
}
Expand Down Expand Up @@ -289,6 +335,11 @@ public final class SingleTrackPlayer {
public func play() {
if playerState == .stopped {
setNowPlayingMetadata()
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch {
SentryDebug.capture(error: error)
}
}

guard let player else {
Expand Down
Loading
Loading