Skip to content
This repository has been archived by the owner on May 6, 2024. It is now read-only.

Commit

Permalink
chore: handle landscape for new dashboard and component navigation (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Muhammad Umer committed Jul 10, 2023
1 parent 77649b1 commit e628e2a
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 65 deletions.
7 changes: 5 additions & 2 deletions Source/AccessibilityCLButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
7 changes: 1 addition & 6 deletions Source/CourseContentPageViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -434,18 +434,13 @@ public class CourseContentPageViewController : UIPageViewController, UIPageViewC

guard let nextController = controllerForBlock(block: block) else { return }

setPageControllers(with: [nextController], direction: direction, animated: true) { [weak self] finished in
setPageControllers(with: [nextController], direction: direction, animated: false) { [weak self] finished in
guard let weakSelf = self else { return }
weakSelf.updateTransitionState(is: false)
if weakSelf.shouldCelebrationAppear {
weakSelf.showCelebratoryModal(direction: direction, overController: nextController)
}
}

currentPageItemIndex = contentLoader.value?.currentIndex() ?? 0

updateNavigationBars()
navigationDelegate?.courseContentPageViewController(controller: self, enteredBlockWithID: cursor.current.block.blockID, parentID: cursor.current.parent)
}

func controllerForBlock(block : CourseBlock, shouldCelebrationAppear: Bool = false) -> UIViewController? {
Expand Down
5 changes: 5 additions & 0 deletions Source/CourseDashboardHeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ protocol CourseDashboardHeaderViewDelegate: AnyObject {
}

enum HeaderViewState {
case initial
case animating
case expanded
case collapsed
Expand All @@ -37,6 +38,8 @@ class CourseDashboardHeaderView: UIView {
private lazy var datesBannerView = NewCourseDateBannerView()
private var bannerInfo: DatesBannerInfo? = nil

var state: HeaderViewState = .initial

private lazy var orgLabel: UILabel = {
let label = UILabel()
label.accessibilityIdentifier = "CourseDashboardHeaderView:org-label"
Expand Down Expand Up @@ -245,6 +248,8 @@ class CourseDashboardHeaderView: UIView {
make.trailing.equalTo(closeButton.snp.leading).offset(-StandardHorizontalMargin)
}

if state == .collapsed { return }

courseInfoContainerView.snp.remakeConstraints { make in
make.top.equalTo(closeButton.snp.bottom)
make.leading.equalTo(containerView).offset(StandardHorizontalMargin)
Expand Down
10 changes: 7 additions & 3 deletions Source/CutomePlayer/VideoPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -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
Expand Down
66 changes: 42 additions & 24 deletions Source/NewCourseContentController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,14 @@ 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)

Expand All @@ -77,7 +79,6 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi
} else {
findCourseBlockToShow()
}
setStatusBar(color: environment.styles.primaryLightColor())
}

required init?(coder aDecoder: NSCoder) {
Expand All @@ -99,6 +100,7 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi
override func viewDidLoad() {
super.viewDidLoad()

setStatusBar(color: environment.styles.primaryLightColor())
addSubViews()
setupComponentView()
setupCompletedBlocksView()
Expand Down Expand Up @@ -150,7 +152,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)
Expand All @@ -170,20 +172,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()
Expand All @@ -200,15 +197,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() {
Expand All @@ -224,7 +219,12 @@ class NewCourseContentController: UIViewController, InterfaceOrientationOverridi
}

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
setStatusBar(color: environment.styles.primaryLightColor())
coordinator.animate { [weak self] _ in
guard let weakSelf = self else { return }
DispatchQueue.main.async {
weakSelf.setStatusBar(color: weakSelf.environment.styles.primaryLightColor())
}
}
}
}

Expand All @@ -235,6 +235,24 @@ extension NewCourseContentController: CourseContentPageViewControllerDelegate {
if var controller = controller.viewControllers?.first as? ScrollableDelegateProvider {
controller.scrollableDelegate = self
}

// header animation is overlapping with UIPageController animation which results in crash
// calling the header animation after a delay of 1 sec to overcome the issue
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
self?.updateHeaderState(with: controller)
}
}

private func updateHeaderState(with controller: CourseContentPageViewController) {
if let controller = controller.viewControllers?.first as? VideoBlockViewController {
if currentOrientation() != .portrait {
collapseHeaderView()
} else if headerViewState == .collapsed {
collapseHeaderView()
} else if headerViewState == .expanded {
expandHeaderView()
}
}
}
}

Expand Down
68 changes: 50 additions & 18 deletions Source/NewCourseDashboardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ class NewCourseDashboardViewController: UIViewController, InterfaceOrientationOv
private var error: NSError?
private var courseAccessHelper: CourseAccessHelper?
private var selectedTabbarItem: TabBarItem?
private var headerViewState: HeaderViewState = .expanded

private var headerViewState: HeaderViewState = .expanded {
didSet {
headerView.state = headerViewState
}
}
private var tabBarItems: [TabBarItem] = []
private var isModalDismissable = true
private let courseStream: BackedStream<UserCourseEnrollment>
Expand Down Expand Up @@ -103,6 +108,16 @@ class NewCourseDashboardViewController: UIViewController, InterfaceOrientationOv
environment.analytics.trackScreen(withName: OEXAnalyticsScreenCourseDashboard, courseID: courseID, value: nil)
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

if headerViewState == .collapsed {
collapseHeaderView()
} else if headerViewState == .expanded {
expandHeaderView()
}
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setNavigationBarHidden(false, animated: true)
Expand Down Expand Up @@ -253,7 +268,19 @@ class NewCourseDashboardViewController: UIViewController, InterfaceOrientationOv

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
setupContentView()
setStatusBar(color: environment.styles.primaryLightColor())

coordinator.animate { [weak self] _ in
guard let weakSelf = self else { return }
DispatchQueue.main.async {
weakSelf.setStatusBar(color: weakSelf.environment.styles.primaryLightColor())
}
}

if headerViewState == .collapsed {
collapseHeaderView()
} else if headerViewState == .expanded {
expandHeaderView()
}
}

private func prepareTabViewData() {
Expand Down Expand Up @@ -584,22 +611,27 @@ extension NewCourseDashboardViewController: NewCourseDashboardViewControllerDele

public extension UIViewController {
func setStatusBar(color: UIColor) {
DispatchQueue.main.async { [weak self] in
let tag = 123454321
let overView: UIView
if let taggedView = self?.view.viewWithTag(tag) {
overView = taggedView
}
else {
overView = UIView()
overView.tag = tag
self?.view.addSubview(overView)
}

let height = UIApplication.shared.window?.windowScene?.windows.first?.safeAreaInsets.top ?? 0
let frame = UIApplication.shared.window?.windowScene?.statusBarManager?.statusBarFrame ?? .zero
overView.frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width, height: height)
overView.backgroundColor = color
let tag = 123454321
let overView: UIView
if let taggedView = view.viewWithTag(tag) {
overView = taggedView
}
else {
overView = UIView()
overView.tag = tag
view.addSubview(overView)
}

let height = UIApplication.shared.window?.windowScene?.windows.first?.safeAreaInsets.top ?? 0
let frame = UIApplication.shared.window?.windowScene?.statusBarManager?.statusBarFrame ?? .zero
overView.frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.size.width, height: height)
overView.backgroundColor = color
}

func removeStatusBar() {
let tag = 123454321
if let taggedView = view.viewWithTag(tag) {
taggedView.removeFromSuperview()
}
}
}
2 changes: 1 addition & 1 deletion Source/OEXRouter+Swift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions Source/UIViewController+CommonAdditions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,14 @@ extension UIViewController {
}
navigationItem.leftBarButtonItem = backItem
}

func findParentViewController<T: UIViewController>(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
}
}
}
35 changes: 24 additions & 11 deletions Source/VideoBlockViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class VideoBlockViewController : OfflineSupportViewController, CourseBlockViewCo
private var playOverlayButton: UIButton?
private var overlayLabel: UILabel?
var shouldCelebrationAppear: Bool

init(environment : Environment, blockID : CourseBlockID?, courseID: String, shouldCelebrationAppear: Bool = false) {
self.blockID = blockID
self.environment = environment
Expand Down Expand Up @@ -442,16 +442,29 @@ 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 }

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)
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
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)
}
}
}
}
}

Expand Down

0 comments on commit e628e2a

Please sign in to comment.