diff --git a/entry/src/main/ets/common/constants/CommonConstants.ets b/entry/src/main/ets/common/constants/CommonConstants.ets index 6d3bdb6f..e19e5448 100644 --- a/entry/src/main/ets/common/constants/CommonConstants.ets +++ b/entry/src/main/ets/common/constants/CommonConstants.ets @@ -234,6 +234,7 @@ export default class CommonConstants { static readonly SHELF_LIST_DATA:string = 'SHELF_LIST_DATA' static readonly HAS_EXPLORE_URL:string = 'HAS_EXPLORE_URL' static readonly BOOK_IS_BOOK_REFRESHING:string = 'BOOK_IS_BOOK_REFRESHING' + static readonly BOOK_IS_BOOK_GROUPS_REFRESHING:string = 'BOOK_IS_BOOK_GROUPS_REFRESHING' // 订阅源分组数据 //分组是否初始化key static readonly RSS_SOURCES_GROUP_INIT:string = 'RSS_SOURCES_GROUP_INIT' diff --git a/entry/src/main/ets/common/utils/booksUtils.ets b/entry/src/main/ets/common/utils/booksUtils.ets index 798a952e..bc3e7db0 100644 --- a/entry/src/main/ets/common/utils/booksUtils.ets +++ b/entry/src/main/ets/common/utils/booksUtils.ets @@ -7,6 +7,9 @@ import BooksDao from '../../database/dao/BooksDao' import { Books } from '../../database/entities/Books' class booksUtils{ + async isTopBook(id: number): Promise { + return BooksDao.isUpdateBookTop(id) + } async addBooks(books: Books){ BooksDao.insert(books) } diff --git a/entry/src/main/ets/componets/common/InsideCircleIcon.ets b/entry/src/main/ets/componets/common/InsideCircleIcon.ets index 187eb2a5..bc639bc3 100644 --- a/entry/src/main/ets/componets/common/InsideCircleIcon.ets +++ b/entry/src/main/ets/componets/common/InsideCircleIcon.ets @@ -6,7 +6,7 @@ import { buttonList } from '../dataList/buttonList' @Component -export default struct InsideCircleIcon{ +export default struct InsideCircleIcon{ @Prop item:buttonList build() { Column({ diff --git a/entry/src/main/ets/componets/group/GroupType.ets b/entry/src/main/ets/componets/group/GroupType.ets index 6b62ebba..9feb0c23 100644 --- a/entry/src/main/ets/componets/group/GroupType.ets +++ b/entry/src/main/ets/componets/group/GroupType.ets @@ -12,7 +12,7 @@ export default struct groupTypeComponent { @State groupList:BookGroups[] = [] @Link bookTypeNumber:number // initGroup:string[] = ['分组','全部','未分组','本地','书单'] - + @StorageLink('BOOK_IS_BOOK_GROUPS_REFRESHING') @Watch('changeRefresh')BOOK_IS_BOOK_GROUPS_REFRESHING: number = 0 aboutToAppear(): void { this.getGroupList() } diff --git a/entry/src/main/ets/database/dao/BooksDao.ets b/entry/src/main/ets/database/dao/BooksDao.ets index 7e5e19fd..b82dd8f3 100644 --- a/entry/src/main/ets/database/dao/BooksDao.ets +++ b/entry/src/main/ets/database/dao/BooksDao.ets @@ -40,7 +40,7 @@ class BooksDao { if (type !== undefined) { whereClause.push(`bookType = ${type}`); } - if (bookGroup !== undefined) { + if (bookGroup !== undefined && bookGroup !== 2) { whereClause.push(`bookGroup = ${bookGroup}`); } if (searchKey) { @@ -110,7 +110,6 @@ class BooksDao { predicates.equalTo('id', books.id) const count = await DbUtil.queryForCount(predicates, column) if (count === 0 && books instanceof Books) { - // books.createTime = Date.now() this.insert(books) return true } @@ -120,7 +119,59 @@ class BooksDao { console.log('TagInfo, Error, ', JSON.stringify(err)) return false } - + } + //置顶 + async isUpdateBookTop(id: number) { + try { + const column: ColumnInfo[] = AppDatabaseUtil.getColumn(this.TABLE_NAME); + const predicates = DbUtil.getPredicates(this.TABLE_NAME); + predicates.equalTo('id', id) + const count = await DbUtil.queryForList(predicates, column) + if (column.length > 0) { + count.forEach((item) => { + item.isTop = !item.isTop + item.updateTime = Date.now() + this.update(item) + }) + return true + } + return false + } catch (err) { + console.log('TagInfo, Error, ', JSON.stringify(err)) + return false + } + } + //批量更新书籍分组 + async batchUpdateBookGroup(id: number[],groupId:number) { + try { + for (let index = 0; index < id.length; index++) { + this.updateBookGroup(id[index],groupId) + } + return true + } catch (err) { + console.log('TagInfo, Error, ', JSON.stringify(err)) + return false + } + } + //更新书籍分组 + async updateBookGroup(id: number,groupId:number) { + try { + const column: ColumnInfo[] = AppDatabaseUtil.getColumn(this.TABLE_NAME); + const predicates = DbUtil.getPredicates(this.TABLE_NAME); + predicates.equalTo('id', id) + const count = await DbUtil.queryForList(predicates, column) + if (column.length > 0) { + count.forEach((item) => { + item.bookGroup = groupId + this.update(item) + }) + return true + } + return false + } catch (err) { + console.log('TagInfo, Error, ', JSON.stringify(err)) + return false + } } //批量删除订阅源历史记录 diff --git a/entry/src/main/ets/pages/view/bookShelf/IndexShelf.ets b/entry/src/main/ets/pages/view/bookShelf/IndexShelf.ets index 2df431ff..5cabbf52 100644 --- a/entry/src/main/ets/pages/view/bookShelf/IndexShelf.ets +++ b/entry/src/main/ets/pages/view/bookShelf/IndexShelf.ets @@ -1,6 +1,7 @@ import BookMark from '../../../componets/head/BookMark' import { router } from '@kit.ArkUI' import BookBodyContent from './components/BookBodyContent' +import { picker } from '@kit.CoreFileKit' import { FileHandler } from '../../../common/utils/FileHandler' import Dialog from '../../../componets/common/Dialog' @@ -9,32 +10,19 @@ export default struct IndexShelf { @State currentIndex: number = 0 THEME_NAMES: string[] = ['书籍导入', '下载管理', '导入书单', '批量管理'] titleArray: Array = ['小说', '漫画', '有声书'] - @State bookType: string = '全部' - @State bookTypeNumber: number = 2 + + @State bookType:string = '全部' + @State bookTypeNumber:number = 2 @State EXHIBIT: string = '列表' @State GROUP: string = '标签' @State searchValue: string = '最近阅读' @State isClear: boolean = false + @State isShowImport: boolean = false @State isShowCloudImport: boolean = false @State isShowImportBookList: boolean = false @StorageLink('topRectHeight') topRectHeight: number = 0 @StorageProp('APP_INDEX_SCROLLABLE') APP_INDEX_SCROLLABLE: boolean = false - @StorageLink('BOOK_IS_BOOK_REFRESHING') isBookRefreshing: number = 0 - // 网址导入dialog - dialogController: CustomDialogController = new CustomDialogController({ - builder: Dialog({ - title: '网址导入', - child: () => { - this.DialogInput("请输入书籍目录或详情页", 10) - } - }), - cornerRadius: 8, - offset: { dx: 0, dy: 0 } - }) - tabsController: TabsController = new TabsController(); - private scrollController: Scroller = new Scroller(); - build() { Column() { Flex({ @@ -163,17 +151,17 @@ export default struct IndexShelf { }) { ForEach(this.titleArray, () => { TabContent() { - Column() { - BookBodyContent({ - currentIndex: this.currentIndex, - EXHIBIT: this.EXHIBIT, - GROUP: this.GROUP, - searchValue: this.searchValue, - isClear: this.isClear, - bookType: this.bookType, - bookTypeNumber: this.bookTypeNumber - }) - } + Column(){ + BookBodyContent({ + currentIndex: this.currentIndex, + EXHIBIT: this.EXHIBIT, + GROUP: this.GROUP, + searchValue: this.searchValue, + isClear: this.isClear, + bookType: this.bookType, + bookTypeNumber:this.bookTypeNumber + }) + } } }) } @@ -196,13 +184,14 @@ export default struct IndexShelf { .borderRadius({ bottomRight: 5, bottomLeft: 5 }) } + @Builder TabBuilderImage(index: number, name: string) { Column() { Image($r('app.media.SUB_theme')) }.width('100%') } - + @StorageLink('BOOK_IS_BOOK_REFRESHING') isBookRefreshing: number = 0 @Builder // 书籍导入UI盒子 ImportClickBox(index: number, image: string, text: string) { @@ -235,16 +224,21 @@ export default struct IndexShelf { .onClick(async () => { switch (index) { case 0: - // 本地导入 - // router.pushUrl({ - // url: 'pages/view/bookShelf/LocalImportPage' - // }); - let FileResult = await FileHandler.documentPickerFile(1, ['.txt', '.epub']) - FileHandler.CopyFile(FileResult[0], this.currentIndex) + // 本地导入 + // router.pushUrl({ + // url: 'pages/view/bookShelf/LocalImportPage' + // }); + let documentSelectOptions = new picker.DocumentSelectOptions(); + let documentPicker = new picker.DocumentViewPicker(); + let filePath: string = "" + await documentPicker.select(documentSelectOptions).then((documentSelectResult: Array) => { + filePath = documentSelectResult[0]; + }) + FileHandler.CopyFile(filePath,this.currentIndex) this.isShowImport = false - setTimeout(() => { + setTimeout(()=>{ this.isBookRefreshing++ - }, 500) + },500) break case 1: // 云盘导入 @@ -304,6 +298,20 @@ export default struct IndexShelf { } } + // 网址导入dialog + dialogController: CustomDialogController = new CustomDialogController({ + builder: Dialog({ + title: '网址导入', + child: () => { + this.DialogInput("请输入书籍目录或详情页", 10) + } + }), + cornerRadius: 8, + offset: { dx: 0, dy: 0 } + }) + tabsController: TabsController = new TabsController(); + private scrollController: Scroller = new Scroller(); + @Builder DialogInput(placeholder: string, maxlength: number) { Row() { @@ -472,17 +480,17 @@ export default struct IndexShelf { // 右上角更多 switch (themeNum) { case 0: - // 书籍导入弹窗 + // 书籍导入弹窗 this.isShowImport = true break case 1: - // 下载管理页 + // 下载管理页 router.pushUrl({ url: 'pages/view/bookShelf/DownloadManagementPage' }); break case 2: - // 导入书单弹窗 + // 导入书单弹窗 this.isShowImportBookList = true break case 3: diff --git a/entry/src/main/ets/pages/view/bookShelf/components/dialog/BookInfoDialogs.ets b/entry/src/main/ets/pages/view/bookShelf/components/dialog/BookInfoDialogs.ets index 4353552f..c2708ba3 100644 --- a/entry/src/main/ets/pages/view/bookShelf/components/dialog/BookInfoDialogs.ets +++ b/entry/src/main/ets/pages/view/bookShelf/components/dialog/BookInfoDialogs.ets @@ -6,6 +6,7 @@ import { showMessage } from '../../../../../componets/common/promptShow' import confirmDialogExample from '../../../../../componets/common/confirmDialog' import { sleep } from '../../../../../common/utils/utils' import booksUtil from '../../../../../common/utils/booksUtils' +import BookSelectGroupDialog from './BookSelectGroupDialog' @CustomDialog /** @@ -14,10 +15,10 @@ import booksUtil from '../../../../../common/utils/booksUtils' export default struct BookInfoDialogs{ controller?: CustomDialogController //推送提醒 - @Link bookData:Books + @Prop bookData:Books @State pushReminder:boolean = false @State buttonListInfo:buttonList[] = [ - new buttonList(1,'置顶',$r('app.media.top')), + new buttonList(1,this.bookData.isTop?'取消置顶':'置顶',$r('app.media.top')), new buttonList(2,'移动至',$r('app.media.folder')), new buttonList(3,'加入书单',$r('app.media.shelf')), new buttonList(4,'删除',$r('app.media.ic_public_delete')) @@ -90,10 +91,9 @@ export default struct BookInfoDialogs{ bookInfoButton(id:number){ switch (id){ case 1 : - showMessage(!this.bookData.isTop?'置顶':'取消置顶'); - this.isFolderTop(); break; + this.isTopBook(); break; case 2 : - showMessage('移动至'); break; + this.bookMoveGroup?.open(); break; case 3 : showMessage('加入书单'); break; case 4 : @@ -101,14 +101,6 @@ export default struct BookInfoDialogs{ } } - isFolderTop(){ - this.bookData.isTop = !this.bookData.isTop - this.buttonListInfo[0].title = this.bookData.isTop?'取消置顶':'置顶' - //刷新数组buttonListInfo - this.buttonListInfo = this.buttonListInfo.slice(0) - this.bookData.updateTime = Date.now() - } - @State delCache:boolean = false //弹窗 bookDelDialog: CustomDialogController | null = new CustomDialogController({ @@ -142,4 +134,36 @@ export default struct BookInfoDialogs{ showMessage('删除成功') } + async isTopBook(){ + booksUtil.isTopBook(this.bookData.id || 0).then((val)=>{ + val?showMessage(this.bookData.isTop?'置顶成功':'取消置顶成功'):showMessage('数据更新失败') + }) + setTimeout(()=>{ + this.controller?.close() + this.isBookRefreshing++ + },500) + } + + //移动分组 + //弹窗 + bookMoveGroup: CustomDialogController | null = new CustomDialogController({ + builder: BookSelectGroupDialog({ + moveGroup: ()=> { + this.bookMoveGroup?.close() + setTimeout(()=>{ + this.isBookRefreshing++ + },500) + }, + currentIndex:this.bookData.bookType, + booId:this.bookData.id + }), + height: 400, + cancel: this.exitApp, + autoCancel: true, + alignment: DialogAlignment.Center, + gridCount: 4, + customStyle: false, + cornerRadius: 25, + }) + } \ No newline at end of file diff --git a/entry/src/main/ets/pages/view/bookShelf/components/dialog/BookSelectGroupDialog.ets b/entry/src/main/ets/pages/view/bookShelf/components/dialog/BookSelectGroupDialog.ets new file mode 100644 index 00000000..f634dc3c --- /dev/null +++ b/entry/src/main/ets/pages/view/bookShelf/components/dialog/BookSelectGroupDialog.ets @@ -0,0 +1,189 @@ +/** + * @author 2008 + * @datetime 2024/7/25 13:44 + * @className: BookSelectGroupDialog + * 移动分组弹窗 + */ +import CommonConstants from '../../../../../common/constants/CommonConstants' +import PaddingConstants from '../../../../../common/constants/PaddingConstants' +import addBookTypeDialog from '../../../../../componets/common/addBookTypeDialog' +import { showMessage } from '../../../../../componets/common/promptShow' +import TitleContentDialog from '../../../../../componets/common/TitleContentDialog' +import BookGroupsDao from '../../../../../database/dao/BookGroupsDao' +import BooksDao from '../../../../../database/dao/BooksDao' +import { BookGroups } from '../../../../../database/entities/BookGroups' + +@Component +@CustomDialog +export default struct BookSelectGroupDialog{ + controller?: CustomDialogController + currentIndex:number = 0 + booId:number = 0 + moveGroup:Function = ()=>{ + + } + @StorageLink('BOOK_IS_BOOK_GROUPS_REFRESHING') BOOK_IS_BOOK_GROUPS_REFRESHING: number = 0 + aboutToAppear(): void { + this.getGroupList() + } + + @State groupList:BookGroups[] = [] + getGroupList(){ + BookGroupsDao.search({ + type:this.currentIndex + }).then((val)=>{ + this.groupList = val + }) + } + + build() { + Column() { + Column(){ + Text('移动分组') + .fontSize(16) + .fontWeight(700) + .lineHeight(24) + + }.padding({right:20,left:20,top:12,bottom:12}) + + Divider().strokeWidth(0.5) + Scroll(){ + GridRow({ + columns:3 + }){ + GridCol(){ + this.title() + } + ForEach(this.groupList,(item:BookGroups)=>{ + if (item.groupId && item.groupId > 5) { + GridCol(){ + this.title(item) + } + } + }) + }.padding(PaddingConstants.PADDING_20) + } + .align(Alignment.Top) + .height('65%') + .scrollBar(BarState.Off) + Divider().strokeWidth(0.5) + Column() { + Text('取消').fontSize(16).fontWeight(400) + .lineHeight(24) + } + .onClick(()=>{ + this.controller?.close() + }) + .alignItems(HorizontalAlign.Center) + .padding({ + left: 32, + right:32, + top: 16 + }) + } + .width(CommonConstants.FULL_WIDTH) + .height(CommonConstants.FULL_HEIGHT) + } + @State moveGroupId:number = 0 + @Builder title(item?:BookGroups) { + Column() { + if (item){ + Text(item.groupName).fontSize(14).textOverflow({ + overflow:TextOverflow.Ellipsis + }).ellipsisMode(EllipsisMode.END).maxLines(1) + } else { + Image($r('app.media.add')).width(24) + } + } + .onClick(()=>{ + if(!item){ + this.addBookType?.open() + return + } + if (item.groupId) { + this.moveGroupId = item.groupId + this.clickBookTypeDialog?.open() + } + }) + .margin({ + bottom:PaddingConstants.PADDING_16 + }) + .width(85).height(36) + .backgroundColor('rgba(0, 0, 0,0.06)') + .padding({ + left:16, + right:16, + top:8, + bottom:8 + }) + } + + @State bookType:string = '' + addBookType: CustomDialogController | null = new CustomDialogController({ + builder: addBookTypeDialog({ + cancel: ()=> { this.onCancel() }, + confirm: ()=> { this.onAccept() }, + bookType: this.bookType + }), + cancel: this.exitDialog, + autoCancel: true, + alignment: DialogAlignment.Center, + gridCount: 4, + customStyle: false, + cornerRadius: 25 + }) + //退出弹框 + exitDialog(){ + this.bookType = '' + } + //取消 + onCancel(){ + this.bookType = '' + } + //确定 + onAccept(){ + let isInsert = true + //对比bookType看是否BooTypeList数组中存在 + this.groupList.forEach((element:BookGroups) => { + if (element.groupName === this.bookType) { + showMessage(`已存${this.bookType}分组`) + this.bookType= '' + isInsert = false + } + }) + if(isInsert){ + let bookGroups = new BookGroups() + bookGroups.groupName = this.bookType + bookGroups.groupType = this.currentIndex + bookGroups.coverUrl = 'app.media.cover_list' + BookGroupsDao.insert(bookGroups) + this.bookType= '' + showMessage(`已添加${this.bookType}分组`) + setTimeout(()=>{ + this.BOOK_IS_BOOK_GROUPS_REFRESHING++ + this.getGroupList() + },500) + } + } + + //是否确认移动分组 + clickBookTypeDialog: CustomDialogController | null = new CustomDialogController({ + builder: TitleContentDialog({ + confirm: ()=> { + this.clickBookAccept() + }, + title:`移动分组至${this.bookType}` + }), + autoCancel: true, + alignment: DialogAlignment.Center, + gridCount: 4, + customStyle: false, + cornerRadius: 25, + }) + + clickBookAccept() { + BooksDao.updateBookGroup(this.booId,this.moveGroupId) + this.moveGroup() + } + +} \ No newline at end of file diff --git a/entry/src/main/ets/storage/bookListData.ets b/entry/src/main/ets/storage/bookListData.ets index 880a8ec1..49195c42 100644 --- a/entry/src/main/ets/storage/bookListData.ets +++ b/entry/src/main/ets/storage/bookListData.ets @@ -10,6 +10,7 @@ let KEY = '' export const initBookListData = ()=>{ AppStorage.setOrCreate(CommonConstants.BOOK_IS_BOOK_REFRESHING, 0) + AppStorage.setOrCreate(CommonConstants.BOOK_IS_BOOK_GROUPS_REFRESHING, 0) // AppStorage.setOrCreate(CommonConstants.PREFERENCES_BOOK_TYPE_NUMBER,0) AppStorage.setOrCreate(CommonConstants.KEY_NOVEL_BOOK_DATA,getBookData(0)) AppStorage.setOrCreate(CommonConstants.KEY_SOUND_BOOK_DATA,getBookData(1))