From 4c83d7ed640685414b647ee167134188fbc4e83e Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Mon, 28 Feb 2022 21:37:37 -0800 Subject: [PATCH 01/16] pass and isCompact bool to inner feed view --- .../App/Views/Home/HomeFeedViewIOS.swift | 20 ++++++++++--------- .../Sources/App/Views/Home/HomeView.swift | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 69d3f436f..5725df706 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -12,7 +12,7 @@ import Views var body: some View { NavigationView { - HomeFeedContainerView(viewModel: viewModel) + HomeFeedContainerView(isCompact: true, viewModel: viewModel) .toolbar { ToolbarItem { NavigationLink( @@ -32,13 +32,14 @@ import Views } struct HomeFeedContainerView: View { + let isCompact: Bool @EnvironmentObject var dataService: DataService @State private var searchQuery = "" @ObservedObject var viewModel: HomeFeedViewModel var body: some View { if #available(iOS 15.0, *) { - HomeFeedView(searchQuery: $searchQuery, viewModel: viewModel) + HomeFeedView(isCompact: isCompact, searchQuery: $searchQuery, viewModel: viewModel) .refreshable { viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) } @@ -62,7 +63,7 @@ import Views viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) } } else { - HomeFeedView(searchQuery: $searchQuery, viewModel: viewModel).toolbar { + HomeFeedView(isCompact: isCompact, searchQuery: $searchQuery, viewModel: viewModel).toolbar { ToolbarItem { Button( action: { viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) }, @@ -75,6 +76,7 @@ import Views } struct HomeFeedView: View { + let isCompact: Bool @EnvironmentObject var dataService: DataService @Binding var searchQuery: String @@ -174,7 +176,7 @@ import Views .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in // Don't refresh the list if the user is currently reading an article if selectedLinkItem == nil { - refresh() + viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) } } .onReceive(NotificationCenter.default.publisher(for: Notification.Name("PushFeedItem"))) { notification in @@ -195,14 +197,14 @@ import Views } .onAppear { if viewModel.items.isEmpty { - refresh() + viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) } } } - - private func refresh() { - viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) - } } + // struct HomeFeedListView: View {} +// + // struct HomeFeedGridView: View {} + #endif diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift index cc074c995..701814b53 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift @@ -8,7 +8,7 @@ struct HomeView: View { if UIDevice.isIPhone { CompactHomeView(viewModel: viewModel) } else { - HomeFeedContainerView(viewModel: viewModel) + HomeFeedContainerView(isCompact: false, viewModel: viewModel) } #elseif os(macOS) HomeFeedView(viewModel: viewModel) From 533b83360cf10262f9bbfcd04265048353a6d2de Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 08:12:05 -0800 Subject: [PATCH 02/16] apply notification modifiers to HomeFeedContainerView --- .../App/Views/Home/HomeFeedViewIOS.swift | 100 +++++++++++------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 5725df706..b9702ce9f 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -35,11 +35,22 @@ import Views let isCompact: Bool @EnvironmentObject var dataService: DataService @State private var searchQuery = "" + @State private var snoozePresented = false + @State private var itemToSnooze: FeedItem? + @State private var selectedLinkItem: FeedItem? @ObservedObject var viewModel: HomeFeedViewModel var body: some View { - if #available(iOS 15.0, *) { - HomeFeedView(isCompact: isCompact, searchQuery: $searchQuery, viewModel: viewModel) + Group { + if #available(iOS 15.0, *) { + HomeFeedView( + isCompact: isCompact, + searchQuery: $searchQuery, + selectedLinkItem: $selectedLinkItem, + snoozePresented: $snoozePresented, + itemToSnooze: $itemToSnooze, + viewModel: viewModel + ) .refreshable { viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) } @@ -62,16 +73,53 @@ import Views .onSubmit(of: .search) { viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) } - } else { - HomeFeedView(isCompact: isCompact, searchQuery: $searchQuery, viewModel: viewModel).toolbar { - ToolbarItem { - Button( - action: { viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) }, - label: { Label("Refresh Feed", systemImage: "arrow.clockwise") } - ) + } else { + HomeFeedView( + isCompact: isCompact, + searchQuery: $searchQuery, + selectedLinkItem: $selectedLinkItem, + snoozePresented: $snoozePresented, + itemToSnooze: $itemToSnooze, + viewModel: viewModel + ) + .toolbar { + ToolbarItem { + Button( + action: { viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) }, + label: { Label("Refresh Feed", systemImage: "arrow.clockwise") } + ) + } } } } + .navigationTitle("Home") + .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in + // Don't refresh the list if the user is currently reading an article + if selectedLinkItem == nil { + viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) + } + } + .onReceive(NotificationCenter.default.publisher(for: Notification.Name("PushFeedItem"))) { notification in + if let feedItem = notification.userInfo?["feedItem"] as? FeedItem { + viewModel.pushFeedItem(item: feedItem) + self.selectedLinkItem = feedItem + } + } + .formSheet(isPresented: $snoozePresented) { + SnoozeView(snoozePresented: $snoozePresented, itemToSnooze: $itemToSnooze) { + viewModel.snoozeUntil( + dataService: dataService, + linkId: $0.feedItemId, + until: $0.snoozeUntilDate, + successMessage: $0.successMessage + ) + } + } + .onAppear { + if viewModel.items.isEmpty { + viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) + } + } } } @@ -79,12 +127,12 @@ import Views let isCompact: Bool @EnvironmentObject var dataService: DataService @Binding var searchQuery: String + @Binding var selectedLinkItem: FeedItem? + @Binding var snoozePresented: Bool + @Binding var itemToSnooze: FeedItem? - @State private var selectedLinkItem: FeedItem? @State private var itemToRemove: FeedItem? @State private var confirmationShown = false - @State private var snoozePresented = false - @State private var itemToSnooze: FeedItem? @ObservedObject var viewModel: HomeFeedViewModel @@ -172,34 +220,6 @@ import Views } } .listStyle(PlainListStyle()) - .navigationTitle("Home") - .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in - // Don't refresh the list if the user is currently reading an article - if selectedLinkItem == nil { - viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) - } - } - .onReceive(NotificationCenter.default.publisher(for: Notification.Name("PushFeedItem"))) { notification in - if let feedItem = notification.userInfo?["feedItem"] as? FeedItem { - viewModel.pushFeedItem(item: feedItem) - self.selectedLinkItem = feedItem - } - } - .formSheet(isPresented: $snoozePresented) { - SnoozeView(snoozePresented: $snoozePresented, itemToSnooze: $itemToSnooze) { - viewModel.snoozeUntil( - dataService: dataService, - linkId: $0.feedItemId, - until: $0.snoozeUntilDate, - successMessage: $0.successMessage - ) - } - } - .onAppear { - if viewModel.items.isEmpty { - viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true) - } - } } } From f2ac15f58b9583b9023a9d33ace7bea6caed6eeb Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 08:16:54 -0800 Subject: [PATCH 03/16] split HomeFeedView into HomeFeedListView and HomeFeedGridView --- .../App/Views/Home/HomeFeedViewIOS.swift | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index b9702ce9f..f429c55ec 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -125,6 +125,29 @@ import Views struct HomeFeedView: View { let isCompact: Bool + @Binding var searchQuery: String + @Binding var selectedLinkItem: FeedItem? + @Binding var snoozePresented: Bool + @Binding var itemToSnooze: FeedItem? + + @ObservedObject var viewModel: HomeFeedViewModel + + var body: some View { + if isCompact { + HomeFeedListView( + searchQuery: $searchQuery, + selectedLinkItem: $selectedLinkItem, + snoozePresented: $snoozePresented, + itemToSnooze: $itemToSnooze, + viewModel: viewModel + ) + } else { + HomeFeedGridView() + } + } + } + + struct HomeFeedListView: View { @EnvironmentObject var dataService: DataService @Binding var searchQuery: String @Binding var selectedLinkItem: FeedItem? @@ -223,8 +246,10 @@ import Views } } - // struct HomeFeedListView: View {} -// - // struct HomeFeedGridView: View {} + struct HomeFeedGridView: View { + var body: some View { + Text("Grid View") + } + } #endif From d9f642d46b207ed940adb3b5304716257aa03b8b Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 08:27:08 -0800 Subject: [PATCH 04/16] add back list items to HomeFeedGridView --- .../App/Views/Home/HomeFeedViewIOS.swift | 62 ++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index f429c55ec..33682f8fd 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -142,7 +142,13 @@ import Views viewModel: viewModel ) } else { - HomeFeedGridView() + HomeFeedGridView( + searchQuery: $searchQuery, + selectedLinkItem: $selectedLinkItem, + snoozePresented: $snoozePresented, + itemToSnooze: $itemToSnooze, + viewModel: viewModel + ) } } } @@ -247,8 +253,60 @@ import Views } struct HomeFeedGridView: View { + @EnvironmentObject var dataService: DataService + @Binding var searchQuery: String + @Binding var selectedLinkItem: FeedItem? + @Binding var snoozePresented: Bool + @Binding var itemToSnooze: FeedItem? + + @State private var itemToRemove: FeedItem? + @State private var confirmationShown = false + + @ObservedObject var viewModel: HomeFeedViewModel + var body: some View { - Text("Grid View") + List { + Section { + ForEach(viewModel.items) { item in + let link = ZStack { + FeedCardNavigationLink( + item: item, + searchQuery: searchQuery, + selectedLinkItem: $selectedLinkItem, + viewModel: viewModel + ) + }.contextMenu { + FeedItemContextMenuView( + item: item, + selectedLinkItem: $selectedLinkItem, + snoozePresented: $snoozePresented, + itemToSnooze: $itemToSnooze, + viewModel: viewModel + ) + } + if #available(iOS 15.0, *) { + link + .alert("Are you sure?", isPresented: $confirmationShown) { + Button("Remove Link", role: .destructive) { + if let itemToRemove = itemToRemove { + withAnimation { + viewModel.removeLink(dataService: dataService, linkId: itemToRemove.id) + } + } + self.itemToRemove = nil + } + Button("Cancel", role: .cancel) { self.itemToRemove = nil } + } + } else { + link + } + } + } + + if viewModel.isLoading { + LoadingSection() + } + } } } From 547860850266b35a96609809d4455832eb19f54b Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 08:34:55 -0800 Subject: [PATCH 05/16] use lazyVGrid for wide ios home layout --- .../OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 33682f8fd..9aa82ee9a 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -265,8 +265,8 @@ import Views @ObservedObject var viewModel: HomeFeedViewModel var body: some View { - List { - Section { + ScrollView { + LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 20) { ForEach(viewModel.items) { item in let link = ZStack { FeedCardNavigationLink( From f6b0eb667d37b0fc8f5b133447f6e99139b29cea Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 08:40:42 -0800 Subject: [PATCH 06/16] remove compact home feed view struct --- .../App/Views/Home/HomeFeedViewIOS.swift | 24 ------------------- .../Sources/App/Views/Home/HomeView.swift | 18 +++++++++++++- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 9aa82ee9a..9ca04870d 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -7,30 +7,6 @@ import Utils import Views #if os(iOS) - struct CompactHomeView: View { - @ObservedObject var viewModel: HomeFeedViewModel - - var body: some View { - NavigationView { - HomeFeedContainerView(isCompact: true, viewModel: viewModel) - .toolbar { - ToolbarItem { - NavigationLink( - destination: { ProfileView() }, - label: { - Image.profile - .resizable() - .frame(width: 26, height: 26) - .padding() - } - ) - } - } - } - .accentColor(.appGrayTextContrast) - } - } - struct HomeFeedContainerView: View { let isCompact: Bool @EnvironmentObject var dataService: DataService diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift index 701814b53..0a49242b4 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift @@ -6,7 +6,23 @@ struct HomeView: View { var body: some View { #if os(iOS) if UIDevice.isIPhone { - CompactHomeView(viewModel: viewModel) + NavigationView { + HomeFeedContainerView(isCompact: true, viewModel: viewModel) + .toolbar { + ToolbarItem { + NavigationLink( + destination: { ProfileView() }, + label: { + Image.profile + .resizable() + .frame(width: 26, height: 26) + .padding() + } + ) + } + } + } + .accentColor(.appGrayTextContrast) } else { HomeFeedContainerView(isCompact: false, viewModel: viewModel) } From 48521c2c128bacebaa125eefb591da67aa867e81 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 09:04:02 -0800 Subject: [PATCH 07/16] add a GridCardNavigationLink view --- .../Components/FeedCardNavigationLink.swift | 26 +++++++++++++++++++ .../App/Views/Home/HomeFeedViewIOS.swift | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index 7fd196068..fbb629673 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -28,3 +28,29 @@ struct FeedCardNavigationLink: View { FeedCard(item: item) } } + +struct GridCardNavigationLink: View { + @EnvironmentObject var dataService: DataService + + let item: FeedItem + let searchQuery: String + + @Binding var selectedLinkItem: FeedItem? + + @ObservedObject var viewModel: HomeFeedViewModel + var body: some View { + NavigationLink( + destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item)), + tag: item, + selection: $selectedLinkItem + ) { + EmptyView() + } + .opacity(0) + .buttonStyle(PlainButtonStyle()) + .onAppear { + viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) + } + FeedCard(item: item) + } +} diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 9ca04870d..647366eaf 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -245,7 +245,7 @@ import Views LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 20) { ForEach(viewModel.items) { item in let link = ZStack { - FeedCardNavigationLink( + GridCardNavigationLink( item: item, searchQuery: searchQuery, selectedLinkItem: $selectedLinkItem, From 0a9d06efb1942c75185f7656de45e0a55b927c80 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 09:13:20 -0800 Subject: [PATCH 08/16] create GridCard view --- .../Components/FeedCardNavigationLink.swift | 2 +- .../App/Views/Home/HomeFeedViewIOS.swift | 30 ++++++------ .../App/Views/Home/HomeFeedViewMac.swift | 15 +++--- .../Sources/Views/HomeFeedCardView.swift | 48 +++++++++++++++++++ 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index fbb629673..f6b87b670 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -51,6 +51,6 @@ struct GridCardNavigationLink: View { .onAppear { viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) } - FeedCard(item: item) + GridCard(item: item) } } diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 647366eaf..c5034c443 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -145,14 +145,13 @@ import Views List { Section { ForEach(viewModel.items) { item in - let link = ZStack { - FeedCardNavigationLink( - item: item, - searchQuery: searchQuery, - selectedLinkItem: $selectedLinkItem, - viewModel: viewModel - ) - }.contextMenu { + let link = FeedCardNavigationLink( + item: item, + searchQuery: searchQuery, + selectedLinkItem: $selectedLinkItem, + viewModel: viewModel + ) + .contextMenu { FeedItemContextMenuView( item: item, selectedLinkItem: $selectedLinkItem, @@ -244,14 +243,13 @@ import Views ScrollView { LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 20) { ForEach(viewModel.items) { item in - let link = ZStack { - GridCardNavigationLink( - item: item, - searchQuery: searchQuery, - selectedLinkItem: $selectedLinkItem, - viewModel: viewModel - ) - }.contextMenu { + let link = GridCardNavigationLink( + item: item, + searchQuery: searchQuery, + selectedLinkItem: $selectedLinkItem, + viewModel: viewModel + ) + .contextMenu { FeedItemContextMenuView( item: item, selectedLinkItem: $selectedLinkItem, diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift index 56aa8dee5..6f767a15d 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift @@ -22,14 +22,13 @@ import Views List { Section { ForEach(viewModel.items) { item in - ZStack { - FeedCardNavigationLink( - item: item, - searchQuery: searchQuery, - selectedLinkItem: $selectedLinkItem, - viewModel: viewModel - ) - }.contextMenu { + FeedCardNavigationLink( + item: item, + searchQuery: searchQuery, + selectedLinkItem: $selectedLinkItem, + viewModel: viewModel + ) + .contextMenu { FeedItemContextMenuView( item: item, selectedLinkItem: $selectedLinkItem, diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index 310759e6c..e48d3d4ca 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -48,3 +48,51 @@ public struct FeedCard: View { .frame(maxWidth: .infinity, minHeight: 100, idealHeight: 100, maxHeight: 100) } } + +public struct GridCard: View { + let item: FeedItem + + public init(item: FeedItem) { + self.item = item + } + + public var body: some View { + HStack(alignment: .top, spacing: 6) { + VStack(alignment: .leading, spacing: 6) { + Text(item.title) + .font(.appSubheadline) + .foregroundColor(.appGrayTextContrast) + .lineLimit(2) + .frame(maxWidth: .infinity, alignment: .leading) + + if let author = item.author { + Text("By \(author)") + .font(.appCaption) + .foregroundColor(.appGrayText) + .lineLimit(1) + } + + if let publisherURL = item.publisherHostname { + Text(publisherURL) + .font(.appCaption) + .foregroundColor(.appGrayText) + .underline() + .lineLimit(1) + } + } + .frame(maxWidth: .infinity) + .multilineTextAlignment(.leading) + .padding(0) + + Group { + if let imageURL = item.imageURL { + AsyncImage(url: imageURL, isResizable: true) + .aspectRatio(1, contentMode: .fill) + .frame(width: 80, height: 80) + .cornerRadius(6) + } + } + } + .frame(maxWidth: .infinity, minHeight: 100, idealHeight: 100, maxHeight: 100) + } +} From e8873ad5f4a4c6562818335d3cf8a7eea7bf6ab6 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 10:07:50 -0800 Subject: [PATCH 09/16] stub in grid feed card wireframe --- .../Components/FeedCardNavigationLink.swift | 25 ++++--- .../Sources/Views/HomeFeedCardView.swift | 75 +++++++++++++------ 2 files changed, 65 insertions(+), 35 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index f6b87b670..22296c679 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -39,18 +39,19 @@ struct GridCardNavigationLink: View { @ObservedObject var viewModel: HomeFeedViewModel var body: some View { - NavigationLink( - destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item)), - tag: item, - selection: $selectedLinkItem - ) { - EmptyView() + ZStack { + NavigationLink( + destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item)), + tag: item, + selection: $selectedLinkItem + ) { + GridCard(item: item) + } +// .opacity(0) +// .buttonStyle(PlainButtonStyle()) + .onAppear { + viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) + } } - .opacity(0) - .buttonStyle(PlainButtonStyle()) - .onAppear { - viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) - } - GridCard(item: item) } } diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index e48d3d4ca..d0674fa62 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -57,42 +57,71 @@ public struct GridCard: View { } public var body: some View { - HStack(alignment: .top, spacing: 6) { - VStack(alignment: .leading, spacing: 6) { - Text(item.title) - .font(.appSubheadline) - .foregroundColor(.appGrayTextContrast) - .lineLimit(2) - .frame(maxWidth: .infinity, alignment: .leading) + VStack(alignment: .leading, spacing: 16) { + // Progress Bar + ProgressView(value: Double.random(in: 0 ... 1)) + .foregroundColor(.appYellow48) + .frame(maxWidth: .infinity, alignment: .leading) - if let author = item.author { - Text("By \(author)") - .font(.appCaption) - .foregroundColor(.appGrayText) + // Title, Subtitle, Menu Button + VStack(alignment: .leading, spacing: 6) { + HStack { + Text(item.title) + .font(.appSubheadline) + .foregroundColor(.appGrayTextContrast) .lineLimit(1) + Spacer() + Button( + action: { print("grid button tapped") }, + label: { Image.profile } + ) } - if let publisherURL = item.publisherHostname { - Text(publisherURL) - .font(.appCaption) - .foregroundColor(.appGrayText) - .underline() - .lineLimit(1) + HStack { + if let author = item.author { + Text("by \(author)") + .font(.appCaption) + .foregroundColor(.appGrayText) + .lineLimit(1) + } + + if let publisherURL = item.publisherHostname { + Text(publisherURL) + .font(.appCaption) + .foregroundColor(.appGrayText) + .underline() + .lineLimit(1) + } + + Spacer() } } - .frame(maxWidth: .infinity) - .multilineTextAlignment(.leading) - .padding(0) + .frame(height: 40) + + // Description, Image + HStack { + Text(item.description ?? "No description") + .font(.appSubheadline) + .foregroundColor(.appGrayTextContrast) + .lineLimit(nil) + + Spacer() - Group { if let imageURL = item.imageURL { AsyncImage(url: imageURL, isResizable: true) .aspectRatio(1, contentMode: .fill) - .frame(width: 80, height: 80) + .frame(width: 135, height: 90) .cornerRadius(6) } } + .frame(height: 140) + + // Labels + HStack { + Text("Label 1") + Text("Label 2") + Spacer() + } } - .frame(maxWidth: .infinity, minHeight: 100, idealHeight: 100, maxHeight: 100) } } From ce8075afede884b9ff67e310f5fceaf63ff78351 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 13:12:56 -0800 Subject: [PATCH 10/16] update styling for grid item cards --- .../Components/FeedCardNavigationLink.swift | 11 ++- .../App/Views/Home/HomeFeedViewIOS.swift | 6 +- .../Sources/App/Views/Home/HomeView.swift | 4 +- .../Sources/Views/HomeFeedCardView.swift | 83 +++++++++++++++---- 4 files changed, 85 insertions(+), 19 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index 22296c679..52c4e83b0 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -12,6 +12,7 @@ struct FeedCardNavigationLink: View { @Binding var selectedLinkItem: FeedItem? @ObservedObject var viewModel: HomeFeedViewModel + var body: some View { NavigationLink( destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item)), @@ -38,6 +39,7 @@ struct GridCardNavigationLink: View { @Binding var selectedLinkItem: FeedItem? @ObservedObject var viewModel: HomeFeedViewModel + var body: some View { ZStack { NavigationLink( @@ -47,11 +49,16 @@ struct GridCardNavigationLink: View { ) { GridCard(item: item) } -// .opacity(0) -// .buttonStyle(PlainButtonStyle()) +// .buttonStyle(FlatLinkStyle()) .onAppear { viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) } } } } + +struct FlatLinkStyle: ButtonStyle { + func makeBody(configuration: Configuration) -> some View { + configuration.label + } +} diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index c5034c443..926e55535 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -239,9 +239,11 @@ import Views @ObservedObject var viewModel: HomeFeedViewModel + private let columns = Array(repeating: GridItem(.flexible(), spacing: 20), count: 2) + var body: some View { ScrollView { - LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 20) { + LazyVGrid(columns: columns, spacing: 20) { ForEach(viewModel.items) { item in let link = GridCardNavigationLink( item: item, @@ -276,6 +278,8 @@ import Views } } } + .padding() + .background(Color(.systemGroupedBackground)) if viewModel.isLoading { LoadingSection() diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift index 0a49242b4..62181c412 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeView.swift @@ -24,7 +24,9 @@ struct HomeView: View { } .accentColor(.appGrayTextContrast) } else { - HomeFeedContainerView(isCompact: false, viewModel: viewModel) + GeometryReader { geo in + HomeFeedContainerView(isCompact: geo.size.width < 500, viewModel: viewModel) + } } #elseif os(macOS) HomeFeedView(viewModel: viewModel) diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index d0674fa62..4bb50bf8b 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -59,15 +59,20 @@ public struct GridCard: View { public var body: some View { VStack(alignment: .leading, spacing: 16) { // Progress Bar - ProgressView(value: Double.random(in: 0 ... 1)) - .foregroundColor(.appYellow48) - .frame(maxWidth: .infinity, alignment: .leading) + if #available(iOS 15.0, *) { + ProgressView(value: Double.random(in: 0 ... 1)) + .tint(.appYellow48) + .frame(maxWidth: .infinity, alignment: .leading) + } else { + ProgressView(value: Double.random(in: 0 ... 1)) + .frame(maxWidth: .infinity, alignment: .leading) + } // Title, Subtitle, Menu Button - VStack(alignment: .leading, spacing: 6) { + VStack(alignment: .leading, spacing: 4) { HStack { Text(item.title) - .font(.appSubheadline) + .font(.appHeadline) .foregroundColor(.appGrayTextContrast) .lineLimit(1) Spacer() @@ -80,14 +85,14 @@ public struct GridCard: View { HStack { if let author = item.author { Text("by \(author)") - .font(.appCaption) + .font(.appCaptionTwo) .foregroundColor(.appGrayText) .lineLimit(1) } if let publisherURL = item.publisherHostname { Text(publisherURL) - .font(.appCaption) + .font(.appCaptionTwo) .foregroundColor(.appGrayText) .underline() .lineLimit(1) @@ -96,14 +101,16 @@ public struct GridCard: View { Spacer() } } - .frame(height: 40) + .frame(height: 30) + .padding(.horizontal) // Description, Image - HStack { - Text(item.description ?? "No description") - .font(.appSubheadline) + HStack(alignment: .top) { + Text(item.description ?? item.title) + .font(.appFootnote) .foregroundColor(.appGrayTextContrast) .lineLimit(nil) + .multilineTextAlignment(.leading) Spacer() @@ -111,17 +118,63 @@ public struct GridCard: View { AsyncImage(url: imageURL, isResizable: true) .aspectRatio(1, contentMode: .fill) .frame(width: 135, height: 90) - .cornerRadius(6) + .cornerRadius(3) } } - .frame(height: 140) + .frame(height: 95) + .padding(.horizontal) // Labels HStack { - Text("Label 1") - Text("Label 2") + if Bool.random() { + TextChip(text: "label", color: .red) + TextChip(text: "longer label", color: .blue) + } Spacer() } + .frame(height: 30) + .padding(.horizontal) + .padding(.bottom, 8) } + .background(Color(.secondarySystemGroupedBackground)) + .cornerRadius(6) + } +} + +struct TextChipdep: View { + let text: String + let color: Color + + var body: some View { + Capsule() + .fill(color.opacity(0.3)) + .border(color.opacity(0.7), width: 3) + .overlay( + Text(text) + .font(.appFootnote) + .foregroundColor(color) + .padding() + ) + } +} + +struct TextChip: View { + let text: String + let color: Color + let cornerRadius = 20.0 + + var body: some View { + Text(text) + .padding(.horizontal, 10) + .padding(.vertical, 5) + .font(.appFootnote) + .foregroundColor(color) + .lineLimit(1) + .background(color.opacity(0.1)) + .cornerRadius(cornerRadius) + .overlay( + RoundedRectangle(cornerRadius: cornerRadius) + .stroke(color.opacity(0.3), lineWidth: 1) + ) } } From d130ba6b92368b1b612ab0edeb32969b304b5639 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 13:38:50 -0800 Subject: [PATCH 11/16] add feature flag for showing tags on grid item cards --- .../Components/FeedCardNavigationLink.swift | 6 ++-- .../Sources/Utils/FeatureFlags.swift | 1 + .../Sources/Views/HomeFeedCardView.swift | 29 +++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index 52c4e83b0..a7a3276aa 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -12,7 +12,7 @@ struct FeedCardNavigationLink: View { @Binding var selectedLinkItem: FeedItem? @ObservedObject var viewModel: HomeFeedViewModel - + var body: some View { NavigationLink( destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item)), @@ -39,7 +39,7 @@ struct GridCardNavigationLink: View { @Binding var selectedLinkItem: FeedItem? @ObservedObject var viewModel: HomeFeedViewModel - + var body: some View { ZStack { NavigationLink( @@ -49,7 +49,7 @@ struct GridCardNavigationLink: View { ) { GridCard(item: item) } -// .buttonStyle(FlatLinkStyle()) + .buttonStyle(FlatLinkStyle()) .onAppear { viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) } diff --git a/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift b/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift index 43385fcc4..67a1faf37 100644 --- a/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift +++ b/apple/OmnivoreKit/Sources/Utils/FeatureFlags.swift @@ -14,4 +14,5 @@ public enum FeatureFlag { public static let enablePushNotifications = false public static let enableShareButton = false public static let enableSnooze = false + public static let showFeedItemTags = false } diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index 4bb50bf8b..0d559f443 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -1,5 +1,6 @@ import Models import SwiftUI +import Utils public struct FeedCard: View { let item: FeedItem @@ -60,11 +61,11 @@ public struct GridCard: View { VStack(alignment: .leading, spacing: 16) { // Progress Bar if #available(iOS 15.0, *) { - ProgressView(value: Double.random(in: 0 ... 1)) + ProgressView(value: min(abs(item.readingProgress) / 100, 1)) .tint(.appYellow48) .frame(maxWidth: .infinity, alignment: .leading) } else { - ProgressView(value: Double.random(in: 0 ... 1)) + ProgressView(value: max(abs(item.readingProgress) / 100, 1)) .frame(maxWidth: .infinity, alignment: .leading) } @@ -104,7 +105,7 @@ public struct GridCard: View { .frame(height: 30) .padding(.horizontal) - // Description, Image + // Link description and image HStack(alignment: .top) { Text(item.description ?? item.title) .font(.appFootnote) @@ -124,17 +125,21 @@ public struct GridCard: View { .frame(height: 95) .padding(.horizontal) - // Labels - HStack { - if Bool.random() { - TextChip(text: "label", color: .red) - TextChip(text: "longer label", color: .blue) + // Category Labels + if FeatureFlag.showFeedItemTags { + ScrollView(.horizontal, showsIndicators: false) { + HStack { + TextChip(text: "label", color: .red) + TextChip(text: "longer label", color: .blue) + Spacer() + } + .frame(height: 30) + .padding(.horizontal) + .padding(.bottom, 8) } - Spacer() + } else { + Spacer(minLength: 8) } - .frame(height: 30) - .padding(.horizontal) - .padding(.bottom, 8) } .background(Color(.secondarySystemGroupedBackground)) .cornerRadius(6) From 81522aef22e45e80a1131f2d2dae1ba29f264711 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 14:30:12 -0800 Subject: [PATCH 12/16] show context menu on button tap --- .../Components/FeedCardNavigationLink.swift | 3 ++- .../App/Views/Home/HomeFeedViewIOS.swift | 9 +++++++ .../Sources/Views/HomeFeedCardView.swift | 27 ++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index a7a3276aa..7557374c1 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -35,6 +35,7 @@ struct GridCardNavigationLink: View { let item: FeedItem let searchQuery: String + let actionHandler: (GridCardAction) -> Void @Binding var selectedLinkItem: FeedItem? @@ -47,7 +48,7 @@ struct GridCardNavigationLink: View { tag: item, selection: $selectedLinkItem ) { - GridCard(item: item) + GridCard(item: item, actionHandler: actionHandler) } .buttonStyle(FlatLinkStyle()) .onAppear { diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 926e55535..241aca58f 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -248,6 +248,15 @@ import Views let link = GridCardNavigationLink( item: item, searchQuery: searchQuery, + actionHandler: { action in + switch action { + case .toggleArchiveStatus: + viewModel.setLinkArchived(dataService: dataService, linkId: item.id, archived: !item.isArchived) + case .delete: + itemToRemove = item + confirmationShown = true + } + }, selectedLinkItem: $selectedLinkItem, viewModel: viewModel ) diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index 0d559f443..5fb4e8675 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -50,11 +50,18 @@ public struct FeedCard: View { } } +public enum GridCardAction { + case toggleArchiveStatus + case delete +} + public struct GridCard: View { let item: FeedItem + let actionHandler: (GridCardAction) -> Void - public init(item: FeedItem) { + public init(item: FeedItem, actionHandler: @escaping (GridCardAction) -> Void) { self.item = item + self.actionHandler = actionHandler } public var body: some View { @@ -77,8 +84,22 @@ public struct GridCard: View { .foregroundColor(.appGrayTextContrast) .lineLimit(1) Spacer() - Button( - action: { print("grid button tapped") }, + Menu( + content: { + Button( + action: { actionHandler(.toggleArchiveStatus) }, + label: { + Label( + item.isArchived ? "Unarchive" : "Archive", + systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" + ) + } + ) + Button( + action: { actionHandler(.delete) }, + label: { Label("Delete Link", systemImage: "trash") } + ) + }, label: { Image.profile } ) } From 0289cacad9dc2f039eec5532dcdc2b9148844189 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 14:43:04 -0800 Subject: [PATCH 13/16] extract contextMenuView action into function --- .../App/Views/Home/HomeFeedViewIOS.swift | 29 ++++------ .../Sources/Views/HomeFeedCardView.swift | 55 +++++++------------ 2 files changed, 31 insertions(+), 53 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 241aca58f..ab5df11ae 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -241,6 +241,16 @@ import Views private let columns = Array(repeating: GridItem(.flexible(), spacing: 20), count: 2) + func contextMenuActionHandler(item: FeedItem, action: GridCardAction) { + switch action { + case .toggleArchiveStatus: + viewModel.setLinkArchived(dataService: dataService, linkId: item.id, archived: !item.isArchived) + case .delete: + itemToRemove = item + confirmationShown = true + } + } + var body: some View { ScrollView { LazyVGrid(columns: columns, spacing: 20) { @@ -248,27 +258,10 @@ import Views let link = GridCardNavigationLink( item: item, searchQuery: searchQuery, - actionHandler: { action in - switch action { - case .toggleArchiveStatus: - viewModel.setLinkArchived(dataService: dataService, linkId: item.id, archived: !item.isArchived) - case .delete: - itemToRemove = item - confirmationShown = true - } - }, + actionHandler: { contextMenuActionHandler(item: item, action: $0) }, selectedLinkItem: $selectedLinkItem, viewModel: viewModel ) - .contextMenu { - FeedItemContextMenuView( - item: item, - selectedLinkItem: $selectedLinkItem, - snoozePresented: $snoozePresented, - itemToSnooze: $itemToSnooze, - viewModel: viewModel - ) - } if #available(iOS 15.0, *) { link .alert("Are you sure?", isPresented: $confirmationShown) { diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index 5fb4e8675..9107b2a7d 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -64,6 +64,24 @@ public struct GridCard: View { self.actionHandler = actionHandler } + var contextMenuView: some View { + Group { + Button( + action: { actionHandler(.toggleArchiveStatus) }, + label: { + Label( + item.isArchived ? "Unarchive" : "Archive", + systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" + ) + } + ) + Button( + action: { actionHandler(.delete) }, + label: { Label("Delete Link", systemImage: "trash") } + ) + } + } + public var body: some View { VStack(alignment: .leading, spacing: 16) { // Progress Bar @@ -84,24 +102,7 @@ public struct GridCard: View { .foregroundColor(.appGrayTextContrast) .lineLimit(1) Spacer() - Menu( - content: { - Button( - action: { actionHandler(.toggleArchiveStatus) }, - label: { - Label( - item.isArchived ? "Unarchive" : "Archive", - systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" - ) - } - ) - Button( - action: { actionHandler(.delete) }, - label: { Label("Delete Link", systemImage: "trash") } - ) - }, - label: { Image.profile } - ) + Menu(content: { contextMenuView }, label: { Image.profile }) } HStack { @@ -164,23 +165,7 @@ public struct GridCard: View { } .background(Color(.secondarySystemGroupedBackground)) .cornerRadius(6) - } -} - -struct TextChipdep: View { - let text: String - let color: Color - - var body: some View { - Capsule() - .fill(color.opacity(0.3)) - .border(color.opacity(0.7), width: 3) - .overlay( - Text(text) - .font(.appFootnote) - .foregroundColor(color) - .padding() - ) + .contextMenu { contextMenuView } } } From a787c134e70f974b42235b3e134f88417b967fc4 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Tue, 1 Mar 2022 22:35:13 -0800 Subject: [PATCH 14/16] handle gid card taps as well as grid card button taps --- .../Components/FeedCardNavigationLink.swift | 25 ++++++++------ .../Sources/Views/HomeFeedCardView.swift | 33 ++++++++++++++----- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index 7557374c1..b5ec6df25 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -33,6 +33,9 @@ struct FeedCardNavigationLink: View { struct GridCardNavigationLink: View { @EnvironmentObject var dataService: DataService + @State private var scale = 1.0 + @State private var isActive = false + let item: FeedItem let searchQuery: String let actionHandler: (GridCardAction) -> Void @@ -45,21 +48,23 @@ struct GridCardNavigationLink: View { ZStack { NavigationLink( destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item)), - tag: item, - selection: $selectedLinkItem + isActive: $isActive ) { - GridCard(item: item, actionHandler: actionHandler) + EmptyView() } - .buttonStyle(FlatLinkStyle()) .onAppear { viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) } + GridCard(item: item, actionHandler: actionHandler, tapAction: { + withAnimation { + scale = 0.95 + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(150)) { + scale = 1.0 + isActive = true + } + } + }) + .scaleEffect(scale) } } } - -struct FlatLinkStyle: ButtonStyle { - func makeBody(configuration: Configuration) -> some View { - configuration.label - } -} diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index 9107b2a7d..c361706de 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -58,10 +58,16 @@ public enum GridCardAction { public struct GridCard: View { let item: FeedItem let actionHandler: (GridCardAction) -> Void + let tapAction: () -> Void - public init(item: FeedItem, actionHandler: @escaping (GridCardAction) -> Void) { + public init( + item: FeedItem, + actionHandler: @escaping (GridCardAction) -> Void, + tapAction: @escaping () -> Void + ) { self.item = item self.actionHandler = actionHandler + self.tapAction = tapAction } var contextMenuView: some View { @@ -85,14 +91,17 @@ public struct GridCard: View { public var body: some View { VStack(alignment: .leading, spacing: 16) { // Progress Bar - if #available(iOS 15.0, *) { - ProgressView(value: min(abs(item.readingProgress) / 100, 1)) - .tint(.appYellow48) - .frame(maxWidth: .infinity, alignment: .leading) - } else { - ProgressView(value: max(abs(item.readingProgress) / 100, 1)) - .frame(maxWidth: .infinity, alignment: .leading) + Group { + if #available(iOS 15.0, *) { + ProgressView(value: min(abs(item.readingProgress) / 100, 1)) + .tint(.appYellow48) + .frame(maxWidth: .infinity, alignment: .leading) + } else { + ProgressView(value: max(abs(item.readingProgress) / 100, 1)) + .frame(maxWidth: .infinity, alignment: .leading) + } } + .onTapGesture { tapAction() } // Title, Subtitle, Menu Button VStack(alignment: .leading, spacing: 4) { @@ -101,6 +110,7 @@ public struct GridCard: View { .font(.appHeadline) .foregroundColor(.appGrayTextContrast) .lineLimit(1) + .onTapGesture { tapAction() } Spacer() Menu(content: { contextMenuView }, label: { Image.profile }) } @@ -123,6 +133,7 @@ public struct GridCard: View { Spacer() } + .onTapGesture { tapAction() } } .frame(height: 30) .padding(.horizontal) @@ -146,6 +157,7 @@ public struct GridCard: View { } .frame(height: 95) .padding(.horizontal) + .onTapGesture { tapAction() } // Category Labels if FeatureFlag.showFeedItemTags { @@ -163,7 +175,10 @@ public struct GridCard: View { Spacer(minLength: 8) } } - .background(Color(.secondarySystemGroupedBackground)) + .background( + Color(.secondarySystemGroupedBackground) + .onTapGesture { tapAction() } + ) .cornerRadius(6) .contextMenu { contextMenuView } } From 2868e95716d38b296610e75962ad28b4d37a24f6 Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Wed, 2 Mar 2022 09:36:59 -0800 Subject: [PATCH 15/16] track context menu open status so we can ignore element tap actions --- .../Components/FeedCardNavigationLink.swift | 5 ++- .../App/Views/Home/HomeFeedViewIOS.swift | 2 + .../Sources/Views/HomeFeedCardView.swift | 39 +++++++++++++++---- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift index b5ec6df25..093310ca1 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift @@ -41,6 +41,7 @@ struct GridCardNavigationLink: View { let actionHandler: (GridCardAction) -> Void @Binding var selectedLinkItem: FeedItem? + @Binding var isContextMenuOpen: Bool @ObservedObject var viewModel: HomeFeedViewModel @@ -55,7 +56,7 @@ struct GridCardNavigationLink: View { .onAppear { viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService) } - GridCard(item: item, actionHandler: actionHandler, tapAction: { + GridCard(item: item, isContextMenuOpen: $isContextMenuOpen, actionHandler: actionHandler, tapAction: { withAnimation { scale = 0.95 DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(150)) { @@ -64,7 +65,7 @@ struct GridCardNavigationLink: View { } } }) - .scaleEffect(scale) } + .scaleEffect(scale) } } diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index ab5df11ae..e6cf98415 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -236,6 +236,7 @@ import Views @State private var itemToRemove: FeedItem? @State private var confirmationShown = false + @State var isContextMenuOpen = false @ObservedObject var viewModel: HomeFeedViewModel @@ -260,6 +261,7 @@ import Views searchQuery: searchQuery, actionHandler: { contextMenuActionHandler(item: item, action: $0) }, selectedLinkItem: $selectedLinkItem, + isContextMenuOpen: $isContextMenuOpen, viewModel: viewModel ) if #available(iOS 15.0, *) { diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift index c361706de..f4830896d 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift @@ -56,24 +56,42 @@ public enum GridCardAction { } public struct GridCard: View { + @Binding var isContextMenuOpen: Bool let item: FeedItem let actionHandler: (GridCardAction) -> Void let tapAction: () -> Void public init( item: FeedItem, + isContextMenuOpen: Binding, actionHandler: @escaping (GridCardAction) -> Void, tapAction: @escaping () -> Void ) { self.item = item + self._isContextMenuOpen = isContextMenuOpen self.actionHandler = actionHandler self.tapAction = tapAction } + // Menu doesn't provide an API to observe it's open state + // so we have keep track of it's state manually + func tapHandler() { + if isContextMenuOpen { + isContextMenuOpen = false + } else { + tapAction() + } + } + + func menuActionHandler(_ action: GridCardAction) { + isContextMenuOpen = false + actionHandler(action) + } + var contextMenuView: some View { Group { Button( - action: { actionHandler(.toggleArchiveStatus) }, + action: { menuActionHandler(.toggleArchiveStatus) }, label: { Label( item.isArchived ? "Unarchive" : "Archive", @@ -82,7 +100,7 @@ public struct GridCard: View { } ) Button( - action: { actionHandler(.delete) }, + action: { menuActionHandler(.delete) }, label: { Label("Delete Link", systemImage: "trash") } ) } @@ -101,7 +119,7 @@ public struct GridCard: View { .frame(maxWidth: .infinity, alignment: .leading) } } - .onTapGesture { tapAction() } + .onTapGesture { tapHandler() } // Title, Subtitle, Menu Button VStack(alignment: .leading, spacing: 4) { @@ -110,9 +128,14 @@ public struct GridCard: View { .font(.appHeadline) .foregroundColor(.appGrayTextContrast) .lineLimit(1) - .onTapGesture { tapAction() } + .onTapGesture { tapHandler() } Spacer() - Menu(content: { contextMenuView }, label: { Image.profile }) + + Menu( + content: { contextMenuView }, + label: { Image.profile } + ) + .onTapGesture { isContextMenuOpen = true } } HStack { @@ -133,7 +156,7 @@ public struct GridCard: View { Spacer() } - .onTapGesture { tapAction() } + .onTapGesture { tapHandler() } } .frame(height: 30) .padding(.horizontal) @@ -157,7 +180,7 @@ public struct GridCard: View { } .frame(height: 95) .padding(.horizontal) - .onTapGesture { tapAction() } + .onTapGesture { tapHandler() } // Category Labels if FeatureFlag.showFeedItemTags { @@ -177,7 +200,7 @@ public struct GridCard: View { } .background( Color(.secondarySystemGroupedBackground) - .onTapGesture { tapAction() } + .onTapGesture { tapHandler() } ) .cornerRadius(6) .contextMenu { contextMenuView } From b19ac104f495e878435b30ec533505badce58c3e Mon Sep 17 00:00:00 2001 From: Satindar Dhillon Date: Wed, 2 Mar 2022 10:24:35 -0800 Subject: [PATCH 16/16] fix context menus so all actions are included across devices --- .../Components/FeedItemContextMenuView.swift | 44 --------- .../App/Views/Home/HomeFeedViewIOS.swift | 30 +++++-- .../App/Views/Home/HomeFeedViewMac.swift | 56 +++++++++--- .../Sources/Views/Colors/Colors.swift | 4 + .../GridCard.swift} | 89 +++---------------- .../Views/FeedItem/HomeFeedCardView.swift | 51 +++++++++++ .../OmnivoreKit/Sources/Views/TextChip.swift | 22 +++++ 7 files changed, 160 insertions(+), 136 deletions(-) delete mode 100644 apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedItemContextMenuView.swift rename apple/OmnivoreKit/Sources/Views/{HomeFeedCardView.swift => FeedItem/GridCard.swift} (66%) create mode 100644 apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift create mode 100644 apple/OmnivoreKit/Sources/Views/TextChip.swift diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedItemContextMenuView.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedItemContextMenuView.swift deleted file mode 100644 index 6441e5454..000000000 --- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedItemContextMenuView.swift +++ /dev/null @@ -1,44 +0,0 @@ -import Models -import Services -import SwiftUI -import Utils -import Views - -struct FeedItemContextMenuView: View { - @EnvironmentObject var dataService: DataService - - let item: FeedItem - - @Binding var selectedLinkItem: FeedItem? - @Binding var snoozePresented: Bool - @Binding var itemToSnooze: FeedItem? - - @ObservedObject var viewModel: HomeFeedViewModel - - var body: some View { - if !item.isArchived { - Button(action: { - withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived(dataService: dataService, linkId: item.id, archived: true) - if item == selectedLinkItem { - selectedLinkItem = nil - } - } - }, label: { Label("Archive", systemImage: "archivebox") }) - } else { - Button(action: { - withAnimation(.linear(duration: 0.4)) { - viewModel.setLinkArchived(dataService: dataService, linkId: item.id, archived: false) - } - }, label: { Label("Unarchive", systemImage: "tray.and.arrow.down.fill") }) - } - if FeatureFlag.enableSnooze { - Button { - itemToSnooze = item - snoozePresented = true - } label: { - Label { Text("Snooze") } icon: { Image.moon } - } - } - } -} diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index e6cf98415..95832a2d0 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -152,13 +152,31 @@ import Views viewModel: viewModel ) .contextMenu { - FeedItemContextMenuView( - item: item, - selectedLinkItem: $selectedLinkItem, - snoozePresented: $snoozePresented, - itemToSnooze: $itemToSnooze, - viewModel: viewModel + Button(action: { + withAnimation(.linear(duration: 0.4)) { + viewModel.setLinkArchived(dataService: dataService, linkId: item.id, archived: !item.isArchived) + } + }, label: { + Label( + item.isArchived ? "Unarchive" : "Archive", + systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" + ) + }) + Button( + action: { + itemToRemove = item + confirmationShown = true + }, + label: { Label("Delete Link", systemImage: "trash") } ) + if FeatureFlag.enableSnooze { + Button { + itemToSnooze = item + snoozePresented = true + } label: { + Label { Text("Snooze") } icon: { Image.moon } + } + } } if #available(iOS 15.0, *) { link diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift index 6f767a15d..2018fe402 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewMac.swift @@ -22,18 +22,54 @@ import Views List { Section { ForEach(viewModel.items) { item in - FeedCardNavigationLink( - item: item, - searchQuery: searchQuery, - selectedLinkItem: $selectedLinkItem, - viewModel: viewModel - ) - .contextMenu { - FeedItemContextMenuView( + if #available(macOS 12.0, *) { + FeedCardNavigationLink( item: item, + searchQuery: searchQuery, + selectedLinkItem: $selectedLinkItem, + viewModel: viewModel + ) + .contextMenu { + Button(action: { + viewModel.setLinkArchived(dataService: dataService, linkId: item.id, archived: !item.isArchived) + }, label: { + Label( + item.isArchived ? "Unarchive" : "Archive", + systemImage: item.isArchived ? "tray.and.arrow.down.fill" : "archivebox" + ) + }) + Button( + action: { + itemToRemove = item + confirmationShown = true + }, + label: { Label("Delete Link", systemImage: "trash") } + ) + if FeatureFlag.enableSnooze { + Button { + itemToSnooze = item + snoozePresented = true + } label: { + Label { Text("Snooze") } icon: { Image.moon } + } + } + } + .alert("Are you sure?", isPresented: $confirmationShown) { + Button("Remove Link", role: .destructive) { + if let itemToRemove = itemToRemove { + withAnimation { + viewModel.removeLink(dataService: dataService, linkId: itemToRemove.id) + self.itemToRemove = nil + } + } + } + Button("Cancel", role: .cancel) { self.itemToRemove = nil } + } + } else { + FeedCardNavigationLink( + item: item, + searchQuery: searchQuery, selectedLinkItem: $selectedLinkItem, - snoozePresented: $snoozePresented, - itemToSnooze: $itemToSnooze, viewModel: viewModel ) } diff --git a/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift b/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift index 6111d40d6..e3270b61c 100644 --- a/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift +++ b/apple/OmnivoreKit/Sources/Views/Colors/Colors.swift @@ -21,8 +21,12 @@ public extension Color { #if os(iOS) static var systemBackground: Color { Color(.systemBackground) } static var systemPlaceholder: Color { Color(.placeholderText) } + static var secondarySystemGroupedBackground: Color { Color(.secondarySystemGroupedBackground) } #elseif os(macOS) static var systemBackground: Color { Color(.windowBackgroundColor) } static var systemPlaceholder: Color { Color(.placeholderTextColor) } + + // Just for compilation. secondarySystemGroupedBackground shouldn't be used on macOS + static var secondarySystemGroupedBackground: Color { Color(.windowBackgroundColor) } #endif } diff --git a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/GridCard.swift similarity index 66% rename from apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift rename to apple/OmnivoreKit/Sources/Views/FeedItem/GridCard.swift index f4830896d..9049024b1 100644 --- a/apple/OmnivoreKit/Sources/Views/HomeFeedCardView.swift +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/GridCard.swift @@ -2,54 +2,6 @@ import Models import SwiftUI import Utils -public struct FeedCard: View { - let item: FeedItem - - public init(item: FeedItem) { - self.item = item - } - - public var body: some View { - HStack(alignment: .top, spacing: 6) { - VStack(alignment: .leading, spacing: 6) { - Text(item.title) - .font(.appSubheadline) - .foregroundColor(.appGrayTextContrast) - .lineLimit(2) - .frame(maxWidth: .infinity, alignment: .leading) - - if let author = item.author { - Text("By \(author)") - .font(.appCaption) - .foregroundColor(.appGrayText) - .lineLimit(1) - } - - if let publisherURL = item.publisherHostname { - Text(publisherURL) - .font(.appCaption) - .foregroundColor(.appGrayText) - .underline() - .lineLimit(1) - } - } - .frame(maxWidth: .infinity) - .multilineTextAlignment(.leading) - .padding(0) - - Group { - if let imageURL = item.imageURL { - AsyncImage(url: imageURL, isResizable: true) - .aspectRatio(1, contentMode: .fill) - .frame(width: 80, height: 80) - .cornerRadius(6) - } - } - } - .frame(maxWidth: .infinity, minHeight: 100, idealHeight: 100, maxHeight: 100) - } -} - public enum GridCardAction { case toggleArchiveStatus case delete @@ -110,14 +62,20 @@ public struct GridCard: View { VStack(alignment: .leading, spacing: 16) { // Progress Bar Group { - if #available(iOS 15.0, *) { - ProgressView(value: min(abs(item.readingProgress) / 100, 1)) - .tint(.appYellow48) - .frame(maxWidth: .infinity, alignment: .leading) - } else { + // Remove os check when dropping macOS 11 + #if os(iOS) + if #available(iOS 15.0, *) { + ProgressView(value: min(abs(item.readingProgress) / 100, 1)) + .tint(.appYellow48) + .frame(maxWidth: .infinity, alignment: .leading) + } else { + ProgressView(value: max(abs(item.readingProgress) / 100, 1)) + .frame(maxWidth: .infinity, alignment: .leading) + } + #else ProgressView(value: max(abs(item.readingProgress) / 100, 1)) .frame(maxWidth: .infinity, alignment: .leading) - } + #endif } .onTapGesture { tapHandler() } @@ -199,31 +157,10 @@ public struct GridCard: View { } } .background( - Color(.secondarySystemGroupedBackground) + Color.secondarySystemGroupedBackground .onTapGesture { tapHandler() } ) .cornerRadius(6) .contextMenu { contextMenuView } } } - -struct TextChip: View { - let text: String - let color: Color - let cornerRadius = 20.0 - - var body: some View { - Text(text) - .padding(.horizontal, 10) - .padding(.vertical, 5) - .font(.appFootnote) - .foregroundColor(color) - .lineLimit(1) - .background(color.opacity(0.1)) - .cornerRadius(cornerRadius) - .overlay( - RoundedRectangle(cornerRadius: cornerRadius) - .stroke(color.opacity(0.3), lineWidth: 1) - ) - } -} diff --git a/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift b/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift new file mode 100644 index 000000000..5f917ae30 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/FeedItem/HomeFeedCardView.swift @@ -0,0 +1,51 @@ +import Models +import SwiftUI +import Utils + +public struct FeedCard: View { + let item: FeedItem + + public init(item: FeedItem) { + self.item = item + } + + public var body: some View { + HStack(alignment: .top, spacing: 6) { + VStack(alignment: .leading, spacing: 6) { + Text(item.title) + .font(.appSubheadline) + .foregroundColor(.appGrayTextContrast) + .lineLimit(2) + .frame(maxWidth: .infinity, alignment: .leading) + + if let author = item.author { + Text("By \(author)") + .font(.appCaption) + .foregroundColor(.appGrayText) + .lineLimit(1) + } + + if let publisherURL = item.publisherHostname { + Text(publisherURL) + .font(.appCaption) + .foregroundColor(.appGrayText) + .underline() + .lineLimit(1) + } + } + .frame(maxWidth: .infinity) + .multilineTextAlignment(.leading) + .padding(0) + + Group { + if let imageURL = item.imageURL { + AsyncImage(url: imageURL, isResizable: true) + .aspectRatio(1, contentMode: .fill) + .frame(width: 80, height: 80) + .cornerRadius(6) + } + } + } + .frame(maxWidth: .infinity, minHeight: 100, idealHeight: 100, maxHeight: 100) + } +} diff --git a/apple/OmnivoreKit/Sources/Views/TextChip.swift b/apple/OmnivoreKit/Sources/Views/TextChip.swift new file mode 100644 index 000000000..775ad6854 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Views/TextChip.swift @@ -0,0 +1,22 @@ +import SwiftUI + +struct TextChip: View { + let text: String + let color: Color + let cornerRadius = 20.0 + + var body: some View { + Text(text) + .padding(.horizontal, 10) + .padding(.vertical, 5) + .font(.appFootnote) + .foregroundColor(color) + .lineLimit(1) + .background(color.opacity(0.1)) + .cornerRadius(cornerRadius) + .overlay( + RoundedRectangle(cornerRadius: cornerRadius) + .stroke(color.opacity(0.3), lineWidth: 1) + ) + } +}