|
@@ -0,0 +1,679 @@
|
|
|
|
|
+import { common } from '@kit.AbilityKit'
|
|
|
|
|
+import { promptAction, SegmentButton, SegmentButtonItemTuple, SegmentButtonOptions } from '@kit.ArkUI'
|
|
|
|
|
+import { DialogAction, DialogHelper } from '@pura/harmony-dialog'
|
|
|
|
|
+import { CommonConstants } from '../common/constants/CommonConstants'
|
|
|
|
|
+import cacheManageService, { CacheBrowserItem, CacheDirectoryInfo } from '../common/util/CacheManageService'
|
|
|
|
|
+import { Utility } from '../common/util/Utility'
|
|
|
|
|
+import { ButtonFancyModifier, ShadowModifier, SymbolGlyphFancyModifier } from '../common/util/AttributeModifierUtil'
|
|
|
|
|
+
|
|
|
|
|
+interface CacheRootSegmentItem {
|
|
|
|
|
+ text: string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface CacheRootGroup {
|
|
|
|
|
+ key: string
|
|
|
|
|
+ title: string
|
|
|
|
|
+ path: string
|
|
|
|
|
+ description: string
|
|
|
|
|
+ removableSize: number
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@Component
|
|
|
|
|
+export struct CacheManageSheet {
|
|
|
|
|
+ @StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR
|
|
|
|
|
+
|
|
|
|
|
+ @State private directoryList: Array<CacheDirectoryInfo> = []
|
|
|
|
|
+ @State private rootGroups: Array<CacheRootGroup> = []
|
|
|
|
|
+ @State private currentPath: string = ''
|
|
|
|
|
+ @State private activeRootPath: string = ''
|
|
|
|
|
+ @State private activeRootTitle: string = ''
|
|
|
|
|
+ @State private browserItems: Array<CacheBrowserItem> = []
|
|
|
|
|
+ @State private selectedPaths: Array<string> = []
|
|
|
|
|
+ @State private isLoading: boolean = false
|
|
|
|
|
+ @State private isDeleting: boolean = false
|
|
|
|
|
+ @State private totalCacheSize: number = 0
|
|
|
|
|
+ @State @Watch('onRootSegmentChanged') private selectedRootIndexes: number[] = [0]
|
|
|
|
|
+
|
|
|
|
|
+ @Prop context?: common.Context
|
|
|
|
|
+ onCacheChanged: () => void = () => {
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ aboutToAppear(): void {
|
|
|
|
|
+ if (this.context) {
|
|
|
|
|
+ cacheManageService.init(this.context)
|
|
|
|
|
+ }
|
|
|
|
|
+ void this.loadDirectoryList()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async loadDirectoryList(): Promise<void> {
|
|
|
|
|
+ this.isLoading = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ this.directoryList = await cacheManageService.getCacheDirectoryList()
|
|
|
|
|
+ this.rootGroups = this.buildRootGroups(this.directoryList)
|
|
|
|
|
+ this.totalCacheSize = this.calcTotalCacheSize(this.directoryList)
|
|
|
|
|
+ if (this.rootGroups.length === 0) {
|
|
|
|
|
+ this.currentPath = ''
|
|
|
|
|
+ this.activeRootPath = ''
|
|
|
|
|
+ this.activeRootTitle = ''
|
|
|
|
|
+ this.browserItems = []
|
|
|
|
|
+ this.selectedPaths = []
|
|
|
|
|
+ this.syncRootSegmentSelection('')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.activeRootPath.length === 0 || this.resolveRootGroupIndexByPath(this.activeRootPath) < 0) {
|
|
|
|
|
+ this.activeRootPath = this.rootGroups[0].path
|
|
|
|
|
+ this.activeRootTitle = this.rootGroups[0].title
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.currentPath.length === 0 || !this.isPathInsideRoot(this.activeRootPath, this.currentPath)) {
|
|
|
|
|
+ this.currentPath = this.activeRootPath
|
|
|
|
|
+ }
|
|
|
|
|
+ await this.loadBrowserItems(this.currentPath, this.activeRootPath, this.activeRootTitle)
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ const err: Error = error as Error
|
|
|
|
|
+ promptAction.showToast({ message: `加载缓存目录失败:${err.message}` })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.isLoading = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private calcTotalCacheSize(list: Array<CacheDirectoryInfo>): number {
|
|
|
|
|
+ let totalSize: number = 0
|
|
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
|
|
+ if (list[i].removable) {
|
|
|
|
|
+ totalSize += list[i].size
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return totalSize
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private buildRootGroups(list: Array<CacheDirectoryInfo>): Array<CacheRootGroup> {
|
|
|
|
|
+ const groups: Array<CacheRootGroup> = []
|
|
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
|
|
+ const item: CacheDirectoryInfo = list[i]
|
|
|
|
|
+ groups.push({
|
|
|
|
|
+ key: item.key,
|
|
|
|
|
+ title: item.title,
|
|
|
|
|
+ path: item.path,
|
|
|
|
|
+ description: item.description,
|
|
|
|
|
+ removableSize: item.removable ? item.size : 0
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ return groups
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private isPathInsideRoot(rootPath: string, path: string): boolean {
|
|
|
|
|
+ if (rootPath.length === 0 || path.length === 0) {
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ return path === rootPath || path.startsWith(`${rootPath}/`)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private resolveRootGroupIndexByPath(path: string): number {
|
|
|
|
|
+ if (path.length === 0 || this.rootGroups.length === 0) {
|
|
|
|
|
+ return -1
|
|
|
|
|
+ }
|
|
|
|
|
+ let matchedIndex: number = -1
|
|
|
|
|
+ let matchedLength: number = -1
|
|
|
|
|
+ for (let i = 0; i < this.rootGroups.length; i++) {
|
|
|
|
|
+ const item: CacheRootGroup = this.rootGroups[i]
|
|
|
|
|
+ if (!this.isPathInsideRoot(item.path, path)) {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ if (item.path.length > matchedLength) {
|
|
|
|
|
+ matchedIndex = i
|
|
|
|
|
+ matchedLength = item.path.length
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return matchedIndex
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private syncRootSegmentSelection(path: string): void {
|
|
|
|
|
+ let nextIndex: number = this.resolveRootGroupIndexByPath(path)
|
|
|
|
|
+ if (nextIndex < 0) {
|
|
|
|
|
+ nextIndex = 0
|
|
|
|
|
+ }
|
|
|
|
|
+ const currentIndex: number = this.selectedRootIndexes.length > 0 ? this.selectedRootIndexes[0] : -1
|
|
|
|
|
+ if (currentIndex !== nextIndex) {
|
|
|
|
|
+ this.selectedRootIndexes = [nextIndex]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private onRootSegmentChanged(): void {
|
|
|
|
|
+ if (this.selectedRootIndexes.length === 0 || this.rootGroups.length === 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const nextIndex: number = this.selectedRootIndexes[0]
|
|
|
|
|
+ if (nextIndex < 0 || nextIndex >= this.rootGroups.length) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const currentRootIndex: number = this.resolveRootGroupIndexByPath(this.activeRootPath)
|
|
|
|
|
+ if (currentRootIndex === nextIndex) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const item: CacheRootGroup = this.rootGroups[nextIndex]
|
|
|
|
|
+ void this.loadBrowserItems(item.path, item.path, item.title)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private getCurrentGroup(): CacheRootGroup | null {
|
|
|
|
|
+ const currentIndex: number = this.resolveRootGroupIndexByPath(this.activeRootPath)
|
|
|
|
|
+ if (currentIndex >= 0 && currentIndex < this.rootGroups.length) {
|
|
|
|
|
+ return this.rootGroups[currentIndex]
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.rootGroups.length > 0) {
|
|
|
|
|
+ return this.rootGroups[0]
|
|
|
|
|
+ }
|
|
|
|
|
+ return null
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private getCurrentGroupDescription(): string {
|
|
|
|
|
+ const group: CacheRootGroup | null = this.getCurrentGroup()
|
|
|
|
|
+ if (!group) {
|
|
|
|
|
+ return ''
|
|
|
|
|
+ }
|
|
|
|
|
+ if (group.removableSize > 0) {
|
|
|
|
|
+ return `${group.description} · ${Utility.formatFileSize(group.removableSize)}`
|
|
|
|
|
+ }
|
|
|
|
|
+ return group.description
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private buildRootSegmentOptions(): SegmentButtonOptions {
|
|
|
|
|
+ const buttons: Array<CacheRootSegmentItem> = []
|
|
|
|
|
+ if (this.rootGroups.length === 0) {
|
|
|
|
|
+ buttons.push({ text: '暂无' })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ for (let i = 0; i < this.rootGroups.length; i++) {
|
|
|
|
|
+ buttons.push({ text: this.rootGroups[i].title })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return SegmentButtonOptions.capsule({
|
|
|
|
|
+ buttons: buttons as SegmentButtonItemTuple,
|
|
|
|
|
+ backgroundColor: $r('app.color.index_background'),
|
|
|
|
|
+ selectedBackgroundColor: $r('app.color.start_window_background'),
|
|
|
|
|
+ selectedFontColor: $r('app.color.text_color'),
|
|
|
|
|
+ buttonPadding: { top: 10, bottom: 10 },
|
|
|
|
|
+ multiply: false
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async loadBrowserItems(path: string, rootPath: string = '', rootTitle: string = ''): Promise<void> {
|
|
|
|
|
+ this.isLoading = true
|
|
|
|
|
+ this.selectedPaths = []
|
|
|
|
|
+ try {
|
|
|
|
|
+ this.currentPath = path
|
|
|
|
|
+ if (rootPath.length > 0) {
|
|
|
|
|
+ this.activeRootPath = rootPath
|
|
|
|
|
+ } else if (this.activeRootPath.length === 0) {
|
|
|
|
|
+ this.activeRootPath = path
|
|
|
|
|
+ }
|
|
|
|
|
+ if (rootTitle.length > 0) {
|
|
|
|
|
+ this.activeRootTitle = rootTitle
|
|
|
|
|
+ }
|
|
|
|
|
+ this.syncRootSegmentSelection(this.activeRootPath.length > 0 ? this.activeRootPath : path)
|
|
|
|
|
+ this.browserItems = await cacheManageService.listBrowserItems(path)
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ const err: Error = error as Error
|
|
|
|
|
+ promptAction.showToast({ message: `读取目录失败:${err.message}` })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.isLoading = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private getParentPath(path: string): string {
|
|
|
|
|
+ const index: number = path.lastIndexOf('/')
|
|
|
|
|
+ if (index <= 0) {
|
|
|
|
|
+ return path
|
|
|
|
|
+ }
|
|
|
|
|
+ return path.substring(0, index)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async goBackDirectory(): Promise<void> {
|
|
|
|
|
+ if (this.currentPath.length === 0 || this.activeRootPath.length === 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.currentPath === this.activeRootPath) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const parentPath: string = this.getParentPath(this.currentPath)
|
|
|
|
|
+ const nextPath: string = parentPath.length < this.activeRootPath.length ? this.activeRootPath : parentPath
|
|
|
|
|
+ await this.loadBrowserItems(nextPath, this.activeRootPath, this.activeRootTitle)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private isRootPath(): boolean {
|
|
|
|
|
+ if (this.activeRootPath.length === 0) {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ return this.currentPath === this.activeRootPath
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private toggleSelection(path: string, isOn: boolean): void {
|
|
|
|
|
+ if (isOn) {
|
|
|
|
|
+ if (!this.selectedPaths.includes(path)) {
|
|
|
|
|
+ this.selectedPaths = this.selectedPaths.concat([path])
|
|
|
|
|
+ }
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const nextList: Array<string> = []
|
|
|
|
|
+ for (let i = 0; i < this.selectedPaths.length; i++) {
|
|
|
|
|
+ if (this.selectedPaths[i] !== path) {
|
|
|
|
|
+ nextList.push(this.selectedPaths[i])
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ this.selectedPaths = nextList
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private isSelected(path: string): boolean {
|
|
|
|
|
+ return this.selectedPaths.includes(path)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private isAllVisibleSelected(): boolean {
|
|
|
|
|
+ if (this.browserItems.length === 0) {
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ for (let i = 0; i < this.browserItems.length; i++) {
|
|
|
|
|
+ if (!this.selectedPaths.includes(this.browserItems[i].path)) {
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private canToggleVisibleSelection(): boolean {
|
|
|
|
|
+ return !this.isDeleting && this.browserItems.length > 0
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private toggleVisibleSelection(): void {
|
|
|
|
|
+ if (!this.canToggleVisibleSelection()) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.isAllVisibleSelected()) {
|
|
|
|
|
+ this.selectedPaths = []
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const nextList: Array<string> = []
|
|
|
|
|
+ for (let i = 0; i < this.browserItems.length; i++) {
|
|
|
|
|
+ nextList.push(this.browserItems[i].path)
|
|
|
|
|
+ }
|
|
|
|
|
+ this.selectedPaths = nextList
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async refreshAfterDelete(): Promise<void> {
|
|
|
|
|
+ this.directoryList = await cacheManageService.getCacheDirectoryList()
|
|
|
|
|
+ this.rootGroups = this.buildRootGroups(this.directoryList)
|
|
|
|
|
+ this.totalCacheSize = this.calcTotalCacheSize(this.directoryList)
|
|
|
|
|
+ if (this.rootGroups.length === 0) {
|
|
|
|
|
+ this.currentPath = ''
|
|
|
|
|
+ this.activeRootPath = ''
|
|
|
|
|
+ this.activeRootTitle = ''
|
|
|
|
|
+ this.browserItems = []
|
|
|
|
|
+ this.selectedPaths = []
|
|
|
|
|
+ this.syncRootSegmentSelection('')
|
|
|
|
|
+ this.onCacheChanged()
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.activeRootPath.length === 0 || this.resolveRootGroupIndexByPath(this.activeRootPath) < 0) {
|
|
|
|
|
+ this.activeRootPath = this.rootGroups[0].path
|
|
|
|
|
+ this.activeRootTitle = this.rootGroups[0].title
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.currentPath.length === 0 || !this.isPathInsideRoot(this.activeRootPath, this.currentPath)) {
|
|
|
|
|
+ this.currentPath = this.activeRootPath
|
|
|
|
|
+ }
|
|
|
|
|
+ this.syncRootSegmentSelection(this.activeRootPath)
|
|
|
|
|
+ this.browserItems = await cacheManageService.listBrowserItems(this.currentPath)
|
|
|
|
|
+ this.selectedPaths = []
|
|
|
|
|
+ this.onCacheChanged()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private confirmDeleteSelected(): void {
|
|
|
|
|
+ if (this.selectedPaths.length === 0) {
|
|
|
|
|
+ promptAction.showToast({ message: '请先选择文件或目录' })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ DialogHelper.showAlertDialog({
|
|
|
|
|
+ content: `确定删除已选 ${this.selectedPaths.length} 项吗?`,
|
|
|
|
|
+ onAction: (action: DialogAction) => {
|
|
|
|
|
+ if (action === DialogAction.TWO) {
|
|
|
|
|
+ void this.deleteSelectedPaths()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async deleteSelectedPaths(): Promise<void> {
|
|
|
|
|
+ if (this.isDeleting || this.selectedPaths.length === 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.isDeleting = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const releasedSize: number = await cacheManageService.deletePaths(this.selectedPaths)
|
|
|
|
|
+ await this.refreshAfterDelete()
|
|
|
|
|
+ promptAction.showToast({ message: `已删除,释放 ${Utility.formatFileSize(releasedSize)}` })
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ const err: Error = error as Error
|
|
|
|
|
+ promptAction.showToast({ message: `删除失败:${err.message}` })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.isDeleting = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async clearAllRemovableCaches(): Promise<void> {
|
|
|
|
|
+ if (this.isDeleting) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.isDeleting = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const releasedSize: number = await cacheManageService.clearRemovableCaches()
|
|
|
|
|
+ await this.refreshAfterDelete()
|
|
|
|
|
+ promptAction.showToast({ message: `缓存已清理,释放 ${Utility.formatFileSize(releasedSize)}` })
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ const err: Error = error as Error
|
|
|
|
|
+ promptAction.showToast({ message: `清理失败:${err.message}` })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.isDeleting = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private canDeleteSelected(): boolean {
|
|
|
|
|
+ return !this.isDeleting && this.selectedPaths.length > 0
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private getSelectedSize(): number {
|
|
|
|
|
+ if (this.selectedPaths.length === 0 || this.browserItems.length === 0) {
|
|
|
|
|
+ return 0
|
|
|
|
|
+ }
|
|
|
|
|
+ let totalSize: number = 0
|
|
|
|
|
+ for (let i = 0; i < this.browserItems.length; i++) {
|
|
|
|
|
+ const item: CacheBrowserItem = this.browserItems[i]
|
|
|
|
|
+ if (this.selectedPaths.includes(item.path)) {
|
|
|
|
|
+ totalSize += item.size
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return totalSize
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private clearAllButtonBuilder(): void {
|
|
|
|
|
+ Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ SymbolGlyph($r('sys.symbol.trash'))
|
|
|
|
|
+ .fontColor([this.themeColor])
|
|
|
|
|
+ .fontSize(16)
|
|
|
|
|
+ Text(this.isDeleting ? '处理中' : '一键清理')
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .margin({ left: 6 })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .enabled(!this.isDeleting)
|
|
|
|
|
+ .padding({ left: 12, right: 12 })
|
|
|
|
|
+ .attributeModifier(new ButtonFancyModifier(126, 40))
|
|
|
|
|
+ .attributeModifier(new ShadowModifier())
|
|
|
|
|
+ .opacity(this.isDeleting ? 0.65 : 1)
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ DialogHelper.showAlertDialog({
|
|
|
|
|
+ content: '确定清理所有可再生缓存吗?不会删除歌曲、歌单和已保存设置。',
|
|
|
|
|
+ onAction: (action: DialogAction) => {
|
|
|
|
|
+ if (action === DialogAction.TWO) {
|
|
|
|
|
+ void this.clearAllRemovableCaches()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private backButtonBuilder(): void {
|
|
|
|
|
+ Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ SymbolGlyph($r('sys.symbol.chevron_left'))
|
|
|
|
|
+ .attributeModifier(new SymbolGlyphFancyModifier(18, '', ''))
|
|
|
|
|
+ Text('返回')
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .margin({ left: 4 })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .enabled(!this.isRootPath() && !this.isLoading)
|
|
|
|
|
+ .padding({ left: 10, right: 12 })
|
|
|
|
|
+ .attributeModifier(new ButtonFancyModifier(86, 40))
|
|
|
|
|
+ .attributeModifier(new ShadowModifier())
|
|
|
|
|
+ .opacity(!this.isRootPath() && !this.isLoading ? 1 : 0.55)
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ void this.goBackDirectory()
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private openDirectoryButtonBuilder(path: string): void {
|
|
|
|
|
+ Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ Text('查看')
|
|
|
|
|
+ .fontSize(12)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor(this.themeColor)
|
|
|
|
|
+ SymbolGlyph($r('sys.symbol.chevron_right'))
|
|
|
|
|
+ .fontSize(14)
|
|
|
|
|
+ .fontColor([this.themeColor])
|
|
|
|
|
+ .margin({ left: 3 })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .padding({ left: 10, right: 10 })
|
|
|
|
|
+ .height(34)
|
|
|
|
|
+ .backgroundColor($r('app.color.index_background'))
|
|
|
|
|
+ .border({ width: 1, color: $r('app.color.start_window_background') })
|
|
|
|
|
+ .borderRadius(14)
|
|
|
|
|
+ .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.85 })
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ void this.loadBrowserItems(path, this.activeRootPath, this.activeRootTitle)
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private selectToggleButtonBuilder(): void {
|
|
|
|
|
+ Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ SymbolGlyph($r('sys.symbol.checkmark_square_on_square'))
|
|
|
|
|
+ .fontSize(15)
|
|
|
|
|
+ .fontColor([this.themeColor])
|
|
|
|
|
+ Text(this.isAllVisibleSelected() ? '反选' : '全选')
|
|
|
|
|
+ .fontSize(12)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .margin({ left: 6 })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .enabled(this.canToggleVisibleSelection())
|
|
|
|
|
+ .padding({ left: 12, right: 12 })
|
|
|
|
|
+ .height(36)
|
|
|
|
|
+ .backgroundColor($r('app.color.index_background'))
|
|
|
|
|
+ .border({ width: 1, color: $r('app.color.start_window_background') })
|
|
|
|
|
+ .borderRadius(14)
|
|
|
|
|
+ .opacity(this.canToggleVisibleSelection() ? 1 : 0.55)
|
|
|
|
|
+ .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.85 })
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ this.toggleVisibleSelection()
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private deleteSelectedButtonBuilder(): void {
|
|
|
|
|
+ Button({ type: ButtonType.Normal, stateEffect: true }) {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ SymbolGlyph($r('sys.symbol.trash'))
|
|
|
|
|
+ .fontSize(15)
|
|
|
|
|
+ .fontColor([Color.White])
|
|
|
|
|
+ Text(this.isDeleting ? '删除中' : '删除所选')
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor(Color.White)
|
|
|
|
|
+ .margin({ left: 6 })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .enabled(this.canDeleteSelected())
|
|
|
|
|
+ .padding({ left: 14, right: 14 })
|
|
|
|
|
+ .height(42)
|
|
|
|
|
+ .backgroundColor(this.canDeleteSelected() ? '#E84A4A' : '#CFCFCF')
|
|
|
|
|
+ .borderRadius(16)
|
|
|
|
|
+ .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.85 })
|
|
|
|
|
+ .onClick(() => {
|
|
|
|
|
+ this.confirmDeleteSelected()
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private headerCardBuilder(): void {
|
|
|
|
|
+ Column({ space: 14 }) {
|
|
|
|
|
+ Row({ space: 12 }) {
|
|
|
|
|
+ Column({ space: 4 }) {
|
|
|
|
|
+ Text('缓存管理')
|
|
|
|
|
+ .fontSize(14)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ Text(Utility.formatFileSize(this.totalCacheSize))
|
|
|
|
|
+ .fontSize(28)
|
|
|
|
|
+ .fontWeight(700)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .alignItems(HorizontalAlign.Start)
|
|
|
|
|
+
|
|
|
|
|
+ this.clearAllButtonBuilder()
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+
|
|
|
|
|
+ SegmentButton({
|
|
|
|
|
+ options: this.buildRootSegmentOptions(),
|
|
|
|
|
+ selectedIndexes: $selectedRootIndexes
|
|
|
|
|
+ })
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+
|
|
|
|
|
+ Row({ space: 10 }) {
|
|
|
|
|
+ this.backButtonBuilder()
|
|
|
|
|
+
|
|
|
|
|
+ Text(this.currentPath.length > 0 ? this.currentPath : '暂无缓存目录')
|
|
|
|
|
+ .fontSize(11)
|
|
|
|
|
+ .fontColor(Color.Gray)
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.MARQUEE })
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .alignItems(VerticalAlign.Center)
|
|
|
|
|
+ }
|
|
|
|
|
+ .padding(16)
|
|
|
|
|
+ .margin({ left: 12, right: 12, top: 12 })
|
|
|
|
|
+ .backgroundColor($r('app.color.start_window_background'))
|
|
|
|
|
+ .borderRadius(20)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Builder
|
|
|
|
|
+ private emptyStateBuilder(): void {
|
|
|
|
|
+ Column({ space: 10 }) {
|
|
|
|
|
+ SymbolGlyph($r('sys.symbol.folder'))
|
|
|
|
|
+ .fontSize(32)
|
|
|
|
|
+ .fontColor([this.themeColor])
|
|
|
|
|
+ Text(this.currentPath.length > 0 ? '当前目录为空' : '暂无缓存目录')
|
|
|
|
|
+ .fontSize(14)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ Text(this.currentPath.length > 0 ? '可切换上方分类,或点击返回继续查看。' : '暂未扫描到可管理的缓存目录。')
|
|
|
|
|
+ .fontSize(12)
|
|
|
|
|
+ .fontColor(Color.Gray)
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ build() {
|
|
|
|
|
+ Column({ space: 10 }) {
|
|
|
|
|
+ this.headerCardBuilder()
|
|
|
|
|
+
|
|
|
|
|
+ if (this.isLoading) {
|
|
|
|
|
+ Column() {
|
|
|
|
|
+ LoadingProgress()
|
|
|
|
|
+ .width(28)
|
|
|
|
|
+ .height(28)
|
|
|
|
|
+ Text('正在读取缓存目录...')
|
|
|
|
|
+ .fontSize(12)
|
|
|
|
|
+ .fontColor(Color.Gray)
|
|
|
|
|
+ .margin({ top: 8 })
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ } else if (this.browserItems.length === 0) {
|
|
|
|
|
+ this.emptyStateBuilder()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ List() {
|
|
|
|
|
+ ForEach(this.browserItems, (item: CacheBrowserItem) => {
|
|
|
|
|
+ ListItem() {
|
|
|
|
|
+ Column() {
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ Toggle({ type: ToggleType.Checkbox, isOn: this.isSelected(item.path) })
|
|
|
|
|
+ .selectedColor(this.themeColor)
|
|
|
|
|
+ .margin({ right: 10 })
|
|
|
|
|
+ .onChange((isOn: boolean) => {
|
|
|
|
|
+ this.toggleSelection(item.path, isOn)
|
|
|
|
|
+ })
|
|
|
|
|
+ SymbolGlyph(item.isDirectory ? $r('sys.symbol.folder') : $r('sys.symbol.doc'))
|
|
|
|
|
+ .fontSize(20)
|
|
|
|
|
+ .fontColor([this.themeColor])
|
|
|
|
|
+ .margin({ right: 10 })
|
|
|
|
|
+ Column() {
|
|
|
|
|
+ Text(item.name)
|
|
|
|
|
+ .fontSize(14)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ .maxLines(1)
|
|
|
|
|
+ .textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
+ Text(`${item.isDirectory ? '目录' : '文件'} · ${Utility.formatFileSize(item.size)}`)
|
|
|
|
|
+ .fontSize(11)
|
|
|
|
|
+ .fontColor(Color.Gray)
|
|
|
|
|
+ .margin({ top: 2 })
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .alignItems(HorizontalAlign.Start)
|
|
|
|
|
+ if (item.isDirectory) {
|
|
|
|
|
+ this.openDirectoryButtonBuilder(item.path)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ }
|
|
|
|
|
+ .padding({ left: 16, right: 16, top: 14, bottom: 14 })
|
|
|
|
|
+ .backgroundColor($r('app.color.start_window_background'))
|
|
|
|
|
+ .borderRadius(18)
|
|
|
|
|
+ .margin({ left: 12, right: 12, top: 6, bottom: 6 })
|
|
|
|
|
+ }
|
|
|
|
|
+ }, (item: CacheBrowserItem): string => item.path)
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .divider({ strokeWidth: 0 })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Row() {
|
|
|
|
|
+ Row({ space: 6 }) {
|
|
|
|
|
+ this.selectToggleButtonBuilder()
|
|
|
|
|
+ Text(`已选 ${Utility.formatFileSize(this.getSelectedSize())}`)
|
|
|
|
|
+ .fontSize(12)
|
|
|
|
|
+ .fontColor(Color.Gray)
|
|
|
|
|
+ Text(`已选 ${this.selectedPaths.length} 项`)
|
|
|
|
|
+ .fontSize(13)
|
|
|
|
|
+ .fontWeight(600)
|
|
|
|
|
+ .fontColor($r('app.color.text_color'))
|
|
|
|
|
+ }
|
|
|
|
|
+ .layoutWeight(1)
|
|
|
|
|
+
|
|
|
|
|
+ this.deleteSelectedButtonBuilder()
|
|
|
|
|
+ }
|
|
|
|
|
+ .padding({ left: 16, right: 16, top: 14, bottom: 14 })
|
|
|
|
|
+ .margin({ left: 12, right: 12, bottom: 12 })
|
|
|
|
|
+ .backgroundColor($r('app.color.start_window_background'))
|
|
|
|
|
+ .borderRadius(20)
|
|
|
|
|
+ }
|
|
|
|
|
+ .width('100%')
|
|
|
|
|
+ .height('100%')
|
|
|
|
|
+ .backgroundColor($r('app.color.index_background'))
|
|
|
|
|
+ }
|
|
|
|
|
+}
|