Skip to content

Commit e14dc31

Browse files
committed
update
1 parent cd5cf3d commit e14dc31

File tree

4 files changed

+158
-119
lines changed

4 files changed

+158
-119
lines changed

swiftui-loop-videoplayer-example.xcodeproj/project.pbxproj

+6-2
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,9 @@
394394
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
395395
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
396396
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
397-
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
397+
INFOPLIST_KEY_UIStatusBarStyle = UIStatusBarStyleDarkContent;
398+
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
399+
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
398400
LD_RUNPATH_SEARCH_PATHS = (
399401
"$(inherited)",
400402
"@executable_path/Frameworks",
@@ -423,7 +425,9 @@
423425
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
424426
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
425427
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
426-
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
428+
INFOPLIST_KEY_UIStatusBarStyle = UIStatusBarStyleDarkContent;
429+
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
430+
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
427431
LD_RUNPATH_SEARCH_PATHS = (
428432
"$(inherited)",
429433
"@executable_path/Frameworks",

swiftui-loop-videoplayer-example/ContentView.swift

+43-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct ContentView: View {
1919
var body: some View {
2020
NavigationStack{
2121
ZStack{
22-
VStack{
22+
ResponsiveStack(spacing: 5) {
2323
Spacer()
2424
NavigationLink(destination: Video(fileName: $fileName))
2525
{
@@ -64,8 +64,6 @@ struct ContentView: View {
6464
Video2()
6565
.overlay(hintTitleTpl, alignment: .topLeading)
6666
}
67-
68-
6967
}
7068

7169
@ViewBuilder
@@ -79,7 +77,6 @@ struct ContentView: View {
7977
.padding()
8078
}.foregroundColor(.orange)
8179
.font(.system(size: 70))
82-
.fontWeight(.thin)
8380
Spacer()
8481
}
8582
.padding(.top, 50)
@@ -88,7 +85,7 @@ struct ContentView: View {
8885
@ViewBuilder
8986
private func labelTpl(_ name : String, color : Color = .blue) -> some View{
9087
Image(systemName: name)
91-
.font(.system(size: 78))
88+
.font(.system(size: 68))
9289
.padding(8)
9390
.foregroundColor(color)
9491
.frame(width: 102)
@@ -110,13 +107,19 @@ struct Video1 : View{
110107

111108
var body: some View{
112109
GeometryReader{ proxy in
113-
let width = min(proxy.size.width / 1.5, videoWidth)
114-
let ratio = width / videoWidth
115-
let length = videoWidth * ratio
110+
let orient = proxy.size.height > proxy.size.width
111+
let width = orient ? min(proxy.size.width / 1.5, videoWidth) : min(proxy.size.height / 1.5, videoHeight)
112+
let ratio = orient ? width / videoWidth : width / videoHeight
113+
let length = orient ? videoWidth * ratio : videoHeight * ratio
116114
VStack{
117115
Spacer()
118-
LoopPlayerView(fileName : fileName)
119-
.frame(width: videoWidth * ratio, height: videoHeight * ratio)
116+
if orient{
117+
LoopPlayerView(fileName : fileName)
118+
.frame(width: videoWidth * ratio, height: videoHeight * ratio)
119+
}else{
120+
LoopPlayerView(fileName : fileName)
121+
.frame(width: videoHeight * ratio, height: videoHeight * ratio)
122+
}
120123
Spacer()
121124
}.offset(x : proxy.size.width - length)
122125
}
@@ -239,3 +242,33 @@ fileprivate struct CustomButtonStyle: ButtonStyle {
239242
.scaleEffect(configuration.isPressed ? 0.9 : 1.0)
240243
}
241244
}
245+
246+
struct ResponsiveStack<Content: View>: View {
247+
248+
let spacing : CGFloat
249+
250+
@ViewBuilder let content: Content
251+
252+
var body: some View {
253+
GeometryReader { geometry in
254+
if geometry.size.width > geometry.size.height {
255+
// Landscape mode
256+
HStack(alignment: .center, spacing: spacing) {
257+
Spacer()
258+
content
259+
Spacer()
260+
}
261+
.frame(width: geometry.size.width, height: geometry.size.height)
262+
} else {
263+
// Portrait mode
264+
VStack(alignment: .center, spacing: spacing) {
265+
Spacer()
266+
content
267+
Spacer()
268+
}
269+
.frame(width: geometry.size.width, height: geometry.size.height)
270+
}
271+
}
272+
.frame(maxWidth: .infinity, maxHeight: .infinity)
273+
}
274+
}

swiftui-loop-videoplayer-example/Info.plist

+15-15
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
44
<dict>
5-
<key>NSAppTransportSecurity</key>
6-
<dict>
7-
<key>NSExceptionDomains</key>
8-
<dict>
9-
<key>commondatastorage.googleapis.com</key>
10-
<dict>
11-
<key>NSIncludesSubdomains</key>
12-
<true/>
13-
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
14-
<true/>
15-
<key>NSTemporaryExceptionMinimumTLSVersion</key>
16-
<string>TLSv1.0</string>
17-
</dict>
18-
</dict>
19-
</dict>
5+
<key>NSAppTransportSecurity</key>
6+
<dict>
7+
<key>NSExceptionDomains</key>
8+
<dict>
9+
<key>commondatastorage.googleapis.com</key>
10+
<dict>
11+
<key>NSIncludesSubdomains</key>
12+
<true/>
13+
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
14+
<true/>
15+
<key>NSTemporaryExceptionMinimumTLSVersion</key>
16+
<string>TLSv1.0</string>
17+
</dict>
18+
</dict>
19+
</dict>
2020
</dict>
2121
</plist>

swiftui-loop-videoplayer-example/views/Video6.swift

+94-92
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct Video6: View {
4141
}
4242

4343
var body: some View {
44-
VStack {
44+
ResponsiveStack(spacing : 0) {
4545
LoopPlayerView(
4646
settings : $settings,
4747
command: $playbackCommand
@@ -51,105 +51,107 @@ struct Video6: View {
5151
updatePlayingState(for: value)
5252
}
5353

54-
// Control Buttons
55-
HStack {
56-
// Button to move playback to the beginning and pause
57-
makeButton(action: {
58-
playbackCommand = .begin
59-
pause()
60-
}, imageName: "backward.end.fill")
61-
62-
// Button to play the video
63-
makeButton(action: {
64-
playbackCommand = .play
65-
}, imageName: "play.fill", backgroundColor: isPlaying ? .gray : .blue)
66-
.disabled(isPlaying)
67-
68-
// Button to pause the video
69-
makeButton(action: {
70-
playbackCommand = .pause
71-
}, imageName: "pause.fill", backgroundColor: isPlaying ? .blue : .gray)
72-
.disabled(!isPlaying)
73-
74-
// Button to seek back 10 seconds in the video and pause
75-
makeButton(action: {
76-
playbackCommand = .seek(to: 2.0)
77-
pause()
78-
}, imageName: "gobackward.10")
79-
80-
// Button to move playback to the end and pause
81-
makeButton(action: {
82-
playbackCommand = .end
83-
pause()
84-
}, imageName: "forward.end.fill")
85-
86-
// Button to toggle mute and unmute
87-
makeButton(action: {
88-
isMuted.toggle()
89-
playbackCommand = isMuted ? .mute : .unmute
90-
}, imageName: isMuted ? "speaker.slash.fill" : "speaker.2.fill")
91-
Spacer()
92-
}
93-
.padding()
94-
HStack {
95-
// Button to add a vector graphic layer over the video
96-
makeButton(action: {
97-
playbackCommand = .addVector(VectorLogoLayer())
98-
isLogoAdded.toggle()
99-
}, imageName: "diamond.fill", backgroundColor: isLogoAdded ? .gray : .blue )
100-
.disabled(isLogoAdded)
101-
102-
// Button to remove all vector graphic layers from the video
103-
makeButton(action: {
104-
playbackCommand = .removeAllVectors
105-
isLogoAdded.toggle()
106-
}, imageName: "diamond", backgroundColor: isLogoAdded ? .blue : .gray )
107-
.disabled(!isLogoAdded)
108-
Spacer()
109-
// Segmented Control for Filters
110-
Picker("Select Filter", selection: $selectedFilterIndex) {
111-
ForEach(0..<filters.count, id: \.self) { index in
112-
Text(self.filters[index].0).tag(index)
113-
}
114-
}
115-
.pickerStyle(.menu)
116-
.onChange(of: selectedFilterIndex) { newIndex in
117-
// Apply the selected filter
118-
let filter = filters[newIndex]
119-
print(filter.0)
120-
if filter.0 == "None" {
121-
playbackCommand = .removeAllFilters
122-
return
123-
}else if let filter = CIFilter(name: filter.0, parameters: filter.1) {
124-
playbackCommand = .filter(filter, clear: true)
125-
}else{
126-
let filter = ArtFilter()
127-
playbackCommand = .filter(filter, clear: true)
128-
}
54+
VStack(alignment : .leading) {
55+
// Control Buttons
56+
HStack {
57+
// Button to move playback to the beginning and pause
58+
makeButton(action: {
59+
playbackCommand = .begin
60+
pause()
61+
}, imageName: "backward.end.fill")
62+
63+
// Button to play the video
64+
makeButton(action: {
65+
playbackCommand = .play
66+
}, imageName: "play.fill", backgroundColor: isPlaying ? .gray : .blue)
67+
.disabled(isPlaying)
68+
69+
// Button to pause the video
70+
makeButton(action: {
71+
playbackCommand = .pause
72+
}, imageName: "pause.fill", backgroundColor: isPlaying ? .blue : .gray)
73+
.disabled(!isPlaying)
74+
75+
// Button to seek back 10 seconds in the video and pause
76+
makeButton(action: {
77+
playbackCommand = .seek(to: 2.0)
78+
pause()
79+
}, imageName: "gobackward.10")
80+
81+
// Button to move playback to the end and pause
82+
makeButton(action: {
83+
playbackCommand = .end
84+
pause()
85+
}, imageName: "forward.end.fill")
86+
87+
// Button to toggle mute and unmute
88+
makeButton(action: {
89+
isMuted.toggle()
90+
playbackCommand = isMuted ? .mute : .unmute
91+
}, imageName: isMuted ? "speaker.slash.fill" : "speaker.2.fill")
92+
Spacer()
12993
}
130-
}
131-
.padding(.horizontal)
132-
133-
/// Brightness and Contrast: These settings function also filters but are managed separately from the filter stack. Adjustments to brightness and contrast are applied additionally and independently of the image filters.
134-
/// Independent Management: Developers should manage brightness and contrast adjustments through their dedicated methods or properties to ensure these settings are accurately reflected in the video output.
135-
VStack {
94+
.padding()
13695
HStack {
137-
Text("Brightness")
138-
Slider(value: $brightness, in: 0.0...1.0, step: 0.1) { _ in
139-
playbackCommand = .brightness(brightness)
96+
// Button to add a vector graphic layer over the video
97+
makeButton(action: {
98+
playbackCommand = .addVector(VectorLogoLayer())
99+
isLogoAdded.toggle()
100+
}, imageName: "diamond.fill", backgroundColor: isLogoAdded ? .gray : .blue )
101+
.disabled(isLogoAdded)
102+
103+
// Button to remove all vector graphic layers from the video
104+
makeButton(action: {
105+
playbackCommand = .removeAllVectors
106+
isLogoAdded.toggle()
107+
}, imageName: "diamond", backgroundColor: isLogoAdded ? .blue : .gray )
108+
.disabled(!isLogoAdded)
109+
Spacer()
110+
// Segmented Control for Filters
111+
Picker("Select Filter", selection: $selectedFilterIndex) {
112+
ForEach(0..<filters.count, id: \.self) { index in
113+
Text(self.filters[index].0).tag(index)
114+
}
115+
}
116+
.pickerStyle(.menu)
117+
.onChange(of: selectedFilterIndex) { newIndex in
118+
// Apply the selected filter
119+
let filter = filters[newIndex]
120+
print(filter.0)
121+
if filter.0 == "None" {
122+
playbackCommand = .removeAllFilters
123+
return
124+
}else if let filter = CIFilter(name: filter.0, parameters: filter.1) {
125+
playbackCommand = .filter(filter, clear: true)
126+
}else{
127+
let filter = ArtFilter()
128+
playbackCommand = .filter(filter, clear: true)
129+
}
140130
}
141-
.padding()
142131
}
132+
.padding(.horizontal)
143133

144-
HStack {
145-
Text("Contrast")
146-
Slider(value: $contrast, in: 1.0...2.0, step: 0.1) { _ in
147-
playbackCommand = .contrast(contrast)
134+
/// Brightness and Contrast: These settings function also filters but are managed separately from the filter stack. Adjustments to brightness and contrast are applied additionally and independently of the image filters.
135+
/// Independent Management: Developers should manage brightness and contrast adjustments through their dedicated methods or properties to ensure these settings are accurately reflected in the video output.
136+
VStack {
137+
HStack {
138+
Text("Brightness")
139+
Slider(value: $brightness, in: 0.0...1.0, step: 0.1) { _ in
140+
playbackCommand = .brightness(brightness)
141+
}
142+
.padding()
143+
}
144+
145+
HStack {
146+
Text("Contrast")
147+
Slider(value: $contrast, in: 1.0...2.0, step: 0.1) { _ in
148+
playbackCommand = .contrast(contrast)
149+
}
150+
.padding(.horizontal)
148151
}
149-
.padding()
150152
}
153+
.padding(.horizontal)
151154
}
152-
.padding()
153155
}
154156
}
155157

0 commit comments

Comments
 (0)