Merge branch 'main' into feat/ios-display-digest-icon

This commit is contained in:
Jackson Harper
2024-05-13 16:12:42 +08:00
committed by GitHub
33 changed files with 930 additions and 405 deletions

View File

@ -0,0 +1,161 @@
import SwiftUI
import Models
import Services
import Views
import MarkdownUI
import Utils
import Transmission
@MainActor
public class DigestConfigViewModel: ObservableObject {
@Published var isLoading = false
@Published var digest: DigestResult?
@Published var chapterInfo: [(DigestChapter, DigestChapterData)]?
@Published var presentedLibraryItem: String?
@Published var presentWebContainer = false
@AppStorage(UserDefaultKey.lastVisitedDigestId.rawValue) var lastVisitedDigestId = ""
func load(dataService: DataService) async {
isLoading = true
if !digestNeedsRefresh() {
if let digest = dataService.loadStoredDigest() {
self.digest = digest
}
} else {
do {
if let digest = try await dataService.getLatestDigest(timeoutInterval: 10) {
self.digest = digest
}
} catch {
print("ERROR WITH DIGEST: ", error)
self.digest = nil
}
}
isLoading = false
}
func refreshDigest(dataService: DataService) async {
do {
try await dataService.refreshDigest()
} catch {
print("ERROR WITH DIGEST: ", error)
}
}
func digestNeedsRefresh() -> Bool {
let fileManager = FileManager.default
let localURL = URL.om_cachesDirectory.appendingPathComponent("digest.json")
do {
let attributes = try fileManager.attributesOfItem(atPath: localURL.path)
if let modificationDate = attributes[.modificationDate] as? Date {
// Two hours ago
let twoHoursAgo = Date().addingTimeInterval(-2 * 60 * 60)
return modificationDate < twoHoursAgo
}
} catch {
print("Error: \(error)")
}
return true
}
}
@available(iOS 17.0, *)
@MainActor
struct DigestConfigView: View {
@StateObject var viewModel = DigestConfigViewModel()
let dataService: DataService
@Environment(\.dismiss) private var dismiss
public init(dataService: DataService) {
self.dataService = dataService
}
var titleBlock: some View {
HStack {
Text("Omnivore Digest")
.font(Font.system(size: 18, weight: .semibold))
Image.tabDigestSelected
Spacer()
closeButton
}
.padding(.top, 20)
.padding(.horizontal, 20)
}
var body: some View {
VStack {
titleBlock
.padding(.top, 10)
itemBody
.padding(15)
Spacer()
}.task {
await viewModel.load(dataService: dataService)
}
}
var closeButton: some View {
Button(action: {
dismiss()
}, label: {
Text("Close")
.foregroundColor(Color.blue)
})
.buttonStyle(.plain)
}
var logoBlock: some View {
HStack {
Image.coloredSmallOmnivoreLogo
.resizable()
.frame(width: 20, height: 20)
Text("Omnivore.app")
.font(Font.system(size: 14))
.foregroundColor(Color.themeLibraryItemSubtle)
Spacer()
}
}
@available(iOS 17.0, *)
var itemBody: some View {
VStack(alignment: .leading, spacing: 20) {
logoBlock
let description1 =
"""
Omnivore Digest is a free daily digest of your best recent library items. Omnivore
filters and ranks all the items recently added to your library, uses AI to summarize them,
and creates a short library item, email, or a daily podcast you can listen to in our iOS app.
Note that if you sign up for Digest, your recent library items will be processed by an AI
service (Anthropic, or OpenAI). Your highlights, notes, and labels will not be sent to the AI
service.
Digest is available to all users that have saved at least ten items and added two subscriptions.
"""
Markdown(description1)
.lineSpacing(10)
.accentColor(.appGraySolid)
.font(.appSubheadline)
.padding(5)
.frame(maxWidth: .infinity, alignment: .leading)
HStack {
Spacer()
Button(action: {}, label: { Text("Hide digest") })
.buttonStyle(RoundedRectButtonStyle())
Button(action: {}, label: { Text("Enable digest") })
.buttonStyle(RoundedRectButtonStyle(color: Color.blue, textColor: Color.white))
}
}
.padding(15)
.background(Color.themeLabelBackground.opacity(0.6))
.cornerRadius(5)
}
}

View File

@ -331,15 +331,15 @@ struct AnimatingCellHeight: AnimatableModifier {
Text("Sorry digest is only available on iOS 17 and above")
}
}
// .sheet(isPresented: $showDigestConfig) {
// if #available(iOS 17.0, *) {
// NavigationView {
// DigestConfigView(dataService: dataService)
// }
// } else {
// Text("Sorry digest is only available on iOS 17 and above")
// }
// }
.sheet(isPresented: $showDigestConfig) {
if #available(iOS 17.0, *) {
NavigationView {
DigestConfigView(dataService: dataService)
}
} else {
Text("Sorry digest is only available on iOS 17 and above")
}
}
.toolbar {
toolbarItems
}
@ -422,6 +422,15 @@ struct AnimatingCellHeight: AnimatableModifier {
// .buttonStyle(.plain)
// .padding(.trailing, 4)
// }
if #available(iOS 17.0, *), !dataService.featureFlags.digestEnabled, !viewModel.digestHidden {
// Give the user an opportunity to enable digest
Button(
action: { showDigestConfig = true },
label: { Image.tabDigestSelected }
)
.buttonStyle(.plain)
.padding(.trailing, 4)
}
if prefersListLayout {
Button(
action: { isEditMode = isEditMode == .active ? .inactive : .active },

View File

@ -51,6 +51,7 @@ enum LoadingBarStyle {
@AppStorage("LibraryTabView::hideFollowingTab") var hideFollowingTab = false
@AppStorage("LibraryTabView::digestHidden") var digestHidden = false
@AppStorage(UserDefaultKey.lastVisitedDigestId.rawValue) var lastVisitedDigestId = ""
@AppStorage("LibraryTabView::digestHidden") var digestHidden = false
@AppStorage(UserDefaultKey.lastSelectedFeaturedItemFilter.rawValue) var featureFilter = FeaturedItemFilter.continueReading.rawValue