Skip to content

Commit

Permalink
Merge pull request #40 from e7mac/autoplay
Browse files Browse the repository at this point in the history
Autoplay next item in list
  • Loading branch information
GianniCarlo authored Mar 28, 2018
2 parents fc8e985 + 850c7ff commit eb7bc50
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 110 deletions.
32 changes: 32 additions & 0 deletions Audiobook Player/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,37 @@
</constraints>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="cwf-yA-MUf">
<rect key="frame" x="0.0" y="264" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="cwf-yA-MUf" id="c6h-aD-X5V">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Autoplay" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="H7W-Dk-2tK">
<rect key="frame" x="16" y="2" width="67" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DMC-QU-7H6">
<rect key="frame" x="308" y="6" width="51" height="31"/>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Automatically play the next audiobook" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="I97-xz-sez">
<rect key="frame" x="16" y="20" width="260" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="10"/>
<color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="DMC-QU-7H6" secondAttribute="trailing" constant="18" id="OGz-wY-wdD"/>
<constraint firstItem="DMC-QU-7H6" firstAttribute="centerY" secondItem="c6h-aD-X5V" secondAttribute="centerY" id="OPG-rO-M9A"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
Expand All @@ -792,6 +823,7 @@
</navigationItem>
<size key="freeformSize" width="375" height="600"/>
<connections>
<outlet property="autoplaySwitch" destination="DMC-QU-7H6" id="81a-9k-lOh"/>
<outlet property="boostVolumeSwitch" destination="0Nl-PG-HKW" id="tiT-du-KK6"/>
<outlet property="globalSpeedSwitch" destination="VQk-Go-koN" id="GM7-fx-xNg"/>
<outlet property="smartRewindSwitch" destination="GRM-ck-C3M" id="69t-8D-ecN"/>
Expand Down
1 change: 1 addition & 0 deletions Audiobook Player/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ struct UserDefaultsConstants {
static let smartRewindEnabled = "userSettingsSmartRewind";
static let boostVolumeEnabled = "userSettingsBoostVolume";
static let globalSpeedEnabled = "userSettingsGlobalSpeed";
static let autoplayEnabled = "userSettingsAutoplay";
}
3 changes: 3 additions & 0 deletions Audiobook Player/DataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ struct Book {
}
}

var displayTitle: String {
return title + " - " + author
}
var title: String
var author: String
var artwork: UIImage
Expand Down
1 change: 1 addition & 0 deletions Audiobook Player/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ extension Notification.Name {
public static let bookPlayed = Notification.Name(rawValue: "com.tortugapower.audiobookplayer.book.play")
public static let bookPaused = Notification.Name(rawValue: "com.tortugapower.audiobookplayer.book.pause")
public static let bookEnd = Notification.Name(rawValue: "com.tortugapower.audiobookplayer.book.end")
public static let bookChange = Notification.Name(rawValue: "com.tortugapower.audiobookplayer.book.change")
}
}

85 changes: 65 additions & 20 deletions Audiobook Player/ListBooksViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ListBooksViewController: UIViewController, UIGestureRecognizerDelegate {
//keep in memory images to toggle play/pause
let miniPlayImage = UIImage(named: "miniPlayButton")
let miniPauseButton = UIImage(named: "miniPauseButton")
var currentBooks: [Book] = []

//TableView's datasource
var bookArray = [Book]()
Expand All @@ -35,7 +36,7 @@ class ListBooksViewController: UIViewController, UIGestureRecognizerDelegate {

override func viewDidLoad() {
super.viewDidLoad()

//pull-down-to-refresh support
self.refreshControl.attributedTitle = NSAttributedString(string: "Pull down to reload books")
self.refreshControl.addTarget(self, action: #selector(loadFiles), for: .valueChanged)
Expand Down Expand Up @@ -89,15 +90,21 @@ class ListBooksViewController: UIViewController, UIGestureRecognizerDelegate {
//register for percentage change notifications
NotificationCenter.default.addObserver(self, selector: #selector(self.updatePercentage(_:)), name: Notification.Name.AudiobookPlayer.updatePercentage, object: nil)

//register notifications when the book is ready
NotificationCenter.default.addObserver(self, selector: #selector(self.bookReady), name: Notification.Name.AudiobookPlayer.bookReady, object: nil)

//register notifications when the book is played
NotificationCenter.default.addObserver(self, selector: #selector(self.bookPlayed), name: Notification.Name.AudiobookPlayer.bookPlayed, object: nil)

//register notifications when the book is paused
NotificationCenter.default.addObserver(self, selector: #selector(self.bookPaused), name: Notification.Name.AudiobookPlayer.bookPaused, object: nil)

//register for book end notifications
NotificationCenter.default.addObserver(self, selector: #selector(self.bookEnd(_:)), name: Notification.Name.AudiobookPlayer.bookEnd, object: nil)

//register for book change notifications
NotificationCenter.default.addObserver(self, selector: #selector(self.bookChange(_:)), name: Notification.Name.AudiobookPlayer.bookChange, object: nil)

//register for remote events
self.registerRemoteEvents()

Expand Down Expand Up @@ -188,11 +195,10 @@ class ListBooksViewController: UIViewController, UIGestureRecognizerDelegate {
}

@IBAction func didPressShowDetail(_ sender: UIButton) {
guard let indexPath = self.tableView.indexPathForSelectedRow else {
guard !currentBooks.isEmpty else {
return
}

self.tableView(self.tableView, didSelectRowAt: indexPath)
play(books: currentBooks)
}

//percentage callback
Expand All @@ -211,7 +217,12 @@ class ListBooksViewController: UIViewController, UIGestureRecognizerDelegate {

cell.completionLabel.text = percentageString
}


@objc func bookReady(){
MBProgressHUD.hideAllHUDs(for: self.view, animated: true)
PlayerManager.sharedInstance.playPressed(autoplayed: true)
}

@objc func bookPlayed(){
self.footerPlayButton.setImage(self.miniPauseButton, for: UIControlState())
}
Expand All @@ -223,6 +234,16 @@ class ListBooksViewController: UIViewController, UIGestureRecognizerDelegate {
@objc func bookEnd(_ notification:Notification) {
self.footerPlayButton.setImage(self.miniPlayImage, for: UIControlState())
}

@objc func bookChange(_ notification:Notification) {
guard let userInfo = notification.userInfo,
let books = userInfo["books"] as? [Book],
let currentBook = books.first else {
return
}
setupFooter(book: currentBook)
}

}

extension ListBooksViewController: UITableViewDataSource {
Expand All @@ -236,9 +257,10 @@ extension ListBooksViewController: UITableViewDataSource {
let book = self.bookArray[indexPath.row]

cell.titleLabel.text = book.title
cell.titleLabel.highlightedTextColor = UIColor.black
cell.authorLabel.text = book.author

cell.selectionStyle = .none

//NOTE: we should have a default image for artwork
cell.artworkImageView.image = book.artwork

Expand Down Expand Up @@ -302,26 +324,49 @@ extension ListBooksViewController: UITableViewDelegate {
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let book = self.bookArray[indexPath.row]
let books = Array(self.bookArray.suffix(from: indexPath.row))
play(books: books)
}

func play(books: [Book]) {
guard !books.isEmpty else {
return
}
self.currentBooks = books
let book = currentBooks.first!
setupPlayer(book: book)
showPlayerView(book: book)
setupFooter(book: book)
}

func setupPlayer(book: Book) {
//make sure player is for a different book
guard PlayerManager.sharedInstance.fileURL != book.fileURL else {
showPlayerView(book: book)
return
}

MBProgressHUD.showAdded(to: self.view, animated: true)
//replace player with new one
PlayerManager.sharedInstance.load(self.currentBooks) { (audioPlayer) in
self.showPlayerView(book: book)
}
}

func setupFooter(book: Book) {
self.footerView.isHidden = false
self.footerTitleLabel.text = book.displayTitle
self.footerImageView.image = book.artwork
self.footerHeightConstraint.constant = 55
}

func showPlayerView(book: Book) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let playerVC = storyboard.instantiateViewController(withIdentifier: "PlayerViewController") as! PlayerViewController
playerVC.currentBook = book

guard let cell = tableView.cellForRow(at: indexPath) as? BookCellView else {
self.presentModal(playerVC, animated: true)
return
}

let title = cell.titleLabel.text ?? book.fileURL.lastPathComponent
let author = cell.authorLabel.text ?? "Unknown Author"

//show the current player
self.presentModal(playerVC, animated: true) {
self.footerView.isHidden = false
self.footerTitleLabel.text = title + " - " + author
self.footerImageView.image = cell.artworkImageView.image
self.footerHeightConstraint.constant = 55
}
}
}
Expand Down
42 changes: 31 additions & 11 deletions Audiobook Player/PlayerManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class PlayerManager: NSObject {

//current item to play
var playerItem:AVPlayerItem!
var currentBook:Book!
var currentBooks:[Book]!

var fileURL:URL!

Expand Down Expand Up @@ -69,18 +69,21 @@ class PlayerManager: NSObject {



func load(_ book:Book, completion:@escaping (AVAudioPlayer?) -> Void) {
func load(_ books:[Book], completion:@escaping (AVAudioPlayer?) -> Void) {

if let player = self.audioPlayer {
player.stop()
//notify?
if self.currentBooks != nil && self.currentBooks!.count == books.count { //todo : fix logic
if let player = self.audioPlayer {
player.stop()
//notify?
}
}


self.currentBooks = books
let book = books.first!

self.playerItem = AVPlayerItem(asset: book.asset)
self.fileURL = book.fileURL
self.identifier = book.identifier
self.currentBook = book
self.currentChapter = nil
self.chapterArray = []
//notify metadata
Expand Down Expand Up @@ -265,7 +268,7 @@ extension PlayerManager: AVAudioPlayerDelegate {
}

//toggle play/pause of book
func playPressed() {
func playPressed(autoplayed: Bool = false) {
guard let audioplayer = self.audioPlayer else {
return
}
Expand Down Expand Up @@ -298,8 +301,14 @@ extension PlayerManager: AVAudioPlayerDelegate {

try! AVAudioSession.sharedInstance().setActive(true)

let completed = Int(audioplayer.duration) == Int(audioplayer.currentTime)

if autoplayed && completed {
return
}

//if book is completed, reset to start
if Int(audioplayer.duration) == Int(audioplayer.currentTime) {
if completed {
audioplayer.currentTime = 0
}

Expand Down Expand Up @@ -347,7 +356,7 @@ extension PlayerManager: AVAudioPlayerDelegate {
"percentage":percentage,
"percentageString":percentageString,
"hasChapters":!self.chapterArray.isEmpty,
"fileURL":self.currentBook.fileURL] as [String : Any]
"fileURL":self.currentBooks.first!.fileURL] as [String : Any]

//notify percentage
if storedPercentage != percentageString {
Expand Down Expand Up @@ -387,7 +396,7 @@ extension PlayerManager: AVAudioPlayerDelegate {
let chapterString = "Chapter \(chapter.index) of \(self.chapterArray.count)"
//notify
let userInfo = ["chapterString": chapterString,
"fileURL":self.currentBook.fileURL] as [String : Any]
"fileURL":self.currentBooks.first!.fileURL] as [String : Any]

//notify
NotificationCenter.default.post(name: Notification.Name.AudiobookPlayer.updateChapter, object: nil, userInfo: userInfo)
Expand All @@ -400,6 +409,17 @@ extension PlayerManager: AVAudioPlayerDelegate {
if flag {
player.currentTime = player.duration
self.updateTimer()

if (UserDefaults.standard.bool(forKey: UserDefaultsConstants.autoplayEnabled)) {
if self.currentBooks.count > 1 {
let currentBooks = Array(PlayerManager.sharedInstance.currentBooks.dropFirst())
load(currentBooks, completion: { (audioPlayer) in
let userInfo = ["books": currentBooks]
NotificationCenter.default.post(name: Notification.Name.AudiobookPlayer.bookChange, object: nil, userInfo: userInfo)
})
}
}

}
}

Expand Down
Loading

0 comments on commit eb7bc50

Please sign in to comment.