Skip to content

Commit 8017361

Browse files
committed
code optimization
1 parent f755c3c commit 8017361

File tree

7 files changed

+109
-30
lines changed

7 files changed

+109
-30
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ Please note that using videos from URLs requires ensuring that you have the righ
2020

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

2828
### Playback Commands
2929

@@ -71,7 +71,7 @@ or in a declarative way
7171

7272
```swift
7373
LoopPlayerView{
74-
Settings{
74+
VideoSettings{
7575
SourceName("swipe")
7676
Ext("mp8") // Set default extension here If not provided then mp4 is default
7777
Gravity(.resizeAspectFill)
@@ -85,7 +85,7 @@ or in a declarative way
8585
8686
```swift
8787
LoopPlayerView{
88-
Settings{
88+
VideoSettings{
8989
SourceName("swipe")
9090
Gravity(.resizeAspectFill)
9191
EFontSize(27)
@@ -95,7 +95,7 @@ or in a declarative way
9595

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

129129
```swift
130130
LoopPlayerView{
131-
Settings{
131+
VideoSettings{
132132
SourceName('https://example.com/video')
133133
Gravity(.resizeAspectFill) // Video content fit
134134
ErrorGroup{
@@ -160,7 +160,7 @@ struct VideoView: View {
160160
var body: some View {
161161
LoopPlayerView(
162162
{
163-
Settings {
163+
VideoSettings {
164164
SourceName("swipe")
165165
}
166166
},

Sources/swiftui-loop-videoplayer/LoopPlayerView.swift

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import AVKit
1515
public struct LoopPlayerView: View {
1616

1717
/// Set of settings for video the player
18-
public let settings: Settings
18+
@Binding public var settings: VideoSettings
1919

2020
/// Binding to a playback command that controls playback actions
2121
@Binding public var command: PlaybackCommand
@@ -44,7 +44,8 @@ public struct LoopPlayerView: View {
4444
) {
4545
self._command = command
4646

47-
settings = Settings {
47+
_settings = .constant(
48+
VideoSettings {
4849
SourceName(fileName)
4950
Ext(ext)
5051
Gravity(gravity)
@@ -53,25 +54,38 @@ public struct LoopPlayerView: View {
5354
EFontSize(eFontSize)
5455
}
5556
}
57+
)
5658
}
5759

5860
/// Player initializer in a declarative way
5961
/// - Parameters:
6062
/// - settings: Set of settings
6163
/// - command: A binding to control playback actions
6264
public init(
63-
_ settings: () -> Settings,
65+
_ settings: () -> VideoSettings,
6466
command: Binding<PlaybackCommand> = .constant(.play)
6567
) {
68+
69+
self._command = command
70+
_settings = .constant(settings())
71+
}
72+
73+
/// Player initializer in a declarative way
74+
/// - Parameters:
75+
/// - settings: A binding to the set of settings for the video player
76+
/// - command: A binding to control playback actions
77+
public init(
78+
settings: Binding<VideoSettings>,
79+
command: Binding<PlaybackCommand> = .constant(.play)
80+
) {
81+
self._settings = settings
6682
self._command = command
67-
self.settings = settings()
6883
}
6984

7085
// MARK: - API
7186

7287
public var body: some View {
73-
LoopPlayerMultiPlatform(settings: settings, command: $command)
88+
LoopPlayerMultiPlatform(settings: $settings, command: $command)
7489
.frame(maxWidth: .infinity, maxHeight: .infinity)
75-
.id(videoId)
7690
}
7791
}

Sources/swiftui-loop-videoplayer/fn/fn+.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func cleanUp(player: inout AVQueuePlayer?, playerLooper: inout AVPlayerLooper?,
7373
/// - settings: The settings for the video player.
7474
/// - asset: The asset for the video player.
7575
/// - Returns: The detected error or nil if no error.
76-
func detectError(settings: Settings, asset: AVURLAsset?) -> VPErrors? {
76+
func detectError(settings: VideoSettings, asset: AVURLAsset?) -> VPErrors? {
7777
if !settings.areUnique {
7878
return .settingsNotUnique
7979
} else if asset == nil {

Sources/swiftui-loop-videoplayer/protocol/view/LoopPlayerViewProtocol.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@ public protocol LoopPlayerViewProtocol {
3333
#endif
3434

3535
/// Settings for configuring the video player.
36-
var settings: Settings { get }
36+
var settings: VideoSettings { get set }
3737

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

4747
}
4848

Sources/swiftui-loop-videoplayer/protocol/view/LoopingPlayerProtocol.swift

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,47 @@ public protocol LoopingPlayerProtocol: AbstractPlayer {
7070
}
7171

7272
extension LoopingPlayerProtocol {
73-
73+
74+
/// The current asset being played, if available.
75+
///
76+
/// This computed property checks the current item of the player.
77+
/// If the current item exists and its asset can be cast to AVURLAsset,
78+
var currentAsset : AVURLAsset?{
79+
if let currentItem = player?.currentItem {
80+
return currentItem.asset as? AVURLAsset
81+
}
82+
return nil
83+
}
84+
85+
/// Updates the player to play a new asset and handles the playback state.
86+
///
87+
/// This method pauses the player if it was previously playing,
88+
/// replaces the current player item with a new item created from the provided asset,
89+
/// and seeks to the start of the new item. It resumes playing if the player was playing before the update.
90+
///
91+
/// - Parameters:
92+
/// - asset: The AVURLAsset to load into the player.
93+
func update(asset: AVURLAsset){
94+
// Optionally, check if the player is currently playing
95+
let wasPlaying = player?.rate != 0
96+
97+
// Pause the player if it was playing
98+
if wasPlaying {
99+
player?.pause()
100+
}
101+
102+
// Replace the current item with a new item created from the asset
103+
let newItem = AVPlayerItem(asset: asset)
104+
player?.replaceCurrentItem(with: newItem)
105+
106+
// Seek to the beginning of the item if you want to start from the start
107+
player?.seek(to: .zero, completionHandler: { _ in
108+
// Resume playing if the player was playing before
109+
if wasPlaying {
110+
self.player?.play()
111+
}
112+
})
113+
}
74114

75115
/// Sets up the player components using the provided asset and video gravity.
76116
///

Sources/swiftui-loop-videoplayer/utils/Settings.swift renamed to Sources/swiftui-loop-videoplayer/utils/VideoSettings.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import SwiftUI
99
import AVKit
1010

1111
@available(iOS 14.0, macOS 11.0, tvOS 14.0, *)
12-
public struct Settings: Equatable{
12+
public struct VideoSettings: Equatable{
1313

1414
// MARK: - Public properties
1515

Sources/swiftui-loop-videoplayer/view/loop/main/LoopPlayerMultiPlatform.swift

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ struct LoopPlayerMultiPlatform: LoopPlayerViewProtocol {
4040
@Binding public var command : PlaybackCommand
4141

4242
/// Settings for the player view
43-
public let settings: Settings
44-
45-
/// The video asset to be played.
46-
private let asset: AVURLAsset?
47-
43+
@Binding public var settings: VideoSettings
44+
4845
/// State to store any error that occurs
4946
@State private var error: VPErrors?
47+
48+
var asset : AVURLAsset?{
49+
assetForName(name: settings.name, ext: settings.ext)
50+
}
5051

5152
/// Initializes a new instance with the provided settings and playback command.
5253
///
@@ -55,11 +56,12 @@ struct LoopPlayerMultiPlatform: LoopPlayerViewProtocol {
5556
/// - command: A binding to a `PlaybackCommand` that controls playback actions.
5657
///
5758
/// This initializer sets up the necessary configuration and command bindings for playback functionality.
58-
init(settings: Settings, command: Binding<PlaybackCommand>) {
59-
self.settings = settings
59+
init(settings: Binding<VideoSettings>, command: Binding<PlaybackCommand>) {
60+
self._settings = settings
6061
self._command = command
61-
self.asset = assetForName(name: settings.name, ext: settings.ext)
62-
self._error = State(initialValue: detectError(settings: settings, asset: self.asset))
62+
let settings = settings.wrappedValue
63+
let asset = assetForName(name: settings.name, ext: settings.ext)
64+
self._error = State(initialValue: detectError(settings: settings, asset: asset))
6365
}
6466

6567

@@ -109,7 +111,7 @@ extension LoopPlayerMultiPlatform: NSViewRepresentable{
109111
/// - Returns: A fully configured NSView containing both the media player and potentially an error message display.
110112
@MainActor func makeNSView(context: Context) -> NSView {
111113
let container = NSView()
112-
114+
113115
if let player: PlayerView = makePlayerView(
114116
container,
115117
asset: asset){
@@ -128,9 +130,32 @@ extension LoopPlayerMultiPlatform: NSViewRepresentable{
128130
@MainActor func updateNSView(_ nsView: NSView, context: Context) {
129131
nsView.subviews.filter { $0 is ErrorView }.forEach { $0.removeFromSuperview() }
130132

131-
nsView.subviews.compactMap{ $0 as? LoopingPlayerProtocol }.forEach { $0.setCommand(command) }
133+
nsView.subviews.compactMap{ $0 as? LoopingPlayerProtocol }.forEach {
134+
if let asset = getAssetIfChanged(settings: settings, asset: $0.currentAsset){
135+
$0.update(asset: asset)
136+
}else{
137+
$0.setCommand(command)
138+
}
139+
}
132140

133141
updateView(nsView, error: error)
134142
}
135143
}
136144
#endif
145+
146+
fileprivate func getAssetIfChanged(settings: VideoSettings, asset: AVURLAsset?) -> AVURLAsset?{
147+
let a = assetForName(name: settings.name, ext: settings.ext)
148+
149+
guard asset != nil else{
150+
return a
151+
}
152+
153+
if let newUrl = a?.url, let oldUrl = asset?.url, newUrl != oldUrl{
154+
return a
155+
}
156+
157+
return nil
158+
}
159+
160+
161+

0 commit comments

Comments
 (0)