// // ViewController.swift // Note // // Created by fish on 2026/7/12. // import UIKit class ViewController: UIViewController { private var tableView: UITableView! private var editButton: UIBarButtonItem! private let menuOrderKey = "homeMenuOrder" private struct MenuItem { let icon: String let iconColor: UIColor let title: String let identifier: String } private let defaultMenuItems: [MenuItem] = [ MenuItem(icon: "tray.full", iconColor: .systemIndigo, title: "收集箱", identifier: "inbox"), MenuItem(icon: "note.text", iconColor: .systemYellow, title: "打开备忘录", identifier: "notes"), MenuItem(icon: "doc.text", iconColor: .systemBlue, title: "格式化日志", identifier: "formatLog"), MenuItem(icon: "text.alignleft", iconColor: .systemGreen, title: "格式化笔记", identifier: "formatNote"), MenuItem(icon: "folder", iconColor: .systemOrange, title: "打开文件", identifier: "files") ] private var menuItems: [[MenuItem]] = [] override func viewDidLoad() { super.viewDidLoad() menuItems = [loadMenuOrder()] setupUI() setupAppStateObserver() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) 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() { title = "首页" navigationController?.navigationBar.prefersLargeTitles = true navigationItem.largeTitleDisplayMode = .always view.backgroundColor = .systemGroupedBackground editButton = UIBarButtonItem(title: "编辑", style: .plain, target: self, action: #selector(didTapEditButton)) navigationItem.rightBarButtonItem = editButton tableView = UITableView(frame: .zero, style: .insetGrouped) tableView.translatesAutoresizingMaskIntoConstraints = false tableView.delegate = self tableView.dataSource = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: "menuCell") tableView.backgroundColor = .systemGroupedBackground view.addSubview(tableView) NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), 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 { func numberOfSections(in tableView: UITableView) -> Int { return menuItems.count } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return menuItems[section].count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "menuCell", for: indexPath) let item = menuItems[indexPath.section][indexPath.row] var config = cell.defaultContentConfiguration() config.text = item.title config.image = UIImage(systemName: item.icon) config.imageProperties.tintColor = item.iconColor config.imageToTextPadding = 12 cell.contentConfiguration = config cell.accessoryType = tableView.isEditing ? .none : .disclosureIndicator cell.selectionStyle = tableView.isEditing ? .none : .default 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 { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) guard !tableView.isEditing else { return } let item = menuItems[indexPath.section][indexPath.row] switch item.identifier { case "inbox": let viewController = ClipInboxViewController() navigationController?.pushViewController(viewController, animated: true) case "notes": openSystemNotesApp() case "formatLog": let viewController = FormatLogViewController() navigationController?.pushViewController(viewController, animated: true) case "formatNote": let viewController = FormatNoteViewController() navigationController?.pushViewController(viewController, animated: true) case "files": openFilesApp() default: 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() { Task { guard let count = try? await ClipStore.shared.count(), count > 0 else { await MainActor.run { self.updateInboxTitle("收集箱") } return } await MainActor.run { self.updateInboxTitle("收集箱(\(count))") } } } private func updateInboxTitle(_ title: String) { for (sectionIndex, section) in menuItems.enumerated() { for (rowIndex, item) in section.enumerated() { if item.identifier == "inbox" { menuItems[sectionIndex][rowIndex] = MenuItem( icon: item.icon, iconColor: item.iconColor, title: title, identifier: item.identifier ) let indexPath = IndexPath(row: rowIndex, section: sectionIndex) tableView.reloadRows(at: [indexPath], with: .none) return } } } } private func openSystemNotesApp() { openURLIfPossible("mobilenotes://") } private func openFilesApp() { openURLIfPossible("shareddocuments://") } private func openURLIfPossible(_ string: String) { guard let url = URL(string: string) else { return } guard UIApplication.shared.canOpenURL(url) else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } }