Skip to content

Commit

Permalink
UPDATE ui structure to support history view
Browse files Browse the repository at this point in the history
  • Loading branch information
ConradSun committed Aug 27, 2023
1 parent 64828d6 commit e3a1966
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 141 deletions.
8 changes: 6 additions & 2 deletions PasteShow.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
3A11B3DC2A82171B0023AD0E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A11B3DB2A82171B0023AD0E /* Preview Assets.xcassets */; };
3A11B3E42A8219AF0023AD0E /* PasteboardManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A11B3E32A8219AF0023AD0E /* PasteboardManager.swift */; };
3ACB8A592A847B37001DDE30 /* ContentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACB8A582A847B37001DDE30 /* ContentsView.swift */; };
3ADE2FE12A94A81A00E0C146 /* SplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ADE2FE02A94A81A00E0C146 /* SplitView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -24,6 +25,7 @@
3A11B3E32A8219AF0023AD0E /* PasteboardManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteboardManager.swift; sourceTree = "<group>"; };
3ACB8A582A847B37001DDE30 /* ContentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentsView.swift; sourceTree = "<group>"; };
3ACB8A5A2A847DF6001DDE30 /* PasteShow.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = PasteShow.entitlements; sourceTree = "<group>"; };
3ADE2FE02A94A81A00E0C146 /* SplitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -58,6 +60,7 @@
children = (
3A11B3D42A8217160023AD0E /* App.swift */,
3A11B3D62A8217160023AD0E /* MainView.swift */,
3ADE2FE02A94A81A00E0C146 /* SplitView.swift */,
3ACB8A582A847B37001DDE30 /* ContentsView.swift */,
3A11B3E32A8219AF0023AD0E /* PasteboardManager.swift */,
3A11B3D82A82171B0023AD0E /* Assets.xcassets */,
Expand Down Expand Up @@ -146,6 +149,7 @@
buildActionMask = 2147483647;
files = (
3A11B3D72A8217160023AD0E /* MainView.swift in Sources */,
3ADE2FE12A94A81A00E0C146 /* SplitView.swift in Sources */,
3A11B3E42A8219AF0023AD0E /* PasteboardManager.swift in Sources */,
3ACB8A592A847B37001DDE30 /* ContentsView.swift in Sources */,
3A11B3D52A8217160023AD0E /* App.swift in Sources */,
Expand Down Expand Up @@ -293,7 +297,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nuwastone.PasteShow;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down Expand Up @@ -321,7 +325,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 2.0;
PRODUCT_BUNDLE_IDENTIFIER = com.nuwastone.PasteShow;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down
4 changes: 1 addition & 3 deletions PasteShow/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import SwiftUI

@main
struct PasteShowApp: App {
let manager = PasteboardManager.shared

var body: some Scene {
WindowGroup {
MainView()
.environmentObject(manager.copiedInfo)
.environmentObject(PasteboardManager.shared.pasteInfo)
}
}
}
120 changes: 47 additions & 73 deletions PasteShow/ContentsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,107 +9,81 @@ import SwiftUI
import QuickLookUI
import UniformTypeIdentifiers

enum ContentsType {
case UTF8Text
case UTF16Text
case RTFText
case HTMLText
case Image
case Other
}

struct ContentsView: View {
@EnvironmentObject var status: NavigationStatus
let itemType: String
let itemData: Data
let utType: UTType

init(itemType: String, itemData: Data) {
self.itemType = itemType
self.itemData = itemData
self.utType = UTType(itemType) ?? .plainText
}

func getContentsType(itemType: String) -> ContentsType {
var contentsType = ContentsType.UTF8Text

switch utType {
case .utf8PlainText, .url:
contentsType = .UTF8Text
case .utf16ExternalPlainText:
contentsType = .UTF16Text
case .rtf, .rtfd, .flatRTFD:
contentsType = .RTFText
case .html:
contentsType = .HTMLText
case .image:
contentsType = .Image
default:
contentsType = .Other
func getPlainTextView(text: String) -> some View {
GeometryReader(content: { geometry in
Text(text)
Spacer()
.frame(width: geometry.size.width)
})
.onAppear {
status.titleString = itemType
status.subtitleString = String("\(itemData.count.formatted(.byteCount(style: .file)))")
}

return contentsType
}

func getRichTextView(attrText: NSAttributedString) -> some View {
RichTextView(attrText: attrText)
.onAppear {
status.titleString = itemType
status.subtitleString = String("\(itemData.count.formatted(.byteCount(style: .file)))")
}
}

var body: some View {
let contentsType = getContentsType(itemType: itemType)
switch contentsType {
case .UTF8Text, .UTF16Text, .RTFText, .HTMLText:
CopiedTextView(textType: contentsType, textData: itemData)
.navigationSubtitle("\(itemData.count.formatted(.byteCount(style: .file)))")
case .Image:
let utType = UTType(itemType) ?? .plainText
switch utType {
case .utf8PlainText, .fileURL:
getPlainTextView(text: String(data: itemData, encoding: .utf8)!)
case .utf16ExternalPlainText:
getPlainTextView(text: String(data: itemData, encoding: .utf16)!)
case .rtf:
getRichTextView(attrText: NSAttributedString(rtf: itemData, documentAttributes: nil)!)
case .rtfd:
getRichTextView(attrText: NSAttributedString(rtfd: itemData, documentAttributes: nil)!)
case .flatRTFD:
getRichTextView(attrText: NSAttributedString(rtfd: itemData, documentAttributes: nil)!)
case .html:
getRichTextView(attrText: NSAttributedString(html: itemData, documentAttributes: nil)!)
case .png, .jpeg, .tiff, .bmp, .gif, .webP:
let image = NSImage(data: itemData)!
Image(nsImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: image.size.width, maxHeight: image.size.height)
.navigationSubtitle("\(Int(image.size.width)) * \(Int(image.size.height)) pixel")
.onAppear {
status.titleString = itemType
status.subtitleString = String("\(Int(image.size.width)) * \(Int(image.size.height)) pixel")
}
default:
QuickLookView(data: itemData, type: utType)
.onAppear {
status.titleString = itemType
status.subtitleString = ""
}
}
}
}

struct CopiedTextView: NSViewRepresentable {
struct RichTextView: NSViewRepresentable {
typealias NSViewType = NSScrollView

let textType: ContentsType
let textData: Data

func updateTextView(textView: UnsafePointer<NSTextView>) {
textView.pointee.textStorage?.setAttributedString(NSAttributedString())

switch textType {
case .UTF8Text:
textView.pointee.string = String(data: textData, encoding: .utf8)
?? "No Preview"
case .UTF16Text:
textView.pointee.string = String(data: textData, encoding: .utf16)
?? "No Preview"
case .RTFText:
let attrText = NSAttributedString(rtf: textData, documentAttributes: nil)
?? NSAttributedString(rtfd: textData, documentAttributes: nil)!
textView.pointee.textStorage?.setAttributedString(attrText)
case .HTMLText:
let attrText = NSAttributedString(html: textData, documentAttributes: nil)!
textView.pointee.textStorage?.setAttributedString(attrText)
default:
textView.pointee.string = "No Preview"
}
}
let attrText: NSAttributedString

func makeNSView(context: Context) -> NSViewType {
let scrollView = NSTextView.scrollableTextView()
var textView = scrollView.documentView as! NSTextView

updateTextView(textView: &textView)
let textView = scrollView.documentView as! NSTextView
textView.textStorage?.setAttributedString(attrText)

return scrollView
}

func updateNSView(_ nsView: NSViewType, context: Context) {
var textView = nsView.documentView as! NSTextView

updateTextView(textView: &textView)
let textView = nsView.documentView as! NSTextView
textView.textStorage?.setAttributedString(attrText)
}
}

Expand Down
61 changes: 13 additions & 48 deletions PasteShow/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,24 @@
import SwiftUI

struct MainView: View {
@EnvironmentObject private var info: CopiedInfo
@StateObject var status = NavigationStatus()

var body: some View {
NavigationSplitView(sidebar: {
List(info.copiedItems, id: \.self) { item in
Section("CopiedItem") {
ForEach(item.keys.sorted(), id: \.self) { key in
NavigationLink {
ContentsView(itemType: key, itemData: item[key]!)
.navigationTitle(key)
} label: {
Text(key)
.contextMenu {
Button("Copy Data Type") {
PasteboardManager.shared.setDataWithoutReserve(data: key, forType: .string)
}
Button("Remove This Type") {
PasteboardManager.shared.removeDataWithReserve(data: item[key]!, forType: key)
}
}
}
}
NavigationSplitView {
SidebarView()
} content: {
ContentView()
.safeAreaInset(edge: .bottom, alignment: .leading) {
SourceView()
.padding()
}
}
.listStyle(.sidebar)
.safeAreaInset(edge: .bottom, alignment: .leading) {
if info.sourceURL != nil {
VStack(alignment: .leading) {
Section {
Label {
let name = info.sourceURL!.lastPathComponent
Text(name.replacingOccurrences(of: ".app", with: ""))
.lineLimit(1)
} icon: {
let path = info.sourceURL!.path().removingPercentEncoding
Image(nsImage: NSWorkspace.shared.icon(forFile: path!))
.frame(height: 18)
}
} header: {
Text("Source")
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.secondary)
}
}
.padding()
}
}
}, detail: {
})

} detail: {
DetailView()
}
.padding()
.navigationSplitViewStyle(.balanced)
.frame(minWidth: CGFloat(600), minHeight: CGFloat(360))
.environmentObject(status)
}
}

Expand Down

0 comments on commit e3a1966

Please sign in to comment.