Compare commits
5 Commits
adf13ae47c
...
1ff250fa17
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ff250fa17 | |||
| 42e647c932 | |||
| 080c7f00ce | |||
| 545e023ffc | |||
| 10ba84e349 |
@@ -25,13 +25,28 @@ struct SaveClipIntent: AppIntent {
|
|||||||
self.source = source
|
self.source = source
|
||||||
}
|
}
|
||||||
|
|
||||||
func perform() async throws -> some IntentResult {
|
func perform() async throws -> some IntentResult & ReturnsValue<String> {
|
||||||
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
guard !trimmed.isEmpty else {
|
guard !trimmed.isEmpty else {
|
||||||
return .result(dialog: "文案为空,未保存。")
|
return .result(value: "文案为空,未保存。")
|
||||||
|
}
|
||||||
|
|
||||||
|
guard !isSystemClipboardPlaceholder(trimmed) else {
|
||||||
|
return .result(value: "剪贴板没有有效文本,未保存。")
|
||||||
}
|
}
|
||||||
|
|
||||||
try await ClipStore.shared.save(text: trimmed, source: source)
|
try await ClipStore.shared.save(text: trimmed, source: source)
|
||||||
return .result(dialog: "已保存到收集箱。")
|
return .result(value: "已保存到收集箱。")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func isSystemClipboardPlaceholder(_ text: String) -> Bool {
|
||||||
|
let lowercased = text.lowercased()
|
||||||
|
if lowercased.hasPrefix("clipboard ") && lowercased.contains(" at ") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if text == "获取剪贴板" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+94
-17
@@ -10,26 +10,32 @@ import UIKit
|
|||||||
class ViewController: UIViewController {
|
class ViewController: UIViewController {
|
||||||
|
|
||||||
private var tableView: UITableView!
|
private var tableView: UITableView!
|
||||||
|
private var editButton: UIBarButtonItem!
|
||||||
|
|
||||||
|
private let menuOrderKey = "homeMenuOrder"
|
||||||
|
|
||||||
private struct MenuItem {
|
private struct MenuItem {
|
||||||
let icon: String
|
let icon: String
|
||||||
let iconColor: UIColor
|
let iconColor: UIColor
|
||||||
let title: String
|
let title: String
|
||||||
|
let identifier: String
|
||||||
}
|
}
|
||||||
|
|
||||||
private var menuItems: [[MenuItem]] = [
|
private let defaultMenuItems: [MenuItem] = [
|
||||||
[
|
MenuItem(icon: "tray.full", iconColor: .systemIndigo, title: "收集箱", identifier: "inbox"),
|
||||||
MenuItem(icon: "tray.full", iconColor: .systemIndigo, title: "收集箱"),
|
MenuItem(icon: "note.text", iconColor: .systemYellow, title: "打开备忘录", identifier: "notes"),
|
||||||
MenuItem(icon: "note.text", iconColor: .systemYellow, title: "打开备忘录"),
|
MenuItem(icon: "doc.text", iconColor: .systemBlue, title: "格式化日志", identifier: "formatLog"),
|
||||||
MenuItem(icon: "doc.text", iconColor: .systemBlue, title: "格式化日志"),
|
MenuItem(icon: "text.alignleft", iconColor: .systemGreen, title: "格式化笔记", identifier: "formatNote"),
|
||||||
MenuItem(icon: "text.alignleft", iconColor: .systemGreen, title: "格式化笔记"),
|
MenuItem(icon: "folder", iconColor: .systemOrange, title: "打开文件", identifier: "files")
|
||||||
MenuItem(icon: "folder", iconColor: .systemOrange, title: "打开文件")
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
private var menuItems: [[MenuItem]] = []
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
menuItems = [loadMenuOrder()]
|
||||||
setupUI()
|
setupUI()
|
||||||
|
setupAppStateObserver()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
@@ -37,12 +43,32 @@ class ViewController: UIViewController {
|
|||||||
updateInboxBadge()
|
updateInboxBadge()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupAppStateObserver() {
|
||||||
|
NotificationCenter.default.addObserver(
|
||||||
|
self,
|
||||||
|
selector: #selector(appDidBecomeActive),
|
||||||
|
name: UIApplication.didBecomeActiveNotification,
|
||||||
|
object: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func appDidBecomeActive() {
|
||||||
|
updateInboxBadge()
|
||||||
|
}
|
||||||
|
|
||||||
private func setupUI() {
|
private func setupUI() {
|
||||||
title = "首页"
|
title = "首页"
|
||||||
navigationController?.navigationBar.prefersLargeTitles = true
|
navigationController?.navigationBar.prefersLargeTitles = true
|
||||||
navigationItem.largeTitleDisplayMode = .always
|
navigationItem.largeTitleDisplayMode = .always
|
||||||
view.backgroundColor = .systemGroupedBackground
|
view.backgroundColor = .systemGroupedBackground
|
||||||
|
|
||||||
|
editButton = UIBarButtonItem(title: "编辑", style: .plain, target: self, action: #selector(didTapEditButton))
|
||||||
|
navigationItem.rightBarButtonItem = editButton
|
||||||
|
|
||||||
tableView = UITableView(frame: .zero, style: .insetGrouped)
|
tableView = UITableView(frame: .zero, style: .insetGrouped)
|
||||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
tableView.delegate = self
|
tableView.delegate = self
|
||||||
@@ -58,6 +84,34 @@ class ViewController: UIViewController {
|
|||||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func didTapEditButton() {
|
||||||
|
tableView.setEditing(!tableView.isEditing, animated: true)
|
||||||
|
editButton.title = tableView.isEditing ? "完成" : "编辑"
|
||||||
|
}
|
||||||
|
|
||||||
|
private func loadMenuOrder() -> [MenuItem] {
|
||||||
|
guard let savedOrder = UserDefaults.standard.array(forKey: menuOrderKey) as? [String] else {
|
||||||
|
return defaultMenuItems
|
||||||
|
}
|
||||||
|
|
||||||
|
var orderedItems: [MenuItem] = []
|
||||||
|
for identifier in savedOrder {
|
||||||
|
if let item = defaultMenuItems.first(where: { $0.identifier == identifier }) {
|
||||||
|
orderedItems.append(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let remaining = defaultMenuItems.filter { item in
|
||||||
|
!orderedItems.contains { $0.identifier == item.identifier }
|
||||||
|
}
|
||||||
|
return orderedItems + remaining
|
||||||
|
}
|
||||||
|
|
||||||
|
private func saveMenuOrder() {
|
||||||
|
let identifiers = menuItems.flatMap { $0.map(\.identifier) }
|
||||||
|
UserDefaults.standard.set(identifiers, forKey: menuOrderKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ViewController: UITableViewDataSource {
|
extension ViewController: UITableViewDataSource {
|
||||||
@@ -80,37 +134,59 @@ extension ViewController: UITableViewDataSource {
|
|||||||
config.imageProperties.tintColor = item.iconColor
|
config.imageProperties.tintColor = item.iconColor
|
||||||
config.imageToTextPadding = 12
|
config.imageToTextPadding = 12
|
||||||
cell.contentConfiguration = config
|
cell.contentConfiguration = config
|
||||||
cell.accessoryType = .disclosureIndicator
|
cell.accessoryType = tableView.isEditing ? .none : .disclosureIndicator
|
||||||
|
cell.selectionStyle = tableView.isEditing ? .none : .default
|
||||||
|
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
|
||||||
|
guard sourceIndexPath != destinationIndexPath else { return }
|
||||||
|
|
||||||
|
let item = menuItems[sourceIndexPath.section].remove(at: sourceIndexPath.row)
|
||||||
|
menuItems[destinationIndexPath.section].insert(item, at: destinationIndexPath.row)
|
||||||
|
saveMenuOrder()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ViewController: UITableViewDelegate {
|
extension ViewController: UITableViewDelegate {
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
|
guard !tableView.isEditing else { return }
|
||||||
|
|
||||||
let item = menuItems[indexPath.section][indexPath.row]
|
let item = menuItems[indexPath.section][indexPath.row]
|
||||||
switch item.title {
|
switch item.identifier {
|
||||||
case "收集箱":
|
case "inbox":
|
||||||
let viewController = ClipInboxViewController()
|
let viewController = ClipInboxViewController()
|
||||||
navigationController?.pushViewController(viewController, animated: true)
|
navigationController?.pushViewController(viewController, animated: true)
|
||||||
case "打开备忘录":
|
case "notes":
|
||||||
openSystemNotesApp()
|
openSystemNotesApp()
|
||||||
case "格式化日志":
|
case "formatLog":
|
||||||
let viewController = FormatLogViewController()
|
let viewController = FormatLogViewController()
|
||||||
navigationController?.pushViewController(viewController, animated: true)
|
navigationController?.pushViewController(viewController, animated: true)
|
||||||
case "格式化笔记":
|
case "formatNote":
|
||||||
let viewController = FormatNoteViewController()
|
let viewController = FormatNoteViewController()
|
||||||
navigationController?.pushViewController(viewController, animated: true)
|
navigationController?.pushViewController(viewController, animated: true)
|
||||||
case "打开文件":
|
case "files":
|
||||||
openFilesApp()
|
openFilesApp()
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
||||||
|
return .none
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private func updateInboxBadge() {
|
private func updateInboxBadge() {
|
||||||
Task {
|
Task {
|
||||||
guard let count = try? await ClipStore.shared.count(), count > 0 else {
|
guard let count = try? await ClipStore.shared.count(), count > 0 else {
|
||||||
@@ -128,11 +204,12 @@ extension ViewController: UITableViewDelegate {
|
|||||||
private func updateInboxTitle(_ title: String) {
|
private func updateInboxTitle(_ title: String) {
|
||||||
for (sectionIndex, section) in menuItems.enumerated() {
|
for (sectionIndex, section) in menuItems.enumerated() {
|
||||||
for (rowIndex, item) in section.enumerated() {
|
for (rowIndex, item) in section.enumerated() {
|
||||||
if item.title.hasPrefix("收集箱") {
|
if item.identifier == "inbox" {
|
||||||
menuItems[sectionIndex][rowIndex] = MenuItem(
|
menuItems[sectionIndex][rowIndex] = MenuItem(
|
||||||
icon: item.icon,
|
icon: item.icon,
|
||||||
iconColor: item.iconColor,
|
iconColor: item.iconColor,
|
||||||
title: title
|
title: title,
|
||||||
|
identifier: item.identifier
|
||||||
)
|
)
|
||||||
let indexPath = IndexPath(row: rowIndex, section: sectionIndex)
|
let indexPath = IndexPath(row: rowIndex, section: sectionIndex)
|
||||||
tableView.reloadRows(at: [indexPath], with: .none)
|
tableView.reloadRows(at: [indexPath], with: .none)
|
||||||
|
|||||||
Reference in New Issue
Block a user