Files
suixinkan_ios_new/suixinkan/Features/Tasks/ViewModels/TaskCloudFileSelectionViewModel.swift
汉秋 8e34a45d50 移除 MJRefresh 依赖,恢复 SwiftUI 系统下拉刷新。
同时收紧各 ViewModel 内部 isLoading 可见性,避免不必要的视图刷新。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 10:55:45 +08:00

139 lines
4.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// TaskCloudFileSelectionViewModel.swift
// suixinkan
//
// Created by Codex on 2026/6/23.
//
import Foundation
import Combine
///
enum TaskCloudFileFilter: Int, CaseIterable, Identifiable {
case all = 0
case video = 1
case image = 2
var id: Int { rawValue }
///
var title: String {
switch self {
case .all:
"全部"
case .video:
"视频"
case .image:
"图片"
}
}
}
/// ViewModel
@MainActor
final class TaskCloudFileSelectionViewModel: ObservableObject {
@Published var path: [CloudDriveFile] = [CloudDriveFile(id: 0, name: "云盘")]
@Published var files: [CloudDriveFile] = []
@Published var total = 0
@Published var page = 1
@Published var searchText = ""
@Published var selectedFilter: TaskCloudFileFilter = .all
@Published var selectedFiles: [CloudDriveFile] = []
private var isLoading = false
@Published var isLoadingMore = false
@Published var errorMessage: String?
private let pageSize = 20
/// ID
var currentFolderId: Int {
path.last?.id ?? 0
}
///
var hasMore: Bool {
files.count < total
}
///
func reload(api: any TaskServing) async throws {
isLoading = true
errorMessage = nil
defer { isLoading = false }
do {
let payload = try await requestFiles(api: api, page: 1)
page = 1
files = payload.list
total = payload.total
} catch {
files = []
total = 0
page = 1
errorMessage = error.localizedDescription
throw error
}
}
///
func loadMore(api: any TaskServing) async throws {
guard hasMore, !isLoadingMore else { return }
isLoadingMore = true
defer { isLoadingMore = false }
let nextPage = page + 1
let payload = try await requestFiles(api: api, page: nextPage)
page = nextPage
total = payload.total
files.append(contentsOf: payload.list)
}
///
func enterFolder(_ folder: CloudDriveFile, api: any TaskServing) async throws {
guard folder.isFolder else { return }
path.append(folder)
try await reload(api: api)
}
///
func popToFolder(at index: Int, api: any TaskServing) async throws {
guard path.indices.contains(index) else { return }
path = Array(path.prefix(index + 1))
try await reload(api: api)
}
///
func toggleSelection(_ file: CloudDriveFile) {
guard !file.isFolder else { return }
if let index = selectedFiles.firstIndex(where: { $0.id == file.id }) {
selectedFiles.remove(at: index)
} else {
selectedFiles.append(file)
}
}
///
func isSelected(_ file: CloudDriveFile) -> Bool {
selectedFiles.contains { $0.id == file.id }
}
///
func makeSelectionItems() -> [TaskCloudSelectionItem] {
selectedFiles.map {
TaskCloudSelectionItem(id: $0.id, fileName: $0.name, fileType: $0.type, remark: "")
}
}
///
private func requestFiles(api: any TaskServing, page: Int) async throws -> ListPayload<CloudDriveFile> {
try await api.cloudFileList(
parentFolderId: currentFolderId,
name: searchText.trimmingCharacters(in: .whitespacesAndNewlines),
type: selectedFilter.rawValue,
orderBy: 2,
page: page,
pageSize: pageSize
)
}
}