Skip to content

Commit

Permalink
[iOS] Completion doesn't work for videos in PiP mode. (#414)
Browse files Browse the repository at this point in the history
* chore: player refactor

* chore: removed url property

* chore: fixed completion and rate view for player

* chore: removed commented code

* chore: added error handler

* chore: refactor

* chore: refactor

* chore: refactor

* chore: refactor

* chore: refactor

* chore: tests

* chore: refactor

* chore: review requested changes

* chore: merge conflict resolve
  • Loading branch information
forgotvas authored May 16, 2024
1 parent 353f8a0 commit 32bf7d9
Show file tree
Hide file tree
Showing 20 changed files with 1,145 additions and 596 deletions.
13 changes: 13 additions & 0 deletions Core/Core/Data/Model/UserSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ public enum StreamingQuality: Codable {
public var value: String? {
return String(describing: self).components(separatedBy: "(").first
}

public var resolution: CGSize {
switch self {
case .auto:
return CGSize(width: 1280, height: 720)
case .low:
return CGSize(width: 640, height: 360)
case .medium:
return CGSize(width: 854, height: 480)
case .high:
return CGSize(width: 1280, height: 720)
}
}
}

public enum DownloadQuality: Codable, CaseIterable {
Expand Down
32 changes: 28 additions & 4 deletions Course/Course.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,20 @@
02D4FC2E2BBD7C9C00C47748 /* MessageSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D4FC2D2BBD7C9C00C47748 /* MessageSectionView.swift */; };
02F0144F28F46474002E513D /* CourseContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F0144E28F46474002E513D /* CourseContainerView.swift */; };
02F0145728F4A2FF002E513D /* CourseContainerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F0145628F4A2FF002E513D /* CourseContainerViewModel.swift */; };
02F066E829DC71750073E13B /* SubtittlesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F066E729DC71750073E13B /* SubtittlesView.swift */; };
02F3BFDD29252E900051930C /* CourseRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F3BFDC29252E900051930C /* CourseRouter.swift */; };
02F78AEB29E6BCA20038DE30 /* VideoPlayerViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F78AEA29E6BCA20038DE30 /* VideoPlayerViewModelTests.swift */; };
02F98A8128F8224200DE94C0 /* Discussion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02F98A8028F8224200DE94C0 /* Discussion.framework */; };
02FCB2B32BBEB36600373180 /* CourseHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02FCB2B22BBEB36600373180 /* CourseHeaderView.swift */; };
02FFAD0D29E4347300140E46 /* VideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02FFAD0C29E4347300140E46 /* VideoPlayerViewModel.swift */; };
060E8BCA2B5FD68C0080C952 /* UnitStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 060E8BC92B5FD68C0080C952 /* UnitStack.swift */; };
065275352BB1B39C0093BCCA /* PlayerViewControllerHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 065275342BB1B39C0093BCCA /* PlayerViewControllerHolder.swift */; };
067B7B4E2BED339200D1768F /* PlayerTrackerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B7B472BED339200D1768F /* PlayerTrackerProtocol.swift */; };
067B7B4F2BED339200D1768F /* PlayerDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B7B482BED339200D1768F /* PlayerDelegateProtocol.swift */; };
067B7B502BED339200D1768F /* PlayerControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B7B492BED339200D1768F /* PlayerControllerProtocol.swift */; };
067B7B512BED339200D1768F /* PipManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B7B4A2BED339200D1768F /* PipManagerProtocol.swift */; };
067B7B522BED339200D1768F /* SubtitlesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B7B4B2BED339200D1768F /* SubtitlesView.swift */; };
067B7B532BED339200D1768F /* PlayerServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B7B4C2BED339200D1768F /* PlayerServiceProtocol.swift */; };
067B7B542BED339200D1768F /* YoutubePlayerViewControllerHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 067B7B4D2BED339200D1768F /* YoutubePlayerViewControllerHolder.swift */; };
068DDA5F2B1E198700FF8CCB /* CourseUnitDropDownList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 068DDA5B2B1E198700FF8CCB /* CourseUnitDropDownList.swift */; };
068DDA602B1E198700FF8CCB /* CourseUnitVerticalsDropdownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 068DDA5C2B1E198700FF8CCB /* CourseUnitVerticalsDropdownView.swift */; };
068DDA612B1E198700FF8CCB /* CourseUnitDropDownCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 068DDA5D2B1E198700FF8CCB /* CourseUnitDropDownCell.swift */; };
Expand Down Expand Up @@ -147,14 +153,20 @@
02ED50CF29A64BB6008341CD /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
02F0144E28F46474002E513D /* CourseContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseContainerView.swift; sourceTree = "<group>"; };
02F0145628F4A2FF002E513D /* CourseContainerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseContainerViewModel.swift; sourceTree = "<group>"; };
02F066E729DC71750073E13B /* SubtittlesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubtittlesView.swift; sourceTree = "<group>"; };
02F3BFDC29252E900051930C /* CourseRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseRouter.swift; sourceTree = "<group>"; };
02F78AEA29E6BCA20038DE30 /* VideoPlayerViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = VideoPlayerViewModelTests.swift; path = CourseTests/Presentation/Unit/VideoPlayerViewModelTests.swift; sourceTree = SOURCE_ROOT; };
02F98A8028F8224200DE94C0 /* Discussion.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Discussion.framework; sourceTree = BUILT_PRODUCTS_DIR; };
02FCB2B22BBEB36600373180 /* CourseHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseHeaderView.swift; sourceTree = "<group>"; };
02FFAD0C29E4347300140E46 /* VideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerViewModel.swift; sourceTree = "<group>"; };
060E8BC92B5FD68C0080C952 /* UnitStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitStack.swift; sourceTree = "<group>"; };
065275342BB1B39C0093BCCA /* PlayerViewControllerHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerViewControllerHolder.swift; sourceTree = "<group>"; };
067B7B472BED339200D1768F /* PlayerTrackerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerTrackerProtocol.swift; sourceTree = "<group>"; };
067B7B482BED339200D1768F /* PlayerDelegateProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerDelegateProtocol.swift; sourceTree = "<group>"; };
067B7B492BED339200D1768F /* PlayerControllerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerControllerProtocol.swift; sourceTree = "<group>"; };
067B7B4A2BED339200D1768F /* PipManagerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PipManagerProtocol.swift; sourceTree = "<group>"; };
067B7B4B2BED339200D1768F /* SubtitlesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubtitlesView.swift; sourceTree = "<group>"; };
067B7B4C2BED339200D1768F /* PlayerServiceProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerServiceProtocol.swift; sourceTree = "<group>"; };
067B7B4D2BED339200D1768F /* YoutubePlayerViewControllerHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YoutubePlayerViewControllerHolder.swift; sourceTree = "<group>"; };
068DDA5B2B1E198700FF8CCB /* CourseUnitDropDownList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseUnitDropDownList.swift; sourceTree = "<group>"; };
068DDA5C2B1E198700FF8CCB /* CourseUnitVerticalsDropdownView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseUnitVerticalsDropdownView.swift; sourceTree = "<group>"; };
068DDA5D2B1E198700FF8CCB /* CourseUnitDropDownCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseUnitDropDownCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -459,8 +471,14 @@
070019AA28F6F79E00D5FC78 /* Video */ = {
isa = PBXGroup;
children = (
067B7B4A2BED339200D1768F /* PipManagerProtocol.swift */,
067B7B492BED339200D1768F /* PlayerControllerProtocol.swift */,
067B7B482BED339200D1768F /* PlayerDelegateProtocol.swift */,
067B7B4C2BED339200D1768F /* PlayerServiceProtocol.swift */,
067B7B472BED339200D1768F /* PlayerTrackerProtocol.swift */,
067B7B4B2BED339200D1768F /* SubtitlesView.swift */,
067B7B4D2BED339200D1768F /* YoutubePlayerViewControllerHolder.swift */,
065275342BB1B39C0093BCCA /* PlayerViewControllerHolder.swift */,
02F066E729DC71750073E13B /* SubtittlesView.swift */,
0766DFCB299AA7A600EBEF6A /* YouTubeVideoPlayer.swift */,
022F8E152A1DFBC6008EFAB9 /* YouTubeVideoPlayerViewModel.swift */,
0766DFCD299AB26D00EBEF6A /* EncodedVideoPlayer.swift */,
Expand Down Expand Up @@ -834,6 +852,7 @@
buildActionMask = 2147483647;
files = (
06FD7EE32B1F3FF6008D632B /* DropdownAnimationModifier.swift in Sources */,
067B7B542BED339200D1768F /* YoutubePlayerViewControllerHolder.swift in Sources */,
02FFAD0D29E4347300140E46 /* VideoPlayerViewModel.swift in Sources */,
02454CA42A26193F0043052A /* WebView.swift in Sources */,
022C64DA29ACEC50000F532B /* HandoutsViewModel.swift in Sources */,
Expand All @@ -844,6 +863,7 @@
BA58CF612B471041005B102E /* VideoDownloadQualityBarView.swift in Sources */,
0270210328E736E700F54332 /* CourseOutlineView.swift in Sources */,
068DDA602B1E198700FF8CCB /* CourseUnitVerticalsDropdownView.swift in Sources */,
067B7B512BED339200D1768F /* PipManagerProtocol.swift in Sources */,
022C64E029ADEA9B000F532B /* Data_UpdatesResponse.swift in Sources */,
02D4FC2E2BBD7C9C00C47748 /* MessageSectionView.swift in Sources */,
02454CA02A2618E70043052A /* YouTubeView.swift in Sources */,
Expand Down Expand Up @@ -874,20 +894,24 @@
BAAD62C82AFD00EE000E6103 /* CourseStructureNestedListView.swift in Sources */,
02A8076829474831007F53AB /* CourseVerticalView.swift in Sources */,
97E7DF0F2B7C852A00A2A09B /* DatesStatusInfoView.swift in Sources */,
067B7B4F2BED339200D1768F /* PlayerDelegateProtocol.swift in Sources */,
0231124D28EDA804002588FB /* CourseUnitView.swift in Sources */,
027020FC28E7362100F54332 /* Data_CourseOutlineResponse.swift in Sources */,
DB7D6EB02ADFDA0E0036BB13 /* CourseDates.swift in Sources */,
067B7B532BED339200D1768F /* PlayerServiceProtocol.swift in Sources */,
BAD9CA2D2B2736BB00DE790A /* LessonLineProgressView.swift in Sources */,
060E8BCA2B5FD68C0080C952 /* UnitStack.swift in Sources */,
0295C889299BBE8200ABE571 /* CourseNavigationView.swift in Sources */,
06FD7EDF2B1F29F3008D632B /* CourseVerticalImageView.swift in Sources */,
BAC0E0DB2B32F0AE006B68A9 /* CourseVideoDownloadBarViewModel.swift in Sources */,
DB7D6EAE2ADFCB4A0036BB13 /* CourseDatesViewModel.swift in Sources */,
02F066E829DC71750073E13B /* SubtittlesView.swift in Sources */,
067B7B522BED339200D1768F /* SubtitlesView.swift in Sources */,
07DE59862BECB868001CBFBC /* CourseAnalytics.swift in Sources */,
022C64E229ADEB83000F532B /* CourseUpdate.swift in Sources */,
BA58CF642B471363005B102E /* VideoDownloadQualityContainerView.swift in Sources */,
BA58CF5D2B3D804D005B102E /* CourseStorage.swift in Sources */,
067B7B502BED339200D1768F /* PlayerControllerProtocol.swift in Sources */,
067B7B4E2BED339200D1768F /* PlayerTrackerProtocol.swift in Sources */,
02454CA62A26196C0043052A /* UnknownView.swift in Sources */,
0766DFD0299AB29000EBEF6A /* PlayerViewController.swift in Sources */,
022C64DC29ACFDEE000F532B /* Data_HandoutsResponse.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Course/Course/Presentation/Unit/Subviews/YouTubeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct YouTubeView: View {
var body: some View {
let vm = Container.shared.resolve(
YouTubeVideoPlayerViewModel.self,
arguments: url,
arguments: URL(string: url),
blockID,
courseID,
languages,
Expand Down
61 changes: 13 additions & 48 deletions Course/Course/Presentation/Video/EncodedVideoPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ public struct EncodedVideoPlayer: View {
@State private var orientation = UIDevice.current.orientation
@State private var isLoading: Bool = true
@State private var isAnimating: Bool = false
@State private var isViewedOnce: Bool = false
@State private var currentTime: Double = 0
@State private var isOrientationChanged: Bool = false
@State private var pause: Bool = false

@State var showAlert = false
@State var alertMessage: String? {
Expand All @@ -57,32 +54,13 @@ public struct EncodedVideoPlayer: View {
VStack(spacing: 10) {
HStack {
VStack {
PlayerViewController(
videoURL: viewModel.url,
playerHolder: viewModel.controllerHolder,
bitrate: viewModel.getVideoResolution(),
progress: { progress in
if progress >= 0.8 {
if !isViewedOnce {
Task {
await viewModel.blockCompletionRequest()
}
isViewedOnce = true
}
}
if progress == 1 {
viewModel.router.presentAppReview()
}

}, seconds: { seconds in
currentTime = seconds
})
PlayerViewController(playerController: viewModel.controller)
.aspectRatio(16 / 9, contentMode: .fit)
.frame(minWidth: playerWidth(for: reader.size))
.cornerRadius(12)
.onAppear {
if !viewModel.controllerHolder.isPlayingInPip,
!viewModel.controllerHolder.isOtherPlayerInPip {
if !viewModel.isPlayingInPip,
!viewModel.isOtherPlayerInPip {
viewModel.controller.player?.play()
}
}
Expand All @@ -91,9 +69,9 @@ public struct EncodedVideoPlayer: View {
}
}
if isHorizontal {
SubtittlesView(
SubtitlesView(
languages: viewModel.languages,
currentTime: $currentTime,
currentTime: $viewModel.currentTime,
viewModel: viewModel,
scrollTo: { date in
viewModel.controller.player?.seek(
Expand All @@ -103,15 +81,15 @@ public struct EncodedVideoPlayer: View {
)
)
viewModel.controller.player?.play()
pauseScrolling()
currentTime = (date.secondsSinceMidnight() + 1)
viewModel.pauseScrolling()
viewModel.currentTime = (date.secondsSinceMidnight() + 1)
})
}
}
if !isHorizontal {
SubtittlesView(
SubtitlesView(
languages: viewModel.languages,
currentTime: $currentTime,
currentTime: $viewModel.currentTime,
viewModel: viewModel,
scrollTo: { date in
viewModel.controller.player?.seek(
Expand All @@ -121,8 +99,8 @@ public struct EncodedVideoPlayer: View {
)
)
viewModel.controller.player?.play()
pauseScrolling()
currentTime = (date.secondsSinceMidnight() + 1)
viewModel.pauseScrolling()
viewModel.currentTime = (date.secondsSinceMidnight() + 1)
})
}
}
Expand All @@ -134,17 +112,11 @@ public struct EncodedVideoPlayer: View {
viewModel.controller.player?.allowsExternalPlayback = false
}
.onAppear {
viewModel.controller.player?.allowsExternalPlayback = true
viewModel.controller.setNeedsStatusBarAppearanceUpdate()
}
}

private func pauseScrolling() {
pause = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.pause = false
}
}

private func playerWidth(for size: CGSize) -> CGFloat {
if isHorizontal {
return size.width * 0.6
Expand All @@ -163,17 +135,10 @@ struct EncodedVideoPlayer_Previews: PreviewProvider {
static var previews: some View {
EncodedVideoPlayer(
viewModel: EncodedVideoPlayerViewModel(
url: URL(string: "")!,
blockID: "",
courseID: "",
languages: [],
playerStateSubject: CurrentValueSubject<VideoPlayerState?, Never>(nil),
interactor: CourseInteractor(repository: CourseRepositoryMock()),
router: CourseRouterMock(),
appStorage: CoreStorageMock(),
connectivity: Connectivity(),
pipManager: PipManagerProtocolMock(),
selectedCourseTab: 0
playerHolder: PlayerViewControllerHolder.mock
),
isOnScreen: true
)
Expand Down
Loading

0 comments on commit 32bf7d9

Please sign in to comment.