Skip to content
Open
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
12 changes: 12 additions & 0 deletions Build.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Build.xcconfig
// uPic
//
// Created by Licardo on 2025/11/10.
//

// Configuration settings file format documentation can be found at:
// https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project

MARKETING_VERSION = 2.0.0
CURRENT_PROJECT_VERSION = 1
6 changes: 5 additions & 1 deletion macOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@
import AppKit
import KeyboardShortcuts
import SimpleLogger
import SwiftUI

class AppDelegate: NSResponder, NSApplicationDelegate {
var statusItem: NSStatusItem?
@Environment(\.openWindow) var openWindow

func applicationWillFinishLaunching(_: Notification) {
Noti.shared.requestNotificationAuthorization()

// Add URL scheme listening
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(self.handleGetURLEvent(event:withReplyEvent:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(handleGetURLEvent(event:withReplyEvent:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
}

func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool {
NSApp.activate(ignoringOtherApps: true)
openWindow(id: "settings")
return true
}

Expand Down
20 changes: 10 additions & 10 deletions macOS/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1401,39 +1401,39 @@
}
}
},
"Preview" : {
"comment" : "The label of a button that previews an image in a new window.",
"Print this help message" : {
"comment" : "A help message for the \"help\" option.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "预览"
"value" : "打印此帮助信息"
}
}
}
},
"Print this help message" : {
"comment" : "A help message for the \"help\" option.",
"extractionState" : "stale",
"Quality" : {
"comment" : "A label describing the quality setting for Weibo Quick.",
"isCommentAutoGenerated" : true,
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "打印此帮助信息"
"value" : "质量"
}
}
}
},
"Quality" : {
"comment" : "A label describing the quality setting for Weibo Quick.",
"Quick Look" : {
"comment" : "The label of a button that previews an image in a new window.",
"isCommentAutoGenerated" : true,
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "质量"
"value" : "快速查看"
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions macOS/Manager/URLSchemeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class URLSchemeManager {
case "files":
if keyValue.count == 2 {
let pathStr = String(keyValue.last ?? "")
AppLogger.urlScheme.debug("URLScheme pload type file: \(pathStr)")
AppLogger.urlScheme.debug("URLScheme upload type file: \(pathStr)")
await uploader.upload(fileURLs: [URL(filePath: pathStr)])
}
case "url":
Expand All @@ -48,7 +48,7 @@ class URLSchemeManager {
}
}
case .some(let str) where str.contains("x-callback-url"):
AppLogger.urlScheme.debug("URLScheme pload type: x-callback-url")
AppLogger.urlScheme.debug("URLScheme upload type: x-callback-url")

if str.contains("acceptSnip") {
AppLogger.urlScheme.info("Processing x-callback-url request: \(keyValue)")
Expand Down
9 changes: 6 additions & 3 deletions macOS/Manager/UploadManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public class UploadManager: ObservableObject {
// MARK: - Dependencies

private var modelContext: ModelContext?
private let notificationCenter = NotificationCenter.default

// MARK: - Initialization

Expand Down Expand Up @@ -82,7 +81,7 @@ public class UploadManager: ObservableObject {

// 使用 DiskPermissionManager 管理磁盘访问权限
let diskPermissionManager = BookmarkManager.shared
let _ = diskPermissionManager.startDirectoryAccessing()
_ = diskPermissionManager.startDirectoryAccessing()

var items: [UploadItem] = []

Expand Down Expand Up @@ -260,7 +259,11 @@ public class UploadManager: ObservableObject {
let url = try await performSingleUpload(hostModel: hostModel, item: item)
AppLogger.uploader.info("Upload successful: \(url)")

Noti.shared.postUploadSuccessful(url)
if Defaults[.autoCopyUrlToClipboard] {
Tools.shared.copyUrlsToClipboard([url], afterUpload: true)
} else {
Noti.shared.postUploadSuccessful("\(Tools.shared.formatOutputUrls([url]))")
}

await saveToHistory(item: item, url: url, hostModel: hostModel)
successCount += 1
Expand Down
6 changes: 5 additions & 1 deletion macOS/Utils/Noti.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ extension Noti {
}

func postUploadSuccessful(_ body: String? = "") {
self.post(title: String(localized: "Uploaded successfully"), body: body)
}

func postUploadAndCopyToClipboardSuccessful(_ body: String? = "") {
self.post(title: String(localized: "Uploaded successfully"), subtitle: String(localized: "URL has been copied to the clipboard"), body: body)
}

func postCopySuccessful(_ body: String? = "") {
func postCopyToClipboardSuccessful(_ body: String? = "") {
self.post(title: String(localized: "URL has been copied to the clipboard"), body: body)
}

Expand Down
12 changes: 7 additions & 5 deletions macOS/Utils/Tools.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import UPicCore
class Tools {
static let shared = Tools()

func copyUrls(_ urls: [String]) {
AppLogger.tools.debug("Ready to copy upload results to clipboard: \(urls.joined(separator: ","))")

func copyUrlsToClipboard(_ urls: [String], afterUpload: Bool = false) {
let outputUrls = formatOutputUrls(urls)
let outputStr = outputUrls.joined(separator: "\n")
NSPasteboard.general.clearContents()
Expand All @@ -23,10 +21,14 @@ class Tools {

AppLogger.tools.info("Copy upload result to clipboard: \(outputStr)")

Noti.shared.postCopySuccessful(outputStr)
if afterUpload {
Noti.shared.postUploadAndCopyToClipboardSuccessful(outputStr)
} else {
Noti.shared.postCopyToClipboardSuccessful(outputStr)
}
}

private func formatOutputUrls(_ urls: [String], _ outputType: OutputFormatModel? = nil) -> [String] {
func formatOutputUrls(_ urls: [String], _ outputType: OutputFormatModel? = nil) -> [String] {
let outputUrls = urls.map { url in
OutputFormatModel.formatUrl(url, outputFormat: outputType)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
//

import QuickLook
import SimpleLogger
import SwiftData
import SwiftUI
import UPicCore
import SimpleLogger

struct HistoryTableView: View {
let uploadHistory: [UploadHistoryModel]
Expand Down Expand Up @@ -57,29 +57,47 @@ struct HistoryTableView: View {
}
}
.contextMenu(forSelectionType: UploadHistoryModel.ID.self) { selectedIds in
if let selectedId = selectedIds.first, let history = uploadHistory.first(where: { $0.id == selectedId }) {
Button("Preview", systemImage: "eye") {
if let url = URL(string: history.url) {
quickLookURL = url
}
}
let selectedHistories = selectedIds.compactMap { selectedId in
uploadHistory.first(where: { $0.id == selectedId })
}

Button("Copy URL", systemImage: "clipboard") {
Tools.shared.copyUrls([history.url])
}
Button("Copy URL", systemImage: "clipboard") {
Tools.shared.copyUrlsToClipboard(selectedHistories.compactMap { $0.url })
}

Button("Open in Browser", systemImage: "network") {
Button("Open in Browser", systemImage: "network") {
for history in selectedHistories {
if let url = URL(string: history.url) {
openURL(url)
}
}
}

if selectedHistories.count == 1 {
// Quick Look 只对第一个选中的项目
Divider()

Button("Delete", systemImage: "trash", role: .destructive) {
Button("Quick Look", systemImage: "eye") {
if let firstHistory = selectedHistories.first, let url = URL(string: firstHistory.url) {
quickLookURL = url
}
}
}

Divider()

Button("Delete", systemImage: "trash", role: .destructive) {
for history in selectedHistories {
deleteHistory(history)
}
}
} primaryAction: { selectedIds in
let selectedUrls = selectedIds.compactMap { selectedId in
uploadHistory.first(where: { $0.id == selectedId })?.url
}
if !selectedUrls.isEmpty {
Tools.shared.copyUrlsToClipboard(selectedUrls)
}
}
.alert("Clear History Record", isPresented: $showClearHistoryAlert) {
Button("Cancel", role: .cancel) {}
Expand All @@ -98,7 +116,7 @@ struct HistoryTableView: View {

HStack(spacing: 2) {
Text("\(uploadHistory.count) Items")

Spacer()

HStack(spacing: 2) {
Expand Down
6 changes: 3 additions & 3 deletions macOS/View/StatusMenu/HistoryMenuItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct HistoryMenuItem: View {
var body: some View {
Menu {
Button("Copy URL", systemImage: "clipboard") {
Tools.shared.copyUrls([history.url])
Tools.shared.copyUrlsToClipboard([history.url])
}

Button("Open in Browser", systemImage: "globe") {
Expand All @@ -34,7 +34,7 @@ struct HistoryMenuItem: View {

Divider()

Button("Preview", systemImage: "eye") {
Button("Quick Look", systemImage: "eye") {
if let url = URL(string: history.url) {
quickLookURL = url
}
Expand Down Expand Up @@ -65,7 +65,7 @@ struct HistoryMenuItem: View {
.truncationMode(.middle)
}
} primaryAction: {
Tools.shared.copyUrls([history.url])
Tools.shared.copyUrlsToClipboard([history.url])
}
}

Expand Down
Loading