From 0fa45750a454ddecb7aba6d764f5a0b89255e20b Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 28 Nov 2023 14:19:48 +0800 Subject: [PATCH] Dont attempt local searches for custom saved searches on iOS --- .../App/Views/Home/HomeFeedViewIOS.swift | 118 ++++++++++-------- .../App/Views/WebReader/WebReader.swift | 6 + .../Services/DataService/NetworkMonitor.swift | 31 +++++ .../InternalModels/InternalFilter.swift | 2 +- 4 files changed, 102 insertions(+), 55 deletions(-) create mode 100644 apple/OmnivoreKit/Sources/Services/DataService/NetworkMonitor.swift diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift index 05dc1a342..0bfae8717 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift @@ -164,11 +164,12 @@ struct AnimatingCellHeight: AnimatableModifier { Group { ToolbarItem(placement: .barLeading) { VStack(alignment: .leading) { + let showDate = isListScrolled && !listTitle.isEmpty if let title = viewModel.appliedFilter?.name { Text(title) - .font(Font.system(size: isListScrolled ? 10 : 18, weight: .semibold)) + .font(Font.system(size: showDate ? 10 : 18, weight: .semibold)) - if prefersListLayout, isListScrolled || !showFeatureCards { + if showDate, prefersListLayout, isListScrolled || !showFeatureCards { Text(listTitle) .font(Font.system(size: 15, weight: .regular)) .foregroundColor(Color.appGrayText) @@ -544,6 +545,8 @@ struct AnimatingCellHeight: AnimatableModifier { } } + @ObservedObject var networkMonitor = NetworkMonitor() + var body: some View { let horizontalInset = CGFloat(UIDevice.isIPad ? 20 : 10) VStack(spacing: 0) { @@ -558,64 +561,71 @@ struct AnimatingCellHeight: AnimatableModifier { .listRowSeparator(.hidden, edges: .all) .listRowInsets(.init(top: 0, leading: horizontalInset, bottom: 0, trailing: horizontalInset)) - if showFeatureCards { - featureCard - .listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0)) - .listRowSeparator(.hidden, edges: .all) - .modifier(AnimatingCellHeight(height: 190 + 13)) - .onDisappear { - withAnimation { - isListScrolled = true + if let appliedFilter = viewModel.appliedFilter, + networkMonitor.status == .disconnected, + !appliedFilter.allowLocalFetch + { + HStack { + Text("This search requires an internet connection.") + .padding() + .foregroundColor(Color.white) + .frame(maxWidth: .infinity, alignment: .center) + } + .background(Color.blue) + .frame(maxWidth: .infinity, alignment: .center) + .listRowSeparator(.hidden, edges: .all) + .listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0)) + } else { + if showFeatureCards { + featureCard + .listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0)) + .listRowSeparator(.hidden, edges: .all) + .modifier(AnimatingCellHeight(height: 190 + 13)) + .onDisappear { + withAnimation { + isListScrolled = true + } } - } - .onAppear { - withAnimation { - isListScrolled = false + .onAppear { + withAnimation { + isListScrolled = false + } } - } - } + } - ForEach(Array(viewModel.items.enumerated()), id: \.1.unwrappedID) { _, item in - FeedCardNavigationLink( - item: item, - isInMultiSelectMode: viewModel.isInMultiSelectMode, - viewModel: viewModel - ) - .background(GeometryReader { geometry in - Color.clear - .preference(key: ScrollOffsetPreferenceKey.self, value: geometry.frame(in: .named("scroll")).origin) - }) - .onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in - if value.y < 100, value.y > 0 { - if item.savedAt != nil, topItem != item { - setTopItem(item) + ForEach(Array(viewModel.items.enumerated()), id: \.1.unwrappedID) { _, item in + FeedCardNavigationLink( + item: item, + isInMultiSelectMode: viewModel.isInMultiSelectMode, + viewModel: viewModel + ) + .background(GeometryReader { geometry in + Color.clear + .preference(key: ScrollOffsetPreferenceKey.self, value: geometry.frame(in: .named("scroll")).origin) + }) + .onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in + if value.y < 100, value.y > 0 { + if item.savedAt != nil, topItem != item { + setTopItem(item) + } + } + } + .listRowSeparatorTint(Color.thBorderColor) + .listRowInsets(.init(top: 0, leading: horizontalInset, bottom: 10, trailing: horizontalInset)) + .contextMenu { + menuItems(for: item) + } + .swipeActions(edge: .leading, allowsFullSwipe: true) { + ForEach(viewModel.listConfig.leadingSwipeActions, id: \.self) { action in + swipeActionButton(action: action, item: item) + } + } + .swipeActions(edge: .trailing, allowsFullSwipe: true) { + ForEach(viewModel.listConfig.trailingSwipeActions, id: \.self) { action in + swipeActionButton(action: action, item: item) } } } - .listRowSeparatorTint(Color.thBorderColor) - .listRowInsets(.init(top: 0, leading: horizontalInset, bottom: 10, trailing: horizontalInset)) - .contextMenu { - menuItems(for: item) - } - .swipeActions(edge: .leading, allowsFullSwipe: true) { - ForEach(viewModel.listConfig.leadingSwipeActions, id: \.self) { action in - swipeActionButton(action: action, item: item) - } - } - .swipeActions(edge: .trailing, allowsFullSwipe: true) { - ForEach(viewModel.listConfig.trailingSwipeActions, id: \.self) { action in - swipeActionButton(action: action, item: item) - } - } -// if idx > 0, -// isEditMode != .active, -// let savedAt = item.savedAt, -// Calendar.current.isDateInToday(savedAt) || Calendar.current.isDateInYesterday(savedAt), -// let previousSavedAt = viewModel.items[idx - 1].savedAt, -// Calendar.current.isDate(previousSavedAt, equalTo: savedAt, toGranularity: .day) -// { -// dateSummaryCard(previousSavedAt) -// } } } .padding(0) diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift index 4aa42a91b..029a443e7 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReader.swift @@ -73,6 +73,12 @@ struct WebReader: PlatformViewRepresentable { webView.setValue(false, forKey: "drawsBackground") #endif + #if DEBUG + if #available(iOS 16.4, *) { + webView.isInspectable = true + } + #endif + for action in WebViewAction.allCases { webView.configuration.userContentController.add(context.coordinator, name: action.rawValue) } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/NetworkMonitor.swift b/apple/OmnivoreKit/Sources/Services/DataService/NetworkMonitor.swift new file mode 100644 index 000000000..a94514a94 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Services/DataService/NetworkMonitor.swift @@ -0,0 +1,31 @@ +import Network +import SwiftUI + +public enum NetworkStatus: String { + case connected + case disconnected +} + +@MainActor +public class NetworkMonitor: ObservableObject { + private let monitor = NWPathMonitor() + private let queue = DispatchQueue(label: "Monitor") + + @Published public var status: NetworkStatus = .connected + + public init() { + monitor.pathUpdateHandler = { [weak self] path in + guard let self = self else { return } + + DispatchQueue.main.async { + if path.status == .satisfied { + self.status = .connected + + } else { + self.status = .disconnected + } + } + } + monitor.start(queue: queue) + } +} diff --git a/apple/OmnivoreKit/Sources/Services/InternalModels/InternalFilter.swift b/apple/OmnivoreKit/Sources/Services/InternalModels/InternalFilter.swift index b88f6c7e0..f4de0afa4 100644 --- a/apple/OmnivoreKit/Sources/Services/InternalModels/InternalFilter.swift +++ b/apple/OmnivoreKit/Sources/Services/InternalModels/InternalFilter.swift @@ -110,7 +110,7 @@ public struct InternalFilter: Encodable, Identifiable, Hashable { } public var allowLocalFetch: Bool { - true + predicate != nil } public var predicate: NSPredicate? {