Files
suixinkan_ios_uikit/suixinkan_ios/Features/Tasks/ViewModels/TaskCloudFileSelectionViewModel.swift
2026-06-26 14:33:31 +08:00

139 lines
4.3 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
///
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 {
var onChange: (() -> Void)?
var path: [CloudDriveFile] = [CloudDriveFile(id: 0, name: "云盘")] { didSet { onChange?() } }
var files: [CloudDriveFile] = [] { didSet { onChange?() } }
var total = 0 { didSet { onChange?() } }
var page = 1 { didSet { onChange?() } }
var searchText = "" { didSet { onChange?() } }
var selectedFilter: TaskCloudFileFilter = .all { didSet { onChange?() } }
var selectedFiles: [CloudDriveFile] = [] { didSet { onChange?() } }
var isLoading = false { didSet { onChange?() } }
var isLoadingMore = false { didSet { onChange?() } }
var errorMessage: String? { didSet { onChange?() } }
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
)
}
}