Skip to content

Commit f094964

Browse files
authored
feat: add detail title copy button (#720)
## Problem Detail pages show the title text prominently, but there is no direct way to copy it from the header itself. ## Approach Add a shared `DetailTitleView` that keeps the title rendering in one place and adds a lightweight copy action on iOS and macOS. Update the book, series, oneshot, collection, and read list detail content views to use the shared title row while preserving existing badges and layout. ## Scope - add a reusable copy action for detail titles - adopt the shared title row across detail content views - bump the build version to 395 via the repo automation
1 parent 73a8c37 commit f094964

7 files changed

Lines changed: 46 additions & 25 deletions

File tree

KMReader.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@
438438
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "KMReader/KMReader-macOS.entitlements";
439439
CODE_SIGN_IDENTITY = "Apple Development";
440440
CODE_SIGN_STYLE = Automatic;
441-
CURRENT_PROJECT_VERSION = 394;
441+
CURRENT_PROJECT_VERSION = 395;
442442
DEVELOPMENT_TEAM = M777UHWZA4;
443443
ENABLE_APP_SANDBOX = YES;
444444
ENABLE_HARDENED_RUNTIME = YES;
@@ -496,7 +496,7 @@
496496
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "KMReader/KMReader-macOS.entitlements";
497497
CODE_SIGN_IDENTITY = "Apple Distribution";
498498
CODE_SIGN_STYLE = Manual;
499-
CURRENT_PROJECT_VERSION = 394;
499+
CURRENT_PROJECT_VERSION = 395;
500500
DEVELOPMENT_TEAM = "";
501501
"DEVELOPMENT_TEAM[sdk=appletvos*]" = M777UHWZA4;
502502
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = M777UHWZA4;
@@ -556,7 +556,7 @@
556556
CODE_SIGN_ENTITLEMENTS = KMReaderWidgets/KMReaderWidgets.entitlements;
557557
CODE_SIGN_IDENTITY = "Apple Development";
558558
CODE_SIGN_STYLE = Automatic;
559-
CURRENT_PROJECT_VERSION = 394;
559+
CURRENT_PROJECT_VERSION = 395;
560560
DEVELOPMENT_TEAM = M777UHWZA4;
561561
GENERATE_INFOPLIST_FILE = YES;
562562
INFOPLIST_FILE = KMReaderWidgets/Info.plist;
@@ -590,7 +590,7 @@
590590
CODE_SIGN_IDENTITY = "Apple Distribution";
591591
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
592592
CODE_SIGN_STYLE = Manual;
593-
CURRENT_PROJECT_VERSION = 394;
593+
CURRENT_PROJECT_VERSION = 395;
594594
DEVELOPMENT_TEAM = "";
595595
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = M777UHWZA4;
596596
GENERATE_INFOPLIST_FILE = YES;

KMReader/Features/Book/Views/BookDetailContentView.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@ struct BookDetailContentView: View {
2929
.fixedSize(horizontal: false, vertical: true)
3030
.textSelectionIfAvailable()
3131

32-
Text(book.metadata.title)
33-
.font(.title2)
34-
.fixedSize(horizontal: false, vertical: true)
35-
.textSelectionIfAvailable()
32+
DetailTitleView(title: book.metadata.title)
3633

3734
HStack(alignment: .top) {
3835
ThumbnailImage(

KMReader/Features/Collection/Views/CollectionDetailContentView.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ struct CollectionDetailContentView: View {
1111

1212
var body: some View {
1313
VStack(alignment: .leading) {
14-
Text(collection.name)
15-
.font(.title2)
16-
.textSelectionIfAvailable()
14+
DetailTitleView(title: collection.name)
1715

1816
HStack(alignment: .top) {
1917
ThumbnailImage(

KMReader/Features/OneShot/OneShotDetailContentView.swift

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,12 @@ struct OneShotDetailContentView: View {
3434

3535
var body: some View {
3636
VStack(alignment: .leading) {
37-
HStack(alignment: .bottom) {
38-
Text(book.metadata.title)
39-
.font(.title2)
40-
.fixedSize(horizontal: false, vertical: true)
41-
.textSelectionIfAvailable()
37+
HStack(alignment: .bottom, spacing: 8) {
38+
DetailTitleView(title: book.metadata.title)
4239
if let ageRating = series.metadata.ageRating, ageRating > 0 {
4340
AgeRatingBadge(ageRating: ageRating)
4441
}
45-
Spacer()
42+
Spacer(minLength: 0)
4643
}
4744

4845
HStack(alignment: .top) {

KMReader/Features/ReadList/Views/ReadListDetailContentView.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ struct ReadListDetailContentView: View {
1111

1212
var body: some View {
1313
VStack(alignment: .leading) {
14-
Text(readList.name)
15-
.font(.title2)
16-
.textSelectionIfAvailable()
14+
DetailTitleView(title: readList.name)
1715

1816
HStack(alignment: .top) {
1917
ThumbnailImage(

KMReader/Features/Series/Views/SeriesDetailContentView.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,12 @@ struct SeriesDetailContentView: View {
2121

2222
var body: some View {
2323
VStack(alignment: .leading) {
24-
HStack(alignment: .bottom) {
25-
Text(series.metadata.title)
26-
.font(.title2)
27-
.textSelectionIfAvailable()
24+
HStack(alignment: .bottom, spacing: 8) {
25+
DetailTitleView(title: series.metadata.title)
2826
if let ageRating = series.metadata.ageRating, ageRating > 0 {
2927
AgeRatingBadge(ageRating: ageRating)
3028
}
31-
Spacer()
29+
Spacer(minLength: 0)
3230
}
3331

3432
HStack(alignment: .top) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import SwiftUI
2+
3+
struct DetailTitleView: View {
4+
let title: String
5+
6+
var body: some View {
7+
HStack(alignment: .center, spacing: 8) {
8+
Text(title)
9+
.font(.title2)
10+
.fixedSize(horizontal: false, vertical: true)
11+
.textSelectionIfAvailable()
12+
.layoutPriority(1)
13+
14+
#if os(iOS) || os(macOS)
15+
Button {
16+
copyTitle()
17+
} label: {
18+
Image(systemName: "doc.on.doc")
19+
.font(.subheadline)
20+
}
21+
.adaptiveButtonStyle(.plain)
22+
.foregroundStyle(.secondary)
23+
#endif
24+
}
25+
}
26+
27+
private func copyTitle() {
28+
#if os(iOS) || os(macOS)
29+
PlatformHelper.generalPasteboard.string = title
30+
ErrorManager.shared.notify(message: String(localized: "notification.copied"))
31+
#endif
32+
}
33+
}

0 commit comments

Comments
 (0)