From 9b712299b10aa9a32453e2a7770867ad047db64c Mon Sep 17 00:00:00 2001 From: Muhammad Umer Date: Mon, 3 Jul 2023 18:01:51 +0500 Subject: [PATCH] chore: handle landscape mode for new component screen for videos --- Source/AccessibilityCLButton.swift | 7 ++- Source/CutomePlayer/VideoPlayer.swift | 10 ++- Source/NewCourseContentController.swift | 61 ++++++++++++------- Source/NewCourseDashboardViewController.swift | 5 ++ Source/OEXRouter+Swift.swift | 2 +- Source/UIViewController+CommonAdditions.swift | 10 +++ Source/VideoBlockViewController.swift | 35 ++++++++--- 7 files changed, 93 insertions(+), 37 deletions(-) diff --git a/Source/AccessibilityCLButton.swift b/Source/AccessibilityCLButton.swift index fef2b984b3..37aa97a944 100644 --- a/Source/AccessibilityCLButton.swift +++ b/Source/AccessibilityCLButton.swift @@ -34,9 +34,12 @@ class AccessibilityCLButton: CustomPlayerButton { } public override func draw(_ rect: CGRect) { - let r = UIBezierPath(ovalIn: rect) + let diameter = min(rect.width, rect.height) + let circleRect = CGRect(x: rect.origin.x, y: rect.origin.y, width: diameter, height: diameter) + let path = UIBezierPath(ovalIn: circleRect) UIColor.black.withAlphaComponent(0.65).setFill() - r.fill() + path.fill() + super.draw(rect) } } diff --git a/Source/CutomePlayer/VideoPlayer.swift b/Source/CutomePlayer/VideoPlayer.swift index 87a3599ffd..e503032083 100644 --- a/Source/CutomePlayer/VideoPlayer.swift +++ b/Source/CutomePlayer/VideoPlayer.swift @@ -31,7 +31,7 @@ protocol VideoPlayerDelegate: AnyObject { private var playbackLikelyToKeepUpContext = 0 class VideoPlayer: UIViewController,VideoPlayerControlsDelegate,TranscriptManagerDelegate { - typealias Environment = OEXInterfaceProvider & OEXAnalyticsProvider & OEXStylesProvider + typealias Environment = OEXInterfaceProvider & OEXAnalyticsProvider & OEXStylesProvider & OEXConfigProvider public let environment : Environment fileprivate var controls: VideoPlayerControls? @@ -684,9 +684,13 @@ class VideoPlayer: UIViewController,VideoPlayerControlsDelegate,TranscriptManage func setFullscreen(fullscreen: Bool, animated: Bool, with deviceOrientation: UIInterfaceOrientation, forceRotate rotate: Bool) { if !isVisible { return } isFullScreen = fullscreen + if fullscreen { - - fullScreenContainerView = UIApplication.shared.window?.rootViewController?.view ?? UIApplication.shared.windows[0].rootViewController?.view + if environment.config.isNewComponentNavigationEnabled { + fullScreenContainerView = parent?.findParentViewController(type: NewCourseContentController.self)?.view ?? UIApplication.shared.windows.first?.rootViewController?.view + } else { + fullScreenContainerView = UIApplication.shared.window?.rootViewController?.view ?? UIApplication.shared.windows.first?.rootViewController?.view + } if movieBackgroundView.frame == .zero { movieBackgroundView.frame = movieBackgroundFrame diff --git a/Source/NewCourseContentController.swift b/Source/NewCourseContentController.swift index d5a76a19c0..0f3f3f0533 100644 --- a/Source/NewCourseContentController.swift +++ b/Source/NewCourseContentController.swift @@ -63,21 +63,23 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi private let parentID: CourseBlockID? private let courseID: CourseBlockID private let courseQuerier: CourseOutlineQuerier + private let courseOutlineMode: CourseOutlineMode - init(environment: Environment, blockID: CourseBlockID?, resumeCourseBlockID: CourseBlockID? = nil, parentID: CourseBlockID? = nil, courseID: CourseBlockID) { + init(environment: Environment, blockID: CourseBlockID?, resumeCourseBlockID: CourseBlockID? = nil, parentID: CourseBlockID? = nil, courseID: CourseBlockID, courseOutlineMode: CourseOutlineMode? = .full) { self.environment = environment self.blockID = blockID self.parentID = parentID self.courseID = courseID + self.courseOutlineMode = courseOutlineMode ?? .full courseQuerier = environment.dataManager.courseDataManager.querierForCourseWithID(courseID: courseID, environment: environment) super.init(nibName: nil, bundle: nil) + setStatusBar(color: environment.styles.primaryLightColor()) if let resumeCourseBlockID = resumeCourseBlockID { currentBlock = courseQuerier.blockWithID(id: resumeCourseBlockID).firstSuccess().value } else { findCourseBlockToShow() } - setStatusBar(color: environment.styles.primaryLightColor()) } required init?(coder aDecoder: NSCoder) { @@ -106,6 +108,7 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + setStatusBar(color: environment.styles.primaryLightColor()) navigationController?.setNavigationBarHidden(true, animated: false) } @@ -150,7 +153,7 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi let parent = courseQuerier.parentOfBlockWith(id: currentBlock.blockID).firstSuccess().value else { return } - let courseContentViewController = CourseContentPageViewController(environment: environment, courseID: courseID, rootID: parent.blockID, initialChildID: currentBlock.blockID, forMode: .full) + let courseContentViewController = CourseContentPageViewController(environment: environment, courseID: courseID, rootID: parent.blockID, initialChildID: currentBlock.blockID, forMode: courseOutlineMode) courseContentViewController.navigationDelegate = self let childViewController = ForwardingNavigationController(rootViewController: courseContentViewController) @@ -170,20 +173,15 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi private func setupCompletedBlocksView() { guard let block = currentBlock, - let section = courseQuerier.parentOfBlockWith(id: block.blockID, type: .Section).firstSuccess().value + let section = courseQuerier.parentOfBlockWith(id: block.blockID, type: .Section).firstSuccess().value, + let sectionChildren = courseQuerier.childrenOfBlockWithID(blockID: section.blockID, forMode: courseOutlineMode).value else { return } - let childBlocks: [CourseBlock] = section.children - .compactMap { item -> CourseBlock? in - return courseQuerier.blockWithID(id: item).firstSuccess().value - } - .flatMap { item -> [CourseBlockID] in - return item.children - } - .compactMap { item -> CourseBlock? in - return courseQuerier.blockWithID(id: item).firstSuccess().value - } - + let childBlocks: [CourseBlock] = sectionChildren.children.compactMap { item in + courseQuerier.childrenOfBlockWithID(blockID: item.blockID, forMode: courseOutlineMode) + .firstSuccess().value?.children ?? [] + }.flatMap { $0 } + let childViews: [UIView] = childBlocks.map { block -> UIView in let view = UIView() view.backgroundColor = block.isCompleted ? environment.styles.accentBColor() : environment.styles.neutralDark() @@ -200,15 +198,13 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi .firstSuccess().value?.children.compactMap({ $0 }).filter({ $0.type == .Unit }) else { return } - guard let firstInCompleteBlock = childBlocks.flatMap({ $0.children }) - .compactMap({ courseQuerier.blockWithID(id: $0).value }) - .first(where: { !$0.isCompleted }) - else { - currentBlock = courseQuerier.childrenOfBlockWithID(blockID: childBlocks.last?.blockID, forMode: .full).firstSuccess().value?.children.last - return + let blocks: [CourseBlock] = childBlocks.flatMap { block in + courseQuerier.childrenOfBlockWithID(blockID: block.blockID, forMode: courseOutlineMode).value?.children.compactMap { child in + courseQuerier.blockWithID(id: child.blockID).value + } ?? [] } - - currentBlock = firstInCompleteBlock + + currentBlock = blocks.first(where: { !$0.isCompleted }) ?? blocks.last } private func updateView() { @@ -235,6 +231,11 @@ extension NewCourseContentController: CourseContentPageViewControllerDelegate { if var controller = controller.viewControllers?.first as? ScrollableDelegateProvider { controller.scrollableDelegate = self } + + if let controller = controller.viewControllers?.first as? VideoBlockViewController { + controller.orientationDelegate = self + changeOrientation(orientation: currentOrientation()) + } } } @@ -299,6 +300,20 @@ extension NewCourseContentController { } } +extension NewCourseContentController: VideoBlockViewControllerOrientationDelegate { + func changeOrientation(orientation: UIInterfaceOrientation) { + if orientation == .portrait { + if headerViewState == .collapsed { + headerViewState = .animating + expandHeaderView() + } + } else if headerViewState == .expanded { + headerViewState = .animating + collapseHeaderView() + } + } +} + fileprivate extension UIStackView { func addArrangedSubviews(_ views: [UIView]) { views.forEach { addArrangedSubview($0) } diff --git a/Source/NewCourseDashboardViewController.swift b/Source/NewCourseDashboardViewController.swift index e7fbeee6d6..798469ee76 100644 --- a/Source/NewCourseDashboardViewController.swift +++ b/Source/NewCourseDashboardViewController.swift @@ -103,6 +103,11 @@ class NewCourseDashboardViewController: UIViewController, InterfaceOrientationOv environment.analytics.trackScreen(withName: OEXAnalyticsScreenCourseDashboard, courseID: courseID, value: nil) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + expandHeaderView() + } + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.setNavigationBarHidden(false, animated: true) diff --git a/Source/OEXRouter+Swift.swift b/Source/OEXRouter+Swift.swift index e05df5a30d..64b10e75f9 100644 --- a/Source/OEXRouter+Swift.swift +++ b/Source/OEXRouter+Swift.swift @@ -138,7 +138,7 @@ extension OEXRouter { func showContainerForBlockWithID(blockID: CourseBlockID?, type: CourseBlockDisplayType, parentID: CourseBlockID?, courseID: CourseBlockID, fromController controller: UIViewController, forMode mode: CourseOutlineMode? = .full, completion: ((UIViewController) -> Void)? = nil) { if environment.config.isNewComponentNavigationEnabled { - let contentController = NewCourseContentController(environment: environment, blockID: blockID, parentID: parentID, courseID: courseID) + let contentController = NewCourseContentController(environment: environment, blockID: blockID, parentID: parentID, courseID: courseID, courseOutlineMode: mode) controller.navigationController?.pushViewController(contentController, animated: true, completion: completion) } else { showContainerForBlockWithIDOld(blockID: blockID, type: type, parentID: parentID, courseID: courseID, fromController: controller, forMode: mode, completion: completion) diff --git a/Source/UIViewController+CommonAdditions.swift b/Source/UIViewController+CommonAdditions.swift index 02ac2fa1f1..7ad3ee397a 100644 --- a/Source/UIViewController+CommonAdditions.swift +++ b/Source/UIViewController+CommonAdditions.swift @@ -65,4 +65,14 @@ extension UIViewController { } navigationItem.leftBarButtonItem = backItem } + + func findParentViewController(type: T.Type) -> T? { + if let parentViewController = self.parent as? T { + return parentViewController + } else if let parentViewController = self.parent { + return parentViewController.findParentViewController(type: type) + } else { + return nil + } + } } diff --git a/Source/VideoBlockViewController.swift b/Source/VideoBlockViewController.swift index b4e6d144dd..46ec231d84 100644 --- a/Source/VideoBlockViewController.swift +++ b/Source/VideoBlockViewController.swift @@ -10,6 +10,10 @@ import Foundation import MediaPlayer import UIKit +protocol VideoBlockViewControllerOrientationDelegate { + func changeOrientation(orientation: UIInterfaceOrientation) +} + class VideoBlockViewController : OfflineSupportViewController, CourseBlockViewController, StatusBarOverriding, InterfaceOrientationOverriding, VideoTranscriptDelegate, RatingViewControllerDelegate, VideoPlayerDelegate { typealias Environment = DataManagerProvider & OEXInterfaceProvider & ReachabilityProvider & OEXConfigProvider & OEXRouterProvider & OEXAnalyticsProvider & OEXStylesProvider & OEXSessionProvider & NetworkManagerProvider @@ -442,16 +446,31 @@ class VideoBlockViewController : OfflineSupportViewController, CourseBlockViewCo } } - // willTransition only called in case of iPhone because iPhone has regular and compact vertical classes. - // This method is specially for iPad override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - guard UIDevice.current.userInterfaceIdiom == .pad else { return } + orientationDelegate?.changeOrientation(orientation: currentOrientation()) - if videoPlayer.isFullScreen { - videoPlayer.setFullscreen(fullscreen: !UIDevice.current.orientation.isPortrait, animated: true, with: currentOrientation(), forceRotate: false) - } - else if UIDevice.current.orientation.isLandscape { - videoPlayer.setFullscreen(fullscreen: true, animated: true, with: currentOrientation(), forceRotate: false) + if UIDevice.current.userInterfaceIdiom == .pad { + if videoPlayer.isFullScreen { + videoPlayer.setFullscreen(fullscreen: !UIDevice.current.orientation.isPortrait, animated: true, with: currentOrientation(), forceRotate: false) + } else if UIDevice.current.orientation.isLandscape { + videoPlayer.setFullscreen(fullscreen: true, animated: true, with: currentOrientation(), forceRotate: false) + } + } else { + DispatchQueue.main.async { [weak self] in + if let weakSelf = self { + if weakSelf.chromeCastManager.isMiniPlayerAdded { return } + + if weakSelf.videoPlayer.isFullScreen { + if UITraitCollection.current.verticalSizeClass == .regular { + weakSelf.videoPlayer.setFullscreen(fullscreen: false, animated: true, with: weakSelf.currentOrientation(), forceRotate: false) + } else { + weakSelf.videoPlayer.setFullscreen(fullscreen: true, animated: true, with: weakSelf.currentOrientation(), forceRotate: false) + } + } else if UITraitCollection.current.verticalSizeClass == .compact && !weakSelf.shouldCelebrationAppear { + weakSelf.videoPlayer.setFullscreen(fullscreen: true, animated: true, with: weakSelf.currentOrientation(), forceRotate: false) + } + } + } } }