Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions PickaView/Views/Player/FullscreenPlayerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,6 @@ class FullscreenPlayerViewController: UIViewController {
/// 시스템 제스처 연기 (모든 엣지)
override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge { .all }

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscape
}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeRight
}
Expand Down
9 changes: 0 additions & 9 deletions PickaView/Views/Player/PlayerViewController+Gestures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,7 @@ extension PlayerViewController: UIGestureRecognizerDelegate {
}
}

/// 위로 스와이프: 전체화면 진입(세로모드일 때만)
@objc func handleSwipeToFullscreen(_ gesture: UISwipeGestureRecognizer) {
guard !isFullscreenMode else { return }
let isPortrait: Bool
if let orientation = view.window?.windowScene?.interfaceOrientation {
isPortrait = orientation.isPortrait
} else {
isPortrait = UIDevice.current.orientation.isPortrait
}
guard isPortrait else { return }
presentFullscreen()
}

Expand Down
2 changes: 1 addition & 1 deletion PickaView/Views/Player/PlayerViewController+UI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ extension PlayerViewController {
/// 가로/세로 모드에 따라 제약조건 전환
func updateConstraintsForOrientation() {
let isLandscape = UIDevice.current.orientation.isLandscape
if isFullscreenMode || isLandscape {
if isFullscreenMode {
NSLayoutConstraint.deactivate(portraitConstraints)
NSLayoutConstraint.activate(landscapeConstraints)
collectionView.isHidden = true
Expand Down
123 changes: 86 additions & 37 deletions PickaView/Views/Player/PlayerViewController+collectionViewUI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@ import UIKit

/// PlayerViewController의 UICollectionView에 대한 UI 구성 및 레이아웃 설정을 담당
extension PlayerViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

func collectionView(
_ collectionView: UICollectionView,
numberOfItemsInSection section: Int
) -> Int {
return 11
}

// 각 인덱스에 맞는 셀 구성: 0번은 가로 스크롤 태그 셀, 나머지는 비디오 셀
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
func collectionView(
_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath
) -> UICollectionViewCell {
guard let viewModel else { fatalError("viewModel nil") }
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(
Expand All @@ -38,9 +45,11 @@ extension PlayerViewController: UICollectionViewDataSource, UICollectionViewDele
}

// 섹션 헤더 뷰의 크기 설정 (사용자 정보 + 좋아요 등)
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForHeaderInSection section: Int) -> CGSize {
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
referenceSizeForHeaderInSection section: Int
) -> CGSize {
let width = collectionView.bounds.width

let font = UIFont.preferredFont(forTextStyle: .footnote)
Expand All @@ -61,9 +70,11 @@ extension PlayerViewController: UICollectionViewDataSource, UICollectionViewDele
}

// 섹션 헤더 뷰를 생성 및 설정
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath) -> UICollectionReusableView {
func collectionView(
_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath
) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
guard let viewModel else { fatalError("viewModel nil") }
let header = collectionView.dequeueReusableSupplementaryView(
Expand All @@ -87,57 +98,59 @@ extension PlayerViewController: UICollectionViewDataSource, UICollectionViewDele
}

// 각 셀의 크기 계산
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize {
// 0번 인덱스는 태그 셀이므로 기존 로직을 유지합니다.
if indexPath.item == 0 {
let font = UIFont.preferredFont(forTextStyle: .body)
let text = "Sample" as NSString
let labelHeight = text.size(withAttributes: [.font: font]).height

let insets: CGFloat = 8

let height = ceil(labelHeight) + (insets * 2)

return CGSize(width: collectionView.bounds.width, height: height)
} else {
let width = collectionView.bounds.width

var itemsPerRow: CGFloat = 1
var insets: CGFloat = 10

let isPad = traitCollection.userInterfaceIdiom == .pad

if isPad {
itemsPerRow = 2
} else {
itemsPerRow = 1
insets = 0
}

let spacing: CGFloat = 10
let totalSpacing = spacing * (itemsPerRow - 1) + insets * 2
let itemWidth = (width - totalSpacing) / itemsPerRow

return CGSize(width: itemWidth, height: (itemWidth * 9 / 16) + (itemWidth * 1 / 6) + 8)
return calculateVideoCellSize(
for: collectionView,
layout: collectionViewLayout,
at: indexPath
)
}
}

// 셀 간 세로 간격 설정
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int
) -> CGFloat {
return 30
}

// 셀 간 가로 간격 설정
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int
) -> CGFloat {
return 10
}

// 디바이스 방향과 크기에 따라 섹션 여백 설정
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int
) -> UIEdgeInsets {
let width = collectionView.bounds.width
let height = collectionView.bounds.height
let isPhonePortrait = traitCollection.userInterfaceIdiom == .phone && width < height

return isPhonePortrait ? .zero : UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
return isPhonePortrait ? .zero : .init(horizontal: 10)
}

// 셀 선택 시 동작 처리
Expand All @@ -160,15 +173,51 @@ extension PlayerViewController: UICollectionViewDataSource, UICollectionViewDele
guard let self, let viewModel = self.viewModel else { return }

let storyboard = UIStoryboard(name: "Player", bundle: nil)
guard let newPlayerVC = storyboard.instantiateViewController(withIdentifier: String(describing: PlayerViewController.self)) as? PlayerViewController else {
return
}
guard let newPlayerVC = storyboard.instantiateViewController(
withIdentifier: String(
describing: PlayerViewController.self
)
) as? PlayerViewController else { return }
newPlayerVC.modalPresentationStyle = .fullScreen

let newPlayerVM = PlayerViewModel(video: video, coreDataManager: viewModel.getCoreDataManager())
let newPlayerVM = PlayerViewModel(
video: video,
coreDataManager: viewModel.getCoreDataManager()
)
newPlayerVC.viewModel = newPlayerVM

presentingVC.present(newPlayerVC, animated: false)
}
}

private func calculateVideoCellSize(
for collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
at indexPath: IndexPath
) -> CGSize {
let insets = self.collectionView(
collectionView,
layout: collectionViewLayout,
insetForSectionAt: indexPath.section
)
let interitemSpacing = self.collectionView(
collectionView,
layout: collectionViewLayout,
minimumInteritemSpacingForSectionAt: indexPath.section
)

let isPad = traitCollection.userInterfaceIdiom == .pad

let itemsPerRow: CGFloat = isPad ? 2 : 1

let totalHorizontalSpacing = insets.left + insets.right + (interitemSpacing * (itemsPerRow - 1))

let itemWidth = (collectionView.bounds.width - totalHorizontalSpacing) / itemsPerRow

let thumbnailHeight = itemWidth * 9 / 16
let userInfoHeight = itemWidth * 1 / 6
let itemHeight = thumbnailHeight + userInfoHeight + 8

return CGSize(width: itemWidth, height: itemHeight)
}
}
32 changes: 28 additions & 4 deletions PickaView/Views/Player/PlayerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class PlayerViewController: UIViewController, PlayerViewControllerDelegate {
@IBOutlet weak var rateTwoView: UIView!

var viewModel: PlayerViewModel!

private var videoPlayerHeightConstraint: NSLayoutConstraint?

// MARK: - Player Properties

Expand Down Expand Up @@ -163,6 +165,7 @@ class PlayerViewController: UIViewController, PlayerViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()

setupPlayerHieght(for: view.bounds.size)
// 백그라운드 실행 금지
try? AVAudioSession.sharedInstance().setCategory(.ambient, mode: .moviePlayback, options: [])

Expand Down Expand Up @@ -235,8 +238,20 @@ class PlayerViewController: UIViewController, PlayerViewControllerDelegate {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
playerLayer?.frame = videoContainerView.bounds
collectionView.collectionViewLayout.invalidateLayout()
}

override func viewWillTransition(
to size: CGSize,
with coordinator: any UIViewControllerTransitionCoordinator
) {
guard isViewLoaded else { return }
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.collectionView.collectionViewLayout.invalidateLayout()
})
setupPlayerHieght(for: size)
}

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

Expand Down Expand Up @@ -477,10 +492,19 @@ class PlayerViewController: UIViewController, PlayerViewControllerDelegate {
UIViewController.attemptRotationToDeviceOrientation()
}
}

/// 현재 지원되는 화면 방향
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return isFullscreenMode ? .landscape : .portrait

private func setupPlayerHieght(for size: CGSize) {
videoPlayerHeightConstraint?.isActive = false

if traitCollection.userInterfaceIdiom == .pad {
let isPortrait = size.width < size.height
let heightMultiplier = isPortrait ? 0.4 : 0.3
videoPlayerHeightConstraint = videoPlayerView.heightAnchor.constraint(
equalTo: view.widthAnchor,
multiplier: heightMultiplier
)
}
videoPlayerHeightConstraint?.isActive = true
}

/// 프리젠테이션시 기본 방향
Expand Down