ASCollectionView for iOS Live TV channnels

This commit is contained in:
jhays 2022-06-06 15:24:35 -05:00
parent bc8f5e95d9
commit aba2e48072
3 changed files with 67 additions and 73 deletions

View File

@ -286,6 +286,7 @@
C4BE07892728448B003F4AD1 /* LiveTVChannelsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BE07872728448B003F4AD1 /* LiveTVChannelsCoordinator.swift */; };
C4BE078C272844AF003F4AD1 /* LiveTVChannelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BE078A272844AF003F4AD1 /* LiveTVChannelsView.swift */; };
C4BE078E27298818003F4AD1 /* LiveTVHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BE078D27298817003F4AD1 /* LiveTVHomeView.swift */; };
C4D0CE4B2848570700345D11 /* ASCollectionView in Frameworks */ = {isa = PBXBuildFile; productRef = C4D0CE4A2848570700345D11 /* ASCollectionView */; };
C4E5081B2703F82A0045C9AB /* LibraryListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E508172703E8190045C9AB /* LibraryListView.swift */; };
C4E5081D2703F8370045C9AB /* LibrarySearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E5081C2703F8370045C9AB /* LibrarySearchView.swift */; };
C4E5598928124C10003DECA5 /* LiveTVChannelItemElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E5598828124C10003DECA5 /* LiveTVChannelItemElement.swift */; };
@ -945,6 +946,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C4D0CE4B2848570700345D11 /* ASCollectionView in Frameworks */,
62666E3E27E503FA00EC0ECD /* MediaAccessibility.framework in Frameworks */,
62666DFF27E5016400EC0ECD /* CFNetwork.framework in Frameworks */,
E13DD3D327168E65009D4DAF /* Defaults in Frameworks */,
@ -1960,6 +1962,7 @@
E1002B672793CFBA00E47059 /* Algorithms */,
62666E3827E502CE00EC0ECD /* SwizzleSwift */,
E1101176281B1E8A006A3584 /* Puppy */,
C4D0CE4A2848570700345D11 /* ASCollectionView */,
);
productName = JellyfinPlayer;
productReference = 5377CBF1263B596A003A4E83 /* Swiftfin iOS.app */;
@ -2054,6 +2057,7 @@
E1002B662793CFBA00E47059 /* XCRemoteSwiftPackageReference "swift-algorithms" */,
62666E3727E502CE00EC0ECD /* XCRemoteSwiftPackageReference "SwizzleSwift" */,
E1101175281B1E8A006A3584 /* XCRemoteSwiftPackageReference "Puppy" */,
C4D0CE492848570700345D11 /* XCRemoteSwiftPackageReference "ASCollectionView" */,
);
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
projectDirPath = "";
@ -3117,6 +3121,14 @@
kind = branch;
};
};
C4D0CE492848570700345D11 /* XCRemoteSwiftPackageReference "ASCollectionView" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apptekstudios/ASCollectionView";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.0.0;
};
};
E1002B662793CFBA00E47059 /* XCRemoteSwiftPackageReference "swift-algorithms" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apple/swift-algorithms.git";
@ -3253,6 +3265,11 @@
package = 62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */;
productName = Stinsen;
};
C4D0CE4A2848570700345D11 /* ASCollectionView */ = {
isa = XCSwiftPackageProductDependency;
package = C4D0CE492848570700345D11 /* XCRemoteSwiftPackageReference "ASCollectionView" */;
productName = ASCollectionView;
};
E1002B672793CFBA00E47059 /* Algorithms */ = {
isa = XCSwiftPackageProductDependency;
package = E1002B662793CFBA00E47059 /* XCRemoteSwiftPackageReference "swift-algorithms" */;

View File

@ -18,6 +18,15 @@
"version" : "0.6.4"
}
},
{
"identity" : "ascollectionview",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apptekstudios/ASCollectionView",
"state" : {
"revision" : "4288744ba484c1062c109c0f28d72b629d321d55",
"version" : "2.1.1"
}
},
{
"identity" : "combineext",
"kind" : "remoteSourceControl",
@ -45,6 +54,15 @@
"version" : "6.2.1"
}
},
{
"identity" : "differencekit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/ra1028/DifferenceKit",
"state" : {
"revision" : "62745d7780deef4a023a792a1f8f763ec7bf9705",
"version" : "1.2.0"
}
},
{
"identity" : "gifu",
"kind" : "remoteSourceControl",

View File

@ -6,6 +6,7 @@
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
//
import ASCollectionView
import Foundation
import JellyfinAPI
import SwiftUI
@ -20,19 +21,34 @@ struct LiveTVChannelsView: View {
var viewModel = LiveTVChannelsViewModel()
@State
private var isPortrait = false
private var columns: Int {
if UIDevice.current.userInterfaceIdiom == .pad {
return 2
} else {
if isPortrait {
return 1
} else {
return 2
}
}
}
var body: some View {
if viewModel.isLoading == true {
ProgressView()
} else if !viewModel.rows.isEmpty {
CollectionView(rows: viewModel.rows) { _, _ in
createGridLayout()
} cell: { indexPath, cell in
makeCellView(indexPath: indexPath, cell: cell)
} supplementaryView: { _, indexPath in
EmptyView()
.accessibilityIdentifier("\(indexPath.section).\(indexPath.row)")
}
} else if !viewModel.channelPrograms.isEmpty {
ASCollectionView(data: viewModel.channelPrograms, dataID: \.self)
{ channelProgram, _ in
makeCellView(channelProgram)
}
.layout
{
.grid(
layoutMode: .fixedNumberOfColumns(columns),
itemSpacing: 16,
lineSpacing: 4,
itemSize: .absolute(144))
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.ignoresSafeArea()
.onAppear {
@ -58,22 +74,21 @@ struct LiveTVChannelsView: View {
}
@ViewBuilder
func makeCellView(indexPath: IndexPath, cell: LiveTVChannelRowCell) -> some View {
let item = cell.item
let channel = item.channel
let currentProgramDisplayText = item.currentProgram?
func makeCellView(_ channelProgram: LiveTVChannelProgram) -> some View {
let channel = channelProgram.channel
let currentProgramDisplayText = channelProgram.currentProgram?
.programDisplayText(timeFormatter: viewModel.timeFormatter) ?? LiveTVChannelViewProgram(timeDisplay: "", title: "")
let nextItems = item.programs.filter { program in
let nextItems = channelProgram.programs.filter { program in
guard let start = program.startDate else {
return false
}
guard let currentStart = item.currentProgram?.startDate else {
guard let currentStart = channelProgram.currentProgram?.startDate else {
return false
}
return start > currentStart
}
LiveTVChannelItemWideElement(channel: channel,
currentProgram: item.currentProgram,
currentProgram: channelProgram.currentProgram,
currentProgramText: currentProgramDisplayText,
nextProgramsText: nextProgramsDisplayText(nextItems: nextItems,
timeFormatter: viewModel.timeFormatter),
@ -88,62 +103,6 @@ struct LiveTVChannelsView: View {
})
}
private func createGridLayout() -> NSCollectionLayoutSection {
if UIDevice.current.userInterfaceIdiom == .pad {
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute((UIScreen.main.bounds.width / 2) - 16),
heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: .flexible(0), top: nil,
trailing: .flexible(2), bottom: .flexible(2))
let item2 = NSCollectionLayoutItem(layoutSize: itemSize)
item2.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: nil, top: nil,
trailing: .flexible(0), bottom: .flexible(2))
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(144))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
subitems: [item, item2])
let section = NSCollectionLayoutSection(group: group)
return section
} else {
if isPortrait {
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(UIScreen.main.bounds.width - 32),
heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: .flexible(0), top: nil,
trailing: .flexible(2), bottom: .flexible(2))
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(144))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
subitems: [item])
let section = NSCollectionLayoutSection(group: group)
return section
} else {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
var width = (UIScreen.main.bounds.width / 2) - 32
if let safeArea = windowScene?.keyWindow?.safeAreaInsets {
width = (UIScreen.main.bounds.width / 2) - safeArea.left - safeArea.right
}
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(width),
heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: .flexible(0), top: nil,
trailing: .flexible(2), bottom: .flexible(2))
let item2 = NSCollectionLayoutItem(layoutSize: itemSize)
item2.edgeSpacing = NSCollectionLayoutEdgeSpacing(leading: nil, top: nil,
trailing: .flexible(0), bottom: .flexible(2))
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(144))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
subitems: [item, item2])
let section = NSCollectionLayoutSection(group: group)
return section
}
}
}
private func checkOrientation() {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene