Merge pull request #1998 from omnivore-app/fix/ios-display-settings

iOS Reader Settings display updates and theme updates
This commit is contained in:
Jackson Harper 2023-04-11 12:43:28 +08:00 committed by GitHub
commit d60a87d304
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 2521 additions and 357 deletions

View file

@ -86,6 +86,8 @@
playbackRateButton(rate: 1.5, title: "1.5×", selected: audioController.playbackRate == 1.5)
playbackRateButton(rate: 1.7, title: "1.7×", selected: audioController.playbackRate == 1.7)
playbackRateButton(rate: 2.0, title: "2.0×", selected: audioController.playbackRate == 2.0)
playbackRateButton(rate: 2.2, title: "2.2×", selected: audioController.playbackRate == 2.2)
playbackRateButton(rate: 2.5, title: "2.5×", selected: audioController.playbackRate == 2.5)
}
Button(action: { showVoiceSheet = true }, label: { Label("Change Voice", systemImage: "person.wave.2") })
Button(action: { viewArticle() }, label: { Label("View Article", systemImage: "book") })
@ -331,6 +333,8 @@
playbackRateButton(rate: 1.5, title: "1.5×", selected: audioController.playbackRate == 1.5)
playbackRateButton(rate: 1.7, title: "1.7×", selected: audioController.playbackRate == 1.7)
playbackRateButton(rate: 2.0, title: "2.0×", selected: audioController.playbackRate == 2.0)
playbackRateButton(rate: 2.2, title: "2.2×", selected: audioController.playbackRate == 2.2)
playbackRateButton(rate: 2.5, title: "2.5×", selected: audioController.playbackRate == 2.5)
}, label: {
Text("\(String(format: "%.1f", audioController.playbackRate))×")
.font(.appCaption)

View file

@ -9,9 +9,10 @@
@State var annotation = String()
@State var showAnnotationModal = false
let viewModel: HighlightsListViewModel
let viewModel: NotebookViewModel
let highlightParams: HighlightListItemParams
@Binding var hasHighlightMutations: Bool
let onSaveAnnotation: (String) -> Void
let onDeleteHighlight: () -> Void
let onSetLabels: (String) -> Void
@ -180,19 +181,21 @@
noteSection
}
.sheet(isPresented: $showAnnotationModal) {
HighlightAnnotationSheet(
annotation: $annotation,
onSave: {
onSaveAnnotation(annotation)
showAnnotationModal = false
hasHighlightMutations = true
},
onCancel: {
showAnnotationModal = false
},
errorAlertMessage: $errorAlertMessage,
showErrorAlertMessage: $showErrorAlertMessage
)
NavigationView {
HighlightAnnotationSheet(
annotation: $annotation,
onSave: {
onSaveAnnotation(annotation)
showAnnotationModal = false
hasHighlightMutations = true
},
onCancel: {
showAnnotationModal = false
},
errorAlertMessage: $errorAlertMessage,
showErrorAlertMessage: $showErrorAlertMessage
)
}
}
.formSheet(isPresented: $showShareView) {
ShareSheet(activityItems: [viewModel.highlightAsMarkdown(item: self.highlightParams)])

View file

@ -1,127 +0,0 @@
#if os(iOS)
import CoreData
import Models
import Services
import SwiftUI
import Views
struct HighlightsListView: View {
@EnvironmentObject var dataService: DataService
@Environment(\.presentationMode) private var presentationMode
@StateObject var viewModel = HighlightsListViewModel()
let itemObjectID: NSManagedObjectID
@Binding var hasHighlightMutations: Bool
@State var setLabelsHighlight: Highlight?
@State var showShareView: Bool = false
var emptyView: some View {
Text(LocalText.highlightCardNoHighlightsOnPage)
.multilineTextAlignment(.center)
.padding(16)
}
var innerBody: some View {
(viewModel.highlightItems.count > 0 ? AnyView(listView) : AnyView(emptyView))
.navigationTitle("Notebook")
.listStyle(PlainListStyle())
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
dismissButton
}
ToolbarItem(placement: .navigationBarTrailing) {
actionsMenu
}
}.formSheet(isPresented: $showShareView) {
ShareSheet(activityItems: [viewModel.highlightsAsMarkdown()])
}
#else
.toolbar {
ToolbarItemGroup {
dismissButton
}
}
#endif
}
var listView: some View {
List {
Section {
ForEach(viewModel.highlightItems) { highlightParams in
HighlightsListCard(
viewModel: self.viewModel,
highlightParams: highlightParams,
hasHighlightMutations: $hasHighlightMutations,
onSaveAnnotation: {
viewModel.updateAnnotation(
highlightID: highlightParams.highlightID,
annotation: $0,
dataService: dataService
)
},
onDeleteHighlight: {
hasHighlightMutations = true
viewModel.deleteHighlight(
highlightID: highlightParams.highlightID,
dataService: dataService
)
},
onSetLabels: { highlightID in
setLabelsHighlight = Highlight.lookup(byID: highlightID, inContext: dataService.viewContext)
}
)
.listRowSeparator(.hidden)
}
}
}.sheet(item: $setLabelsHighlight) { highlight in
ApplyLabelsView(mode: .highlight(highlight), isSearchFocused: false, onSave: { selectedLabels in
hasHighlightMutations = true
viewModel.setLabelsForHighlight(highlightID: highlight.unwrappedID,
labels: selectedLabels,
dataService: dataService)
})
}
}
var dismissButton: some View {
Button(
action: { presentationMode.wrappedValue.dismiss() },
label: { Text(LocalText.genericClose) }
)
}
var actionsMenu: some View {
Menu(
content: {
Button(
action: { showShareView = true },
label: { Label(LocalText.exportGeneric, systemImage: "square.and.arrow.up") }
)
},
label: {
Image(systemName: "ellipsis")
.foregroundColor(.appGrayTextContrast)
}
)
}
var body: some View {
Group {
#if os(iOS)
NavigationView {
innerBody
}
#elseif os(macOS)
innerBody
.frame(minWidth: 400, minHeight: 400)
#endif
}
.task {
viewModel.load(itemObjectID: itemObjectID, dataService: dataService)
}
}
}
#endif

View file

@ -0,0 +1,224 @@
#if os(iOS)
import CoreData
import MarkdownUI
import Models
import Services
import SwiftUI
import Views
struct NotebookView: View {
@EnvironmentObject var dataService: DataService
@Environment(\.presentationMode) private var presentationMode
@StateObject var viewModel = NotebookViewModel()
@State var showAnnotationModal = false
@State var errorAlertMessage: String?
@State var showErrorAlertMessage = false
@State var noteAnnotation = ""
let itemObjectID: NSManagedObjectID
@Binding var hasHighlightMutations: Bool
@State var setLabelsHighlight: Highlight?
@State var showShareView: Bool = false
@State var showConfirmNoteDelete = false
var emptyView: some View {
Text(LocalText.highlightCardNoHighlightsOnPage)
.multilineTextAlignment(.leading)
.padding(16)
}
var innerBody: some View {
listView
.navigationTitle("Notebook")
.listStyle(PlainListStyle())
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
dismissButton
}
ToolbarItem(placement: .navigationBarTrailing) {
actionsMenu
}
}.formSheet(isPresented: $showShareView) {
ShareSheet(activityItems: [viewModel.highlightsAsMarkdown()])
}.alert("Are you sure you want to delete the note?",
isPresented: $showConfirmNoteDelete) {
Button("Remove Item", role: .destructive) {
viewModel.deleteNote(dataService: dataService)
showConfirmNoteDelete = false
}
Button(LocalText.cancelGeneric, role: .cancel) {
showConfirmNoteDelete = false
}
}
#else
.toolbar {
ToolbarItemGroup {
dismissButton
}
}
#endif
}
var noteSection: some View {
HStack {
// let isEmpty = viewModel.noteItem.annotation.isEmpty
Spacer(minLength: 6)
if let note = viewModel.noteItem, let annotation = note.annotation, !annotation.isEmpty {
Markdown(annotation)
.lineSpacing(6)
.accentColor(.appGraySolid)
.foregroundColor(.appGrayTextContrast)
.font(.appSubheadline)
.padding(12)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.appButtonBackground)
.cornerRadius(8)
.contextMenu {
Button(
action: { UIPasteboard.general.string = note.annotation },
label: { Label("Copy", systemImage: "copy") }
)
Button(
action: {
noteAnnotation = viewModel.noteItem?.annotation ?? ""
showAnnotationModal = true
},
label: { Label("Edit", systemImage: "edit") }
)
}
} else {
Text("Add Notes...")
.lineSpacing(6)
.accentColor(.appGraySolid)
.foregroundColor(.appGrayText)
.font(.appSubheadline)
.padding(12)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.appButtonBackground)
.cornerRadius(8)
}
}
.onTapGesture {
noteAnnotation = viewModel.noteItem?.annotation ?? ""
showAnnotationModal = true
}
}
var listView: some View {
List {
Section("Article Notes") {
noteSection
.listRowSeparator(.hidden, edges: .bottom)
}
Section("Highlights") {
if viewModel.highlightItems.count > 0 {
ForEach(Array(viewModel.highlightItems.enumerated()), id: \.offset) { idx, highlightParams in
HighlightsListCard(
viewModel: self.viewModel,
highlightParams: highlightParams,
hasHighlightMutations: $hasHighlightMutations,
onSaveAnnotation: {
viewModel.updateAnnotation(
highlightID: highlightParams.highlightID,
annotation: $0,
dataService: dataService
)
},
onDeleteHighlight: {
hasHighlightMutations = true
viewModel.deleteHighlight(
highlightID: highlightParams.highlightID,
dataService: dataService
)
},
onSetLabels: { highlightID in
setLabelsHighlight = Highlight.lookup(byID: highlightID, inContext: dataService.viewContext)
}
)
.listRowSeparator(.hidden, edges: idx == 0 ? .bottom : .all)
}
} else {
emptyView
.listRowSeparator(.hidden, edges: .bottom)
}
}
Spacer(minLength: 120)
.listRowSeparator(.hidden, edges: .all)
}.sheet(item: $setLabelsHighlight) { highlight in
ApplyLabelsView(mode: .highlight(highlight), isSearchFocused: false, onSave: { selectedLabels in
hasHighlightMutations = true
viewModel.setLabelsForHighlight(highlightID: highlight.unwrappedID,
labels: selectedLabels,
dataService: dataService)
})
}.sheet(isPresented: $showAnnotationModal) {
NavigationView {
HighlightAnnotationSheet(
annotation: $noteAnnotation,
onSave: {
viewModel.updateNoteAnnotation(
itemObjectID: itemObjectID,
annotation: noteAnnotation,
dataService: dataService
)
showAnnotationModal = false
hasHighlightMutations = true
},
onCancel: {
showAnnotationModal = false
},
errorAlertMessage: $errorAlertMessage,
showErrorAlertMessage: $showErrorAlertMessage
)
}
}
}
var dismissButton: some View {
Button(
action: { presentationMode.wrappedValue.dismiss() },
label: { Text(LocalText.genericClose) }
)
}
var actionsMenu: some View {
Menu(
content: {
Button(
action: { showShareView = true },
label: { Label(LocalText.exportGeneric, systemImage: "square.and.arrow.up") }
)
Button(
action: { showConfirmNoteDelete = true },
label: { Label("Delete Document Note", systemImage: "trash") }
).padding()
},
label: {
Image(systemName: "ellipsis")
.foregroundColor(.appGrayTextContrast)
}
)
}
var body: some View {
Group {
#if os(iOS)
NavigationView {
innerBody
}
#elseif os(macOS)
innerBody
.frame(minWidth: 400, minHeight: 400)
#endif
}
.task {
viewModel.load(itemObjectID: itemObjectID, dataService: dataService)
}
}
}
#endif

View file

@ -14,7 +14,14 @@ struct HighlightListItemParams: Identifiable {
let createdBy: InternalUserProfile?
}
@MainActor final class HighlightsListViewModel: ObservableObject {
struct NoteItemParams: Identifiable {
let id = UUID()
let highlightID: String
let annotation: String?
}
@MainActor final class NotebookViewModel: ObservableObject {
@Published var noteItem: NoteItemParams?
@Published var highlightItems = [HighlightListItemParams]()
func load(itemObjectID: NSManagedObjectID, dataService: DataService) {
@ -38,6 +45,33 @@ struct HighlightListItemParams: Identifiable {
}
}
func updateNoteAnnotation(itemObjectID: NSManagedObjectID, annotation: String, dataService: DataService) {
if let noteItem = self.noteItem {
dataService.updateHighlightAttributes(highlightID: noteItem.highlightID, annotation: annotation)
self.noteItem = NoteItemParams(highlightID: noteItem.highlightID, annotation: annotation)
} else {
let highlightId = UUID().uuidString.lowercased()
let shortId = NanoID.generate(alphabet: NanoID.Alphabet.urlSafe.rawValue, size: 8)
if let linkedItem = dataService.viewContext.object(with: itemObjectID) as? LinkedItem {
noteItem = NoteItemParams(highlightID: highlightId, annotation: annotation)
let highlight = dataService.createNote(shortId: shortId,
highlightID: highlightId,
articleId: linkedItem.unwrappedID,
annotation: annotation)
} else {
//
}
}
}
func deleteNote(dataService: DataService) {
if let highlightID = noteItem?.highlightID {
dataService.deleteHighlight(highlightID: highlightID)
noteItem = nil
}
}
func deleteHighlight(highlightID: String, dataService: DataService) {
dataService.deleteHighlight(highlightID: highlightID)
highlightItems.removeAll { $0.highlightID == highlightID }
@ -72,7 +106,8 @@ struct HighlightListItemParams: Identifiable {
}
private func loadHighlights(item: LinkedItem) {
let unsortedHighlights = item.highlights.asArray(of: Highlight.self).filter { $0.type == "HIGHLIGHT" }
let unsortedHighlights = item.highlights.asArray(of: Highlight.self)
.filter { $0.type == "HIGHLIGHT" && $0.serverSyncStatus != ServerSyncStatus.needsDeletion.rawValue }
let highlights = unsortedHighlights.sorted { left, right in
if left.positionPercent > 0, right.positionPercent > 0 {
@ -91,5 +126,10 @@ struct HighlightListItemParams: Identifiable {
createdBy: $0.createdByMe ? nil : InternalUserProfile.makeSingle($0.createdBy)
)
}
noteItem = item.highlights.asArray(of: Highlight.self)
.filter { $0.type == "NOTE" && $0.serverSyncStatus != ServerSyncStatus.needsDeletion.rawValue }
.first
.map { NoteItemParams(highlightID: $0.unwrappedID, annotation: $0.annotation) }
}
}

View file

@ -81,7 +81,7 @@ struct AnimatingCellHeight: AnimatableModifier {
LinkedItemMetadataEditView(item: item)
}
.sheet(item: $viewModel.itemForHighlightsView) { item in
HighlightsListView(itemObjectID: item.objectID, hasHighlightMutations: $hasHighlightMutations)
NotebookView(itemObjectID: item.objectID, hasHighlightMutations: $hasHighlightMutations)
}
.sheet(isPresented: $viewModel.showCommunityModal) {
CommunityModal()
@ -317,10 +317,6 @@ struct AnimatingCellHeight: AnimatableModifier {
func menuItems(for item: LinkedItem) -> some View {
Group {
Button(
action: { viewModel.itemForHighlightsView = item },
label: { Label("Notebook", systemImage: "highlighter") }
)
Button(
action: { viewModel.itemUnderTitleEdit = item },
label: { Label("Edit Info", systemImage: "info.circle") }

View file

@ -55,11 +55,16 @@ struct WebReader: PlatformViewRepresentable {
#if os(iOS)
webView.isOpaque = false
webView.backgroundColor = Color.isDarkMode ? .systemBackground : .white
webView.backgroundColor = UIColor(ThemeManager.currentBgColor)
webView.underPageBackgroundColor = UIColor(ThemeManager.currentBgColor)
webView.scrollView.backgroundColor = UIColor(ThemeManager.currentBgColor)
webView.scrollView.delegate = context.coordinator
webView.scrollView.contentInset.top = readerViewNavBarHeight
webView.scrollView.verticalScrollIndicatorInsets.top = readerViewNavBarHeight
webView.configuration.userContentController.add(webView, name: "viewerAction")
webView.scrollView.indicatorStyle = ThemeManager.currentTheme.isDark ?
UIScrollView.IndicatorStyle.white :
UIScrollView.IndicatorStyle.black
#else
webView.setValue(false, forKey: "drawsBackground")
#endif
@ -107,6 +112,10 @@ struct WebReader: PlatformViewRepresentable {
(webView as? OmnivoreWebView)?.updateLineHeight()
(webView as? OmnivoreWebView)?.updateLabels(labelsJSON: item.labelsJSONString)
(webView as? OmnivoreWebView)?.updateTitle(title: item.title ?? "")
(webView as? OmnivoreWebView)?.updateJustifyText()
webView.scrollView.indicatorStyle = ThemeManager.currentTheme.isDark ?
UIScrollView.IndicatorStyle.white :
UIScrollView.IndicatorStyle.black
}
if showNavBarActionID != context.coordinator.previousShowNavBarActionID {

View file

@ -14,7 +14,7 @@ struct WebReaderContainerView: View {
@State private var showLabelsModal = false
@State private var showHighlightLabelsModal = false
@State private var showTitleEdit = false
@State private var showHighlightsView = false
@State private var showNotebookView = false
@State private var hasPerformedHighlightMutations = false
@State var showHighlightAnnotationModal = false
@State private var navBarVisibilityRatio = 1.0
@ -61,7 +61,7 @@ struct WebReaderContainerView: View {
lastScrollPercentage = percent
}
func onHighlightListViewDismissal() {
func onNotebookViewDismissal() {
// Reload the web view if mutation happened in highlights list modal
guard hasPerformedHighlightMutations else { return }
@ -143,7 +143,7 @@ struct WebReaderContainerView: View {
textToSpeechButtonImage
}
)
.padding(.horizontal)
.padding(.horizontal, 5)
.scaleEffect(navBarVisibilityRatio))
}
}
@ -204,10 +204,6 @@ struct WebReaderContainerView: View {
func menuItems(for item: LinkedItem) -> some View {
let hasLabels = item.labels?.count != 0
return Group {
Button(
action: { showHighlightsView = true },
label: { Label("Notebook", systemImage: "highlighter") }
)
Button(
action: { showTitleEdit = true },
label: { Label("Edit Info", systemImage: "info.circle") }
@ -261,21 +257,34 @@ struct WebReaderContainerView: View {
}
var navBar: some View {
HStack(alignment: .center) {
HStack(alignment: .center, spacing: 15) {
#if os(iOS)
Button(
action: { self.presentationMode.wrappedValue.dismiss() },
label: {
Image(systemName: "chevron.backward")
.font(.appNavbarIcon)
.foregroundColor(.appGrayTextContrast)
// .foregroundColor(.appGrayTextContrast)
.padding()
}
)
.scaleEffect(navBarVisibilityRatio)
Spacer()
#endif
Button(
action: { showNotebookView = true },
label: {
Image("notebook", bundle: Bundle(url: ViewsPackage.bundleURL))
}
)
.padding(.horizontal, 5)
.scaleEffect(navBarVisibilityRatio)
#if os(iOS)
audioNavbarItem
#endif
Button(
action: { showPreferencesPopover.toggle() },
label: {
@ -283,7 +292,7 @@ struct WebReaderContainerView: View {
.font(.appNavbarIcon)
}
)
.padding(.horizontal)
.padding(.horizontal, 5)
.scaleEffect(navBarVisibilityRatio)
#if os(macOS)
Spacer()
@ -297,7 +306,7 @@ struct WebReaderContainerView: View {
Image(systemName: "ellipsis")
.resizable(resizingMode: Image.ResizingMode.stretch)
.aspectRatio(contentMode: .fit)
.foregroundColor(.appGrayTextContrast)
// .foregroundColor(.appGrayTextContrast)
.frame(width: 20, height: 20)
.scaleEffect(navBarVisibilityRatio)
.padding()
@ -316,7 +325,8 @@ struct WebReaderContainerView: View {
}
.frame(height: readerViewNavBarHeight * navBarVisibilityRatio)
.opacity(navBarVisibilityRatio)
.background(Color.systemBackground)
.foregroundColor(ThemeManager.currentTheme.isDark ? .white : .black)
.background(ThemeManager.currentBgColor)
.alert("Are you sure you want to remove this item? All associated notes and highlights will be deleted.",
isPresented: $showDeleteConfirmation) {
Button("Remove Item", role: .destructive) {
@ -343,8 +353,8 @@ struct WebReaderContainerView: View {
})
}
#if os(iOS)
.sheet(isPresented: $showHighlightsView, onDismiss: onHighlightListViewDismissal) {
HighlightsListView(
.sheet(isPresented: $showNotebookView, onDismiss: onNotebookViewDismissal) {
NotebookView(
itemObjectID: item.objectID,
hasHighlightMutations: $hasPerformedHighlightMutations
)
@ -396,6 +406,7 @@ struct WebReaderContainerView: View {
showBottomBar: $showBottomBar,
showHighlightAnnotationModal: $showHighlightAnnotationModal
)
.background(ThemeManager.currentBgColor)
.onAppear {
if item.isUnread {
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0.1, anchorIndex: 0)
@ -404,15 +415,6 @@ struct WebReaderContainerView: View {
await audioController.preload(itemIDs: [item.unwrappedID])
}
}
.onDisappear {
// if let lastScrollPercentage = self.lastScrollPercentage {
// dataService.updateLinkReadingProgress(
// itemID: item.unwrappedID,
// readingProgress: Double(lastScrollPercentage),
// anchorIndex: 0
// )
// }
}
.confirmationDialog(linkToOpen?.absoluteString ?? "", isPresented: $displayLinkSheet) {
Button(action: {
if let linkToOpen = linkToOpen {
@ -526,7 +528,7 @@ struct WebReaderContainerView: View {
#endif
}
#if os(iOS)
.formSheet(isPresented: $showPreferencesPopover, useSmallDetent: false) {
.formSheet(isPresented: $showPreferencesPopover, modalSize: CGSize(width: 400, height: 465)) {
webPreferencesPopoverView
}
#else

View file

@ -31,7 +31,7 @@ struct WebReaderContent {
self.maxWidthPercentage = maxWidthPercentage
self.item = item
self.isDark = isDark
self.themeKey = isDark ? "Dark" : "Light"
self.themeKey = ThemeManager.currentTheme.themeKey
self.fontFamily = fontFamily
self.articleContent = articleContent
self.prefersHighContrastText = prefersHighContrastText
@ -105,11 +105,7 @@ struct WebReaderContent {
// swiftlint:disable line_length function_body_length
static func emptyContent(isDark: Bool) -> String {
let themeKey = isDark ? "Dark" : "Light"
// let savedAt = "new Date(\(item.unwrappedSavedAt.timeIntervalSince1970 * 1000)).toISOString()"
// let createdAt = "new Date(\(item.unwrappedCreatedAt.timeIntervalSince1970 * 1000)).toISOString()"
// let publishedAt = item.publishDate != nil ? "new Date(\(item.publishDate!.timeIntervalSince1970 * 1000)).toISOString()" : "undefined"
let themeKey = ThemeManager.currentTheme.themeKey
return """
<!DOCTYPE html>
<html>

View file

@ -87,7 +87,9 @@ extension DataService {
return ArticleContent(
title: linkedItem.unwrappedTitle,
htmlContent: htmlContent,
highlightsJSONString: highlights.map { InternalHighlight.make(from: $0) }.asJSONString,
highlightsJSONString: highlights
.filter { $0.serverSyncStatus != ServerSyncStatus.needsDeletion.rawValue }
.map { InternalHighlight.make(from: $0) }.asJSONString,
contentStatus: .succeeded,
objectID: linkedItem.objectID
)

View file

@ -3,9 +3,9 @@ import Foundation
import Models
import SwiftGraphQL
extension DataService {
public extension DataService {
// swiftlint:disable:next function_parameter_count
public func createHighlight(
func createHighlight(
shortId: String,
highlightID: String,
quote: String,
@ -40,7 +40,36 @@ extension DataService {
return internalHighlight.encoded()
}
func syncHighlightCreation(highlight: InternalHighlight, articleId: String) {
func createNote(
shortId: String,
highlightID: String,
articleId: String,
annotation: String
) -> [String: Any]? {
let internalHighlight = InternalHighlight(
id: highlightID,
type: "NOTE",
shortId: shortId,
quote: "",
prefix: nil, suffix: nil,
patch: "",
annotation: annotation,
createdAt: nil,
updatedAt: nil,
createdByMe: true,
createdBy: nil,
positionPercent: nil,
positionAnchorIndex: nil,
labels: []
)
internalHighlight.persist(context: backgroundContext, associatedItemID: articleId)
syncHighlightCreation(highlight: internalHighlight, articleId: articleId)
return internalHighlight.encoded()
}
internal func syncHighlightCreation(highlight: InternalHighlight, articleId: String) {
enum MutationResult {
case saved(highlight: InternalHighlight)
case error(errorCode: Enums.CreateHighlightErrorCode)
@ -62,10 +91,10 @@ extension DataService {
articleId: articleId,
highlightPositionAnchorIndex: OptionalArgument(highlight.positionAnchorIndex),
highlightPositionPercent: OptionalArgument(highlight.positionPercent), id: highlight.id,
patch: OptionalArgument(highlight.patch),
quote: OptionalArgument(highlight.quote),
patch: OptionalArgument(highlight.patch.isEmpty ? nil : highlight.patch),
quote: OptionalArgument(highlight.quote.isEmpty ? nil : highlight.quote),
shortId: highlight.shortId,
type: OptionalArgument(Enums.HighlightType.highlight)
type: OptionalArgument(highlight.type == "NOTE" ? Enums.HighlightType.note : Enums.HighlightType.highlight)
),
selection: selection
)

View file

@ -31,4 +31,5 @@ public enum UserDefaultKey: String {
case shouldPromptCommunityModal
case userWordsPerMinute
case hideFeatureSection
case justifyText
}

View file

@ -25,16 +25,16 @@ public struct HighlightAnnotationSheet: View {
public var body: some View {
VStack {
HStack {
Button(LocalText.cancelGeneric, action: onCancel)
Spacer()
Label("Note", systemImage: "note.text")
Spacer()
Button(LocalText.genericSave) {
onSave()
}
}
.foregroundColor(.appGrayTextContrast)
// HStack {
// Button(LocalText.cancelGeneric, action: onCancel)
// Spacer()
// Text("Note").font(Font.system(size: 18, weight: .bold))
// Spacer()
// Button(LocalText.genericSave) {
// onSave()
// }
// }
// .foregroundColor(.appGrayTextContrast)
ScrollView {
TextEditor(text: $annotation)
@ -49,6 +49,15 @@ public struct HighlightAnnotationSheet: View {
Spacer()
}
.padding()
.navigationTitle("Note")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(leading: Button(action: onCancel, label: {
Text("Cancel")
}))
.navigationBarItems(trailing: Button(action: onSave, label: {
Text("Save").bold()
}))
.listStyle(PlainListStyle())
.alert(errorAlertMessage ?? LocalText.readerError, isPresented: $showErrorAlertMessage) {
Button(LocalText.genericOk, role: .cancel, action: {
errorAlertMessage = nil

View file

@ -44,9 +44,7 @@ public final class OmnivoreWebView: WKWebView {
public func updateTheme() {
do {
if let themeName = UserDefaults.standard.value(forKey: UserDefaultKey.themeName.rawValue) as? String {
try dispatchEvent(.updateTheme(themeName: themeName))
}
try dispatchEvent(.updateTheme(themeName: ThemeManager.currentTheme.themeKey))
} catch {
showErrorInSnackbar("Error updating theme")
}
@ -122,6 +120,16 @@ public final class OmnivoreWebView: WKWebView {
}
}
public func updateJustifyText() {
do {
if let justify = UserDefaults.standard.value(forKey: UserDefaultKey.justifyText.rawValue) as? Bool {
try dispatchEvent(.updateJustifyText(justify: justify))
}
} catch {
showErrorInSnackbar("Error updating justify-text")
}
}
public func updateTitle(title: String) {
do {
try dispatchEvent(.updateTitle(title: title))
@ -167,28 +175,19 @@ public final class OmnivoreWebView: WKWebView {
super.traitCollectionDidChange(previousTraitCollection)
guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else { return }
do {
try dispatchEvent(.updateColorMode(isDark: traitCollection.userInterfaceStyle == .dark))
if ThemeManager.currentTheme == .system {
try dispatchEvent(.updateTheme(themeName: ThemeManager.currentTheme.themeKey))
}
} catch {
showErrorInSnackbar("Error updating theme")
showErrorInSnackbar("Error updating theme due to colormode change")
}
}
#elseif os(macOS)
override public func viewDidChangeEffectiveAppearance() {
super.viewDidChangeEffectiveAppearance()
switch effectiveAppearance.bestMatch(from: [.aqua, .darkAqua]) {
case .some(.darkAqua):
do {
try dispatchEvent(.updateColorMode(isDark: true))
} catch {
showErrorInSnackbar("Error updating theme")
}
default:
do {
try dispatchEvent(.updateColorMode(isDark: false))
} catch {
showErrorInSnackbar("Error updating theme")
}
if ThemeManager.currentTheme == .system {
try dispatchEvent(.updateTheme(themeName: ThemeManager.currentTheme.themeKey))
}
}
#endif
@ -416,9 +415,9 @@ public enum WebViewDispatchEvent {
case updateLineHeight(height: Int)
case updateMaxWidthPercentage(maxWidthPercentage: Int)
case updateFontSize(size: Int)
case updateColorMode(isDark: Bool)
case updateFontFamily(family: String)
case updateTheme(themeName: String)
case updateJustifyText(justify: Bool)
case saveAnnotation(annotation: String)
case annotate
case highlight
@ -450,12 +449,12 @@ public enum WebViewDispatchEvent {
return "updateMaxWidthPercentage"
case .updateFontSize:
return "updateFontSize"
case .updateColorMode:
return "updateColorMode"
case .updateFontFamily:
return "updateFontFamily"
case .updateTheme:
return "updateTheme"
case .updateJustifyText:
return "updateJustifyText"
case .saveAnnotation:
return "saveAnnotation"
case .annotate:
@ -499,8 +498,8 @@ public enum WebViewDispatchEvent {
return "event.themeName = '\(themeName)';"
case let .updateFontSize(size: size):
return "event.fontSize = '\(size)';"
case let .updateColorMode(isDark: isDark):
return "event.isDark = '\(isDark)';"
case let .updateJustifyText(justify: justify):
return "event.justifyText = \(justify);"
case let .updateFontFamily(family: family):
return "event.fontFamily = '\(family)';"
case let .updateLabels(labels):

View file

@ -0,0 +1,97 @@
#if os(iOS)
import Foundation
import SwiftUI
extension UIColor {
func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
UIGraphicsImageRenderer(size: size).image { rendererContext in
self.setFill()
rendererContext.fill(CGRect(origin: .zero, size: size))
}
}
}
class CustomSliderView: UISlider {
@IBInspectable var trackLineHeight: CGFloat = 2
override func trackRect(forBounds bound: CGRect) -> CGRect {
CGRect(origin: CGPoint(x: bound.origin.x, y: bound.midY),
size: CGSize(width: bound.width, height: trackLineHeight))
}
}
struct CustomSlider: UIViewRepresentable {
typealias UIViewType = UISlider
@Binding var value: Int
let minValue: Int
let maxValue: Int
var onEditingChanged: (Bool) -> Void
init(value: Binding<Int>, minValue: Int, maxValue: Int, onEditingChanged: @escaping (Bool) -> Void) {
self._value = value
self.minValue = minValue
self.maxValue = maxValue
self.onEditingChanged = onEditingChanged
}
func asFloat<T: BinaryInteger>(_ numeric: T) -> Float {
Float(Double(numeric))
}
func makeUIView(context: Context) -> UISlider {
let slider = CustomSliderView(frame: .zero)
slider.trackLineHeight = 2
slider.minimumValue = asFloat(minValue)
slider.maximumValue = asFloat(maxValue)
let tintColor = UIColor(Color(hex: "#969594") ?? Color.appGrayBorder)
let thumbImage = UIImage(systemName: "circle.fill",
withConfiguration: UIImage.SymbolConfiguration(scale: .medium))?
.withTintColor(tintColor)
.withRenderingMode(.alwaysOriginal)
slider.setThumbImage(thumbImage, for: .selected)
slider.setThumbImage(thumbImage, for: .normal)
// slider.minimumTrackTintColor = tintColor
slider.addTarget(context.coordinator,
action: #selector(Coordinator.valueChanged(_:)),
for: .valueChanged)
return slider
}
func updateUIView(_ uiView: UISlider, context _: Context) {
uiView.value = Float(value)
uiView.maximumValue = Float(maxValue)
}
func makeCoordinator() -> Coordinator {
let coordinator = Coordinator(value: $value, onEditingChanged: onEditingChanged)
return coordinator
}
class Coordinator: NSObject {
var value: Binding<Int>
var onEditingChanged: (Bool) -> Void
init(value: Binding<Int>, onEditingChanged: @escaping (Bool) -> Void) {
self.value = value
self.onEditingChanged = onEditingChanged
super.init()
}
@objc func valueChanged(_ sender: UISlider) {
let oldValue = value.wrappedValue
value.wrappedValue = Int(round(sender.value))
if oldValue != value.wrappedValue {
onEditingChanged(sender.isTracking)
}
}
}
}
#endif

View file

@ -57,17 +57,17 @@ public enum WebFont: String, CaseIterable {
}
}
public func font() -> Font? {
public func font(size: CGFloat = 22) -> Font? {
#if os(iOS)
if let uiFont = UIFont(name: registeredName, size: 22) {
if let uiFont = UIFont(name: registeredName, size: size) {
return Font(uiFont as CTFont)
}
#else
if let nsFont = NSFont(name: registeredName, size: 22) {
if let nsFont = NSFont(name: registeredName, size: size) {
return Font(nsFont as CTFont)
}
#endif
return Font.system(size: 22)
return Font.system(size: size)
}
}
@ -83,6 +83,7 @@ public enum WebFont: String, CaseIterable {
@AppStorage(UserDefaultKey.enableHighlightOnRelease.rawValue) var enableHighlightOnRelease = false
@AppStorage(UserDefaultKey.preferredWebFont.rawValue) var preferredFont = WebFont.inter.rawValue
@AppStorage(UserDefaultKey.prefersHighContrastWebFont.rawValue) var prefersHighContrastText = true
@AppStorage(UserDefaultKey.justifyText.rawValue) var justifyText = false
public init(
updateReaderPreferences: @escaping () -> Void,
@ -103,7 +104,7 @@ public enum WebFont: String, CaseIterable {
label: {
HStack {
Text(font.displayValue)
.font(font.font())
.font(font.font(size: 22))
.foregroundColor(.appGrayTextContrast)
Spacer()
if font.rawValue == preferredFont {
@ -121,119 +122,315 @@ public enum WebFont: String, CaseIterable {
.navigationTitle("Reader Font")
}
var advancedSettings: some View {
VStack {
Toggle("High Contrast Text:", isOn: $prefersHighContrastText)
.frame(height: 40)
.padding(.trailing, 6)
.onChange(of: prefersHighContrastText) { _ in
updateReaderPreferences()
}
Toggle(LocalText.enableHighlightOnReleaseText, isOn: $enableHighlightOnRelease)
.frame(height: 40)
.padding(.trailing, 6)
.onChange(of: enableHighlightOnRelease) { _ in
updateReaderPreferences()
}
Toggle("Justify Text", isOn: $justifyText)
.frame(height: 40)
.padding(.trailing, 6)
.onChange(of: justifyText) { _ in
updateReaderPreferences()
}
Spacer()
}
.padding(.horizontal, 30)
.listStyle(.plain)
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("Advanced Settings")
}
var themePicker: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 16) {
ForEach(Theme.allCases, id: \.self) { theme in
VStack {
ZStack {
Circle()
.foregroundColor(theme.bgColor)
.frame(minWidth: 32, minHeight: 32)
.padding(8)
}
HStack(spacing: 25) {
ForEach(Theme.allCases.filter { $0 != .system }, id: \.self) { theme in
let isSelected = currentTheme == theme.rawValue
let selectedColor = currentTheme == Theme.apollo.rawValue ? Color.appCtaYellow : Color(hex: "#6A6968")
Text(theme.rawValue).font(.appCaption)
VStack {
Circle()
.strokeBorder(isSelected ? Color(hex: "#6A6968") ?? Color.appGrayBorder : .clear, lineWidth: isSelected ? 2 : 0)
.background(Circle().fill(theme.keyColor))
.frame(width: 32, height: 32)
}
.padding(8)
.background(Color(red: 248 / 255.0, green: 248 / 255.0, blue: 248 / 255.0))
.onTapGesture {
ThemeManager.currentThemeName = theme.rawValue
currentTheme = theme.rawValue
updateReaderPreferences()
}
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(ThemeManager.currentThemeName == theme.rawValue ? Color.appCtaYellow : .clear, lineWidth: 2)
Image("checkmark-small", bundle: .module)
.foregroundColor(isSelected ? selectedColor : .clear)
)
.padding(2)
}
Spacer()
}
}.onChange(of: currentTheme) { _ in
ThemeManager.currentThemeName = currentTheme
isAutoTheme = currentTheme == Theme.system.rawValue
updateReaderPreferences()
}.onAppear {
currentTheme = ThemeManager.currentThemeName
}
}
public var body: some View {
NavigationView {
VStack(alignment: .center) {
// themePicker
// .padding(.bottom, 16)
var fontSizeSlider: some View {
HStack {
Button(action: {
storedFontSize = min(storedFontSize + 2, 28)
}, label: { Image(systemName: "textformat.size.smaller") })
.frame(width: 25, height: 25, alignment: .center)
CustomSlider(value: $storedFontSize, minValue: 10, maxValue: 28) { _ in
if storedFontSize % 2 == 0 {
updateReaderPreferences()
}
}
.padding(.horizontal, 10)
.tint(Color(hex: "#D9D9D9"))
LabelledStepper(
labelText: "Font Size",
onIncrement: {
storedFontSize = min(storedFontSize + 2, 28)
updateReaderPreferences()
},
onDecrement: {
storedFontSize = max(storedFontSize - 2, 10)
updateReaderPreferences()
}
)
Button(action: {
storedFontSize = max(storedFontSize - 2, 10)
}, label: { Image(systemName: "textformat.size.larger") })
.frame(width: 25, height: 25, alignment: .center)
}
}
LabelledStepper(
labelText: "Margin",
onIncrement: {
storedMaxWidthPercentage = max(storedMaxWidthPercentage - 10, 40)
updateReaderPreferences()
},
onDecrement: {
storedMaxWidthPercentage = min(storedMaxWidthPercentage + 10, 100)
updateReaderPreferences()
}
)
var marginSlider: some View {
HStack {
Button(action: {
storedMaxWidthPercentage = min(storedMaxWidthPercentage + 10, 100)
}, label: { Image("margin-smaller", bundle: .module) })
.frame(width: 25, height: 25, alignment: .center)
CustomSlider(value: $storedMaxWidthPercentage, minValue: 40, maxValue: 100) { _ in
updateReaderPreferences()
}
.padding(.horizontal, 10)
.tint(Color(hex: "#D9D9D9"))
LabelledStepper(
labelText: "Line Spacing",
onIncrement: {
storedLineSpacing = min(storedLineSpacing + 25, 300)
updateReaderPreferences()
},
onDecrement: {
storedLineSpacing = max(storedLineSpacing - 25, 100)
updateReaderPreferences()
}
)
Button(action: {
storedMaxWidthPercentage = max(storedMaxWidthPercentage - 10, 40)
}, label: { Image("margin-larger", bundle: .module) })
.frame(width: 25, height: 25, alignment: .center)
}
}
var lineHeightSlider: some View {
HStack {
Button(action: {
storedLineSpacing = min(storedLineSpacing + 25, 300)
}, label: { Image("lineheight-smaller", bundle: .module) })
.frame(width: 25, height: 25, alignment: .center)
CustomSlider(value: $storedLineSpacing, minValue: 100, maxValue: 300) { _ in
updateReaderPreferences()
}
.padding(.horizontal, 10)
.tint(Color(hex: "#D9D9D9"))
Button(action: {
storedLineSpacing = max(storedLineSpacing - 25, 100)
}, label: { Image("lineheight-larger", bundle: .module) })
.frame(width: 25, height: 25, alignment: .center)
}
}
var brightnessSlider: some View {
HStack {
Button(action: {
storedFontSize = min(storedFontSize + 2, 28)
}, label: { Image("brightness-lower", bundle: .module) })
.frame(width: 25, height: 25, alignment: .center)
CustomSlider(value: $storedFontSize, minValue: 10, maxValue: 28) { _ in
updateReaderPreferences()
}
.padding(.horizontal, 10)
Button(action: {
storedFontSize = max(storedFontSize - 2, 10)
}, label: { Image("brightness-higher", bundle: .module) })
.frame(width: 25, height: 25, alignment: .center)
}
}
var preferredFontFont: Font? {
let webFont = WebFont.allCases.first(where: { $0.rawValue == preferredFont })
return webFont?.font(size: 14)
}
var preferredFontDisplayName: String {
let webFont = WebFont.allCases.first(where: { $0.rawValue == preferredFont })
return webFont?.displayValue ?? ""
}
@State var isAutoTheme = true
@State var currentTheme = ThemeManager.currentThemeName
var systemThemeCheckbox: some View {
Toggle(isOn: $isAutoTheme) {
Text("Auto")
.font(Font.system(size: 12))
.foregroundColor(Color(hex: "#999999"))
}
.toggleStyle(CheckboxToggleStyle())
.onChange(of: isAutoTheme, perform: { _ in
if isAutoTheme {
currentTheme = Theme.system.rawValue
} else if currentTheme == Theme.system.rawValue {
// This else if block handles the case where the user toggles off auto
// but not when they click on another theme to toggle off auto
let newTheme = Color.isDarkMode ? Theme.dark : Theme.light
currentTheme = newTheme.rawValue
}
})
.onChange(of: currentTheme, perform: { _ in
isAutoTheme = (currentTheme == Theme.system.rawValue)
})
.onAppear {
isAutoTheme = ThemeManager.currentTheme == .system
}
}
public var controls: some View {
Group {
Group {
HStack(alignment: .center) {
Text(LocalText.genericFont)
.font(Font.system(size: 14, weight: .medium))
.foregroundColor(Color(hex: "#6A6968"))
Spacer()
NavigationLink(destination: fontList) {
Text(preferredFontDisplayName)
.font(preferredFontFont)
.foregroundColor(Color(hex: "#3D3D3D"))
NavigationLink(destination: fontList) {
HStack {
Text(LocalText.genericFont)
Spacer()
Image(systemName: "chevron.right")
.font(Font.system(size: 10))
.foregroundColor(Color(hex: "#A9A9A9"))
}
}
.foregroundColor(.appGrayTextContrast)
.frame(height: 40)
.padding(.top, 10)
.padding(.bottom, 10)
Toggle("High Contrast Text:", isOn: $prefersHighContrastText)
.frame(height: 40)
.padding(.trailing, 6)
.onChange(of: prefersHighContrastText) { _ in
updateReaderPreferences()
fontSizeSlider
}.tint(Color(hex: "#6A6968"))
.padding(.horizontal, 30)
Divider()
.padding(.vertical, 10)
Group {
if UIDevice.isIPad {
Text("Margin")
.font(Font.system(size: 14))
.frame(maxWidth: .infinity, alignment: .leading)
.foregroundColor(Color(hex: "#6A6968"))
marginSlider
.padding(.top, 5)
.padding(.bottom, 10)
}
Text("Line Height")
.font(Font.system(size: 14))
.frame(maxWidth: .infinity, alignment: .leading)
.foregroundColor(Color(hex: "#6A6968"))
lineHeightSlider
// .padding(.bottom, 20)
// Text("Brightness")
// .font(Font.system(size: 14))
// .frame(maxWidth: .infinity, alignment: .leading)
// .foregroundColor(Color(hex: "#6A6968"))
//
// brightnessSlider
}.tint(Color(hex: "#6A6968"))
.padding(.horizontal, 30)
Divider()
.padding(.vertical, 10)
Group {
HStack(alignment: .center) {
Text("Theme")
.font(Font.system(size: 14))
.frame(maxWidth: .infinity, alignment: .leading)
.foregroundColor(Color(hex: "#6A6968"))
Spacer()
systemThemeCheckbox
}
themePicker
}.tint(Color(hex: "#6A6968"))
.padding(.horizontal, 30)
Divider()
.padding(.vertical, 10)
Group {
HStack(alignment: .center) {
Button(action: {
currentTheme = Theme.system.rawValue
storedFontSize = UITraitCollection.current.preferredWebFontSize
storedLineSpacing = 150
storedMaxWidthPercentage = 100
enableHighlightOnRelease = false
preferredFont = WebFont.inter.rawValue
prefersHighContrastText = true
enableHighlightOnRelease = false
}, label: {
Text("Reset")
.font(Font.system(size: 12, weight: .bold))
.foregroundColor(Color(hex: "#3D3D3D"))
})
Spacer()
NavigationLink(destination: advancedSettings) {
Text("Advanced Settings")
.font(Font.system(size: 12))
Image(systemName: "chevron.right")
.font(Font.system(size: 10))
.foregroundColor(Color(hex: "#A9A9A9"))
}
}
.foregroundColor(.appGrayTextContrast)
}
.padding(.horizontal, 30)
}
}
Toggle(LocalText.enableHighlightOnReleaseText, isOn: $enableHighlightOnRelease)
.frame(height: 40)
.padding(.trailing, 6)
.onChange(of: enableHighlightOnRelease) { _ in
updateReaderPreferences()
}
// updateFontSize(20)
// setMarginWidth(290)
// setLineHeight(150)
// setFontFamily(DEFAULT_FONT)
public var body: some View {
NavigationView {
VStack(alignment: .center) {
controls
Spacer()
}
.padding()
.navigationTitle("Reader Preferences")
.navigationBarTitleDisplayMode(.inline)
// .toolbar {
// ToolbarItem(placement: .barTrailing) {
// Button(
// action: dismissAction,
// label: { Text(LocalText.doneGeneric).foregroundColor(.appGrayTextContrast).padding() }
// )
// }
// }
}
// .navigationViewStyle(.stack)
// .accentColor(.appGrayTextContrast)
}
}
@ -322,4 +519,20 @@ public enum WebFont: String, CaseIterable {
}
}
}
struct CheckboxToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
Button(action: {
configuration.isOn.toggle()
}, label: {
HStack {
configuration.label
Image(systemName: configuration.isOn ? "checkmark.square" : "square")
.foregroundColor(Color(hex: "#D9D9D9"))
}
})
.buttonStyle(.plain)
}
}
#endif

View file

@ -14,33 +14,37 @@ import SwiftUI
var onDismiss: (() -> Void)?
var modalSize: CGSize
let useSmallDetent: Bool
let useLargeDetent: Bool
private var hostVC: UIHostingController<Content>?
@available(*, unavailable)
required init?(coder _: NSCoder) { fatalError("") }
init(content: @escaping () -> Content, modalSize: CGSize, useSmallDetent: Bool) {
init(content: @escaping () -> Content, modalSize: CGSize, useSmallDetent: Bool, useLargeDetent: Bool) {
self.content = content
self.modalSize = modalSize
self.useSmallDetent = useSmallDetent
self.useLargeDetent = useLargeDetent
super.init(nibName: nil, bundle: nil)
}
func show() {
guard hostVC == nil else { return }
let controller: UIHostingController<Content> = {
if UIDevice.isIPhone, useSmallDetent {
return FormSheetHostingController(rootView: content(), height: 100)
} else {
return UIHostingController(rootView: content())
}
// if UIDevice.isIPhone, useSmallDetent {
// return FormSheetHostingController(rootView: content(), height: 100)
// } else {
UIHostingController(rootView: content())
// }
}()
controller.preferredContentSize = modalSize
if UIDevice.isIPhone {
if let sheet = controller.sheetPresentationController {
sheet.prefersGrabberVisible = false
sheet.detents = [.medium()]
sheet.detents = [.medium(), .large()]
sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
@ -74,6 +78,7 @@ import SwiftUI
let modalSize: CGSize
let useSmallDetent: Bool
let useLargeDetent: Bool
let content: () -> Content
func makeUIViewController(
@ -82,7 +87,8 @@ import SwiftUI
let controller = FormSheetWrapper(
content: content,
modalSize: modalSize,
useSmallDetent: useSmallDetent
useSmallDetent: useSmallDetent,
useLargeDetent: useLargeDetent
)
controller.onDismiss = { self.show = false }
return controller
@ -105,6 +111,7 @@ import SwiftUI
isPresented: Binding<Bool>,
modalSize: CGSize = CGSize(width: 320, height: 320),
useSmallDetent: Bool = false,
useLargeDetent: Bool = false,
@ViewBuilder content: @escaping () -> Content
) -> some View {
background(
@ -112,6 +119,7 @@ import SwiftUI
show: isPresented,
modalSize: modalSize,
useSmallDetent: useSmallDetent,
useLargeDetent: useLargeDetent,
content: content
)
)

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "brightness-higher.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,265 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 5.941650 4.441528 cm
0.415686 0.411765 0.407843 scn
9.735207 6.742626 m
9.735207 4.261430 7.723800 2.250023 5.242603 2.250023 c
5.242603 0.750023 l
8.552227 0.750023 11.235207 3.433002 11.235207 6.742626 c
9.735207 6.742626 l
h
5.242603 2.250023 m
2.761407 2.250023 0.750000 4.261430 0.750000 6.742626 c
-0.750000 6.742626 l
-0.750000 3.433002 1.932980 0.750023 5.242603 0.750023 c
5.242603 2.250023 l
h
0.750000 6.742626 m
0.750000 9.223823 2.761407 11.235229 5.242603 11.235229 c
5.242603 12.735229 l
1.932980 12.735229 -0.750000 10.052250 -0.750000 6.742626 c
0.750000 6.742626 l
h
5.242603 11.235229 m
7.723800 11.235229 9.735207 9.223823 9.735207 6.742626 c
11.235207 6.742626 l
11.235207 10.052250 8.552227 12.735229 5.242603 12.735229 c
5.242603 11.235229 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 11.184082 17.722900 cm
0.415686 0.411765 0.407843 scn
-0.750000 1.500024 m
-0.750000 1.085811 -0.414214 0.750024 0.000000 0.750024 c
0.414214 0.750024 0.750000 1.085811 0.750000 1.500024 c
-0.750000 1.500024 l
h
0.750000 3.247559 m
0.750000 3.661772 0.414214 3.997559 0.000000 3.997559 c
-0.414214 3.997559 -0.750000 3.661772 -0.750000 3.247559 c
0.750000 3.247559 l
h
0.750000 1.500024 m
0.750000 3.247559 l
-0.750000 3.247559 l
-0.750000 1.500024 l
0.750000 1.500024 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 4.264160 15.226074 cm
0.415686 0.411765 0.407843 scn
0.701682 1.116076 m
0.994575 0.823183 1.469449 0.823183 1.762342 1.116076 c
2.055235 1.408969 2.055235 1.883843 1.762342 2.176736 c
0.701682 1.116076 l
h
0.530330 3.408748 m
0.237437 3.701641 -0.237437 3.701641 -0.530330 3.408748 c
-0.823223 3.115855 -0.823223 2.640981 -0.530330 2.348088 c
0.530330 3.408748 l
h
1.762342 2.176736 m
0.530330 3.408748 l
-0.530330 2.348088 l
0.701682 1.116076 l
1.762342 2.176736 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 1.397949 9.684082 cm
0.415686 0.411765 0.407843 scn
1.747534 0.750000 m
2.161748 0.750000 2.497534 1.085786 2.497534 1.500000 c
2.497534 1.914214 2.161748 2.250000 1.747534 2.250000 c
1.747534 0.750000 l
h
0.000000 2.250000 m
-0.414214 2.250000 -0.750000 1.914214 -0.750000 1.500000 c
-0.750000 1.085786 -0.414214 0.750000 0.000000 0.750000 c
0.000000 2.250000 l
h
1.747534 2.250000 m
0.000000 2.250000 l
0.000000 0.750000 l
1.747534 0.750000 l
1.747534 2.250000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 4.264160 2.617432 cm
0.415686 0.411765 0.407843 scn
1.762342 2.348088 m
2.055235 2.640981 2.055235 3.115855 1.762342 3.408748 c
1.469449 3.701641 0.994575 3.701641 0.701682 3.408748 c
1.762342 2.348088 l
h
-0.530330 2.176737 m
-0.823223 1.883844 -0.823223 1.408970 -0.530330 1.116077 c
-0.237437 0.823184 0.237437 0.823184 0.530330 1.116077 c
-0.530330 2.176737 l
h
0.701682 3.408748 m
-0.530330 2.176737 l
0.530330 1.116077 l
1.762342 2.348088 l
0.701682 3.408748 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 11.184082 -0.102051 cm
0.415686 0.411765 0.407843 scn
0.750000 3.247559 m
0.750000 3.661772 0.414214 3.997559 0.000000 3.997559 c
-0.414214 3.997559 -0.750000 3.661772 -0.750000 3.247559 c
0.750000 3.247559 l
h
-0.750000 1.500024 m
-0.750000 1.085811 -0.414214 0.750024 0.000000 0.750024 c
0.414214 0.750024 0.750000 1.085811 0.750000 1.500024 c
-0.750000 1.500024 l
h
-0.750000 3.247559 m
-0.750000 1.500024 l
0.750000 1.500024 l
0.750000 3.247559 l
-0.750000 3.247559 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 16.872559 2.617432 cm
0.415686 0.411765 0.407843 scn
0.530330 3.408748 m
0.237437 3.701641 -0.237437 3.701641 -0.530330 3.408748 c
-0.823223 3.115855 -0.823223 2.640981 -0.530330 2.348088 c
0.530330 3.408748 l
h
0.701681 1.116077 m
0.994574 0.823184 1.469448 0.823184 1.762341 1.116077 c
2.055234 1.408970 2.055234 1.883844 1.762341 2.176737 c
0.701681 1.116077 l
h
-0.530330 2.348088 m
0.701681 1.116077 l
1.762341 2.176737 l
0.530330 3.408748 l
-0.530330 2.348088 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 19.222900 9.684082 cm
0.415686 0.411765 0.407843 scn
0.000000 2.250000 m
-0.414214 2.250000 -0.750000 1.914214 -0.750000 1.500000 c
-0.750000 1.085786 -0.414214 0.750000 0.000000 0.750000 c
0.000000 2.250000 l
h
1.747534 0.750000 m
2.161748 0.750000 2.497534 1.085786 2.497534 1.500000 c
2.497534 1.914214 2.161748 2.250000 1.747534 2.250000 c
1.747534 0.750000 l
h
0.000000 0.750000 m
1.747534 0.750000 l
1.747534 2.250000 l
0.000000 2.250000 l
0.000000 0.750000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 16.872559 15.226074 cm
0.415686 0.411765 0.407843 scn
-0.530330 2.176736 m
-0.823223 1.883843 -0.823223 1.408969 -0.530330 1.116076 c
-0.237437 0.823183 0.237437 0.823183 0.530330 1.116076 c
-0.530330 2.176736 l
h
1.762341 2.348088 m
2.055234 2.640981 2.055234 3.115855 1.762341 3.408748 c
1.469447 3.701641 0.994574 3.701641 0.701681 3.408748 c
1.762341 2.348088 l
h
0.530330 1.116076 m
1.762341 2.348088 l
0.701681 3.408748 l
-0.530330 2.176736 l
0.530330 1.116076 l
h
f
n
Q
endstream
endobj
3 0 obj
4961
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 22.368408 22.368408 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000005051 00000 n
0000005074 00000 n
0000005247 00000 n
0000005321 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
5380
%%EOF

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "brightness-lower.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,265 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 5.942139 4.442017 cm
0.415686 0.411765 0.407843 scn
9.735938 6.742993 m
9.735938 4.261595 7.724367 2.250024 5.242969 2.250024 c
5.242969 0.750024 l
8.552794 0.750024 11.235938 3.433167 11.235938 6.742993 c
9.735938 6.742993 l
h
5.242969 2.250024 m
2.761571 2.250024 0.750000 4.261595 0.750000 6.742993 c
-0.750000 6.742993 l
-0.750000 3.433167 1.933144 0.750024 5.242969 0.750024 c
5.242969 2.250024 l
h
0.750000 6.742993 m
0.750000 9.224391 2.761571 11.235962 5.242969 11.235962 c
5.242969 12.735962 l
1.933144 12.735962 -0.750000 10.052818 -0.750000 6.742993 c
0.750000 6.742993 l
h
5.242969 11.235962 m
7.724367 11.235962 9.735938 9.224391 9.735938 6.742993 c
11.235938 6.742993 l
11.235938 10.052818 8.552794 12.735962 5.242969 12.735962 c
5.242969 11.235962 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 11.185059 17.724243 cm
0.415686 0.411765 0.407843 scn
-0.750000 1.500034 m
-0.750000 1.085821 -0.414214 0.750034 0.000000 0.750034 c
0.414214 0.750034 0.750000 1.085821 0.750000 1.500034 c
-0.750000 1.500034 l
h
0.750000 2.199097 m
0.750000 2.613310 0.414214 2.949097 0.000000 2.949097 c
-0.414214 2.949097 -0.750000 2.613310 -0.750000 2.199097 c
0.750000 2.199097 l
h
0.750000 1.500034 m
0.750000 2.199097 l
-0.750000 2.199097 l
-0.750000 1.500034 l
0.750000 1.500034 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 5.007080 15.227173 cm
0.415686 0.411765 0.407843 scn
-0.040986 1.116190 m
0.251907 0.823297 0.726781 0.823297 1.019674 1.116190 c
1.312567 1.409083 1.312567 1.883957 1.019674 2.176850 c
-0.040986 1.116190 l
h
0.530330 2.666194 m
0.237437 2.959088 -0.237437 2.959088 -0.530330 2.666194 c
-0.823223 2.373301 -0.823223 1.898427 -0.530330 1.605534 c
0.530330 2.666194 l
h
1.019674 2.176850 m
0.530330 2.666194 l
-0.530330 1.605534 l
-0.040986 1.116190 l
1.019674 2.176850 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 2.446777 9.684937 cm
0.415686 0.411765 0.407843 scn
0.699063 0.750000 m
1.113276 0.750000 1.449063 1.085786 1.449063 1.500000 c
1.449063 1.914214 1.113276 2.250000 0.699063 2.250000 c
0.699063 0.750000 l
h
0.000000 2.250000 m
-0.414214 2.250000 -0.750000 1.914214 -0.750000 1.500000 c
-0.750000 1.085786 -0.414214 0.750000 0.000000 0.750000 c
0.000000 2.250000 l
h
0.699063 2.250000 m
0.000000 2.250000 l
0.000000 0.750000 l
0.699063 0.750000 l
0.699063 2.250000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 5.007080 3.360352 cm
0.415686 0.411765 0.407843 scn
1.019673 1.605534 m
1.312567 1.898427 1.312567 2.373300 1.019675 2.666194 c
0.726782 2.959087 0.251908 2.959088 -0.040986 2.666195 c
1.019673 1.605534 l
h
-0.530330 2.176852 m
-0.823223 1.883959 -0.823224 1.409085 -0.530331 1.116192 c
-0.237438 0.823298 0.237436 0.823298 0.530330 1.116191 c
-0.530330 2.176852 l
h
-0.040986 2.666195 m
-0.530330 2.176852 l
0.530330 1.116191 l
1.019673 1.605534 l
-0.040986 2.666195 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 11.185059 0.946655 cm
0.415686 0.411765 0.407843 scn
0.750000 2.199097 m
0.750000 2.613310 0.414214 2.949097 0.000000 2.949097 c
-0.414214 2.949097 -0.750000 2.613310 -0.750000 2.199097 c
0.750000 2.199097 l
h
-0.750000 1.500034 m
-0.750000 1.085821 -0.414214 0.750034 0.000000 0.750034 c
0.414214 0.750034 0.750000 1.085821 0.750000 1.500034 c
-0.750000 1.500034 l
h
-0.750000 2.199097 m
-0.750000 1.500034 l
0.750000 1.500034 l
0.750000 2.199097 l
-0.750000 2.199097 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 16.873535 3.360352 cm
0.415686 0.411765 0.407843 scn
0.530330 2.666194 m
0.237437 2.959088 -0.237437 2.959088 -0.530330 2.666194 c
-0.823223 2.373301 -0.823223 1.898427 -0.530330 1.605534 c
0.530330 2.666194 l
h
-0.040987 1.116191 m
0.251906 0.823298 0.726780 0.823298 1.019673 1.116191 c
1.312566 1.409084 1.312566 1.883958 1.019673 2.176852 c
-0.040987 1.116191 l
h
-0.530330 1.605534 m
-0.040987 1.116191 l
1.019673 2.176852 l
0.530330 2.666194 l
-0.530330 1.605534 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 19.224365 9.684937 cm
0.415686 0.411765 0.407843 scn
0.000000 2.250000 m
-0.414214 2.250000 -0.750000 1.914214 -0.750000 1.500000 c
-0.750000 1.085786 -0.414214 0.750000 0.000000 0.750000 c
0.000000 2.250000 l
h
0.699063 0.750000 m
1.113276 0.750000 1.449063 1.085786 1.449063 1.500000 c
1.449063 1.914214 1.113276 2.250000 0.699063 2.250000 c
0.699063 0.750000 l
h
0.000000 0.750000 m
0.699063 0.750000 l
0.699063 2.250000 l
0.000000 2.250000 l
0.000000 0.750000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 16.873535 15.227173 cm
0.415686 0.411765 0.407843 scn
-0.530331 2.176850 m
-0.823224 1.883956 -0.823223 1.409083 -0.530330 1.116190 c
-0.237436 0.823297 0.237438 0.823297 0.530331 1.116191 c
-0.530331 2.176850 l
h
1.019674 1.605535 m
1.312567 1.898428 1.312566 2.373302 1.019673 2.666195 c
0.726779 2.959088 0.251905 2.959087 -0.040988 2.666194 c
1.019674 1.605535 l
h
0.530331 1.116191 m
1.019674 1.605535 l
-0.040988 2.666194 l
-0.530331 2.176850 l
0.530331 1.116191 l
h
f
n
Q
endstream
endobj
3 0 obj
4971
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 22.370117 22.369995 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000005061 00000 n
0000005084 00000 n
0000005257 00000 n
0000005331 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
5390
%%EOF

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "checkmark-small.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,92 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 1.000000 -1.197144 cm
0.415686 0.411765 0.407843 scn
10.833967 7.865867 m
11.235292 8.245284 11.253052 8.878201 10.873634 9.279525 c
10.494218 9.680849 9.861301 9.698608 9.459977 9.319191 c
10.833967 7.865867 l
h
3.382324 2.197147 m
2.695345 1.470470 l
3.080841 1.106034 3.683832 1.106040 4.069319 1.470485 c
3.382324 2.197147 l
h
0.686979 6.121372 m
0.285646 6.500780 -0.347269 6.483007 -0.726677 6.081674 c
-1.106085 5.680341 -1.088312 5.047426 -0.686979 4.668018 c
0.686979 6.121372 l
h
9.459977 9.319191 m
2.695329 2.923809 l
4.069319 1.470485 l
10.833967 7.865867 l
9.459977 9.319191 l
h
4.069303 2.923824 m
0.686979 6.121372 l
-0.686979 4.668018 l
2.695345 1.470470 l
4.069303 2.923824 l
h
f
n
Q
endstream
endobj
3 0 obj
769
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 12.146973 8.395386 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000000859 00000 n
0000000881 00000 n
0000001053 00000 n
0000001127 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
1186
%%EOF

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "lineheight-larger.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,213 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 9.621338 9.957031 cm
0.415686 0.411765 0.407843 scn
0.000000 2.099902 m
-0.386599 2.099902 -0.700000 1.786502 -0.700000 1.399902 c
-0.700000 1.013303 -0.386599 0.699902 0.000000 0.699902 c
0.000000 2.099902 l
h
11.546720 0.699902 m
11.933319 0.699902 12.246720 1.013303 12.246720 1.399902 c
12.246720 1.786502 11.933319 2.099902 11.546720 2.099902 c
11.546720 0.699902 l
h
0.000000 0.699902 m
11.546720 0.699902 l
11.546720 2.099902 l
0.000000 2.099902 l
0.000000 0.699902 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 9.621338 5.073242 cm
0.415686 0.411765 0.407843 scn
0.000000 2.099902 m
-0.386599 2.099902 -0.700000 1.786502 -0.700000 1.399902 c
-0.700000 1.013303 -0.386599 0.699902 0.000000 0.699902 c
0.000000 2.099902 l
h
11.546720 0.699902 m
11.933319 0.699902 12.246720 1.013303 12.246720 1.399902 c
12.246720 1.786502 11.933319 2.099902 11.546720 2.099902 c
11.546720 0.699902 l
h
0.000000 0.699902 m
11.546720 0.699902 l
11.546720 2.099902 l
0.000000 2.099902 l
0.000000 0.699902 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 9.621338 0.189819 cm
0.415686 0.411765 0.407843 scn
0.000000 2.099902 m
-0.386599 2.099902 -0.700000 1.786502 -0.700000 1.399902 c
-0.700000 1.013303 -0.386599 0.699902 0.000000 0.699902 c
0.000000 2.099902 l
h
11.546720 0.699902 m
11.933319 0.699902 12.246720 1.013303 12.246720 1.399902 c
12.246720 1.786502 11.933319 2.099902 11.546720 2.099902 c
11.546720 0.699902 l
h
0.000000 0.699902 m
11.546720 0.699902 l
11.546720 2.099902 l
0.000000 2.099902 l
0.000000 0.699902 l
h
f
n
Q
q
-0.000000 -1.000000 1.000000 -0.000000 1.470093 12.246704 cm
0.415686 0.411765 0.407843 scn
2.086170 2.641449 m
2.327677 2.943332 2.278732 3.383837 1.976849 3.625344 c
1.674965 3.866850 1.234461 3.817905 0.992954 3.516022 c
2.086170 2.641449 l
h
0.000000 1.154282 m
-0.546608 1.591569 l
-0.751131 1.335916 -0.751131 0.972649 -0.546608 0.716996 c
0.000000 1.154282 l
h
0.992954 -1.207458 m
1.234461 -1.509341 1.674965 -1.558286 1.976849 -1.316779 c
2.278732 -1.075273 2.327677 -0.634768 2.086170 -0.332885 c
0.992954 -1.207458 l
h
0.992954 3.516022 m
-0.546608 1.591569 l
0.546608 0.716996 l
2.086170 2.641449 l
0.992954 3.516022 l
h
-0.546608 0.716996 m
0.992954 -1.207458 l
2.086170 -0.332885 l
0.546608 1.591569 l
-0.546608 0.716996 l
h
f
n
Q
q
-0.000000 -1.000000 1.000000 -0.000000 1.470093 2.239502 cm
0.415686 0.411765 0.407843 scn
0.546608 3.516022 m
0.305102 3.817905 -0.135403 3.866850 -0.437286 3.625344 c
-0.739170 3.383837 -0.788115 2.943332 -0.546608 2.641449 c
0.546608 3.516022 l
h
1.539562 1.154282 m
2.086170 0.716996 l
2.290693 0.972649 2.290693 1.335916 2.086170 1.591569 c
1.539562 1.154282 l
h
-0.546608 -0.332885 m
-0.788115 -0.634768 -0.739170 -1.075273 -0.437286 -1.316779 c
-0.135403 -1.558286 0.305102 -1.509341 0.546608 -1.207458 c
-0.546608 -0.332885 l
h
-0.546608 2.641449 m
0.992954 0.716996 l
2.086170 1.591569 l
0.546608 3.516022 l
-0.546608 2.641449 l
h
0.992954 1.591569 m
-0.546608 -0.332885 l
0.546608 -1.207458 l
2.086170 0.716996 l
0.992954 1.591569 l
h
f
n
Q
q
-0.000000 -1.000000 1.000000 -0.000000 -10.322144 12.246705 cm
0.415686 0.411765 0.407843 scn
0.000000 13.646655 m
-0.386599 13.646655 -0.700000 13.333255 -0.700000 12.946655 c
-0.700000 12.560056 -0.386599 12.246655 0.000000 12.246655 c
0.000000 13.646655 l
h
11.546720 12.246655 m
11.933319 12.246655 12.246720 12.560056 12.246720 12.946655 c
12.246720 13.333255 11.933319 13.646655 11.546720 13.646655 c
11.546720 12.246655 l
h
0.000000 12.246655 m
11.546720 12.246655 l
11.546720 13.646655 l
0.000000 13.646655 l
0.000000 12.246655 l
h
f
n
Q
endstream
endobj
3 0 obj
3642
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 21.868164 12.946655 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000003732 00000 n
0000003755 00000 n
0000003928 00000 n
0000004002 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
4061
%%EOF

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "lineheight-smaller.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,213 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 9.621338 7.957153 cm
0.415686 0.411765 0.407843 scn
0.000000 2.099902 m
-0.386599 2.099902 -0.700000 1.786502 -0.700000 1.399902 c
-0.700000 1.013303 -0.386599 0.699902 0.000000 0.699902 c
0.000000 2.099902 l
h
11.546720 0.699902 m
11.933319 0.699902 12.246720 1.013303 12.246720 1.399902 c
12.246720 1.786502 11.933319 2.099902 11.546720 2.099902 c
11.546720 0.699902 l
h
0.000000 0.699902 m
11.546720 0.699902 l
11.546720 2.099902 l
0.000000 2.099902 l
0.000000 0.699902 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 9.621338 5.073364 cm
0.415686 0.411765 0.407843 scn
0.000000 2.099902 m
-0.386599 2.099902 -0.700000 1.786502 -0.700000 1.399902 c
-0.700000 1.013303 -0.386599 0.699902 0.000000 0.699902 c
0.000000 2.099902 l
h
11.546720 0.699902 m
11.933319 0.699902 12.246720 1.013303 12.246720 1.399902 c
12.246720 1.786502 11.933319 2.099902 11.546720 2.099902 c
11.546720 0.699902 l
h
0.000000 0.699902 m
11.546720 0.699902 l
11.546720 2.099902 l
0.000000 2.099902 l
0.000000 0.699902 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 9.621338 2.189819 cm
0.415686 0.411765 0.407843 scn
0.000000 2.099902 m
-0.386599 2.099902 -0.700000 1.786502 -0.700000 1.399902 c
-0.700000 1.013303 -0.386599 0.699902 0.000000 0.699902 c
0.000000 2.099902 l
h
11.546720 0.699902 m
11.933319 0.699902 12.246720 1.013303 12.246720 1.399902 c
12.246720 1.786502 11.933319 2.099902 11.546720 2.099902 c
11.546720 0.699902 l
h
0.000000 0.699902 m
11.546720 0.699902 l
11.546720 2.099902 l
0.000000 2.099902 l
0.000000 0.699902 l
h
f
n
Q
q
-0.000000 -1.000000 1.000000 -0.000000 1.470093 12.246704 cm
0.415686 0.411765 0.407843 scn
2.086170 2.641449 m
2.327677 2.943332 2.278732 3.383837 1.976849 3.625344 c
1.674965 3.866850 1.234461 3.817905 0.992954 3.516022 c
2.086170 2.641449 l
h
0.000000 1.154282 m
-0.546608 1.591569 l
-0.751131 1.335916 -0.751131 0.972649 -0.546608 0.716996 c
0.000000 1.154282 l
h
0.992954 -1.207458 m
1.234461 -1.509341 1.674965 -1.558286 1.976849 -1.316779 c
2.278732 -1.075273 2.327677 -0.634768 2.086170 -0.332885 c
0.992954 -1.207458 l
h
0.992954 3.516022 m
-0.546608 1.591569 l
0.546608 0.716996 l
2.086170 2.641449 l
0.992954 3.516022 l
h
-0.546608 0.716996 m
0.992954 -1.207458 l
2.086170 -0.332885 l
0.546608 1.591569 l
-0.546608 0.716996 l
h
f
n
Q
q
-0.000000 -1.000000 1.000000 -0.000000 1.470093 2.239624 cm
0.415686 0.411765 0.407843 scn
0.546608 3.516022 m
0.305102 3.817905 -0.135403 3.866850 -0.437286 3.625344 c
-0.739170 3.383837 -0.788115 2.943332 -0.546608 2.641449 c
0.546608 3.516022 l
h
1.539562 1.154282 m
2.086170 0.716996 l
2.290693 0.972649 2.290693 1.335916 2.086170 1.591569 c
1.539562 1.154282 l
h
-0.546608 -0.332885 m
-0.788115 -0.634768 -0.739170 -1.075273 -0.437286 -1.316779 c
-0.135403 -1.558286 0.305102 -1.509341 0.546608 -1.207458 c
-0.546608 -0.332885 l
h
-0.546608 2.641449 m
0.992954 0.716996 l
2.086170 1.591569 l
0.546608 3.516022 l
-0.546608 2.641449 l
h
0.992954 1.591569 m
-0.546608 -0.332885 l
0.546608 -1.207458 l
2.086170 0.716996 l
0.992954 1.591569 l
h
f
n
Q
q
-0.000000 -1.000000 1.000000 -0.000000 -10.322144 12.246705 cm
0.415686 0.411765 0.407843 scn
0.000000 13.646655 m
-0.386599 13.646655 -0.700000 13.333255 -0.700000 12.946655 c
-0.700000 12.560056 -0.386599 12.246655 0.000000 12.246655 c
0.000000 13.646655 l
h
11.546720 12.246655 m
11.933319 12.246655 12.246720 12.560056 12.246720 12.946655 c
12.246720 13.333255 11.933319 13.646655 11.546720 13.646655 c
11.546720 12.246655 l
h
0.000000 12.246655 m
11.546720 12.246655 l
11.546720 13.646655 l
0.000000 13.646655 l
0.000000 12.246655 l
h
f
n
Q
endstream
endobj
3 0 obj
3642
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 21.868164 12.946655 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000003732 00000 n
0000003755 00000 n
0000003928 00000 n
0000004002 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
4061
%%EOF

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "margin-wider.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,191 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 12.500000 2.447754 cm
0.415686 0.411765 0.407843 scn
0.750000 18.605225 m
0.750000 19.019438 0.414214 19.355225 0.000000 19.355225 c
-0.414214 19.355225 -0.750000 19.019438 -0.750000 18.605225 c
0.750000 18.605225 l
h
-0.750000 1.499958 m
-0.750000 1.085745 -0.414214 0.749958 0.000000 0.749958 c
0.414214 0.749958 0.750000 1.085745 0.750000 1.499958 c
-0.750000 1.499958 l
h
-0.750000 18.605225 m
-0.750000 1.499958 l
0.750000 1.499958 l
0.750000 18.605225 l
-0.750000 18.605225 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 1.315674 11.000000 cm
0.415686 0.411765 0.407843 scn
0.000000 2.250000 m
-0.414214 2.250000 -0.750000 1.914214 -0.750000 1.500000 c
-0.750000 1.085786 -0.414214 0.750000 0.000000 0.750000 c
0.000000 2.250000 l
h
7.894738 0.750000 m
8.308951 0.750000 8.644737 1.085786 8.644737 1.500000 c
8.644737 1.914214 8.308951 2.250000 7.894738 2.250000 c
7.894738 0.750000 l
h
0.000000 0.750000 m
7.894738 0.750000 l
7.894738 2.250000 l
0.000000 2.250000 l
0.000000 0.750000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 5.921143 7.563843 cm
0.415686 0.411765 0.407843 scn
0.530330 8.755794 m
0.237437 9.048687 -0.237437 9.048687 -0.530330 8.755794 c
-0.823223 8.462901 -0.823223 7.988027 -0.530330 7.695134 c
0.530330 8.755794 l
h
3.289474 4.935990 m
3.819804 4.405660 l
4.112697 4.698553 4.112697 5.173427 3.819804 5.466320 c
3.289474 4.935990 l
h
-0.530330 2.176847 m
-0.823223 1.883953 -0.823223 1.409080 -0.530330 1.116186 c
-0.237437 0.823293 0.237437 0.823293 0.530330 1.116186 c
-0.530330 2.176847 l
h
-0.530330 7.695134 m
2.759144 4.405660 l
3.819804 5.466320 l
0.530330 8.755794 l
-0.530330 7.695134 l
h
2.759144 5.466320 m
-0.530330 2.176847 l
0.530330 1.116186 l
3.819804 4.405660 l
2.759144 5.466320 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 15.789551 11.000000 cm
0.415686 0.411765 0.407843 scn
7.894738 0.750000 m
8.308951 0.750000 8.644737 1.085786 8.644737 1.500000 c
8.644737 1.914214 8.308951 2.250000 7.894738 2.250000 c
7.894738 0.750000 l
h
0.000000 2.250000 m
-0.414214 2.250000 -0.750000 1.914214 -0.750000 1.500000 c
-0.750000 1.085786 -0.414214 0.750000 0.000000 0.750000 c
0.000000 2.250000 l
h
7.894738 2.250000 m
0.000000 2.250000 l
0.000000 0.750000 l
7.894738 0.750000 l
7.894738 2.250000 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 15.789551 7.521606 cm
0.415686 0.411765 0.407843 scn
2.045927 1.220232 m
2.304684 0.896785 2.776654 0.844344 3.100100 1.103101 c
3.423546 1.361858 3.475987 1.833827 3.217230 2.157274 c
2.045927 1.220232 l
h
0.000000 4.978227 m
-0.585652 5.446748 l
-0.804783 5.172833 -0.804783 4.783619 -0.585652 4.509705 c
0.000000 4.978227 l
h
3.217230 7.799179 m
3.475987 8.122625 3.423546 8.594595 3.100100 8.853352 c
2.776654 9.112109 2.304684 9.059668 2.045927 8.736221 c
3.217230 7.799179 l
h
3.217230 2.157274 m
0.585652 5.446748 l
-0.585652 4.509705 l
2.045927 1.220232 l
3.217230 2.157274 l
h
0.585652 4.509705 m
3.217230 7.799179 l
2.045927 8.736221 l
-0.585652 5.446748 l
0.585652 4.509705 l
h
f
n
Q
endstream
endobj
3 0 obj
3059
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 25.000000 25.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000003149 00000 n
0000003172 00000 n
0000003345 00000 n
0000003419 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
3478
%%EOF

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "margin-smaller.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,147 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 2.631592 7.521851 cm
0.415686 0.411765 0.407843 scn
3.217231 7.799179 m
3.475988 8.122625 3.423547 8.594595 3.100100 8.853352 c
2.776654 9.112109 2.304684 9.059668 2.045927 8.736221 c
3.217231 7.799179 l
h
0.000000 4.978227 m
-0.585652 5.446748 l
-0.804783 5.172833 -0.804783 4.783619 -0.585652 4.509705 c
0.000000 4.978227 l
h
2.045927 1.220232 m
2.304684 0.896785 2.776654 0.844344 3.100100 1.103101 c
3.423547 1.361858 3.475988 1.833827 3.217231 2.157274 c
2.045927 1.220232 l
h
2.045927 8.736221 m
-0.585652 5.446748 l
0.585652 4.509705 l
3.217231 7.799179 l
2.045927 8.736221 l
h
-0.585652 4.509705 m
2.045927 1.220232 l
3.217231 2.157274 l
0.585652 5.446748 l
-0.585652 4.509705 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 19.736816 7.521851 cm
0.415686 0.411765 0.407843 scn
0.585652 8.736221 m
0.326894 9.059668 -0.145075 9.112109 -0.468521 8.853352 c
-0.791968 8.594595 -0.844409 8.122625 -0.585652 7.799179 c
0.585652 8.736221 l
h
2.631579 4.978227 m
3.217231 4.509705 l
3.436362 4.783619 3.436362 5.172833 3.217231 5.446748 c
2.631579 4.978227 l
h
-0.585652 2.157274 m
-0.844409 1.833827 -0.791968 1.361858 -0.468521 1.103101 c
-0.145075 0.844344 0.326894 0.896785 0.585652 1.220232 c
-0.585652 2.157274 l
h
-0.585652 7.799179 m
2.045927 4.509705 l
3.217231 5.446748 l
0.585652 8.736221 l
-0.585652 7.799179 l
h
2.045927 5.446748 m
-0.585652 2.157274 l
0.585652 1.220232 l
3.217231 4.509705 l
2.045927 5.446748 l
h
f
n
Q
q
1.000000 0.000000 -0.000000 1.000000 2.631592 11.000000 cm
0.415686 0.411765 0.407843 scn
0.000000 2.250000 m
-0.414214 2.250000 -0.750000 1.914214 -0.750000 1.500000 c
-0.750000 1.085786 -0.414214 0.750000 0.000000 0.750000 c
0.000000 2.250000 l
h
19.736843 0.750000 m
20.151058 0.750000 20.486843 1.085786 20.486843 1.500000 c
20.486843 1.914214 20.151058 2.250000 19.736843 2.250000 c
19.736843 0.750000 l
h
0.000000 0.750000 m
19.736843 0.750000 l
19.736843 2.250000 l
0.000000 2.250000 l
0.000000 0.750000 l
h
f
n
Q
endstream
endobj
3 0 obj
2027
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 25.000000 25.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002117 00000 n
0000002140 00000 n
0000002313 00000 n
0000002387 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2446
%%EOF

View file

@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "notebook.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#000000" viewBox="0 0 256 256"><path d="M184,112a8,8,0,0,1-8,8H112a8,8,0,0,1,0-16h64A8,8,0,0,1,184,112Zm-8,24H112a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16Zm48-88V208a16,16,0,0,1-16,16H48a16,16,0,0,1-16-16V48A16,16,0,0,1,48,32H208A16,16,0,0,1,224,48ZM48,208H72V48H48Zm160,0V48H88V208H208Z"></path></svg>

After

Width:  |  Height:  |  Size: 363 B

File diff suppressed because one or more lines are too long

View file

@ -13,7 +13,7 @@
// Highlights List Card
"highlightCardHighlightByOther" = "Highlight by ";
"highlightCardNoHighlightsOnPage" = "You have not added any highlights or notes to this page.";
"highlightCardNoHighlightsOnPage" = "You have not added any highlights to this page.";
// Labels View
"labelsViewAssignNameColor" = "Assign a name and color.";

View file

@ -1,5 +1,5 @@
//
// File.swift
// Theme.swift
//
//
// Created by Jackson Harper on 10/27/22.
@ -11,31 +11,56 @@ import Utils
public enum Theme: String, CaseIterable {
case system = "System"
case sepia = "Sepia"
case charcoal = "Charcoal"
case mint = "Mint"
case solarized = "Solarized"
case light = "Light"
case dark = "Dark"
case sepia = "Sepia"
case apollo = "Apollo"
case dark = "Black"
public var bgColor: Color {
switch self {
case .system:
return Color.systemBackground
case .charcoal:
return Color(red: 48 / 255.0, green: 48 / 255.0, blue: 48 / 255.0)
case .sepia:
return Color(red: 249 / 255.0, green: 241 / 255.0, blue: 220 / 255.0)
case .mint:
return Color(red: 202 / 255.0, green: 230 / 255.0, blue: 208 / 255.0)
case .solarized:
return Color(red: 13 / 255.0, green: 39 / 255.0, blue: 50 / 255.0)
return Color.isDarkMode ? .systemBackground : .white
case .light:
return Color.white
return .white
case .dark:
return Color.black
case .sepia:
return Color(hex: "#FBF0D9") ?? Color.white
case .apollo:
return Color(hex: "#6A6968") ?? Color.black
}
}
public var keyColor: Color {
switch self {
case .light:
return Color(hex: "#F5F5F5") ?? .white
case .dark:
return Color(hex: "#3B3938") ?? .black
default:
return bgColor
}
}
public var themeKey: String {
switch self {
case .dark:
return "Black"
case .light, .sepia, .apollo:
return rawValue
case .system:
return Color.isDarkMode ? "Black" : "Light"
}
}
public var isDark: Bool {
switch self {
case .system:
return Color.isDarkMode
case .sepia, .light:
return false
case .dark, .apollo:
return true
}
}
@ -46,4 +71,12 @@ public enum Theme: String, CaseIterable {
public enum ThemeManager {
@AppStorage(UserDefaultKey.themeName.rawValue) public static var currentThemeName = "System"
public static var currentTheme: Theme {
Theme(rawValue: currentThemeName) ?? .system
}
public static var currentBgColor: Color {
currentTheme.bgColor
}
}

View file

@ -67,6 +67,7 @@ const App = () => {
alignment="center"
distribution="center"
className="disable-webkit-callout"
style={{ backgroundColor: 'var(--colors-readerBg)' }}
>
<ArticleContainer
article={window.omnivoreArticle}
@ -80,6 +81,7 @@ const App = () => {
lineHeight={window.lineHeight}
highlightOnRelease={window.highlightOnRelease}
highContrastText={window.prefersHighContrastFont ?? true}
justifyText={window.justifyText}
articleMutations={{
createHighlightMutation: (input) =>
mutation('createHighlight', input),

View file

@ -124,9 +124,10 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
useState<number | null>(null)
const [fontFamilyOverride, setFontFamilyOverride] =
useState<string | null>(null)
const [highContrastText, setHighContrastText] = useState(
props.highContrastText ?? false
)
const [highContrastTextOverride, setHighContrastTextOverride] =
useState<boolean | undefined>(undefined)
const [justifyTextOverride, setJustifyTextOverride] =
useState<boolean | undefined>(undefined)
const highlightHref = useRef(
window.location.hash ? window.location.hash.split('#')[1] : null
)
@ -194,7 +195,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
const handleFontContrastChange = async (event: UpdateFontContrastEvent) => {
const highContrast = event.fontContrast == 'high'
setHighContrastText(highContrast)
setHighContrastTextOverride(highContrast)
}
interface UpdateFontSizeEvent extends Event {
@ -228,6 +229,14 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
updateThemeLocally(isDark === 'true' ? ThemeId.Dark : ThemeId.Light)
}
interface UpdateJustifyText extends Event {
justifyText?: boolean
}
const updateJustifyText = (event: UpdateJustifyText) => {
setJustifyTextOverride(event.justifyText ?? false)
}
interface UpdateLabelsEvent extends Event {
labels?: Label[]
}
@ -274,6 +283,8 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
'handleFontContrastChange',
handleFontContrastChange
)
document.addEventListener('updateJustifyText', updateJustifyText)
document.addEventListener('updateTitle', handleUpdateTitle)
document.addEventListener('updateLabels', handleUpdateLabels)
@ -297,6 +308,7 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
'handleFontContrastChange',
handleFontContrastChange
)
document.removeEventListener('updateJustifyText', updateJustifyText)
document.removeEventListener('updateTitle', handleUpdateTitle)
document.removeEventListener('updateLabels', handleUpdateLabels)
document.removeEventListener('share', share)
@ -308,15 +320,26 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
}
})
const textColorValue = (isHighContrast: boolean) => {
return isHighContrast
? theme.colors.readerFontHighContrast.toString()
: theme.colors.readerFont.toString()
}
const justifyTextValue = (isJustified: boolean) => {
return isJustified ? 'justify' : 'start'
}
const styles = {
fontSize,
margin: props.margin ?? 360,
maxWidthPercentage: maxWidthPercentageOverride ?? props.maxWidthPercentage,
lineHeight: lineHeightOverride ?? props.lineHeight ?? 150,
fontFamily: fontFamilyOverride ?? props.fontFamily ?? 'inter',
readerFontColor: highContrastText
? theme.colors.readerFontHighContrast.toString()
: theme.colors.readerFont.toString(),
readerFontColor:
highContrastTextOverride != undefined
? textColorValue(highContrastTextOverride)
: textColorValue(props.highContrastText ?? false),
readerTableHeaderColor: theme.colors.readerTableHeader.toString(),
readerHeadersColor: theme.colors.readerFont.toString(),
}
@ -338,12 +361,11 @@ export function ArticleContainer(props: ArticleContainerProps): JSX.Element {
paddingTop: '30px',
minHeight: '100vh',
maxWidth: `${styles.maxWidthPercentage ?? 100}%`,
background: props.isAppleAppEmbed
? 'unset'
: theme.colors.readerBg.toString(),
'.article-inner-css': {
textAlign: props.justifyText ? 'justify' : 'start',
},
background: theme.colors.readerBg.toString(),
'--text-align':
justifyTextOverride != undefined
? justifyTextValue(justifyTextOverride)
: justifyTextValue(props.justifyText ?? false),
'--text-font-family': styles.fontFamily,
'--text-font-size': `${styles.fontSize}px`,
'--line-height': `${styles.lineHeight}%`,

View file

@ -6,6 +6,7 @@ export enum ThemeId {
Dark = 'Dark',
Sepia = 'Sepia',
Apollo = 'Apollo',
Black = 'Black',
}
export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
@ -279,6 +280,13 @@ const darkThemeSpec = {
},
}
// This is used by iOS
const blackThemeSpec = {
colors: {
readerBg: 'black',
},
}
const sepiaThemeSpec = {
colors: {
readerBg: '#FBF0D9',
@ -311,6 +319,13 @@ export const apolloTheme = createTheme(ThemeId.Apollo, {
...apolloThemeSpec.colors,
},
})
export const blackTheme = createTheme(ThemeId.Black, {
...darkThemeSpec,
colors: {
...darkThemeSpec.colors,
...blackThemeSpec.colors,
},
})
// Apply global styles in here
export const globalStyles = globalCss({

View file

@ -11,12 +11,16 @@ export const getTopOmnivoreAnchorElement = (
): string | undefined => {
let topVisibleRect: Element | undefined = undefined
const anchors = Array.from(
document.querySelectorAll(`[data-omnivore-anchor-idx]`)
document.querySelectorAll(`p[data-omnivore-anchor-idx]`)
).reverse()
for (const anchor of anchors) {
const rect = anchor.getBoundingClientRect()
if (rect.top >= 0 && rect.bottom <= articleContentElement.clientHeight) {
if (
rect.height > 0 &&
rect.top >= 50 &&
rect.bottom <= articleContentElement.clientHeight
) {
if (
topVisibleRect &&
topVisibleRect.getBoundingClientRect().top < rect.top

View file

@ -61,13 +61,6 @@ export function useSelection(
let shouldCancelSelection = false
const overlapHighlights: HighlightLocation[] = []
console.log(
'checking highlight locations for ',
selectionStart,
selectionEnd
)
console.log(' highlight locations: ', highlightLocations)
highlightLocations
.sort((a, b) => {
if (a.start < b.start) {
@ -156,7 +149,7 @@ export function useSelection(
overlapHighlights: overlapHighlights.map(({ id }) => id),
})
},
[highlightLocations]
[touchStartPos, selectionAttributes, highlightLocations]
)
const copyTextSelection = useCallback(async () => {

View file

@ -3,6 +3,7 @@ import {
darkTheme,
sepiaTheme,
apolloTheme,
blackTheme,
} from '../components/tokens/stitches.config'
const themeKey = 'theme'
@ -31,6 +32,8 @@ function getTheme(themeId: string) {
return sepiaTheme
case ThemeId.Apollo:
return apolloTheme
case ThemeId.Black:
return blackTheme
}
return ThemeId.Light
}
@ -45,6 +48,7 @@ export function updateThemeLocally(themeId: string): void {
sepiaTheme,
darkTheme,
apolloTheme,
blackTheme,
...Object.keys(ThemeId)
)
document.body.classList.add(getTheme(themeId))
@ -60,6 +64,8 @@ export function currentThemeName(): string {
return 'Sepia'
case ThemeId.Apollo:
return 'Apollo'
case ThemeId.Black:
return 'Black'
}
return 'Light'
}
@ -97,5 +103,9 @@ export function applyStoredTheme(syncWithServer = true): ThemeId | undefined {
export function isDarkTheme(): boolean {
const currentTheme = currentThemeName()
return currentTheme === 'Dark' || currentTheme === 'Darker'
return (
currentTheme === 'Dark' ||
currentTheme === 'Darker' ||
currentTheme == 'Black'
)
}

View file

@ -3,7 +3,7 @@
}
:root {
color-scheme: light dark;
color-scheme: var(--colorScheme-colorScheme);
}
.speakingSection {
@ -93,6 +93,7 @@ on smaller screens we display the note icon
font-weight: normal;
color: var(--font-color);
text-align: var(--text-align);
display: block;
margin-block-start: 1em;