Skip to content

Commit

Permalink
code optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
swiftuiux committed Aug 8, 2024
1 parent f755c3c commit 8017361
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 30 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ Please note that using videos from URLs requires ensuring that you have the righ

| Property/Method | Type | Description |
|---------------------------------------|-------------------------------|------------------------------------------------------------------------|
| `settings` | `Settings` | A struct containing configuration settings for the video player. |
| `settings` | `VideoSettings` | A struct containing configuration settings for the video player. |
| `command` | `Binding<PlaybackCommand>` | A binding to control playback actions (play, pause, or seek). |
| `init(fileName:ext:gravity:` <br> `eColor:eFontSize:command:)` | Constructor | Initializes the player with specific video parameters and playback command binding. |
| `init(settings: () -> Settings, command:)` | Constructor | Initializes the player with a declarative settings block and playback command binding. |
| `init(settings: () -> VideoSettings, command:)` | Constructor | Initializes the player with a declarative settings block and playback command binding. |

### Playback Commands

Expand Down Expand Up @@ -71,7 +71,7 @@ or in a declarative way

```swift
LoopPlayerView{
Settings{
VideoSettings{
SourceName("swipe")
Ext("mp8") // Set default extension here If not provided then mp4 is default
Gravity(.resizeAspectFill)
Expand All @@ -85,7 +85,7 @@ or in a declarative way
```swift
LoopPlayerView{
Settings{
VideoSettings{
SourceName("swipe")
Gravity(.resizeAspectFill)
EFontSize(27)
Expand All @@ -95,7 +95,7 @@ or in a declarative way

```swift
LoopPlayerView{
Settings{
VideoSettings{
SourceName('https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_ts/master.m3u8')
ErrorGroup{
EFontSize(27)
Expand Down Expand Up @@ -128,7 +128,7 @@ The package now supports using remote video URLs, allowing you to stream videos

```swift
LoopPlayerView{
Settings{
VideoSettings{
SourceName('https://example.com/video')
Gravity(.resizeAspectFill) // Video content fit
ErrorGroup{
Expand Down Expand Up @@ -160,7 +160,7 @@ struct VideoView: View {
var body: some View {
LoopPlayerView(
{
Settings {
VideoSettings {
SourceName("swipe")
}
},
Expand Down
26 changes: 20 additions & 6 deletions Sources/swiftui-loop-videoplayer/LoopPlayerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import AVKit
public struct LoopPlayerView: View {

/// Set of settings for video the player
public let settings: Settings
@Binding public var settings: VideoSettings

/// Binding to a playback command that controls playback actions
@Binding public var command: PlaybackCommand
Expand Down Expand Up @@ -44,7 +44,8 @@ public struct LoopPlayerView: View {
) {
self._command = command

settings = Settings {
_settings = .constant(
VideoSettings {
SourceName(fileName)
Ext(ext)
Gravity(gravity)
Expand All @@ -53,25 +54,38 @@ public struct LoopPlayerView: View {
EFontSize(eFontSize)
}
}
)
}

/// Player initializer in a declarative way
/// - Parameters:
/// - settings: Set of settings
/// - command: A binding to control playback actions
public init(
_ settings: () -> Settings,
_ settings: () -> VideoSettings,
command: Binding<PlaybackCommand> = .constant(.play)
) {

self._command = command
_settings = .constant(settings())
}

/// Player initializer in a declarative way
/// - Parameters:
/// - settings: A binding to the set of settings for the video player
/// - command: A binding to control playback actions
public init(
settings: Binding<VideoSettings>,
command: Binding<PlaybackCommand> = .constant(.play)
) {
self._settings = settings
self._command = command
self.settings = settings()
}

// MARK: - API

public var body: some View {
LoopPlayerMultiPlatform(settings: settings, command: $command)
LoopPlayerMultiPlatform(settings: $settings, command: $command)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.id(videoId)
}
}
2 changes: 1 addition & 1 deletion Sources/swiftui-loop-videoplayer/fn/fn+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func cleanUp(player: inout AVQueuePlayer?, playerLooper: inout AVPlayerLooper?,
/// - settings: The settings for the video player.
/// - asset: The asset for the video player.
/// - Returns: The detected error or nil if no error.
func detectError(settings: Settings, asset: AVURLAsset?) -> VPErrors? {
func detectError(settings: VideoSettings, asset: AVURLAsset?) -> VPErrors? {
if !settings.areUnique {
return .settingsNotUnique
} else if asset == nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ public protocol LoopPlayerViewProtocol {
#endif

/// Settings for configuring the video player.
var settings: Settings { get }
var settings: VideoSettings { get set }

/// Initializes a new instance with the provided settings and playback command.
///
/// - Parameters:
/// - settings: An instance of `Settings` containing configuration details.
/// - settings: A binding to a `VideoSettings` containing configuration details.
/// - command: A binding to a `PlaybackCommand` that controls playback actions.
///
/// This initializer sets up the necessary configuration and command bindings for playback functionality.
init(settings: Settings, command: Binding<PlaybackCommand>)
init(settings: Binding<VideoSettings>, command: Binding<PlaybackCommand>)

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,47 @@ public protocol LoopingPlayerProtocol: AbstractPlayer {
}

extension LoopingPlayerProtocol {


/// The current asset being played, if available.
///
/// This computed property checks the current item of the player.
/// If the current item exists and its asset can be cast to AVURLAsset,
var currentAsset : AVURLAsset?{
if let currentItem = player?.currentItem {
return currentItem.asset as? AVURLAsset
}
return nil
}

/// Updates the player to play a new asset and handles the playback state.
///
/// This method pauses the player if it was previously playing,
/// replaces the current player item with a new item created from the provided asset,
/// and seeks to the start of the new item. It resumes playing if the player was playing before the update.
///
/// - Parameters:
/// - asset: The AVURLAsset to load into the player.
func update(asset: AVURLAsset){
// Optionally, check if the player is currently playing
let wasPlaying = player?.rate != 0

// Pause the player if it was playing
if wasPlaying {
player?.pause()
}

// Replace the current item with a new item created from the asset
let newItem = AVPlayerItem(asset: asset)
player?.replaceCurrentItem(with: newItem)

// Seek to the beginning of the item if you want to start from the start
player?.seek(to: .zero, completionHandler: { _ in
// Resume playing if the player was playing before
if wasPlaying {
self.player?.play()
}
})
}

/// Sets up the player components using the provided asset and video gravity.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SwiftUI
import AVKit

@available(iOS 14.0, macOS 11.0, tvOS 14.0, *)
public struct Settings: Equatable{
public struct VideoSettings: Equatable{

// MARK: - Public properties

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ struct LoopPlayerMultiPlatform: LoopPlayerViewProtocol {
@Binding public var command : PlaybackCommand

/// Settings for the player view
public let settings: Settings

/// The video asset to be played.
private let asset: AVURLAsset?

@Binding public var settings: VideoSettings

/// State to store any error that occurs
@State private var error: VPErrors?

var asset : AVURLAsset?{
assetForName(name: settings.name, ext: settings.ext)
}

/// Initializes a new instance with the provided settings and playback command.
///
Expand All @@ -55,11 +56,12 @@ struct LoopPlayerMultiPlatform: LoopPlayerViewProtocol {
/// - command: A binding to a `PlaybackCommand` that controls playback actions.
///
/// This initializer sets up the necessary configuration and command bindings for playback functionality.
init(settings: Settings, command: Binding<PlaybackCommand>) {
self.settings = settings
init(settings: Binding<VideoSettings>, command: Binding<PlaybackCommand>) {
self._settings = settings
self._command = command
self.asset = assetForName(name: settings.name, ext: settings.ext)
self._error = State(initialValue: detectError(settings: settings, asset: self.asset))
let settings = settings.wrappedValue
let asset = assetForName(name: settings.name, ext: settings.ext)
self._error = State(initialValue: detectError(settings: settings, asset: asset))
}


Expand Down Expand Up @@ -109,7 +111,7 @@ extension LoopPlayerMultiPlatform: NSViewRepresentable{
/// - Returns: A fully configured NSView containing both the media player and potentially an error message display.
@MainActor func makeNSView(context: Context) -> NSView {
let container = NSView()

if let player: PlayerView = makePlayerView(
container,
asset: asset){
Expand All @@ -128,9 +130,32 @@ extension LoopPlayerMultiPlatform: NSViewRepresentable{
@MainActor func updateNSView(_ nsView: NSView, context: Context) {
nsView.subviews.filter { $0 is ErrorView }.forEach { $0.removeFromSuperview() }

nsView.subviews.compactMap{ $0 as? LoopingPlayerProtocol }.forEach { $0.setCommand(command) }
nsView.subviews.compactMap{ $0 as? LoopingPlayerProtocol }.forEach {
if let asset = getAssetIfChanged(settings: settings, asset: $0.currentAsset){
$0.update(asset: asset)
}else{
$0.setCommand(command)
}
}

updateView(nsView, error: error)
}
}
#endif

fileprivate func getAssetIfChanged(settings: VideoSettings, asset: AVURLAsset?) -> AVURLAsset?{
let a = assetForName(name: settings.name, ext: settings.ext)

guard asset != nil else{
return a
}

if let newUrl = a?.url, let oldUrl = asset?.url, newUrl != oldUrl{
return a
}

return nil
}



0 comments on commit 8017361

Please sign in to comment.