create views for the new player
MODIFY
Podcast.xcodeproj/project.pbxproj
Podcast.xcodeproj/project.pbxproj
/* Begin PBXBuildFile section */
421501271D9F5FE1002839D1 /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 421501261D9F5FE1002839D1 /* Player.swift */; };
+ 424EAA391E5DDF9900F0126C /* TempPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 424EAA381E5DDF9900F0126C /* TempPlayerViewController.swift */; };
+ 425B393D1E512F5D00283CA4 /* PlayerControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425B393C1E512F5D00283CA4 /* PlayerControlsView.swift */; };
+ 425C90621E5A5827004BB7AD /* EpisodeDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425C90611E5A5827004BB7AD /* EpisodeDetailView.swift */; };
+ 4290028A1E5CA6A20069F0BF /* PlayerHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429002891E5CA6A20069F0BF /* PlayerHeaderView.swift */; };
42D7D98D1D80C557000691A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42D7D98C1D80C557000691A4 /* AppDelegate.swift */; };
42D7D9941D80C557000691A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42D7D9931D80C557000691A4 /* Assets.xcassets */; };
42D7D9971D80C557000691A4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42D7D9951D80C557000691A4 /* LaunchScreen.storyboard */; };
/* Begin PBXFileReference section */
13C8D9A7A7FB0C3D27C81500 /* Pods-PodcastTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PodcastTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PodcastTests/Pods-PodcastTests.debug.xcconfig"; sourceTree = "<group>"; };
421501261D9F5FE1002839D1 /* Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Player.swift; sourceTree = "<group>"; };
+ 424EAA381E5DDF9900F0126C /* TempPlayerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TempPlayerViewController.swift; path = ../TempPlayerViewController.swift; sourceTree = "<group>"; };
+ 425B393C1E512F5D00283CA4 /* PlayerControlsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerControlsView.swift; sourceTree = "<group>"; };
+ 425C90611E5A5827004BB7AD /* EpisodeDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EpisodeDetailView.swift; sourceTree = "<group>"; };
+ 429002891E5CA6A20069F0BF /* PlayerHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerHeaderView.swift; sourceTree = "<group>"; };
42D7D9891D80C557000691A4 /* Podcast.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Podcast.app; sourceTree = BUILT_PRODUCTS_DIR; };
42D7D98C1D80C557000691A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
42D7D9931D80C557000691A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 425B393B1E512E8000283CA4 /* Player */ = {
+ isa = PBXGroup;
+ children = (
+ 425B393C1E512F5D00283CA4 /* PlayerControlsView.swift */,
+ 425C90611E5A5827004BB7AD /* EpisodeDetailView.swift */,
+ 429002891E5CA6A20069F0BF /* PlayerHeaderView.swift */,
+ );
+ name = Player;
+ sourceTree = "<group>";
+ };
42D7D9801D80C557000691A4 = {
isa = PBXGroup;
children = (
D3DB5A611DA1879F00E550E8 /* Utilities */,
D393D7531D8F0CC600241460 /* Cells */,
956D851D1E5194AF00D95F7A /* Misc */,
+ 42D7D98C1D80C557000691A4 /* AppDelegate.swift */,
+ FD9421401DB5306200685E14 /* Views */,
+ D39BEE191D8A04C900131936 /* Models */,
+ 7F97FBDD1D8663000073FC0F /* REST.swift */,
+ 42F684EA1D80CC7E0035217A /* PlayerViewController.swift */,
+ 421501261D9F5FE1002839D1 /* Player.swift */,
+ 424EAA381E5DDF9900F0126C /* TempPlayerViewController.swift */,
+ FDF1D1CE1DAEE2E300697379 /* ProfileViewController.swift */,
+ 42D7D9901D80C557000691A4 /* Main.storyboard */,
+ 42D7D9931D80C557000691A4 /* Assets.xcassets */,
+ 42D7D9951D80C557000691A4 /* LaunchScreen.storyboard */,
+ 42D7D9981D80C557000691A4 /* Info.plist */,
+ 42F684EC1D80CC9F0035217A /* DiscoverViewController.swift */,
+ 7F9D0E8F1D85029C00D2BC1C /* Podcast-Bridging-Header.h */,
+ 7F9D0E961D85A37700D2BC1C /* LoginViewController.swift */,
+ D300C0911DAEF801000CDBF5 /* CategoriesFeedViewController.swift */,
+ D37D799F1DEF920000D752F0 /* SearchViewController.swift */,
);
path = Podcast;
sourceTree = "<group>";
isa = PBXGroup;
children = (
FD9421411DB5307B00685E14 /* ProfileHeaderView.swift */,
+ 425B393B1E512E8000283CA4 /* Player */,
FD0159FF1DCBFC80003E7B4E /* ProfileMiniHeader.swift */,
FDF5E0CE1DD3A091005CCB53 /* FollowButton.swift */,
FD8F7DFD1DDD36D600DCC511 /* ProfileSectionHeaderView.swift */,
956D851A1E5193F000D95F7A /* UIFont+.swift in Sources */,
FD295FDB1E6258B500520526 /* EpisodeTableViewCell.swift in Sources */,
FD20F5741E52186500721C46 /* SeriesDetailHeaderView.swift in Sources */,
+ 425B393D1E512F5D00283CA4 /* PlayerControlsView.swift in Sources */,
FDF5E0CF1DD3A091005CCB53 /* FollowButton.swift in Sources */,
7F97FBDA1D85A99F0073FC0F /* Constants.swift in Sources */,
447DA8621E5C99790002BCA0 /* RecommendedTagsCollectionViewCell.swift in Sources */,
447DA8631E5C99790002BCA0 /* RecommendedTagsTableViewCell.swift in Sources */,
7F9D0E971D85A37700D2BC1C /* LoginViewController.swift in Sources */,
FD8F7DFC1DDD20FC00DCC511 /* SeriesCollectionViewCell.swift in Sources */,
+ 425C90621E5A5827004BB7AD /* EpisodeDetailView.swift in Sources */,
FD015A001DCBFC80003E7B4E /* ProfileMiniHeader.swift in Sources */,
42F684ED1D80CC9F0035217A /* FeedViewController.swift in Sources */,
952BD1181E66A2AE006C0370 /* BookmarkViewController.swift in Sources */,
D300C0921DAEF801000CDBF5 /* CategoriesFeedViewController.swift in Sources */,
D3DB5A651DA18FC600E550E8 /* CategoriesCollectionViewCell.swift in Sources */,
FD20F5721E52067400721C46 /* SeriesDetailViewController.swift in Sources */,
+ 4290028A1E5CA6A20069F0BF /* PlayerHeaderView.swift in Sources */,
FD9421421DB5307B00685E14 /* ProfileHeaderView.swift in Sources */,
956D85181E5193C200D95F7A /* UIColor+.swift in Sources */,
D37D79A01DEF920000D752F0 /* SearchViewController.swift in Sources */,
447DA8691E5C998E0002BCA0 /* DiscoverTableViewHeaderView.swift in Sources */,
D3E2692F1E5E806A00793569 /* TagCard.swift in Sources */,
956D85131E51926800D95F7A /* EndpointRequest.swift in Sources */,
+ 424EAA391E5DDF9900F0126C /* TempPlayerViewController.swift in Sources */,
42D7D98D1D80C557000691A4 /* AppDelegate.swift in Sources */,
D39BEE1D1D8A073200131936 /* Series.swift in Sources */,
42F684EB1D80CC7E0035217A /* PlayerViewController.swift in Sources */,

MODIFY
Podcast/Assets.xcassets/sample_series_artwork.imageset/Contents.json
Podcast/Assets.xcassets/sample_series_artwork.imageset/Contents.json
"images" : [
{
"idiom" : "universal",
- "filename" : "mock-podcast-artwork.jpg",
+ "filename" : "icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1.jpg",
"scale" : "1x"
},
{
"idiom" : "universal",
- "filename" : "mock-podcast-artwork-1.jpg",
+ "filename" : "icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-1.jpg",
"scale" : "2x"
},
{
"idiom" : "universal",
- "filename" : "mock-podcast-artwork-2.jpg",
+ "filename" : "icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-2.jpg",
"scale" : "3x"
}
],

ADD
Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-1.jpg
Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-1.jpg
Binary files /dev/null and b/Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-1.jpg differ

ADD
Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-2.jpg
Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-2.jpg
Binary files /dev/null and b/Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1-2.jpg differ

ADD
Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1.jpg
Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1.jpg
Binary files /dev/null and b/Podcast/Assets.xcassets/sample_series_artwork.imageset/icon_344098539-f089cf02094b52708d0979b026a157aa5a1e3ac1.jpg differ

DELETE
Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork-1.jpg
Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork-1.jpg
Binary files a/Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork-1.jpg and /dev/null differ

DELETE
Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork-2.jpg
Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork-2.jpg
Binary files a/Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork-2.jpg and /dev/null differ

DELETE
Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork.jpg
Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork.jpg
Binary files a/Podcast/Assets.xcassets/sample_series_artwork.imageset/mock-podcast-artwork.jpg and /dev/null differ

MODIFY
Podcast/Player.swift
Podcast/Player.swift
@@ -19,6 +19,7 @@ class Player: NSObject {
player = AVPlayer()
autoplay = true
currentItemPrepared = false
+ scrubbing = false
super.init()
}
@@ -41,10 +42,12 @@ class Player: NSObject {
didSet {
autoplay = true
currentItemPrepared = false
+ scrubbing = false
}
}
private var autoplay: Bool
private var currentItemPrepared: Bool
+ var scrubbing: Bool
var isPlaying: Bool {
get {
return player.rate != 0.0 || (!currentItemPrepared && autoplay && (player.currentItem != nil))

MODIFY
Podcast/PlayerViewController.swift
Podcast/PlayerViewController.swift
@@ -11,118 +11,35 @@ import CoreMedia
class PlayerViewController: UIViewController, PlayerDelegate {
- // Mark: Constants
-
- let PlayerControlPanelHeight: CGFloat = 182
-
- let ForwardsBackwardsButtonSize: CGFloat = 44
- let PlayPauseButtonSize: CGFloat = 40
- let SliderHeight: CGFloat = 6
- let SliderInset: CGFloat = 48
- let SliderCenterY: CGFloat = 78
- let EpisodeNameLabelYValue: CGFloat = 21
- let SeriesNameLabelYValue: CGFloat = 40
- let TimeLabelHorizontalInset: CGFloat = 14
- let ControlButtonsCenterY: CGFloat = 120
- let ControlButtonsCenterHorizontalOffset: CGFloat = 55
-
- // Mark: Properties
-
- var controlsView: UIView!
- var artworkImageView: UIImageView!
-
+ var controlsView: PlayerControlsView!
+ var episodeDetailView: EpisodeDetailView!
+ var playerHeaderView: PlayerHeaderView!
var episodeNameLabel: UILabel!
var seriesNameLabel: UILabel!
- var slider: UISlider!
- var playPauseButton: UIButton!
- var forwardsButton: UIButton!
- var forwardsLabel: UILabel!
- var backwardsButton: UIButton!
- var backwardsLabel: UILabel!
- var rightTimeLabel: UILabel!
- var leftTimeLabel: UILabel!
- var scrubbing = false
+
+ let EpisodeDetailViewYVal: CGFloat = 87
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .podcastGrayLight
- tabBarController?.title = "Now Playing"
-
- artworkImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height - PlayerControlPanelHeight - tabBarController!.tabBar.frame.height))
- artworkImageView.contentMode = .scaleAspectFill
- artworkImageView.image = UIImage(named: "sample_series_artwork")
- view.addSubview(artworkImageView)
-
- controlsView = UIView(frame: CGRect(x: 0, y: view.frame.height - PlayerControlPanelHeight - tabBarController!.tabBar.frame.height, width: view.frame.width, height: PlayerControlPanelHeight))
- controlsView.backgroundColor = .white
- view.addSubview(controlsView)
- episodeNameLabel = UILabel(frame: .zero)
- episodeNameLabel.textAlignment = .center
- episodeNameLabel.font = .boldSystemFont(ofSize: 15)
- controlsView.addSubview(episodeNameLabel)
+ playerHeaderView = PlayerHeaderView(frame: .zero)
+ playerHeaderView.frame.size.width = view.frame.width
+ playerHeaderView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(playerHeaderTapped)))
+ view.addSubview(playerHeaderView)
- seriesNameLabel = UILabel(frame: .zero)
- seriesNameLabel.textAlignment = .center
- seriesNameLabel.font = .systemFont(ofSize: 13)
- controlsView.addSubview(seriesNameLabel)
+ episodeDetailView = EpisodeDetailView(frame: .zero)
+ episodeDetailView.frame.size.width = view.frame.width
+ episodeDetailView.frame.origin.y = EpisodeDetailViewYVal
+ view.addSubview(episodeDetailView)
- slider = UISlider(frame: .zero)
- slider.thumbTintColor = .podcastGreenBlue
- slider.minimumTrackTintColor = .podcastBlueLight
- slider.maximumTrackTintColor = .podcastBlueLight
- slider.addTarget(self, action: #selector(sliderValueChanged), for: .valueChanged)
- slider.addTarget(self, action: #selector(endScrubbing), for: .touchUpInside)
- slider.addTarget(self, action: #selector(endScrubbing), for: .touchUpOutside)
- slider.frame = CGRect(x: 0, y: 0, width: view.frame.width - (2 * SliderInset), height: SliderHeight)
- slider.center = CGPoint(x: view.frame.width/2, y: SliderCenterY)
- controlsView.addSubview(slider)
-
- leftTimeLabel = UILabel(frame: .zero)
- leftTimeLabel.font = .systemFont(ofSize: 12)
- leftTimeLabel.textAlignment = .center
- controlsView.addSubview(leftTimeLabel)
-
- rightTimeLabel = UILabel(frame: .zero)
- rightTimeLabel.font = .systemFont(ofSize: 12)
- rightTimeLabel.textAlignment = .center
- controlsView.addSubview(rightTimeLabel)
-
- playPauseButton = UIButton(frame: .zero)
- playPauseButton.setBackgroundImage(UIImage(named: "play_icon"), for: .normal)
- playPauseButton.adjustsImageWhenHighlighted = false
- playPauseButton.addTarget(self, action: #selector(playPauseButtonPress), for: .touchUpInside)
- playPauseButton.frame = CGRect(x: 0, y: 0, width: PlayPauseButtonSize, height: PlayPauseButtonSize)
- playPauseButton.center = CGPoint(x: view.frame.width/2, y: ControlButtonsCenterY)
- controlsView.addSubview(playPauseButton)
-
- forwardsButton = UIButton(frame: .zero)
- forwardsButton.setBackgroundImage(UIImage(named: "skip_forward_icon"), for: .normal)
- forwardsButton.adjustsImageWhenHighlighted = false
- forwardsButton.addTarget(self, action: #selector(forwardButtonPress), for: .touchUpInside)
- forwardsButton.frame = CGRect(x: 0, y: 0, width: ForwardsBackwardsButtonSize, height: ForwardsBackwardsButtonSize)
- forwardsButton.center = CGPoint(x: playPauseButton.frame.maxX + ControlButtonsCenterHorizontalOffset, y: ControlButtonsCenterY)
- controlsView.addSubview(forwardsButton)
-
- forwardsLabel = UILabel(frame: .zero)
- forwardsLabel.text = "30"
- forwardsLabel.sizeToFit()
- forwardsLabel.center = forwardsButton.center
- controlsView.addSubview(forwardsLabel)
+ controlsView = PlayerControlsView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 0))
+ controlsView.frame.origin.y = view.frame.height - controlsView.frame.size.height
+ view.addSubview(controlsView)
- backwardsButton = UIButton(frame: .zero)
- backwardsButton.setBackgroundImage(UIImage(named: "skip_backward_icon"), for: .normal)
- backwardsButton.adjustsImageWhenHighlighted = false
- backwardsButton.addTarget(self, action: #selector(backwardButtonPress), for: .touchUpInside)
- backwardsButton.frame = CGRect(x: 0, y: 0, width: ForwardsBackwardsButtonSize, height: ForwardsBackwardsButtonSize)
- backwardsButton.center = CGPoint(x: playPauseButton.frame.minX - ControlButtonsCenterHorizontalOffset, y: ControlButtonsCenterY)
- controlsView.addSubview(backwardsButton)
+ // TODO: add comments section
- backwardsLabel = UILabel(frame: .zero)
- backwardsLabel.text = "15"
- backwardsLabel.sizeToFit()
- backwardsLabel.center = backwardsButton.center
- controlsView.addSubview(backwardsLabel)
+ updateUI()
Player.sharedInstance.delegate = self
}
@@ -131,62 +48,13 @@ class PlayerViewController: UIViewController, PlayerDelegate {
updateUI()
}
- func endScrubbing() {
- Player.sharedInstance.setProgress(progress: Double(slider.value))
- scrubbing = false
- updateUI()
+ func playerHeaderTapped() {
+ dismiss(animated: true, completion: nil)
}
- func sliderValueChanged() {
- scrubbing = true
- // TODO: update time labels as you scrub
- }
-
- func playPauseButtonPress() {
- Player.sharedInstance.togglePlaying()
- }
-
- func forwardButtonPress() {
- Player.sharedInstance.skip(seconds: 30.0)
- }
-
- func backwardButtonPress() {
- Player.sharedInstance.skip(seconds: -15.0)
- }
-
- // Mark: PlayerDelegate protocol
-
func updateUI() {
- if Player.sharedInstance.isPlaying {
- playPauseButton.setBackgroundImage(UIImage(named: "pause_icon"), for: .normal)
- } else {
- playPauseButton.setBackgroundImage(UIImage(named: "play_icon"), for: .normal)
- }
-
- if let episode = Player.sharedInstance.currentEpisode {
- leftTimeLabel.text = Player.sharedInstance.currentItemElapsedTime().descriptionText
- rightTimeLabel.text = Player.sharedInstance.currentItemRemainingTime().descriptionText
- episodeNameLabel.text = episode.title
- seriesNameLabel.text = episode.series?.title ?? "no series"
- } else {
- leftTimeLabel.text = "0:00"
- rightTimeLabel.text = "0:00"
- episodeNameLabel.text = "no episode"
- seriesNameLabel.text = "no series"
- }
-
- leftTimeLabel.sizeToFit()
- rightTimeLabel.sizeToFit()
- episodeNameLabel.sizeToFit()
- seriesNameLabel.sizeToFit()
-
- leftTimeLabel.center = CGPoint(x: TimeLabelHorizontalInset + leftTimeLabel.frame.width/2, y: SliderCenterY)
- rightTimeLabel.center = CGPoint(x: view.frame.width - rightTimeLabel.frame.width/2 - TimeLabelHorizontalInset, y: SliderCenterY)
- episodeNameLabel.center = CGPoint(x: view.frame.width/2, y: EpisodeNameLabelYValue)
- seriesNameLabel.center = CGPoint(x: view.frame.width/2, y: SeriesNameLabelYValue)
-
- if !scrubbing {
- slider.value = Float(Player.sharedInstance.getProgress())
- }
+ playerHeaderView.updateUI()
+ episodeDetailView.updateUI()
+ controlsView.updateUI()
}
}

create views for the new player