173 lines
4.9 KiB
Swift
173 lines
4.9 KiB
Swift
//
|
|
// CloudStoragePickForTaskViewModel.swift
|
|
// suixinkan
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// 任务云盘多选 ViewModel,对齐 Android 任务模式云盘浏览与多选逻辑。
|
|
final class CloudStoragePickForTaskViewModel {
|
|
|
|
private(set) var pathStack: [CloudPathItem] = [CloudPathItem(id: 0, name: "全部文件")]
|
|
private(set) var files: [CloudFile] = []
|
|
private(set) var selectedFiles: [Int: CloudFile] = [:]
|
|
private(set) var searchText = ""
|
|
private(set) var filterType = 0
|
|
private(set) var sortType = 2
|
|
private(set) var isLoading = false
|
|
private(set) var isRefreshing = false
|
|
private(set) var canLoadMore = false
|
|
|
|
var onStateChange: (() -> Void)?
|
|
var onShowMessage: ((String) -> Void)?
|
|
|
|
private var currentPage = 1
|
|
private var totalCount = 0
|
|
private let pageSize = 20
|
|
private let importedFileIDs: Set<Int>
|
|
private let allowedFileType: Int?
|
|
|
|
/// 初始化云盘多选 ViewModel,可按云盘文件类型限制选择范围。
|
|
init(importedFileIDs: Set<Int> = [], allowedFileType: Int? = nil) {
|
|
self.importedFileIDs = importedFileIDs
|
|
self.allowedFileType = allowedFileType
|
|
self.filterType = allowedFileType ?? 0
|
|
}
|
|
|
|
/// 当前文件夹 ID。
|
|
var currentFolderID: Int {
|
|
pathStack.last?.id ?? 0
|
|
}
|
|
|
|
/// 已选文件列表。
|
|
var selectedFileList: [CloudFile] {
|
|
Array(selectedFiles.values)
|
|
}
|
|
|
|
/// 文件是否已在任务页导入。
|
|
func isImported(_ fileID: Int) -> Bool {
|
|
importedFileIDs.contains(fileID)
|
|
}
|
|
|
|
/// 文件是否已选中。
|
|
func isSelected(_ fileID: Int) -> Bool {
|
|
selectedFiles[fileID] != nil
|
|
}
|
|
|
|
/// 更新搜索词。
|
|
func updateSearchText(_ text: String) {
|
|
searchText = text
|
|
notifyStateChange()
|
|
}
|
|
|
|
/// 更新类型筛选。
|
|
func updateFilterType(_ type: Int) {
|
|
filterType = type
|
|
notifyStateChange()
|
|
}
|
|
|
|
/// 更新排序方式。
|
|
func updateSortType(_ type: Int) {
|
|
sortType = type
|
|
notifyStateChange()
|
|
}
|
|
|
|
/// 首次或刷新加载。
|
|
func refresh(api: TaskAPI) async {
|
|
currentPage = 1
|
|
isRefreshing = true
|
|
notifyStateChange()
|
|
await loadPage(api: api, reset: true)
|
|
isRefreshing = false
|
|
notifyStateChange()
|
|
}
|
|
|
|
/// 加载更多。
|
|
func loadMore(api: TaskAPI) async {
|
|
guard canLoadMore, !isLoading else { return }
|
|
currentPage += 1
|
|
await loadPage(api: api, reset: false)
|
|
}
|
|
|
|
/// 点击文件或文件夹。
|
|
func handleItemTap(_ file: CloudFile, api: TaskAPI) async {
|
|
if file.isFolder {
|
|
pathStack.append(CloudPathItem(id: file.id, name: file.name))
|
|
searchText = ""
|
|
await refresh(api: api)
|
|
return
|
|
}
|
|
guard file.isSelectableMedia else { return }
|
|
if let allowedFileType, file.type != allowedFileType {
|
|
onShowMessage?(allowedFileType == 1 ? "请选择视频素材" : "请选择图片素材")
|
|
return
|
|
}
|
|
if isImported(file.id) {
|
|
onShowMessage?("已选择")
|
|
return
|
|
}
|
|
if selectedFiles[file.id] != nil {
|
|
selectedFiles.removeValue(forKey: file.id)
|
|
} else {
|
|
selectedFiles[file.id] = file
|
|
}
|
|
notifyStateChange()
|
|
}
|
|
|
|
/// 跳转面包屑路径。
|
|
func navigateToPathIndex(_ index: Int, api: TaskAPI) async {
|
|
guard index >= 0, index < pathStack.count else { return }
|
|
pathStack = Array(pathStack.prefix(index + 1))
|
|
searchText = ""
|
|
await refresh(api: api)
|
|
}
|
|
|
|
/// 返回上级目录。
|
|
func navigateBack(api: TaskAPI) async -> Bool {
|
|
guard pathStack.count > 1 else { return false }
|
|
pathStack.removeLast()
|
|
searchText = ""
|
|
await refresh(api: api)
|
|
return true
|
|
}
|
|
|
|
private func loadPage(api: TaskAPI, reset: Bool) async {
|
|
isLoading = true
|
|
notifyStateChange()
|
|
defer {
|
|
isLoading = false
|
|
notifyStateChange()
|
|
}
|
|
|
|
do {
|
|
let response = try await api.cloudFileList(
|
|
parentFolderId: currentFolderID,
|
|
name: searchText,
|
|
type: filterType,
|
|
orderBy: sortType,
|
|
page: currentPage,
|
|
pageSize: pageSize
|
|
)
|
|
totalCount = response.total
|
|
if reset {
|
|
files = response.list
|
|
} else {
|
|
files.append(contentsOf: response.list)
|
|
}
|
|
canLoadMore = files.count < totalCount
|
|
} catch is CancellationError {
|
|
return
|
|
} catch {
|
|
if reset {
|
|
files = []
|
|
}
|
|
canLoadMore = false
|
|
onShowMessage?(error.localizedDescription)
|
|
}
|
|
}
|
|
|
|
private func notifyStateChange() {
|
|
onStateChange?()
|
|
}
|
|
}
|