Skip to content
This repository has been archived by the owner on Jan 16, 2023. It is now read-only.

Commit

Permalink
Merge pull request #337 from clappr/feature/media_control_elements
Browse files Browse the repository at this point in the history
Introducing MediaControl Element to replace MediaControlPlugin
  • Loading branch information
johnmartinstw authored Aug 15, 2019
2 parents f2d738c + 6e6561e commit 5fee47c
Show file tree
Hide file tree
Showing 19 changed files with 188 additions and 179 deletions.
26 changes: 17 additions & 9 deletions Clappr.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
32E4021F1FF43534001C2096 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32E4021D1FF43534001C2096 /* Nimble.framework */; };
32FC971B20B7257800ABA0C2 /* AVURLAssetWithCookiesBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57937C561FB0DD0D000A239E /* AVURLAssetWithCookiesBuilder.swift */; };
32FC971C20B72C4200ABA0C2 /* AVURLAssetWithCookiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57937C581FB0DD27000A239E /* AVURLAssetWithCookiesTests.swift */; };
4807611A23046FF400B1BB0C /* MediaControlElementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4807611723046F9B00B1BB0C /* MediaControlElementTests.swift */; };
4822B6AD220B6F7200D1C134 /* Core+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48563228220B47B10096CDAE /* Core+Ext.swift */; };
4822B6AF220C72AE00D1C134 /* SeekBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4822B6AE220C72AE00D1C134 /* SeekBubble.swift */; };
4822B6B1220C72D100D1C134 /* SeekBubbleSide.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4822B6B0220C72D100D1C134 /* SeekBubbleSide.swift */; };
Expand Down Expand Up @@ -232,7 +233,7 @@
9EED97062088E48700D1C84A /* AVPlayerStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EED97052088E48700D1C84A /* AVPlayerStub.swift */; };
9EED97082088E5B800D1C84A /* AVPlayerItemStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EED97072088E5B800D1C84A /* AVPlayerItemStub.swift */; };
AB0A58DF21FA2F520075729E /* QuickSeekAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB0A58DE21FA2F520075729E /* QuickSeekAnimation.swift */; };
AB163506215AB97800635233 /* MediaControlPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB163505215AB97800635233 /* MediaControlPlugin.swift */; };
AB163506215AB97800635233 /* MediaControlElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB163505215AB97800635233 /* MediaControlElement.swift */; };
AB16350D215AC9FC00635233 /* MediaControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB16350A215AC9FC00635233 /* MediaControlView.swift */; };
AB16350F215AC9FC00635233 /* MediaControlView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB16350B215AC9FC00635233 /* MediaControlView.xib */; };
AB163517215ACA0C00635233 /* MediaControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB163514215ACA0C00635233 /* MediaControl.swift */; };
Expand Down Expand Up @@ -260,7 +261,6 @@
C990DAA62194B17D00EB6FFA /* AVFoundationPlaybackStateMachineEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C990DAA42194B17D00EB6FFA /* AVFoundationPlaybackStateMachineEventsTests.swift */; };
C9B6D6E7216FDD5400588896 /* FullscreenButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6D6E6216FDD5400588896 /* FullscreenButton.swift */; };
C9B8414922E0F454009DE097 /* OrientationObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B8414822E0F454009DE097 /* OrientationObserver.swift */; };
C9EDF8482162C98D00789E2F /* MediaControlPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9EDF8472162C98D00789E2F /* MediaControlPluginTests.swift */; };
C9EDF84A2162CCB700789E2F /* MediaControlTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9EDF8492162CCB700789E2F /* MediaControlTests.swift */; };
C9EDF84D2162CEF500789E2F /* UIViewControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9EDF84C2162CEF500789E2F /* UIViewControllerMock.swift */; };
C9EDF84F2162CF1600789E2F /* UINavigationControllerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9EDF84E2162CF1600789E2F /* UINavigationControllerMock.swift */; };
Expand Down Expand Up @@ -417,6 +417,7 @@
32E4020E1FF43262001C2096 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
32E4021C1FF43533001C2096 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/tvOS/Quick.framework; sourceTree = "<group>"; };
32E4021D1FF43534001C2096 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/tvOS/Nimble.framework; sourceTree = "<group>"; };
4807611723046F9B00B1BB0C /* MediaControlElementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaControlElementTests.swift; sourceTree = "<group>"; };
4822B6AE220C72AE00D1C134 /* SeekBubble.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeekBubble.swift; sourceTree = "<group>"; };
4822B6B0220C72D100D1C134 /* SeekBubbleSide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeekBubbleSide.swift; sourceTree = "<group>"; };
4822B6B32214961900D1C134 /* ClapprAnimationDuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClapprAnimationDuration.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -528,7 +529,7 @@
9EED97052088E48700D1C84A /* AVPlayerStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerStub.swift; sourceTree = "<group>"; };
9EED97072088E5B800D1C84A /* AVPlayerItemStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayerItemStub.swift; sourceTree = "<group>"; };
AB0A58DE21FA2F520075729E /* QuickSeekAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickSeekAnimation.swift; sourceTree = "<group>"; };
AB163505215AB97800635233 /* MediaControlPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaControlPlugin.swift; sourceTree = "<group>"; };
AB163505215AB97800635233 /* MediaControlElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaControlElement.swift; sourceTree = "<group>"; };
AB16350A215AC9FC00635233 /* MediaControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaControlView.swift; sourceTree = "<group>"; };
AB16350B215AC9FC00635233 /* MediaControlView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MediaControlView.xib; sourceTree = "<group>"; };
AB163514215ACA0C00635233 /* MediaControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaControl.swift; sourceTree = "<group>"; };
Expand All @@ -548,7 +549,6 @@
C990DAA42194B17D00EB6FFA /* AVFoundationPlaybackStateMachineEventsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVFoundationPlaybackStateMachineEventsTests.swift; sourceTree = "<group>"; };
C9B6D6E6216FDD5400588896 /* FullscreenButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullscreenButton.swift; sourceTree = "<group>"; };
C9B8414822E0F454009DE097 /* OrientationObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationObserver.swift; sourceTree = "<group>"; };
C9EDF8472162C98D00789E2F /* MediaControlPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaControlPluginTests.swift; sourceTree = "<group>"; };
C9EDF8492162CCB700789E2F /* MediaControlTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaControlTests.swift; sourceTree = "<group>"; };
C9EDF84C2162CEF500789E2F /* UIViewControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerMock.swift; sourceTree = "<group>"; };
C9EDF84E2162CF1600789E2F /* UINavigationControllerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UINavigationControllerMock.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -729,6 +729,14 @@
path = Helper;
sourceTree = "<group>";
};
4807611623046F5B00B1BB0C /* Element */ = {
isa = PBXGroup;
children = (
4807611723046F9B00B1BB0C /* MediaControlElementTests.swift */,
);
path = Element;
sourceTree = "<group>";
};
4822B6B2220C72E300D1C134 /* SeekBubble */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1157,12 +1165,11 @@
isa = PBXGroup;
children = (
C9F6D7B2218264E90055A599 /* Seekbar */,
C9F6D7B8218265140055A599 /* Seekbar.swift */,
AB163509215AC9E600635233 /* Layout */,
AB163505215AB97800635233 /* MediaControlElement.swift */,
E7BEEB58217506C100B8F7FA /* TimeIndicator.swift */,
C9B6D6E6216FDD5400588896 /* FullscreenButton.swift */,
AB163514215ACA0C00635233 /* MediaControl.swift */,
AB163505215AB97800635233 /* MediaControlPlugin.swift */,
320A7A14216FBF89006D2B24 /* PlayButton.swift */,
4856322A220B4C9C0096CDAE /* QuickSeekMediaControlPlugin.swift */,
);
Expand Down Expand Up @@ -1240,10 +1247,10 @@
C9EDF8462162C93900789E2F /* MediaControl */ = {
isa = PBXGroup;
children = (
4807611623046F5B00B1BB0C /* Element */,
E7D0BD15218A382E00F5FDF2 /* Seekbar */,
C9EDF85C2163E17F00789E2F /* Layout */,
C9EDF8492162CCB700789E2F /* MediaControlTests.swift */,
C9EDF8472162C98D00789E2F /* MediaControlPluginTests.swift */,
C98C014B2166B50E009DFE0A /* FullscreenButtonTests.swift */,
E7BEEB5A21751D9600B8F7FA /* TimeIndicatorTests.swift */,
487747D3220B5BCD000167CE /* QuickSeekMediaControlPluginTests.swift */,
Expand Down Expand Up @@ -1284,6 +1291,7 @@
C9F6D7B2218264E90055A599 /* Seekbar */ = {
isa = PBXGroup;
children = (
C9F6D7B8218265140055A599 /* Seekbar.swift */,
C9F6D7B3218264F10055A599 /* Views */,
);
path = Seekbar;
Expand Down Expand Up @@ -1958,13 +1966,13 @@
E7D0BD17218A389B00F5FDF2 /* SeekbarTests.swift in Sources */,
C9EDF84D2162CEF500789E2F /* UIViewControllerMock.swift in Sources */,
EDF652241D46829100627C48 /* UIContainerPluginTests.swift in Sources */,
C9EDF8482162C98D00789E2F /* MediaControlPluginTests.swift in Sources */,
5733D1BE21BAA6E4002107D2 /* Dictionary+ExtTests.swift in Sources */,
96912C3E1C21A1AF003A4AFD /* PosterPluginTests.swift in Sources */,
FBE6A3E42163EEAE0083C9CC /* Loader+Plugins.swift in Sources */,
322EA4CA20F941300018973A /* AVURLAssetStub.swift in Sources */,
23EDF916224D819600FB0D96 /* SwiftVersionTests.swift in Sources */,
C93212472212013700F0C47B /* UIImageViewTests.swift in Sources */,
4807611A23046FF400B1BB0C /* MediaControlElementTests.swift in Sources */,
9EED97062088E48700D1C84A /* AVPlayerStub.swift in Sources */,
96B4656B1BF6028A0025975A /* UIPluginTests.swift in Sources */,
C9EDF8562162D10B00789E2F /* ContainerStub.swift in Sources */,
Expand Down Expand Up @@ -2018,7 +2026,7 @@
96D362CD1D41339400CCB866 /* Playback.swift in Sources */,
96D362D91D41339400CCB866 /* UIView+Ext.swift in Sources */,
96D362DD1D41339400CCB866 /* PlaybackFactory.swift in Sources */,
AB163506215AB97800635233 /* MediaControlPlugin.swift in Sources */,
AB163506215AB97800635233 /* MediaControlElement.swift in Sources */,
96D362E61D41339400CCB866 /* EventProtocol.swift in Sources */,
CD57FCF122949BB300AB24CF /* SimpleContainerPlugin.swift in Sources */,
C9F6D7B9218265140055A599 /* Seekbar.swift in Sources */,
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ Clappr comes with four default components: play/pause button, seekbar, fullscree

#### Media Control Plugins

You can add your own components into the `MediaControl` by creating your own Media Control Plugin.
You can add your own components into the `MediaControl` by creating your own Media Control Element.

To do so, you must:

* Inherit from `MediaControlPlugin`;
* Define in which `panel` and `position` the plugin will be rendered;
* Inherit from `MediaControl.Element`;
* Define in which `panel` and `position` the element will be rendered;
* Have a unique name;

If you provide the same name that an existing plugin (built-in), the plugin will override the existent plugin.
Expand Down
88 changes: 43 additions & 45 deletions Sources/Clappr/Classes/Base/Core.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,19 @@ open class Core: UIObject, UIGestureRecognizerDelegate {

willSet {
activeContainer?.stopListening()
trigger(Event.willChangeActiveContainer.rawValue)
trigger(.willChangeActiveContainer)
}

didSet {
activeContainer?.on(
Event.willChangePlayback.rawValue) { [weak self] (info: EventUserInfo) in
self?.trigger(Event.willChangeActivePlayback.rawValue, userInfo: info)
activeContainer?.on(Event.willChangePlayback.rawValue) { [weak self] info in
self?.trigger(.willChangeActivePlayback, userInfo: info)
}

activeContainer?.on(
Event.didChangePlayback.rawValue) { [weak self] (info: EventUserInfo) in
self?.trigger(Event.didChangeActivePlayback.rawValue, userInfo: info)
activeContainer?.on(Event.didChangePlayback.rawValue) { [weak self] info in
self?.trigger(.didChangeActivePlayback, userInfo: info)
}
trigger(Event.didChangeActiveContainer.rawValue)

trigger(.didChangeActiveContainer)
}
}

Expand All @@ -67,9 +66,7 @@ open class Core: UIObject, UIGestureRecognizerDelegate {
addTapGestures()
bindEventListeners()

Loader.shared.corePlugins.forEach { plugin in
self.addPlugin(plugin.init(context: self))
}
Loader.shared.corePlugins.forEach { addPlugin($0.init(context: self)) }
}

func load() {
Expand Down Expand Up @@ -109,7 +106,7 @@ open class Core: UIObject, UIGestureRecognizerDelegate {
open func attach(to parentView: UIView, controller: UIViewController) {
self.parentController = controller
self.parentView = parentView
trigger(Event.didAttachView)
trigger(.didAttachView)
}

open override func render() {
Expand All @@ -119,35 +116,30 @@ open class Core: UIObject, UIGestureRecognizerDelegate {

#if os(tvOS)
private func renderPlugins() {
plugins.forEach { plugin in
render(plugin)
}
plugins.forEach(render)
}
#endif

#if os(iOS)
private func renderCoreAndMediaControlPlugins() {
renderCorePlugins()
renderMediaControlPlugins()
}

private func renderCorePlugins() {
plugins.filter { isNotMediaControlPlugin($0) }.forEach { plugin in
render(plugin)
}
plugins.filter(isNotMediaControlElement).forEach(render)
}

private func renderMediaControlPlugins() {
let mediaControl = plugins.first { $0 is MediaControl }
private var mediaControl: MediaControl? {
return plugins.first { $0 is MediaControl } as? MediaControl
}

if let mediaControl = mediaControl as? MediaControl {
let mediaControlPlugins = plugins.compactMap { $0 as? MediaControlPlugin }
mediaControl.renderPlugins(mediaControlPlugins)
}
private var mediaControlElements: [MediaControl.Element] {
return plugins.compactMap { $0 as? MediaControl.Element }
}

private func renderMediaControlElements() {
mediaControl?.renderElements(mediaControlElements)
}

private func isNotMediaControlPlugin(_ plugin: Plugin) -> Bool {
return !(plugin is MediaControlPlugin)
private func isNotMediaControlElement(_ plugin: Plugin) -> Bool {
return !(plugin is MediaControl.Element)
}
#endif

Expand All @@ -164,14 +156,18 @@ open class Core: UIObject, UIGestureRecognizerDelegate {
}
}

private var shouldEnterInFullScreen: Bool {
return optionsUnboxer.fullscreen && !optionsUnboxer.fullscreenControledByApp
}

fileprivate func addToContainer() {
#if os(iOS)
if optionsUnboxer.fullscreen && !optionsUnboxer.fullscreenControledByApp {
renderCoreAndMediaControlPlugins()
renderCorePlugins()
renderMediaControlElements()
if shouldEnterInFullScreen {
fullscreenHandler?.enterInFullscreen()
} else {
renderInContainerView()
renderCoreAndMediaControlPlugins()
}
#else
renderInContainerView()
Expand All @@ -197,25 +193,17 @@ open class Core: UIObject, UIGestureRecognizerDelegate {
@objc open func destroy() {
Logger.logDebug("destroying", scope: "Core")

trigger(Event.willDestroy.rawValue)
trigger(.willDestroy)

Logger.logDebug("destroying listeners", scope: "Core")
stopListening()

Logger.logDebug("destroying containers", scope: "Core")
containers.forEach { container in container.destroy() }
containers.forEach { $0.destroy() }
containers.removeAll()

Logger.logDebug("destroying plugins", scope: "Core")
plugins.forEach { plugin in
do {
try ObjC.catchException {
plugin.destroy()
}
} catch {
Logger.logError("\((plugin as Plugin).pluginName) crashed during destroy (\(error.localizedDescription))", scope: "Core")
}
}
plugins.forEach(safeDestroy)
plugins.removeAll()

Logger.logDebug("destroyed", scope: "Core")
Expand All @@ -227,6 +215,16 @@ open class Core: UIObject, UIGestureRecognizerDelegate {
#endif
view.removeFromSuperview()

trigger(Event.didDestroy.rawValue)
trigger(.didDestroy)
}

private func safeDestroy(_ plugin: Plugin) {
do {
try ObjC.catchException {
plugin.destroy()
}
} catch {
Logger.logError("\((plugin as Plugin).pluginName) crashed during destroy (\(error.localizedDescription))", scope: "Core")
}
}
}
8 changes: 4 additions & 4 deletions Sources/Clappr/Classes/Base/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ public let kDefaultAudioSource = "defaultAudioSource"
public let kMinDvrSize = "minDvrSize"
public let kMediaControlAlwaysVisible = "mediaControlAlwaysVisible"

// List of MediaControl Plugins
public let kMediaControlPlugins = "mediaControlPlugins"
// Order of MediaControl Plugins
public let kMediaControlPluginsOrder = "mediaControlPluginsOrder"
// List of MediaControl Elements
public let kMediaControlElements = "mediaControlElements"
// Order of MediaControl Elements
public let kMediaControlElementsOrder = "mediaControlElementsOrder"

public let kLoop = "loop"
public let kMetaData = "metadata"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
open class FullscreenButton: MediaControlPlugin {
open class FullscreenButton: MediaControl.Element {
public var fullscreenIcon = UIImage.fromName("fullscreen", for: FullscreenButton.self)
public var windowedIcon = UIImage.fromName("fullscreen_exit", for: FullscreenButton.self)

Expand Down
Loading

0 comments on commit 5fee47c

Please sign in to comment.