Files
omnivore/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryFeatureCard.swift
2023-04-04 21:04:13 +08:00

121 lines
3.3 KiB
Swift

import Models
import SwiftUI
import Utils
public struct LibraryFeatureCard: View {
let viewer: Viewer?
let tapHandler: () -> Void
@ObservedObject var item: LinkedItem
public init(item: LinkedItem, viewer: Viewer?, tapHandler: @escaping () -> Void = {}) {
self.item = item
self.viewer = viewer
self.tapHandler = tapHandler
}
public var body: some View {
VStack(alignment: .leading, spacing: 5) {
imageBox
title
readInfo
Spacer()
}
.padding(0)
.frame(maxWidth: 150)
}
var isFullyRead: Bool {
item.readingProgress > 95
}
var isPartiallyRead: Bool {
Int(item.readingProgress) > 0
}
var readingSpeed: Int64 {
var result = UserDefaults.standard.integer(forKey: UserDefaultKey.userWordsPerMinute.rawValue)
if result <= 0 {
result = 235
}
return Int64(result)
}
var estimatedReadingTime: String {
if item.wordsCount > 0 {
let readLen = max(1, item.wordsCount / readingSpeed)
return "\(readLen) MIN READ • "
}
return ""
}
var readingProgress: String {
// If there is no wordsCount don't show progress because it will make no sense
if item.wordsCount > 0 {
return "\(String(format: "%d", Int(item.readingProgress)))%"
}
return ""
}
var readInfo: some View {
AnyView(HStack {
Text("\(estimatedReadingTime)")
.font(Font.system(size: 11, weight: .medium))
.foregroundColor(Color.themeMediumGray)
+
Text("\(readingProgress)")
.font(Font.system(size: 11, weight: .medium))
.foregroundColor(isPartiallyRead ? Color.appGreenSuccess : Color.themeMediumGray)
}
.frame(maxWidth: 150, alignment: .leading))
}
var imageBox: some View {
Group {
if let imageURL = item.imageURL {
AsyncImage(url: imageURL) { phase in
switch phase {
case .empty:
Color.systemBackground
.frame(width: 150, height: 90)
.cornerRadius(8)
case let .success(image):
image.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 150, height: 90)
.cornerRadius(8)
case .failure:
Image(systemName: "photo")
.frame(width: 150, height: 90)
.foregroundColor(Color(hex: "#6A6968"))
.background(Color(hex: "#EBEBEB"))
.cornerRadius(8)
@unknown default:
// Since the AsyncImagePhase enum isn't frozen,
// we need to add this currently unused fallback
// to handle any new cases that might be added
// in the future:
EmptyView()
}
}
} else {
Image(systemName: "photo")
.frame(width: 150, height: 90)
.foregroundColor(Color(hex: "#6A6968"))
.background(Color(hex: "#EBEBEB"))
.cornerRadius(8)
}
}
}
var title: some View {
Text(item.unwrappedTitle.trimmingCharacters(in: .whitespacesAndNewlines))
.multilineTextAlignment(.leading)
.font(Font.system(size: 13, weight: .semibold))
.lineSpacing(1.25)
.foregroundColor(.appGrayTextContrast)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(2)
.frame(maxWidth: .infinity, minHeight: 33, alignment: .topLeading)
}
}