From 5efb3a798fe887aed96da8c1e517a6e87882a3a8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Fri, 11 Jun 2021 02:05:59 +0200 Subject: [PATCH] Improve listing --- .swiftlint.yml | 13 ----- Model/DataProvider.swift | 2 +- Model/Video.swift | 43 +++++++++++++- .../xcdebugger/Breakpoints_v2.xcbkptlist | 56 +++++++++++++++++++ Shared/ContentView.swift | 2 +- Shared/PlayerView.swift | 9 ++- Shared/VideoThumbnailView.swift | 48 ++++++++++++---- 7 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 Pearvidious.xcodeproj/xcuserdata/arek.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist diff --git a/.swiftlint.yml b/.swiftlint.yml index 416af209..97a9003b 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,14 +1 @@ parent_config: https://raw.githubusercontent.com/sindresorhus/swiftlint-config/main/.swiftlint.yml - -excluded: - - .build - -identifier_name: - excluded: - - db - - id - - vm - -type_name: - excluded: - - VM diff --git a/Model/DataProvider.swift b/Model/DataProvider.swift index 9c33cede..d94dbd11 100644 --- a/Model/DataProvider.swift +++ b/Model/DataProvider.swift @@ -5,7 +5,7 @@ class DataProvider: ObservableObject { static let instance = "https://invidious.home.arekf.net" static func request(_ path: String) -> DataRequest { - return AF.request(apiURLString(path)) + AF.request(apiURLString(path)) } static func apiURLString(_ path: String) -> String { diff --git a/Model/Video.swift b/Model/Video.swift index d7b8590c..cd5a55a5 100644 --- a/Model/Video.swift +++ b/Model/Video.swift @@ -2,20 +2,26 @@ import Alamofire import Foundation import SwiftyJSON -class Video: Identifiable, ObservableObject { +final class Video: Identifiable, ObservableObject { let id: String var title: String var thumbnailURL: URL var author: String + var length: TimeInterval + var published: String + var views: Int @Published var url: URL? @Published var error: Bool = false - init(id: String, title: String, thumbnailURL: URL, author: String) { + init(id: String, title: String, thumbnailURL: URL, author: String, length: TimeInterval, published: String, views: Int = 0) { self.id = id self.title = title self.thumbnailURL = thumbnailURL self.author = author + self.length = length + self.published = published + self.views = views } init(_ json: JSON) { @@ -23,6 +29,10 @@ class Video: Identifiable, ObservableObject { title = json["title"].stringValue thumbnailURL = json["videoThumbnails"][0]["url"].url! author = json["author"].stringValue + length = json["lengthSeconds"].doubleValue + published = json["publishedText"].stringValue + views = json["viewCount"].intValue + url = formatStreamURL(from: json["formatStreams"].arrayValue) } @@ -36,4 +46,33 @@ class Video: Identifiable, ObservableObject { return stream["url"].url } + + var playTime: String? { + let formatter = DateComponentsFormatter() + + formatter.unitsStyle = .positional + formatter.allowedUnits = length >= (60 * 60) ? [.hour, .minute, .second] : [.minute, .second] + formatter.zeroFormattingBehavior = [.pad] + + return formatter.string(from: length) + } + + var viewsCount: String { + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + formatter.maximumFractionDigits = 1 + + var number: NSNumber + var unit: String + + if views < 1_000_000 { + number = NSNumber(value: Double(views) / 1000.0) + unit = "K" + } else { + number = NSNumber(value: Double(views) / 1_000_000.0) + unit = "M" + } + + return "\(formatter.string(from: number)!)\(unit)" + } } diff --git a/Pearvidious.xcodeproj/xcuserdata/arek.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Pearvidious.xcodeproj/xcuserdata/arek.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..75672899 --- /dev/null +++ b/Pearvidious.xcodeproj/xcuserdata/arek.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + diff --git a/Shared/ContentView.swift b/Shared/ContentView.swift index b35a9028..2dac3f39 100644 --- a/Shared/ContentView.swift +++ b/Shared/ContentView.swift @@ -1,7 +1,7 @@ import SwiftUI struct ContentView: View { - @ObservedObject var popular = PopluarVideosProvider() + @ObservedObject private var popular = PopluarVideosProvider() var items: [GridItem] { Array(repeating: .init(.flexible()), count: 4) diff --git a/Shared/PlayerView.swift b/Shared/PlayerView.swift index 300988b2..276a60e4 100644 --- a/Shared/PlayerView.swift +++ b/Shared/PlayerView.swift @@ -3,7 +3,14 @@ import Foundation import SwiftUI struct PlayerView: View { - @ObservedObject var provider: VideoDetailsProvider + @ObservedObject private var provider: VideoDetailsProvider + + private var id: String + + init(id: String) { + self.id = id + provider = VideoDetailsProvider(id) + } var body: some View { ZStack { diff --git a/Shared/VideoThumbnailView.swift b/Shared/VideoThumbnailView.swift index 717c1080..85e74f39 100644 --- a/Shared/VideoThumbnailView.swift +++ b/Shared/VideoThumbnailView.swift @@ -3,12 +3,12 @@ import URLImage import URLImageStore struct VideoThumbnailView: View { - @Environment(\.isFocused) var focused: Bool + @Environment(\.isFocused) private var focused: Bool var video: Video var body: some View { - NavigationLink(destination: PlayerView(provider: VideoDetailsProvider(video.id))) { + NavigationLink(destination: PlayerView(id: video.id)) { HStack(alignment: .top, spacing: 2) { // to replace with AsyncImage when it is fixed with lazy views URLImage(video.thumbnailURL) { image in @@ -20,17 +20,41 @@ struct VideoThumbnailView: View { .mask(RoundedRectangle(cornerRadius: 12)) .frame(width: 320, height: 180) - VStack(alignment: .leading) { - Text(video.title) - .foregroundColor(.primary) - .bold() - .lineLimit(1) + HStack { + VStack(alignment: .leading) { + Text(video.title) + .foregroundColor(.primary) + .bold() + .lineLimit(1) - Text(video.author) + Text("\(video.author)") + .foregroundColor(.secondary) + .bold() + .lineLimit(1) + + HStack(spacing: 8) { + Image(systemName: "calendar") + Text(video.published) + + Image(systemName: "eye") + Text(video.viewsCount) + } .foregroundColor(.secondary) - .lineLimit(1) + .padding(.top) + } + .padding() - }.padding() + Spacer() + + HStack(spacing: 8) { + Image(systemName: "clock") + + Text(video.playTime ?? "-") + .fontWeight(.bold) + } + .foregroundColor(.secondary) + } + .frame(minHeight: 180) } } } @@ -42,7 +66,9 @@ struct VideoThumbnailView_Previews: PreviewProvider { id: "A", title: "A very very long text which", thumbnailURL: URL(string: "https://invidious.home.arekf.net/vi/yXohcxCKqvo/maxres.jpg")!, - author: "Bear" + author: "Bear", + length: 240, + published: "2 days ago" )).frame(maxWidth: 350) } }