Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions KMReader.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "KMReader/KMReader-macOS.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 342;
CURRENT_PROJECT_VERSION = 343;
DEVELOPMENT_TEAM = M777UHWZA4;
ENABLE_APP_SANDBOX = YES;
ENABLE_HARDENED_RUNTIME = YES;
Expand Down Expand Up @@ -484,7 +484,7 @@
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "KMReader/KMReader-macOS.entitlements";
CODE_SIGN_IDENTITY = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 342;
CURRENT_PROJECT_VERSION = 343;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=appletvos*]" = M777UHWZA4;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = M777UHWZA4;
Expand Down Expand Up @@ -544,7 +544,7 @@
CODE_SIGN_ENTITLEMENTS = KMReaderWidgets/KMReaderWidgets.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 342;
CURRENT_PROJECT_VERSION = 343;
DEVELOPMENT_TEAM = M777UHWZA4;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = KMReaderWidgets/Info.plist;
Expand Down Expand Up @@ -578,7 +578,7 @@
CODE_SIGN_IDENTITY = "Apple Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 342;
CURRENT_PROJECT_VERSION = 343;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = M777UHWZA4;
GENERATE_INFOPLIST_FILE = YES;
Expand Down
1 change: 0 additions & 1 deletion KMReader/Features/Book/Views/BookDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ struct BookDetailView: View {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
.toolbarButtonStyle()
}
}
Expand Down
1 change: 0 additions & 1 deletion KMReader/Features/Browse/Views/BrowseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ struct BrowseView: View {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,5 @@ extension CollectionDetailView {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ struct DashboardSectionDetailView: View {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
}
}
#endif
Expand Down
1 change: 0 additions & 1 deletion KMReader/Features/Dashboard/Views/DashboardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,6 @@ struct DashboardView: View {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
}
}
}
Expand Down
1 change: 0 additions & 1 deletion KMReader/Features/Offline/Views/OfflineView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ struct OfflineView: View {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
}
}
}
Expand Down
1 change: 0 additions & 1 deletion KMReader/Features/OneShot/OneShotDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,6 @@ struct OneshotDetailView: View {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
.toolbarButtonStyle()
}
}
Expand Down
1 change: 0 additions & 1 deletion KMReader/Features/ReadList/Views/ReadListDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ extension ReadListDetailView {
} label: {
Image(systemName: "ellipsis")
}
.appMenuStyle()
}.toolbarButtonStyle()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ struct ReadListDownloadActionsSection: View {
Image(systemName: "chevron.down")
}
}
.appMenuStyle()
.font(.caption)
.adaptiveButtonStyle(status.isProminent ? .borderedProminent : .bordered)

Expand Down
53 changes: 28 additions & 25 deletions KMReader/Features/Reader/Views/DivinaControlsOverlayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,18 +185,20 @@ struct DivinaControlsOverlayView: View {

private var topBar: some View {
HStack(alignment: .top) {
Button {
onDismiss()
} label: {
Image(systemName: "xmark")
}
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#if os(tvOS)
.focused($focusedControl, equals: .close)
.id("closeButton")
#if !os(macOS)
Button {
onDismiss()
} label: {
Image(systemName: "xmark")
}
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#if os(tvOS)
.focused($focusedControl, equals: .close)
.id("closeButton")
#endif
#endif

Spacer()
Expand Down Expand Up @@ -238,19 +240,20 @@ struct DivinaControlsOverlayView: View {

Spacer()

Menu {
menuContent()
} label: {
Image(systemName: "ellipsis")
.padding(4)
}
.appMenuStyle()
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#if os(tvOS)
.focused($focusedControl, equals: .settings)
#if !os(macOS)
Menu {
menuContent()
} label: {
Image(systemName: "ellipsis")
.padding(4)
}
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#if os(tvOS)
.focused($focusedControl, equals: .settings)
#endif
#endif
}
.allowsHitTesting(true)
Expand Down
84 changes: 84 additions & 0 deletions KMReader/Features/Reader/Views/DivinaReaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ struct DivinaReaderView: View {
.onAppear {
viewModel.updateDualPageSettings(noCover: !isolateCoverPage)
updateHandoff()
#if os(macOS)
configureMacReaderCommands()
#endif
}
.onChange(of: isolateCoverPage) { _, newValue in
viewModel.updateDualPageSettings(noCover: !newValue)
Expand Down Expand Up @@ -500,6 +503,9 @@ struct DivinaReaderView: View {
deferredPageMaintenanceTask?.cancel()
deferredPageMaintenanceTask = nil
viewModel.clearPreloadedImages()
#if os(macOS)
readerPresentation.clearMacReaderCommands()
#endif
}
.onChange(of: viewModel.isZoomed) { _, newValue in
if newValue {
Expand All @@ -522,6 +528,9 @@ struct DivinaReaderView: View {
}
#endif
#if os(macOS)
.onChange(of: macReaderCommandState) { _, newState in
readerPresentation.updateMacReaderCommandState(newState)
}
.onChange(of: currentBook) { _, newBook in
// Update window manager state when book changes to refresh window title
if let book = newBook {
Expand Down Expand Up @@ -1135,6 +1144,81 @@ struct DivinaReaderView: View {
jumpToPageID(targetPageID)
}

#if os(macOS)
private var macReaderCommandState: ReaderPresentationManager.MacReaderCommandState {
let supportsDualPageOptions =
readingDirection != .webtoon
&& readingDirection != .vertical
&& pageLayout.supportsDualPageOptions

let supportsSplitWidePageMode =
readingDirection != .webtoon
&& (pageLayout == .single || pageLayout == .auto)

return ReaderPresentationManager.MacReaderCommandState(
isActive: true,
hasPages: viewModel.hasPages,
hasTableOfContents: !viewModel.tableOfContents.isEmpty,
canOpenPreviousBook: currentSegmentPreviousBook != nil,
canOpenNextBook: currentSegmentNextBook != nil,
readingDirection: readingDirection,
pageLayout: pageLayout,
isolateCoverPage: isolateCoverPage,
splitWidePageMode: splitWidePageMode,
supportsDualPageOptions: supportsDualPageOptions,
supportsSplitWidePageMode: supportsSplitWidePageMode
)
}

private func configureMacReaderCommands() {
readerPresentation.configureMacReaderCommands(
state: macReaderCommandState,
handlers: ReaderPresentationManager.MacReaderCommandHandlers(
showReaderSettings: {
showingReaderSettingsSheet = true
},
showBookDetails: {
if currentSegmentBook != nil {
showingDetailSheet = true
}
},
showTableOfContents: {
if !viewModel.tableOfContents.isEmpty {
showingTOCSheet = true
}
},
showPageJump: {
if viewModel.hasPages {
showingPageJumpSheet = true
}
},
openPreviousBook: {
if let previousBook = currentSegmentPreviousBook {
openPreviousBook(previousBookId: previousBook.id)
}
},
openNextBook: {
if let nextBook = currentSegmentNextBook {
openNextBook(nextBookId: nextBook.id)
}
},
setReadingDirection: { direction in
readingDirection = direction
},
setPageLayout: { layout in
pageLayout = layout
},
toggleIsolateCoverPage: {
isolateCoverPage.toggle()
},
setSplitWidePageMode: { mode in
splitWidePageMode = mode
}
)
)
}
#endif

#if os(iOS) || os(macOS)
private var isTapZoneGestureEnabled: Bool {
viewModel.hasPages
Expand Down
36 changes: 34 additions & 2 deletions KMReader/Features/Reader/Views/DivinaTapZoneGestureBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,17 @@
guard configuration.isEnabled else { return false }
guard let attachedView else { return false }

let location = attachedView.convert(event.locationInWindow, from: nil)
guard let hitView = attachedView.hitTest(location) else { return true }
let windowLocation = event.locationInWindow
let location = attachedView.convert(windowLocation, from: nil)
guard
let hitView = resolvedHitView(
for: windowLocation,
attachedView: attachedView
)
else {
return false
}
guard isDescendant(hitView, of: attachedView) else { return false }

let className = hitView.className
if isInteractiveElement(hitView) { return false }
Expand All @@ -523,6 +532,29 @@
return true
}

private func resolvedHitView(for windowLocation: NSPoint, attachedView: NSView) -> NSView? {
if let contentView = attachedView.window?.contentView {
let contentLocation = contentView.convert(windowLocation, from: nil)
if let hitView = contentView.hitTest(contentLocation) {
return hitView
}
}

let attachedLocation = attachedView.convert(windowLocation, from: nil)
return attachedView.hitTest(attachedLocation)
}

private func isDescendant(_ candidate: NSView, of ancestor: NSView) -> Bool {
var cursor: NSView? = candidate
while let current = cursor {
if current === ancestor {
return true
}
cursor = current.superview
}
return false
}

func gestureRecognizer(
_ gestureRecognizer: NSGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: NSGestureRecognizer
Expand Down
43 changes: 23 additions & 20 deletions KMReader/Features/Reader/Views/Pdf/PdfControlsOverlayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,17 @@

private var topBar: some View {
HStack(alignment: .top) {
Button {
onDismiss()
} label: {
Image(systemName: "xmark")
}
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#if !os(macOS)
Button {
onDismiss()
} label: {
Image(systemName: "xmark")
}
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#endif

Spacer()

Expand Down Expand Up @@ -125,17 +127,18 @@

Spacer()

Menu {
menuContent()
} label: {
Image(systemName: "ellipsis")
.padding(4)
}
.appMenuStyle()
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#if !os(macOS)
Menu {
menuContent()
} label: {
Image(systemName: "ellipsis")
.padding(4)
}
.buttonBorderShape(.circle)
.controlSize(.large)
.contentShape(Circle())
.adaptiveButtonStyle(buttonStyle)
#endif
}
.allowsHitTesting(true)
.padding()
Expand Down
Loading