Merge pull request #2528 from omnivore-app/fix/ios-sizing-issues

Fix iOS 15 navbar issues and add dynamic type support
This commit is contained in:
Jackson Harper
2023-07-28 17:48:57 +08:00
committed by GitHub
28 changed files with 184 additions and 165 deletions

File diff suppressed because one or more lines are too long

View File

@ -173,15 +173,6 @@ import Utils
let highlights = annotations?.compactMap { $0 as? HighlightAnnotation }
let shortId = highlights.flatMap { coordinator.shortHighlightIds($0).first }
if let shortId = shortId, FeatureFlag.enableShareButton {
let share = MenuItem(title: "Share", block: {
if let shareURL = viewModel.highlightShareURL(dataService: dataService, shortId: shortId) {
shareLink = ShareLink(id: UUID(), url: shareURL)
}
})
result.append(share)
}
return result
})
.fullScreenCover(isPresented: $readerView, content: {
@ -270,7 +261,7 @@ import Utils
if let customHighlight = annotation.customData?["omnivoreHighlight"] as? [String: String] {
if customHighlight["id"]?.lowercased() == highlightId {
if !document.remove(annotations: [annotation]) {
Snackbar.show(message: "Error removing highlight")
viewModel.snackbar(message: "Error removing highlight")
}
}
}

View File

@ -2,17 +2,26 @@ import Foundation
import Models
import Services
import Utils
// import Views
final class PDFViewerViewModel: ObservableObject {
@Published var errorMessage: String?
@Published var readerView: Bool = false
@Published var showSnackbar: Bool = false
var snackbarMessage: String?
let pdfItem: PDFItem
init(pdfItem: PDFItem) {
self.pdfItem = pdfItem
}
func snackbar(message: String) {
snackbarMessage = message
showSnackbar = true
}
func loadHighlightPatches(completion onComplete: @escaping ([String]) -> Void) {
onComplete(pdfItem.highlights.map { $0.patch ?? "" })
}
@ -75,19 +84,6 @@ final class PDFViewerViewModel: ObservableObject {
)
}
func highlightShareURL(dataService: DataService, shortId: String) -> URL? {
let baseURL = dataService.appEnvironment.serverBaseURL
var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)
if let username = dataService.currentViewer?.username {
components?.path = "/\(username)/\(pdfItem.slug)/highlights/\(shortId)"
} else {
return nil
}
return components?.url
}
func downloadPDF(dataService: DataService) async -> URL? {
do {
if let localPdfURL = pdfItem.localPdfURL, FileManager.default.fileExists(atPath: localPdfURL.path) {

View File

@ -3,7 +3,7 @@ import Services
import Views
extension Snackbar {
static func show(message: String, undoAction: (() -> Void)? = nil) {
NSNotification.operationSuccess(message: message, undoAction: undoAction)
static func showInLibrary(message: String, undoAction: (() -> Void)? = nil) {
NSNotification.librarySnackBar(message: message, undoAction: undoAction)
}
}

View File

@ -35,7 +35,7 @@
pasteBoard.writeObjects([highlightParams.quote as NSString])
#endif
Snackbar.show(message: "Highlight copied")
// Snackbar.show(message: "Highlight copied")
},
label: { Label("Copy", systemImage: "doc.on.doc") }
)

View File

@ -155,7 +155,7 @@
Spacer(minLength: 120)
.listRowSeparator(.hidden, edges: .all)
}.sheet(item: $setLabelsHighlight) { highlight in
ApplyLabelsView(mode: .highlight(highlight), isSearchFocused: false, onSave: { selectedLabels in
ApplyLabelsView(mode: .highlight(highlight), onSave: { selectedLabels in
hasHighlightMutations = true
viewModel.setLabelsForHighlight(highlightID: highlight.unwrappedID,

View File

@ -81,7 +81,7 @@ struct AnimatingCellHeight: AnimatableModifier {
loadItems(isRefresh: true)
}
.sheet(item: $viewModel.itemUnderLabelEdit) { item in
ApplyLabelsView(mode: .item(item), isSearchFocused: false, onSave: nil)
ApplyLabelsView(mode: .item(item), onSave: nil)
}
.sheet(item: $viewModel.itemUnderTitleEdit) { item in
LinkedItemMetadataEditView(item: item)
@ -150,11 +150,12 @@ struct AnimatingCellHeight: AnimatableModifier {
Label(LocalText.genericProfile, systemImage: "person.circle")
})
Button(action: { addLinkPresented = true }, label: {
Label("Add Link", systemImage: "plus.square")
Label("Add Link", systemImage: "plus.circle")
})
}, label: {
Image.utilityMenu
})
.foregroundColor(.appGrayTextContrast)
} else {
EmptyView()
}
@ -241,9 +242,6 @@ struct AnimatingCellHeight: AnimatableModifier {
@Binding var prefersListLayout: Bool
@ObservedObject var viewModel: HomeFeedViewModel
@State var showSnackbar = false
@State var snackbarOperation: SnackbarOperation?
var body: some View {
VStack(spacing: 0) {
if prefersListLayout || !enableGrid {
@ -260,9 +258,9 @@ struct AnimatingCellHeight: AnimatableModifier {
self.viewModel.negatedLabels = $1
}
}
.popup(isPresented: $showSnackbar) {
if let operation = snackbarOperation {
Snackbar(isShowing: $showSnackbar, operation: operation)
.popup(isPresented: $viewModel.showSnackbar) {
if let operation = viewModel.snackbarOperation {
Snackbar(isShowing: $viewModel.showSnackbar, operation: operation)
} else {
EmptyView()
}
@ -272,19 +270,15 @@ struct AnimatingCellHeight: AnimatableModifier {
.autohideIn(2)
.position(.bottom)
.animation(.spring())
.closeOnTapOutside(true)
.isOpaque(false)
}
.onReceive(NSNotification.operationSuccessPublisher) { notification in
if let message = notification.userInfo?["message"] as? String {
snackbarOperation = SnackbarOperation(message: message,
undoAction: notification.userInfo?["undoAction"] as? SnackbarUndoAction)
showSnackbar = true
}
}
.onReceive(NSNotification.operationFailedPublisher) { notification in
if let message = notification.userInfo?["message"] as? String {
showSnackbar = true
snackbarOperation = SnackbarOperation(message: message, undoAction: nil)
.onReceive(NSNotification.librarySnackBarPublisher) { notification in
if !viewModel.showSnackbar {
if let message = notification.userInfo?["message"] as? String {
viewModel.snackbarOperation = SnackbarOperation(message: message,
undoAction: notification.userInfo?["undoAction"] as? SnackbarUndoAction)
viewModel.showSnackbar = true
}
}
}
}
@ -354,6 +348,7 @@ struct AnimatingCellHeight: AnimatableModifier {
}
.listRowSeparator(.hidden)
}
.dynamicTypeSize(.small ... .accessibility1)
}
func menuItems(for item: LinkedItem) -> some View {
@ -438,7 +433,8 @@ struct AnimatingCellHeight: AnimatableModifier {
VStack {
LinearGradient(gradient: Gradient(colors: [.black.opacity(0.06), .systemGray6]),
startPoint: .top, endPoint: .bottom)
.frame(maxWidth: .infinity, maxHeight: 6)
.frame(maxWidth: .infinity, maxHeight: 3)
.opacity(0.4)
Spacer()
}

View File

@ -141,7 +141,7 @@ import Views
Button(LocalText.cancelGeneric, role: .cancel) { self.itemToRemove = nil }
}
.sheet(item: $viewModel.itemUnderLabelEdit) { item in
ApplyLabelsView(mode: .item(item), isSearchFocused: false, onSave: nil)
ApplyLabelsView(mode: .item(item), onSave: nil)
}
.sheet(item: $viewModel.itemUnderTitleEdit) { item in
LinkedItemMetadataEditView(item: item)

View File

@ -37,6 +37,9 @@ import Views
@Published var listConfig: LibraryListConfig
@Published var showSnackbar = false
@Published var snackbarOperation: SnackbarOperation?
var cursor: String?
// These are used to make sure we handle search result
@ -314,9 +317,14 @@ import Views
setItems(dataService.viewContext, fetchedResultsController.fetchedObjects ?? [])
}
func snackbar(_ message: String, undoAction: SnackbarUndoAction? = nil) {
snackbarOperation = SnackbarOperation(message: message, undoAction: undoAction)
showSnackbar = true
}
func setLinkArchived(dataService: DataService, objectID: NSManagedObjectID, archived: Bool) {
dataService.archiveLink(objectID: objectID, archived: archived)
Snackbar.show(message: archived ? "Link archived" : "Link moved to Inbox")
snackbar(archived ? "Link archived" : "Link moved to Inbox")
}
func removeLink(dataService: DataService, objectID: NSManagedObjectID) {
@ -326,9 +334,9 @@ import Views
func recoverItem(dataService: DataService, itemID: String) {
Task {
if await dataService.recoverItem(itemID: itemID) {
Snackbar.show(message: "Item recovered")
snackbar("Item recovered")
} else {
Snackbar.show(message: "Error. Check trash to recover.")
snackbar("Error. Check trash to recover.")
}
}
}
@ -398,7 +406,7 @@ import Views
)
if let message = successMessage {
Snackbar.show(message: message)
snackbar(message)
}
} catch {
NSNotification.operationFailed(message: "Failed to snooze")

View File

@ -5,30 +5,14 @@ import Views
@MainActor
struct HomeView: View {
@State private var viewModel: HomeFeedViewModel
@State var showSnackbar = false
@State var snackbarOperation: SnackbarOperation?
init(viewModel: HomeFeedViewModel) {
self.viewModel = viewModel
}
#if os(iOS)
var navView: some View {
NavigationView {
HomeFeedContainerView(viewModel: viewModel)
}
.navigationViewStyle(.stack)
.accentColor(.appGrayTextContrast)
}
#endif
var body: some View {
#if os(iOS)
if UIDevice.isIPhone {
navView
} else {
HomeFeedContainerView(viewModel: viewModel)
}
HomeFeedContainerView(viewModel: viewModel)
#elseif os(macOS)
HomeFeedView(viewModel: viewModel)
.frame(minWidth: 320)

View File

@ -61,6 +61,7 @@
Form {
TextField("Add Link", text: $newLinkURL)
.keyboardType(.URL)
.autocorrectionDisabled(true)
.textFieldStyle(StandardTextFieldStyle())
.focused($focusedField, equals: .addLinkEditor)

View File

@ -3,6 +3,7 @@ import Services
import SwiftUI
import Views
@MainActor
struct ApplyLabelsView: View {
enum Mode {
case item(LinkedItem)
@ -29,7 +30,6 @@ struct ApplyLabelsView: View {
}
let mode: Mode
let isSearchFocused: Bool
let onSave: (([LinkedItemLabel]) -> Void)?
@EnvironmentObject var dataService: DataService

View File

@ -51,39 +51,37 @@ struct LibraryTabView: View {
) {
EmptyView()
}
// TabView(selection: $selection) {
// BriefingView(
// articleId: "98e017a3-79d5-4049-97bc-ff170153792a"
// )
// .tabItem {
// Label {
// Text("Your Briefing")
// } icon: {
// Image.tabBriefing.padding(.trailing, 5)
// }
// }.tag(0)
// TabView(selection: $selection) {
// BriefingView(
// articleId: "98e017a3-79d5-4049-97bc-ff170153792a"
// )
// .tabItem {
// Label {
// Text("Your Briefing")
// } icon: {
// Image.tabBriefing.padding(.trailing, 5)
// }
// }.tag(0)
HomeView(viewModel: libraryViewModel)
// .tabItem {
// Label {
// Text("Library")
// } icon: {
// Image.tabLibrary
// }
// }.tag(1)
// .tabItem {
// Label {
// Text("Library")
// } icon: {
// Image.tabLibrary
// }
// }.tag(1)
// HomeView(viewModel: highlightsViewModel)
// .tabItem {
// Label {
// Text("Highlights")
// } icon: {
// Image.tabHighlights
// }
// }.tag(2)
// }
// HomeView(viewModel: highlightsViewModel)
// .tabItem {
// Label {
// Text("Highlights")
// } icon: {
// Image.tabHighlights
// }
// }.tag(2)
// }
}
}
.navigationViewStyle(.stack)
.navigationBarTitleDisplayMode(.inline)
}
}

View File

@ -25,7 +25,7 @@ import Views
func handleArchiveAction(dataService: DataService) {
guard let objectID = item?.objectID ?? pdfItem?.objectID else { return }
dataService.archiveLink(objectID: objectID, archived: !isItemArchived)
showInSnackbar(!isItemArchived ? "Link archived" : "Link moved to Inbox")
showInLibrarySnackbar(!isItemArchived ? "Link archived" : "Link moved to Inbox")
}
func handleDeleteAction(dataService: DataService) {

View File

@ -56,26 +56,39 @@ import Views
}
@MainActor struct PrimaryContentSidebar: View {
@State private var addLinkPresented = false
@State private var selectedCategory: PrimaryContentCategory?
let categories: [PrimaryContentCategory]
var innerBody: some View {
List(categories) { category in
NavigationLink(
destination: category.destinationView,
tag: category,
selection: $selectedCategory,
label: { category.listLabel }
)
#if os(iOS)
.listRowBackground(
category == selectedCategory
? Color.appGraySolid.opacity(0.4).cornerRadius(8)
: Color.clear.cornerRadius(8)
List {
ForEach(categories, id: \.self) { category in
NavigationLink(
destination: category.destinationView,
tag: category,
selection: $selectedCategory,
label: { category.listLabel }
)
#endif
#if os(iOS)
.listRowBackground(
category == selectedCategory
? Color.appGraySolid.opacity(0.4).cornerRadius(8)
: Color.clear.cornerRadius(8)
)
#endif
}
Button(action: { addLinkPresented = true }, label: {
Label("Add Link", systemImage: "plus.circle")
})
}
.dynamicTypeSize(.small ... .large)
.listStyle(.sidebar)
.sheet(isPresented: $addLinkPresented) {
NavigationView {
LibraryAddLinkView()
}
}
}
var body: some View {

View File

@ -18,6 +18,9 @@
@Published var realisticVoicesToggle: Bool = false
@Published var waitingForRealisticVoices: Bool = false
@Published var showSnackbar: Bool = false
var snackbarMessage: String?
func requestUltraRealisticFeatureAccess(
dataService: DataService,
audioController: AudioController
@ -50,7 +53,8 @@
realisticVoicesToggle = false
waitingForRealisticVoices = false
audioController.ultraRealisticFeatureRequested = false
Snackbar.show(message: "Error signing up for beta. Please try again.")
snackbarMessage = "Error signing up for beta. Please try again."
showSnackbar = true
}
}
}

View File

@ -27,7 +27,7 @@ func removeLibraryItemAction(dataService: DataService, objectID: NSManagedObject
print("checking if task is canceled: ", Task.isCancelled)
}
Snackbar.show(message: "Item removed", undoAction: {
Snackbar.showInLibrary(message: "Item removed", undoAction: {
print("canceling task", syncTask)
syncTask.cancel()
dataService.viewContext.performAndWait {

View File

@ -95,7 +95,7 @@
return AnyView(Button(action: {
Task {
if await viewModel.recommend(dataService: dataService) {
Snackbar.show(message: "Recommendation sent")
// Snackbar.show(message: "Recommendation sent")
dismiss()
}
}

View File

@ -7,6 +7,7 @@ import WebKit
@MainActor
struct WebReader: PlatformViewRepresentable {
let item: LinkedItem
let viewModel: WebReaderViewModel
let articleContent: ArticleContent
let openLinkAction: (URL) -> Void
let tapHandler: () -> Void
@ -100,7 +101,7 @@ struct WebReader: PlatformViewRepresentable {
do {
try (webView as? OmnivoreWebView)?.dispatchEvent(.saveAnnotation(annotation: annotation))
} catch {
showInSnackbar("Error saving note.")
showInLibrarySnackbar("Error saving note.")
}
}

View File

@ -337,7 +337,7 @@ struct WebReaderContainerView: View {
.foregroundColor(ThemeManager.currentTheme.isDark ? .white : .black)
.background(ThemeManager.currentBgColor)
.sheet(isPresented: $showLabelsModal) {
ApplyLabelsView(mode: .item(item), isSearchFocused: false, onSave: { labels in
ApplyLabelsView(mode: .item(item), onSave: { labels in
showLabelsModal = false
item.labels = NSSet(array: labels)
readerSettingsChangedTransactionID = UUID()
@ -377,6 +377,7 @@ struct WebReaderContainerView: View {
if let articleContent = viewModel.articleContent {
WebReader(
item: item,
viewModel: viewModel,
articleContent: articleContent,
openLinkAction: {
#if os(macOS)
@ -427,7 +428,7 @@ struct WebReaderContainerView: View {
#else
// Pasteboard.general.string = item.unwrappedPageURLString TODO: fix for mac
#endif
showInSnackbar("Link Copied")
showInLibrarySnackbar("Link Copied")
}, label: { Text(LocalText.readerCopyLink) })
Button(action: {
if let linkToOpen = linkToOpen {
@ -478,7 +479,7 @@ struct WebReaderContainerView: View {
}
.sheet(isPresented: $showHighlightLabelsModal) {
if let highlight = Highlight.lookup(byID: self.annotation, inContext: self.dataService.viewContext) {
ApplyLabelsView(mode: .highlight(highlight), isSearchFocused: false) { selectedLabels in
ApplyLabelsView(mode: .highlight(highlight)) { selectedLabels in
viewModel.setLabelsForHighlight(highlightID: highlight.unwrappedID,
labelIDs: selectedLabels.map(\.unwrappedID),
dataService: dataService)
@ -593,6 +594,13 @@ struct WebReaderContainerView: View {
.animation(.spring())
.closeOnTapOutside(true)
}
.onReceive(NSNotification.readerSnackBarPublisher) { notification in
if let message = notification.userInfo?["message"] as? String {
viewModel.snackbarOperation = SnackbarOperation(message: message,
undoAction: notification.userInfo?["undoAction"] as? SnackbarUndoAction)
viewModel.showSnackbar = true
}
}
}
func archive() {
@ -600,7 +608,6 @@ struct WebReaderContainerView: View {
#if os(iOS)
presentationMode.wrappedValue.dismiss()
#endif
viewModel.snackbar(message: !item.isArchived ? "Link archived" : "Link moved to Inbox")
}
func recommend() {
@ -620,9 +627,9 @@ struct WebReaderContainerView: View {
pasteBoard.clearContents()
pasteBoard.writeObjects([deepLink.absoluteString as NSString])
#endif
showInSnackbar("Deeplink Copied")
showInLibrarySnackbar("Deeplink Copied")
} else {
showInSnackbar("Error copying deeplink")
showInLibrarySnackbar("Error copying deeplink")
}
}

View File

@ -2,6 +2,7 @@ import CoreData
import Foundation
import Models
import SwiftGraphQL
import Utils
extension DataService {
public func archiveLink(objectID: NSManagedObjectID, archived: Bool) {
@ -13,6 +14,11 @@ extension DataService {
// Send update to server
self.syncLinkArchiveStatus(itemID: linkedItem.unwrappedID, archived: archived)
let message = archived ? "Link archived" : "Link moved to Inbox"
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
showInLibrarySnackbar(message)
}
}
}

View File

@ -5,7 +5,8 @@ import Models
public extension NSNotification {
static let PushJSONArticle = Notification.Name("PushJSONArticle")
static let PushReaderItem = Notification.Name("PushReaderItem")
static let OperationSuccess = Notification.Name("OperationSuccess")
static let LibrarySnackBar = Notification.Name("LibrarySnackBar")
static let ReaderSnackBar = Notification.Name("ReaderSnackBar")
static let OperationFailure = Notification.Name("OperationFailure")
static let ReaderSettingsChanged = Notification.Name("ReaderSettingsChanged")
static let SpeakingReaderItem = Notification.Name("SpeakingReaderItem")
@ -20,8 +21,12 @@ public extension NSNotification {
NotificationCenter.default.publisher(for: PushReaderItem)
}
static var operationSuccessPublisher: NotificationCenter.Publisher {
NotificationCenter.default.publisher(for: OperationSuccess)
static var readerSnackBarPublisher: NotificationCenter.Publisher {
NotificationCenter.default.publisher(for: ReaderSnackBar)
}
static var librarySnackBarPublisher: NotificationCenter.Publisher {
NotificationCenter.default.publisher(for: LibrarySnackBar)
}
static var operationFailedPublisher: NotificationCenter.Publisher {
@ -67,8 +72,8 @@ public extension NSNotification {
)
}
static func operationSuccess(message: String, undoAction: (() -> Void)?) {
NotificationCenter.default.post(name: NSNotification.OperationSuccess,
static func librarySnackBar(message: String, undoAction: (() -> Void)?) {
NotificationCenter.default.post(name: NSNotification.LibrarySnackBar,
object: nil,
userInfo: ["message": message, "undoAction": undoAction as Any])
}

View File

@ -7,12 +7,12 @@
import Foundation
public func showInSnackbar(_ message: String) {
let nname = Notification.Name("OperationSuccess")
public func showInLibrarySnackbar(_ message: String) {
let nname = Notification.Name("LibrarySnackBar")
NotificationCenter.default.post(name: nname, object: nil, userInfo: ["message": message])
}
public func showErrorInSnackbar(_ message: String) {
let nname = Notification.Name("OperationFailure")
public func showInReaderSnackbar(_ message: String) {
let nname = Notification.Name("ReaderSnackBar")
NotificationCenter.default.post(name: nname, object: nil, userInfo: ["message": message])
}

View File

@ -46,7 +46,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.updateTheme(themeName: ThemeManager.currentTheme.themeKey))
} catch {
showErrorInSnackbar("Error updating theme")
showInReaderSnackbar("Error updating theme")
}
}
@ -56,7 +56,7 @@ public final class OmnivoreWebView: WKWebView {
try dispatchEvent(.updateFontFamily(family: fontFamily))
}
} catch {
showErrorInSnackbar("Error updating font")
showInReaderSnackbar("Error updating font")
}
}
@ -66,7 +66,7 @@ public final class OmnivoreWebView: WKWebView {
try dispatchEvent(.updateFontSize(size: fontSize))
}
} catch {
showErrorInSnackbar("Error updating font")
showInReaderSnackbar("Error updating font")
}
}
@ -77,7 +77,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.updateMaxWidthPercentage(maxWidthPercentage: maxWidthPercentage))
} catch {
showErrorInSnackbar("Error updating max width")
showInReaderSnackbar("Error updating max width")
}
}
}
@ -87,7 +87,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.updateLineHeight(height: height))
} catch {
showErrorInSnackbar("Error updating line height")
showInReaderSnackbar("Error updating line height")
}
}
}
@ -101,7 +101,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.handleFontContrastChange(isHighContrast: isHighContrast))
} catch {
showErrorInSnackbar("Error updating text contrast")
showInReaderSnackbar("Error updating text contrast")
}
}
}
@ -115,7 +115,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.handleAutoHighlightModeChange(isEnabled: isEnabled))
} catch {
showErrorInSnackbar("Error updating text contrast")
showInReaderSnackbar("Error updating text contrast")
}
}
}
@ -126,7 +126,7 @@ public final class OmnivoreWebView: WKWebView {
try dispatchEvent(.updateJustifyText(justify: justify))
}
} catch {
showErrorInSnackbar("Error updating justify-text")
showInReaderSnackbar("Error updating justify-text")
}
}
@ -134,7 +134,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.updateTitle(title: title))
} catch {
showErrorInSnackbar("Error updating title")
showInReaderSnackbar("Error updating title")
}
}
@ -142,7 +142,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.updateLabels(labels: labelsJSON))
} catch {
showErrorInSnackbar("Error updating labels")
showInReaderSnackbar("Error updating labels")
}
}
@ -150,7 +150,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.share)
} catch {
showErrorInSnackbar("Error updating line height")
showInReaderSnackbar("Error updating line height")
}
}
@ -179,7 +179,7 @@ public final class OmnivoreWebView: WKWebView {
try dispatchEvent(.updateTheme(themeName: ThemeManager.currentTheme.themeKey))
}
} catch {
showErrorInSnackbar("Error updating theme due to colormode change")
showInReaderSnackbar("Error updating theme due to colormode change")
}
}
@ -305,7 +305,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.annotate)
} catch {
showErrorInSnackbar("Error creating highlight")
showInReaderSnackbar("Error creating highlight")
}
hideMenu()
}
@ -314,7 +314,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.highlight)
} catch {
showErrorInSnackbar("Error creating highlight")
showInReaderSnackbar("Error creating highlight")
}
hideMenu()
}
@ -323,7 +323,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.share)
} catch {
showErrorInSnackbar("Error sharing highlight")
showInReaderSnackbar("Error sharing highlight")
}
hideMenu()
}
@ -332,7 +332,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.remove)
} catch {
showErrorInSnackbar("Error deleting highlight")
showInReaderSnackbar("Error deleting highlight")
}
hideMenu()
}
@ -342,7 +342,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.copyHighlight)
} catch {
showErrorInSnackbar("Error copying highlight")
showInReaderSnackbar("Error copying highlight")
}
hideMenu()
}
@ -351,7 +351,7 @@ public final class OmnivoreWebView: WKWebView {
do {
try dispatchEvent(.setHighlightLabels)
} catch {
showErrorInSnackbar("Error setting labels for highlight")
showInReaderSnackbar("Error setting labels for highlight")
}
hideMenu()
}

View File

@ -38,6 +38,7 @@ public struct LibraryItemCard: View {
}
.padding(.bottom, 5)
.draggableItem(item: item)
.dynamicTypeSize(.xSmall ... .accessibility1)
}
var isFullyRead: Bool {
@ -126,22 +127,22 @@ public struct LibraryItemCard: View {
AnyView(HStack {
let fgcolor = Color.isDarkMode ? Color.themeDarkWhiteGray : Color.themeMiddleGray
Text("\(estimatedReadingTime)")
.font(Font.system(size: 11, weight: .medium))
.font(.caption2).fontWeight(.medium)
.foregroundColor(fgcolor)
+
Text("\(readingProgress)")
.font(Font.system(size: 11, weight: .medium))
.font(.caption2).fontWeight(.medium)
.foregroundColor(isPartiallyRead ? Color.appGreenSuccess : fgcolor)
+
Text("\(highlightsText)")
.font(Font.system(size: 11, weight: .medium))
.font(.caption2).fontWeight(.medium)
.foregroundColor(fgcolor)
+
Text("\(notesText)")
.font(Font.system(size: 11, weight: .medium))
.font(.caption2).fontWeight(.medium)
.foregroundColor(fgcolor)
}
.frame(maxWidth: .infinity, alignment: .leading))
@ -183,7 +184,7 @@ public struct LibraryItemCard: View {
var byLine: some View {
Text(bylineStr)
.font(Font.system(size: 11, weight: .regular))
.font(.caption2)
.foregroundColor(Color.isDarkMode ? Color.themeLightGray : Color.themeLightestGray)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
@ -192,9 +193,10 @@ public struct LibraryItemCard: View {
public var articleInfo: some View {
VStack(alignment: .leading, spacing: 5) {
readInfo
.dynamicTypeSize(.xSmall ... .medium)
Text(item.unwrappedTitle)
.font(Font.system(size: 14, weight: .semibold))
.font(.body).fontWeight(.semibold)
.lineSpacing(1.25)
.foregroundColor(.appGrayTextContrast)
.fixedSize(horizontal: false, vertical: true)

File diff suppressed because one or more lines are too long

View File

@ -43,13 +43,14 @@ public struct Snackbar: View {
}
.frame(maxWidth: 380)
.frame(height: 44)
.padding(.horizontal, 15)
.padding(.horizontal, 10)
.background(self.colorScheme == .light ? Color.black : Color.white)
.cornerRadius(5)
.clipped()
Spacer(minLength: 20)
}
.padding(.horizontal, 10)
.background(Color.clear)
.frame(height: 44 + 22)
}

View File

@ -78,13 +78,15 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
const focusedHighlightMousePos = useRef({ pageX: 0, pageY: 0 })
const [currentHighlightIdx, setCurrentHighlightIdx] = useState(0)
const [focusedHighlight, setFocusedHighlight] =
useState<Highlight | undefined>(undefined)
const [focusedHighlight, setFocusedHighlight] = useState<
Highlight | undefined
>(undefined)
const [selectionData, setSelectionData] = useSelection(highlightLocations)
const [labelsTarget, setLabelsTarget] =
useState<Highlight | undefined>(undefined)
const [labelsTarget, setLabelsTarget] = useState<Highlight | undefined>(
undefined
)
const windowDimensions = useGetWindowDimensions()
@ -537,6 +539,10 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
}
}
useEffect(() => {
setFocusedHighlight(undefined)
}, [selectionData])
const dispatchHighlightMessage = (actionID: string) => {
if (props.isAppleAppEmbed) {
window?.webkit?.messageHandlers.highlightAction?.postMessage({
@ -672,7 +678,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
dispatchHighlightMessage('noteCreated')
} else {
try {
await createHighlightCallback()
await createHighlightCallback(event.annotation)
dispatchHighlightMessage('noteCreated')
} catch (error) {
dispatchHighlightError('saveAnnotation', error)