Skip to content

Commit

Permalink
Playlist live update added (changes reflect on queue)
Browse files Browse the repository at this point in the history
  • Loading branch information
sitomani committed May 2, 2020
1 parent a34383e commit f6e5a30
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 36 deletions.
61 changes: 38 additions & 23 deletions 4champ/Replay/ModulePlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ enum PlayerStatus:Int {
case paused
}

enum QueueChange: Int {
case newPlaylist
case other
}

/**
Module Player observer delegate protocol.
Note that there can be multiple observers for the player
Expand All @@ -42,7 +47,7 @@ protocol ModulePlayerObserver: class {
func errorOccurred(error: PlayerError)

/// called when play queue changes (e.g. due to playlist change, or when modules are added to queue by user)
func queueChanged()
func queueChanged(changeType:QueueChange)
}

class ModulePlayer: NSObject {
Expand Down Expand Up @@ -177,10 +182,20 @@ class ModulePlayer: NSObject {
renderer.setStereoSeparation(newValue)
}

/// Set new play queue (when user selects a playlist and starts playing)
func setNewPlayQueue(queue: [MMD]) {
cleanup()
playQueue = queue
_ = observers.map {
$0.queueChanged(changeType: .newPlaylist)
}
}

/// Plays the next module in the current playlist. If there are no more modules,
/// the playback will wrap to the first module in the playlist
func playNext() {
guard let current = currentModule, playQueue.count > 0 else {
modulePlayer.stop()
return
}
var nextIndex = 0
Expand Down Expand Up @@ -296,33 +311,33 @@ extension ModulePlayer: ModuleStorageObserver {
}
}
_ = observers.map {
$0.queueChanged()
$0.queueChanged(changeType: .other)
}
}

// At playlist change, load the new queue and start playing
func playlistChange() {
// Cleanup current queue first
if let pl = moduleStorage.currentPlaylist, let plMods = pl.modules {
cleanup()
for item in plMods {
if let mod = item as? ModuleInfo {
playQueue.append(MMD(cdi: mod))
}
}
_ = observers.map {
$0.queueChanged()
}
let shuffle = (pl.playmode?.intValue ?? 0) == 1
if shuffle {
playQueue.shuffle()
}
play(at: 0)
}
_ = observers.map {
$0.queueChanged()
}
// if let pl = moduleStorage.currentPlaylist, let plMods = pl.modules {
// cleanup()
// for item in plMods {
// if let mod = item as? ModuleInfo {
// playQueue.append(MMD(cdi: mod))
// }
// }
// _ = observers.map {
// $0.queueChanged()
// }
//
// let shuffle = (pl.playmode?.intValue ?? 0) == 1
// if shuffle {
// playQueue.shuffle()
// }
// play(at: 0)
// }
//
// _ = observers.map {
// $0.queueChanged()
// }
}
}
2 changes: 1 addition & 1 deletion 4champ/Scenes/Local/LocalViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ extension LocalViewController: ModulePlayerObserver {
//nop at the moment
}

func queueChanged() {
func queueChanged(changeType: QueueChange) {
}
}

Expand Down
2 changes: 1 addition & 1 deletion 4champ/Scenes/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ extension MainViewController: ModulePlayerObserver {
//nop at the moment
}

func queueChanged() {
func queueChanged(changeType: QueueChange) {
//nop at the moment
}
}
Expand Down
37 changes: 37 additions & 0 deletions 4champ/Scenes/Playlists/PlaylistInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ protocol PlaylistBusinessLogic
func moveModule(request: Playlists.Move.Request)
func toggleShuffle()
func toggleFavorite(request: Playlists.Favorite.Request)
func playModule(request: Playlists.Play.Request)
}

protocol PlaylistDataStore
Expand Down Expand Up @@ -94,6 +95,7 @@ class PlaylistInteractor: NSObject, PlaylistBusinessLogic, PlaylistDataStore
currentMode.toggle()
moduleStorage.currentPlaylist?.playmode = NSNumber.init(value: currentMode)
moduleStorage.saveContext()
rebuildQueue()
}

func toggleFavorite(request: Playlists.Favorite.Request) {
Expand All @@ -103,6 +105,30 @@ class PlaylistInteractor: NSObject, PlaylistBusinessLogic, PlaylistDataStore
doPresent()
}

func playModule(request: Playlists.Play.Request) {
rebuildQueue()
if let index = modulePlayer.playQueue.index(of: request.mmd) {
modulePlayer.play(at: index)
}
}

private func rebuildQueue() {
if let pl = frc?.fetchedObjects?.first(where: { ($0 as Playlist).plId == selectedPlaylistId }) {
var playlistQueue: [MMD] = []
if let moduleinfos = pl.modules {
for mod in moduleinfos {
playlistQueue.append(MMD(cdi: (mod as! ModuleInfo)))
}
}
if (pl.playmode?.boolValue ?? false) {
playlistQueue.shuffle()
}

moduleStorage.currentPlaylist = pl
modulePlayer.setNewPlayQueue(queue: playlistQueue)
}
}

private func doPresent() {
if let pl = frc?.fetchedObjects?.first(where: { ($0 as Playlist).plId == selectedPlaylistId }) {
let resp = Playlists.Select.Response(selectedPlaylist: pl)
Expand All @@ -115,6 +141,17 @@ extension PlaylistInteractor: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

guard modulePlayer.radioOn == false else {
return
}

if let pl = anObject as? Playlist, pl.plId == selectedPlaylistId {
rebuildQueue()
}
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
doPresent()
}
Expand Down
6 changes: 6 additions & 0 deletions 4champ/Scenes/Playlists/PlaylistModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ enum Playlists
}
}

enum Play {
struct Request {
let mmd: MMD
}
}

enum Select {
struct Request {
let playlistId: String
Expand Down
9 changes: 4 additions & 5 deletions 4champ/Scenes/Playlists/PlaylistStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class PlaylistStore: ObservableObject, PlaylistDisplayLogic

extension PlaylistStore: ModulePlayerObserver {
func moduleChanged(module: MMD) {
// tableView?.reloadData()
hostingController?.rootView.navigationButtonID = UUID()
}

func statusChanged(status: PlayerStatus) {
Expand All @@ -87,15 +87,14 @@ extension PlaylistStore: ModulePlayerObserver {
//nop at the moment
}

func queueChanged() {
// let req = Playlists.Select.Request(playlistId: moduleStorage.currentPlaylist?.plId ?? "default")
// interactor?.selectPlaylist(request: req)
func queueChanged(changeType: QueueChange) {
//nop
}
}

extension PlaylistStore: ModuleStorageObserver {
func metadataChange(_ mmd: MMD) {
//NOP
//nop
}

func playlistChange() {
Expand Down
4 changes: 2 additions & 2 deletions 4champ/Scenes/Playlists/PlaylistView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct PlaylistView: View {
@State private var show_modal: Bool = false
@State var showNowPlaying: Bool = false
@State var isEditing: Bool = false
@State private var navigationButtonID = UUID()
@State var navigationButtonID = UUID()
@State var selectedPlaylistId: String = "default" {
didSet {
store.interactor?.selectPlaylist(request: Playlists.Select.Request(playlistId: self.selectedPlaylistId))
Expand Down Expand Up @@ -102,7 +102,7 @@ struct PlaylistView: View {
SUIModule(module: mod, faveCallback: self.favorite(module:))
.contentShape(Rectangle())
.onTapGesture {
modulePlayer.play(mmd: mod)
self.store.interactor?.playModule(request: Playlists.Play.Request(mmd: mod))
}.onLongPressGesture {
self.store.router?.toPlaylistSelector(module: mod)
}
Expand Down
18 changes: 16 additions & 2 deletions 4champ/Scenes/Radio/RadioInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,16 @@ class RadioInteractor: NSObject, RadioBusinessLogic, RadioDataStore
stopPlayback()
}
guard request.powerOn == true else {
modulePlayer.removePlayerObserver(self)

presenter?.presentChannelBuffer(buffer: [])
modulePlayer.cleanup()
return
}

modulePlayer.addPlayerObserver(self)
modulePlayer.cleanup()

playbackTimer?.invalidate()
playbackTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
self?.periodicUpdate()
Expand Down Expand Up @@ -325,7 +331,15 @@ extension RadioInteractor: ModulePlayerObserver {
playNext()
}

func queueChanged() {
triggerBufferPresentation()
func queueChanged(changeType: QueueChange) {
if changeType == .newPlaylist && radioOn {
status = .off
modulePlayer.removePlayerObserver(self)
presenter?.presentChannelBuffer(buffer: [])
presenter?.presentControlStatus(status: .off)
playbackTimer?.invalidate()
} else {
triggerBufferPresentation()
}
}
}
2 changes: 2 additions & 0 deletions 4champ/Scenes/Radio/RadioViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,13 @@ class RadioViewController: UIViewController, RadioDisplayLogic
switch viewModel.status {
case .on:
switchTitle?.text = "Radio_StatusOn".l13n()
radioSwitch?.isOn = true
case .off:
switchTitle?.text = "Radio_StatusOff".l13n()
nextUpTitle?.text = ""
switchTitle?.textColor = UIColor.white
radioSwitch?.onTintColor = Appearance.successColor
radioSwitch?.isOn = false
case .noModulesAvailable:
switchTitle?.text = "Radio_NoLocalModules".l13n()
switchTitle?.textColor = Appearance.errorColor
Expand Down
2 changes: 1 addition & 1 deletion 4champ/Scenes/Search/SearchViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ extension SearchViewController: ModulePlayerObserver {
displayDownloadProgress(viewModel: vm)
}

func queueChanged() {
func queueChanged(changeType: QueueChange) {
// nop
}
}
Expand Down
7 changes: 6 additions & 1 deletion 4champ/Scenes/Visualizer/VisualizerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,13 @@ class VisualizerViewController: UIViewController, UIScrollViewDelegate, UIGestur

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
stopVisualisation()
}

override var preferredStatusBarStyle : UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
Expand Down Expand Up @@ -368,7 +373,7 @@ extension VisualizerViewController: ModulePlayerObserver {
//nop at the moment
}

func queueChanged() {
func queueChanged(changeType: QueueChange) {
//nop at the moment
}

Expand Down

0 comments on commit f6e5a30

Please sign in to comment.