diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift index b7c77bc5b..aebbf0e15 100644 --- a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift +++ b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift @@ -79,6 +79,17 @@ public extension LinkedItem { (labels?.count ?? 0) > 0 } + var noteText: String? { + if let highlights = highlights?.compactMap({ $0 as? Highlight }) { + let result = highlights + .filter { $0.type == "NOTE" } + .sorted(by: { $0.updatedAt ?? Date() < $1.updatedAt ?? Date() }) + .first + return result?.annotation + } + return nil + } + var isUnread: Bool { readingProgress <= 0 } diff --git a/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift b/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift index 0e47bffd6..941dce537 100644 --- a/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift +++ b/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift @@ -50,6 +50,7 @@ public extension Color { static var extensionPanelBackground: Color { Color("_extensionPanelBackground", bundle: .module) } static var extensionTextSubtle: Color { Color("_extensionTextSubtle", bundle: .module) } + static var noteContainer: Color { Color("_noteContainer", bundle: .module) } static var textFieldBackground: Color { Color("_textFieldBackground", bundle: .module) } // Apple system UIColor equivalents diff --git a/apple/OmnivoreKit/Sources/Views/Colors/ThemeColors.xcassets/_noteContainer.colorset/Contents.json b/apple/OmnivoreKit/Sources/Views/Colors/ThemeColors.xcassets/_noteContainer.colorset/Contents.json new file mode 100644 index 000000000..f42ff6844 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/Colors/ThemeColors.xcassets/_noteContainer.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xED", + "green" : "0xED", + "red" : "0xED" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x2A", + "green" : "0x2A", + "red" : "0x2A" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift deleted file mode 100644 index 9b5573ad8..000000000 --- a/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift +++ /dev/null @@ -1,117 +0,0 @@ -import Models -import SwiftUI -import Utils - -public struct FeedCard: 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 { - HStack(alignment: .top, spacing: 10) { - VStack(alignment: .leading, spacing: 1) { - Text(item.unwrappedTitle) - .font(.appCallout) - .lineSpacing(1.25) - .foregroundColor(.appGrayTextContrast) - .fixedSize(horizontal: false, vertical: true) - .padding(EdgeInsets(top: 0, leading: 0, bottom: 2, trailing: 0)) - - if let author = item.author { - Text("By \(author)") - .font(.appCaption) - .foregroundColor(.appGrayText) - .lineLimit(1) - } - - if let publisherDisplayName = item.publisherDisplayName { - Text(publisherDisplayName) - .font(.appCaption) - .foregroundColor(.appGrayText) - .lineLimit(1) - } - } - .frame( - minWidth: 0, - maxWidth: .infinity, - minHeight: 0, - maxHeight: .infinity, - alignment: .topLeading - ) - .multilineTextAlignment(.leading) - .padding(0) - - Group { - if let imageURL = item.imageURL { - AsyncImage(url: imageURL) { phase in - if let image = phase.image { - image - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: 80, height: 80) - .cornerRadius(6) - } else { - Color.systemBackground - .frame(width: 80, height: 80) - .cornerRadius(6) - } - } - } - } - } - - if item.hasLabels { - // Category Labels - ScrollView(.horizontal, showsIndicators: false) { - HStack { - ForEach(item.sortedLabels, id: \.self) { - TextChip(feedItemLabel: $0) - } - Spacer() - } - }.introspectScrollView { scrollView in - #if os(iOS) - scrollView.bounces = false - #endif - } - .padding(.top, 0) - #if os(macOS) - .onTapGesture { - tapHandler() - } - #endif - } - - let recs = Recommendation.notViewers(viewer: viewer, item.recommendations) - if recs.count > 0 { - let byStr = Recommendation.byline(recs) - let inStr = Recommendation.groupsLine(recs) - HStack { - Image(systemName: "sparkles") - Text("Recommended by \(byStr) in \(inStr)") - .font(.appCaption) - .frame(alignment: .leading) - Spacer() - } - } - } - .padding(.top, 0) - .padding(.bottom, 8) - .frame( - minWidth: nil, - idealWidth: nil, - maxWidth: nil, - minHeight: 70, - idealHeight: nil, - maxHeight: nil, - alignment: .topLeading - ) - } -} diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift index 47b41f3cf..94ba4f02b 100644 --- a/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/LibraryItemCard.swift @@ -47,6 +47,7 @@ public extension View { public struct LibraryItemCard: View { let viewer: Viewer? @ObservedObject var item: LinkedItem + @State var noteLineLimit: Int? = 3 public init(item: LinkedItem, viewer: Viewer?) { self.item = item @@ -64,6 +65,30 @@ public struct LibraryItemCard: View { if item.hasLabels { labels } + + if let note = item.noteText { + HStack(alignment: .top, spacing: 10) { + avatarImage + .frame(width: 20, height: 20) + .padding(.vertical, 10) + .padding(.leading, 10) + + Text(note) + .font(Font.system(size: 12)) + .multilineTextAlignment(.leading) + .lineLimit(noteLineLimit) + .padding(.vertical, 10) + .padding(.trailing, 10) + } + .frame(maxWidth: .infinity) + .frame(alignment: .topLeading) + .background(Color.noteContainer) + .cornerRadius(5) + .allowsHitTesting(noteLineLimit != nil) + .onTapGesture { + noteLineLimit = nil + } + } } .padding(5) .padding(.top, 10) @@ -79,6 +104,16 @@ public struct LibraryItemCard: View { Int(item.readingProgress) > 0 } + var avatarImage: some View { + ZStack(alignment: .center) { + Circle() + .foregroundColor(Color.appCtaYellow) + Text((viewer?.name ?? "O").prefix(1)) + .font(Font.system(size: 10)) + .foregroundColor(Color.black) + } + } + var readIndicator: some View { HStack { Circle()