mirror of
https://github.com/yattee/yattee.git
synced 2024-12-13 13:50:32 +05:30
Popular videos, playing from mp4
This commit is contained in:
parent
d488ee6679
commit
1772728cb8
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# SwiftLint Remote Config Cache
|
||||
.swiftlint/RemoteConfigCache
|
14
.swiftlint.yml
Normal file
14
.swiftlint.yml
Normal file
@ -0,0 +1,14 @@
|
||||
parent_config: https://raw.githubusercontent.com/sindresorhus/swiftlint-config/main/.swiftlint.yml
|
||||
|
||||
excluded:
|
||||
- .build
|
||||
|
||||
identifier_name:
|
||||
excluded:
|
||||
- db
|
||||
- id
|
||||
- vm
|
||||
|
||||
type_name:
|
||||
excluded:
|
||||
- VM
|
8
Apple TV/Info.plist
Normal file
8
Apple TV/Info.plist
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
14
Model/DataProvider.swift
Normal file
14
Model/DataProvider.swift
Normal file
@ -0,0 +1,14 @@
|
||||
import Alamofire
|
||||
import Foundation
|
||||
|
||||
class DataProvider: ObservableObject {
|
||||
static let instance = "https://invidious.home.arekf.net"
|
||||
|
||||
static func request(_ path: String) -> DataRequest {
|
||||
return AF.request(apiURLString(path))
|
||||
}
|
||||
|
||||
static func apiURLString(_ path: String) -> String {
|
||||
"\(instance)/api/v1/\(path)"
|
||||
}
|
||||
}
|
18
Model/PopularVideosProvider.swift
Normal file
18
Model/PopularVideosProvider.swift
Normal file
@ -0,0 +1,18 @@
|
||||
import Alamofire
|
||||
import Foundation
|
||||
import SwiftyJSON
|
||||
|
||||
final class PopluarVideosProvider: DataProvider {
|
||||
@Published var videos = [Video]()
|
||||
|
||||
func load() {
|
||||
DataProvider.request("popular").responseJSON { response in
|
||||
switch response.result {
|
||||
case let .success(value):
|
||||
self.videos = JSON(value).arrayValue.map { Video($0) }
|
||||
case let .failure(error):
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
Model/Video.swift
Normal file
39
Model/Video.swift
Normal file
@ -0,0 +1,39 @@
|
||||
import Alamofire
|
||||
import Foundation
|
||||
import SwiftyJSON
|
||||
|
||||
class Video: Identifiable, ObservableObject {
|
||||
let id: String
|
||||
var title: String
|
||||
var thumbnailURL: URL
|
||||
var author: String
|
||||
|
||||
@Published var url: URL?
|
||||
@Published var error: Bool = false
|
||||
|
||||
init(id: String, title: String, thumbnailURL: URL, author: String) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.thumbnailURL = thumbnailURL
|
||||
self.author = author
|
||||
}
|
||||
|
||||
init(_ json: JSON) {
|
||||
id = json["videoId"].stringValue
|
||||
title = json["title"].stringValue
|
||||
thumbnailURL = json["videoThumbnails"][0]["url"].url!
|
||||
author = json["author"].stringValue
|
||||
url = formatStreamURL(from: json["formatStreams"].arrayValue)
|
||||
}
|
||||
|
||||
func formatStreamURL(from streams: [JSON]) -> URL? {
|
||||
if streams.isEmpty {
|
||||
error = true
|
||||
return nil
|
||||
}
|
||||
|
||||
let stream = streams.last!
|
||||
|
||||
return stream["url"].url
|
||||
}
|
||||
}
|
25
Model/VideoDetailsProvider.swift
Normal file
25
Model/VideoDetailsProvider.swift
Normal file
@ -0,0 +1,25 @@
|
||||
import Alamofire
|
||||
import Foundation
|
||||
import SwiftyJSON
|
||||
|
||||
final class VideoDetailsProvider: DataProvider {
|
||||
@Published var video: Video?
|
||||
|
||||
var id: String
|
||||
|
||||
init(_ id: String) {
|
||||
self.id = id
|
||||
super.init()
|
||||
}
|
||||
|
||||
func load() {
|
||||
DataProvider.request("videos/\(id)").responseJSON { response in
|
||||
switch response.result {
|
||||
case let .success(value):
|
||||
self.video = Video(JSON(value))
|
||||
case let .failure(error):
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,29 @@
|
||||
37D4B176267164B000C925CA /* PearvidiousUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B175267164B000C925CA /* PearvidiousUITests.swift */; };
|
||||
37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C22671614700C925CA /* PearvidiousApp.swift */; };
|
||||
37D4B1812671653A00C925CA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B0C32671614700C925CA /* ContentView.swift */; };
|
||||
37D4B1832671681B00C925CA /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1822671681B00C925CA /* PlayerView.swift */; };
|
||||
37D4B1842671684E00C925CA /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1822671681B00C925CA /* PlayerView.swift */; };
|
||||
37D4B1852671684F00C925CA /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1822671681B00C925CA /* PlayerView.swift */; };
|
||||
37D4B1862671691600C925CA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 37D4B0C42671614800C925CA /* Assets.xcassets */; };
|
||||
37D4B18C26717B3800C925CA /* VideoThumbnailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoThumbnailView.swift */; };
|
||||
37D4B18D26717B3800C925CA /* VideoThumbnailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoThumbnailView.swift */; };
|
||||
37D4B18E26717B3800C925CA /* VideoThumbnailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B18B26717B3800C925CA /* VideoThumbnailView.swift */; };
|
||||
37D4B19126717C6900C925CA /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 37D4B19026717C6900C925CA /* Alamofire */; };
|
||||
37D4B19326717CE100C925CA /* PopularVideosProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19226717CE100C925CA /* PopularVideosProvider.swift */; };
|
||||
37D4B19426717CE100C925CA /* PopularVideosProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19226717CE100C925CA /* PopularVideosProvider.swift */; };
|
||||
37D4B19526717CE100C925CA /* PopularVideosProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19226717CE100C925CA /* PopularVideosProvider.swift */; };
|
||||
37D4B19726717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
||||
37D4B19826717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
||||
37D4B19926717E1500C925CA /* Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B19626717E1500C925CA /* Video.swift */; };
|
||||
37D4B19D2671817900C925CA /* SwiftyJSON in Frameworks */ = {isa = PBXBuildFile; productRef = 37D4B19C2671817900C925CA /* SwiftyJSON */; };
|
||||
37D4B1AB2672580400C925CA /* URLImage in Frameworks */ = {isa = PBXBuildFile; productRef = 37D4B1AA2672580400C925CA /* URLImage */; };
|
||||
37D4B1AD2672580400C925CA /* URLImageStore in Frameworks */ = {isa = PBXBuildFile; productRef = 37D4B1AC2672580400C925CA /* URLImageStore */; };
|
||||
37D4B1B02672A01000C925CA /* DataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1AF2672A01000C925CA /* DataProvider.swift */; };
|
||||
37D4B1B12672A01000C925CA /* DataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1AF2672A01000C925CA /* DataProvider.swift */; };
|
||||
37D4B1B22672A01000C925CA /* DataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1AF2672A01000C925CA /* DataProvider.swift */; };
|
||||
37D4B1B42672A30700C925CA /* VideoDetailsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1B32672A30700C925CA /* VideoDetailsProvider.swift */; };
|
||||
37D4B1B52672A30700C925CA /* VideoDetailsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1B32672A30700C925CA /* VideoDetailsProvider.swift */; };
|
||||
37D4B1B62672A30700C925CA /* VideoDetailsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D4B1B32672A30700C925CA /* VideoDetailsProvider.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -59,6 +82,13 @@
|
||||
37D4B15E267164AF00C925CA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
37D4B171267164B000C925CA /* Tests Apple TV.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Tests Apple TV.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
37D4B175267164B000C925CA /* PearvidiousUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PearvidiousUITests.swift; sourceTree = "<group>"; };
|
||||
37D4B1822671681B00C925CA /* PlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerView.swift; sourceTree = "<group>"; };
|
||||
37D4B18B26717B3800C925CA /* VideoThumbnailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoThumbnailView.swift; sourceTree = "<group>"; };
|
||||
37D4B19226717CE100C925CA /* PopularVideosProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopularVideosProvider.swift; sourceTree = "<group>"; };
|
||||
37D4B19626717E1500C925CA /* Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Video.swift; sourceTree = "<group>"; };
|
||||
37D4B1AE26729DEB00C925CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
37D4B1AF2672A01000C925CA /* DataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataProvider.swift; sourceTree = "<group>"; };
|
||||
37D4B1B32672A30700C925CA /* VideoDetailsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDetailsProvider.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -94,6 +124,10 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
37D4B1AD2672580400C925CA /* URLImageStore in Frameworks */,
|
||||
37D4B19D2671817900C925CA /* SwiftyJSON in Frameworks */,
|
||||
37D4B1AB2672580400C925CA /* URLImage in Frameworks */,
|
||||
37D4B19126717C6900C925CA /* Alamofire in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -110,6 +144,7 @@
|
||||
37D4B0BC2671614700C925CA = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37D4B1B72672CFE300C925CA /* Model */,
|
||||
37D4B0C12671614700C925CA /* Shared */,
|
||||
37D4B159267164AE00C925CA /* Apple TV */,
|
||||
37D4B174267164B000C925CA /* Tests Apple TV */,
|
||||
@ -122,8 +157,10 @@
|
||||
37D4B0C12671614700C925CA /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37D4B0C22671614700C925CA /* PearvidiousApp.swift */,
|
||||
37D4B0C32671614700C925CA /* ContentView.swift */,
|
||||
37D4B18B26717B3800C925CA /* VideoThumbnailView.swift */,
|
||||
37D4B1822671681B00C925CA /* PlayerView.swift */,
|
||||
37D4B0C22671614700C925CA /* PearvidiousApp.swift */,
|
||||
37D4B0C42671614800C925CA /* Assets.xcassets */,
|
||||
);
|
||||
path = Shared;
|
||||
@ -161,6 +198,7 @@
|
||||
37D4B159267164AE00C925CA /* Apple TV */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37D4B1AE26729DEB00C925CA /* Info.plist */,
|
||||
37D4B15E267164AF00C925CA /* Assets.xcassets */,
|
||||
);
|
||||
path = "Apple TV";
|
||||
@ -174,6 +212,17 @@
|
||||
path = "Tests Apple TV";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
37D4B1B72672CFE300C925CA /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37D4B19626717E1500C925CA /* Video.swift */,
|
||||
37D4B19226717CE100C925CA /* PopularVideosProvider.swift */,
|
||||
37D4B1B32672A30700C925CA /* VideoDetailsProvider.swift */,
|
||||
37D4B1AF2672A01000C925CA /* DataProvider.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -260,6 +309,12 @@
|
||||
dependencies = (
|
||||
);
|
||||
name = "Pearvidious (Apple TV)";
|
||||
packageProductDependencies = (
|
||||
37D4B19026717C6900C925CA /* Alamofire */,
|
||||
37D4B19C2671817900C925CA /* SwiftyJSON */,
|
||||
37D4B1AA2672580400C925CA /* URLImage */,
|
||||
37D4B1AC2672580400C925CA /* URLImageStore */,
|
||||
);
|
||||
productName = Pearvidious;
|
||||
productReference = 37D4B158267164AE00C925CA /* Pearvidious (Apple TV).app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@ -324,6 +379,11 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = 37D4B0BC2671614700C925CA;
|
||||
packageReferences = (
|
||||
37D4B18F26717C6900C925CA /* XCRemoteSwiftPackageReference "Alamofire" */,
|
||||
37D4B19B2671817900C925CA /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
||||
37D4B1A92672580400C925CA /* XCRemoteSwiftPackageReference "url-image" */,
|
||||
);
|
||||
productRefGroup = 37D4B0CA2671614900C925CA /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@ -373,6 +433,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
37D4B1862671691600C925CA /* Assets.xcassets in Resources */,
|
||||
37D4B15F267164AF00C925CA /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -391,7 +452,13 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
37D4B19326717CE100C925CA /* PopularVideosProvider.swift in Sources */,
|
||||
37D4B1832671681B00C925CA /* PlayerView.swift in Sources */,
|
||||
37D4B0E62671614900C925CA /* ContentView.swift in Sources */,
|
||||
37D4B1B02672A01000C925CA /* DataProvider.swift in Sources */,
|
||||
37D4B18C26717B3800C925CA /* VideoThumbnailView.swift in Sources */,
|
||||
37D4B1B42672A30700C925CA /* VideoDetailsProvider.swift in Sources */,
|
||||
37D4B19726717E1500C925CA /* Video.swift in Sources */,
|
||||
37D4B0E42671614900C925CA /* PearvidiousApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -400,7 +467,13 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
37D4B19426717CE100C925CA /* PopularVideosProvider.swift in Sources */,
|
||||
37D4B1852671684F00C925CA /* PlayerView.swift in Sources */,
|
||||
37D4B0E72671614900C925CA /* ContentView.swift in Sources */,
|
||||
37D4B1B12672A01000C925CA /* DataProvider.swift in Sources */,
|
||||
37D4B18D26717B3800C925CA /* VideoThumbnailView.swift in Sources */,
|
||||
37D4B1B52672A30700C925CA /* VideoDetailsProvider.swift in Sources */,
|
||||
37D4B19826717E1500C925CA /* Video.swift in Sources */,
|
||||
37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -425,7 +498,13 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
37D4B19526717CE100C925CA /* PopularVideosProvider.swift in Sources */,
|
||||
37D4B1842671684E00C925CA /* PlayerView.swift in Sources */,
|
||||
37D4B1802671650A00C925CA /* PearvidiousApp.swift in Sources */,
|
||||
37D4B1B22672A01000C925CA /* DataProvider.swift in Sources */,
|
||||
37D4B18E26717B3800C925CA /* VideoThumbnailView.swift in Sources */,
|
||||
37D4B1B62672A30700C925CA /* VideoDetailsProvider.swift in Sources */,
|
||||
37D4B19926717E1500C925CA /* Video.swift in Sources */,
|
||||
37D4B1812671653A00C925CA /* ContentView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -801,6 +880,11 @@
|
||||
DEVELOPMENT_TEAM = 78Z5H3M6RJ;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "Apple TV/Info.plist";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Pearvidious;
|
||||
INFOPLIST_KEY_CFBundleExecutable = "Pearvidious (Apple TV)";
|
||||
INFOPLIST_KEY_CFBundleName = "Pearvidious (Apple TV)";
|
||||
INFOPLIST_KEY_CFBundleVersion = 1;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UIUserInterfaceStyle = Automatic;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -829,6 +913,11 @@
|
||||
DEVELOPMENT_TEAM = 78Z5H3M6RJ;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "Apple TV/Info.plist";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Pearvidious;
|
||||
INFOPLIST_KEY_CFBundleExecutable = "Pearvidious (Apple TV)";
|
||||
INFOPLIST_KEY_CFBundleName = "Pearvidious (Apple TV)";
|
||||
INFOPLIST_KEY_CFBundleVersion = 1;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UIUserInterfaceStyle = Automatic;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -965,6 +1054,56 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
37D4B18F26717C6900C925CA /* XCRemoteSwiftPackageReference "Alamofire" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/Alamofire/Alamofire.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 5.0.0;
|
||||
};
|
||||
};
|
||||
37D4B19B2671817900C925CA /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 5.0.0;
|
||||
};
|
||||
};
|
||||
37D4B1A92672580400C925CA /* XCRemoteSwiftPackageReference "url-image" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/dmytro-anokhin/url-image";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 3.0.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
37D4B19026717C6900C925CA /* Alamofire */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 37D4B18F26717C6900C925CA /* XCRemoteSwiftPackageReference "Alamofire" */;
|
||||
productName = Alamofire;
|
||||
};
|
||||
37D4B19C2671817900C925CA /* SwiftyJSON */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 37D4B19B2671817900C925CA /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
|
||||
productName = SwiftyJSON;
|
||||
};
|
||||
37D4B1AA2672580400C925CA /* URLImage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 37D4B1A92672580400C925CA /* XCRemoteSwiftPackageReference "url-image" */;
|
||||
productName = URLImage;
|
||||
};
|
||||
37D4B1AC2672580400C925CA /* URLImageStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 37D4B1A92672580400C925CA /* XCRemoteSwiftPackageReference "url-image" */;
|
||||
productName = URLImageStore;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 37D4B0BD2671614700C925CA /* Project object */;
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Alamofire",
|
||||
"repositoryURL": "https://github.com/Alamofire/Alamofire.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "f96b619bcb2383b43d898402283924b80e2c4bae",
|
||||
"version": "5.4.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftyJSON",
|
||||
"repositoryURL": "https://github.com/SwiftyJSON/SwiftyJSON.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b3dcd7dbd0d488e1a7077cb33b00f2083e382f07",
|
||||
"version": "5.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "url-image",
|
||||
"repositoryURL": "https://github.com/dmytro-anokhin/url-image",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "a55b6597f6ce67dfbdc136ecfb8c8436b14ca41d",
|
||||
"version": "3.1.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
@ -19,6 +19,27 @@
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>Playground (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
<key>Playground (Playground) 2.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>5</integer>
|
||||
</dict>
|
||||
<key>Playground (Playground).xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
|
@ -1,16 +1,32 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// Shared
|
||||
//
|
||||
// Created by Arkadiusz Fal on 09/06/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
@ObservedObject var popular = PopluarVideosProvider()
|
||||
|
||||
var items: [GridItem] {
|
||||
Array(repeating: .init(.flexible()), count: 4)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Text("Hello, world!")
|
||||
.padding()
|
||||
NavigationView {
|
||||
TabView {
|
||||
Group {
|
||||
List {
|
||||
ForEach(popular.videos) { video in
|
||||
VideoThumbnailView(video: video)
|
||||
.listRowInsets(EdgeInsets(top: .zero, leading: .zero, bottom: .zero, trailing: 30))
|
||||
}
|
||||
}
|
||||
.listStyle(GroupedListStyle())
|
||||
}
|
||||
.tabItem { Text("Popular") }
|
||||
}
|
||||
}
|
||||
.task {
|
||||
async {
|
||||
popular.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,15 @@
|
||||
//
|
||||
// PearvidiousApp.swift
|
||||
// Shared
|
||||
//
|
||||
// Created by Arkadiusz Fal on 09/06/2021.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import URLImage
|
||||
import URLImageStore
|
||||
|
||||
@main
|
||||
struct PearvidiousApp: App {
|
||||
var body: some Scene {
|
||||
let urlImageService = URLImageService(fileStore: URLImageFileStore(),
|
||||
inMemoryStore: URLImageInMemoryStore())
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environment(\.urlImageService, urlImageService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
61
Shared/PlayerView.swift
Normal file
61
Shared/PlayerView.swift
Normal file
@ -0,0 +1,61 @@
|
||||
import AVKit
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct PlayerView: View {
|
||||
@ObservedObject var provider: VideoDetailsProvider
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if let video = provider.video {
|
||||
if video.url != nil {
|
||||
PlayerViewController(video)
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
}
|
||||
|
||||
if video.error {
|
||||
Text("Video can not be loaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
.task {
|
||||
async {
|
||||
provider.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PlayerViewController: UIViewControllerRepresentable {
|
||||
var video: Video
|
||||
|
||||
init(_ video: Video) {
|
||||
self.video = video
|
||||
}
|
||||
|
||||
private var player: AVPlayer {
|
||||
let item = AVPlayerItem(url: video.url!)
|
||||
item.externalMetadata = [makeMetadataItem(.commonIdentifierTitle, value: video.title)]
|
||||
|
||||
return AVPlayer(playerItem: item)
|
||||
}
|
||||
|
||||
private func makeMetadataItem(_ identifier: AVMetadataIdentifier, value: Any) -> AVMetadataItem {
|
||||
let item = AVMutableMetadataItem()
|
||||
item.identifier = identifier
|
||||
item.value = value as? NSCopying & NSObjectProtocol
|
||||
item.extendedLanguageTag = "und"
|
||||
return item.copy() as! AVMetadataItem
|
||||
}
|
||||
|
||||
func makeUIViewController(context _: Context) -> AVPlayerViewController {
|
||||
let controller = AVPlayerViewController()
|
||||
controller.modalPresentationStyle = .fullScreen
|
||||
controller.player = player
|
||||
controller.title = video.title
|
||||
controller.player?.play()
|
||||
return controller
|
||||
}
|
||||
|
||||
func updateUIViewController(_: AVPlayerViewController, context _: Context) {}
|
||||
}
|
48
Shared/VideoThumbnailView.swift
Normal file
48
Shared/VideoThumbnailView.swift
Normal file
@ -0,0 +1,48 @@
|
||||
import SwiftUI
|
||||
import URLImage
|
||||
import URLImageStore
|
||||
|
||||
struct VideoThumbnailView: View {
|
||||
@Environment(\.isFocused) var focused: Bool
|
||||
|
||||
var video: Video
|
||||
|
||||
var body: some View {
|
||||
NavigationLink(destination: PlayerView(provider: VideoDetailsProvider(video.id))) {
|
||||
HStack(alignment: .top, spacing: 2) {
|
||||
// to replace with AsyncImage when it is fixed with lazy views
|
||||
URLImage(video.thumbnailURL) { image in
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 320, height: 180)
|
||||
}
|
||||
.mask(RoundedRectangle(cornerRadius: 12))
|
||||
.frame(width: 320, height: 180)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(video.title)
|
||||
.foregroundColor(.primary)
|
||||
.bold()
|
||||
.lineLimit(1)
|
||||
|
||||
Text(video.author)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
|
||||
}.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VideoThumbnailView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VideoThumbnailView(video: Video(
|
||||
id: "A",
|
||||
title: "A very very long text which",
|
||||
thumbnailURL: URL(string: "https://invidious.home.arekf.net/vi/yXohcxCKqvo/maxres.jpg")!,
|
||||
author: "Bear"
|
||||
)).frame(maxWidth: 350)
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@
|
||||
import XCTest
|
||||
|
||||
class PearvidiousUITests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
import XCTest
|
||||
|
||||
class Tests_iOS: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
import XCTest
|
||||
|
||||
class Tests_macOS: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user