├── .gitignore ├── .idea ├── .gitignore ├── .name ├── AndroidProjectSystem.xml ├── appInsightsSettings.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── deploymentTargetDropDown.xml ├── deploymentTargetSelector.xml ├── gradle.xml ├── icon.png ├── kotlinc.xml ├── migrations.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── .kotlin └── errors │ ├── errors-1722920250294.log │ ├── errors-1723713939782.log │ └── errors-1740210508444.log ├── LICENSE ├── README.md ├── README ├── 1d.jpg ├── 1n.jpg ├── 2d.jpg ├── 2n.jpg ├── 3d.jpg ├── 3n.jpg └── logo.png ├── app ├── .gitignore ├── build.gradle.kts ├── lint-baseline.xml ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cyh128 │ │ └── hikari_novel │ │ └── ExampleInstrumentedTest.kt │ ├── debug │ └── res │ │ └── values │ │ └── strings.xml │ ├── key.jks │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ │ └── com │ │ │ └── cyh128 │ │ │ └── hikari_novel │ │ │ ├── HikariApp.kt │ │ │ ├── base │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseBottomSheetDialogFragment.kt │ │ │ └── BaseFragment.kt │ │ │ ├── data │ │ │ ├── di │ │ │ │ └── DatabaseModule.kt │ │ │ ├── model │ │ │ │ ├── AppTheme.kt │ │ │ │ ├── Bookshelf.kt │ │ │ │ ├── Comment.kt │ │ │ │ ├── DarkMode.kt │ │ │ │ ├── DefaultTab.kt │ │ │ │ ├── Event.kt │ │ │ │ ├── Exception.kt │ │ │ │ ├── HomeBlock.kt │ │ │ │ ├── HorizontalRead.kt │ │ │ │ ├── Language.kt │ │ │ │ ├── ListViewType.kt │ │ │ │ ├── LoadMode.kt │ │ │ │ ├── Novel.kt │ │ │ │ ├── NovelCover.kt │ │ │ │ ├── NovelInfo.kt │ │ │ │ ├── ReadChapter.kt │ │ │ │ ├── ReadParcel.kt │ │ │ │ ├── ReaderOrientation.kt │ │ │ │ ├── Response.kt │ │ │ │ ├── SearchMode.kt │ │ │ │ └── UserInfo.kt │ │ │ ├── repository │ │ │ │ ├── AppRepository.kt │ │ │ │ ├── BookshelfRepository.kt │ │ │ │ ├── HorizontalReadRepository.kt │ │ │ │ ├── ReadColorRepository.kt │ │ │ │ ├── SearchHistoryRepository.kt │ │ │ │ ├── VerticalReadRepository.kt │ │ │ │ ├── VisitHistoryRepository.kt │ │ │ │ └── Wenku8Repository.kt │ │ │ └── source │ │ │ │ ├── local │ │ │ │ ├── database │ │ │ │ │ ├── bookshelf │ │ │ │ │ │ ├── BookshelfDao.kt │ │ │ │ │ │ ├── BookshelfDatabase.kt │ │ │ │ │ │ └── BookshelfEntity.kt │ │ │ │ │ ├── read_history │ │ │ │ │ │ ├── BaseReadHistoryEntity.kt │ │ │ │ │ │ ├── horizontal_read_history │ │ │ │ │ │ │ ├── HorizontalReadHistoryDao.kt │ │ │ │ │ │ │ ├── HorizontalReadHistoryDatabase.kt │ │ │ │ │ │ │ └── HorizontalReadHistoryEntity.kt │ │ │ │ │ │ └── vertical_read_history │ │ │ │ │ │ │ ├── VerticalReadHistoryDao.kt │ │ │ │ │ │ │ ├── VerticalReadHistoryDatabase.kt │ │ │ │ │ │ │ └── VerticalReadHistoryEntity.kt │ │ │ │ │ ├── search_history │ │ │ │ │ │ ├── SearchHistoryDao.kt │ │ │ │ │ │ ├── SearchHistoryDatabase.kt │ │ │ │ │ │ └── SearchHistoryEntity.kt │ │ │ │ │ └── visit_history │ │ │ │ │ │ ├── VisitHistoryDao.kt │ │ │ │ │ │ ├── VisitHistoryDatabase.kt │ │ │ │ │ │ └── VisitHistoryEntity.kt │ │ │ │ └── mmkv │ │ │ │ │ ├── AppConfig.kt │ │ │ │ │ ├── BookshelfInfo.kt │ │ │ │ │ ├── HorizontalReadConfig.kt │ │ │ │ │ ├── LoginInfo.kt │ │ │ │ │ ├── ReadColorConfig.kt │ │ │ │ │ └── VerticalReadConfig.kt │ │ │ │ └── remote │ │ │ │ └── Network.kt │ │ │ ├── ui │ │ │ ├── detail │ │ │ │ ├── NovelChapterListAdapter.kt │ │ │ │ ├── NovelInfoActivity.kt │ │ │ │ ├── NovelInfoContentFragment.kt │ │ │ │ ├── NovelInfoViewModel.kt │ │ │ │ ├── TagChipAdapter.kt │ │ │ │ ├── comment │ │ │ │ │ ├── CommentActivity.kt │ │ │ │ │ ├── CommentListAdapter.kt │ │ │ │ │ ├── CommentViewModel.kt │ │ │ │ │ └── reply │ │ │ │ │ │ ├── ReplyFragment.kt │ │ │ │ │ │ ├── ReplyListAdapter.kt │ │ │ │ │ │ └── ReplyViewModel.kt │ │ │ │ └── user_bookshelf │ │ │ │ │ ├── UserBookshelfActivity.kt │ │ │ │ │ ├── UserBookshelfListAdapter.kt │ │ │ │ │ └── UserBookshelfViewModel.kt │ │ │ ├── main │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── MainViewModel.kt │ │ │ │ ├── NovelCoverListAdapter.kt │ │ │ │ ├── bookshelf │ │ │ │ │ ├── BookshelfContentFragment.kt │ │ │ │ │ ├── BookshelfFragment.kt │ │ │ │ │ ├── BookshelfListFragment.kt │ │ │ │ │ ├── BookshelfViewModel.kt │ │ │ │ │ └── search │ │ │ │ │ │ ├── BookshelfSearchActivity.kt │ │ │ │ │ │ ├── BookshelfSearchContentFragment.kt │ │ │ │ │ │ └── BookshelfSearchViewModel.kt │ │ │ │ ├── home │ │ │ │ │ ├── HomeFragment.kt │ │ │ │ │ ├── category │ │ │ │ │ │ ├── CategoryContentFragment.kt │ │ │ │ │ │ ├── CategoryFragment.kt │ │ │ │ │ │ └── CategoryViewModel.kt │ │ │ │ │ ├── completion │ │ │ │ │ │ ├── CompletionFragment.kt │ │ │ │ │ │ └── CompletionViewModel.kt │ │ │ │ │ ├── ranking │ │ │ │ │ │ ├── RankingContentFragment.kt │ │ │ │ │ │ ├── RankingFragment.kt │ │ │ │ │ │ └── RankingViewModel.kt │ │ │ │ │ ├── recommend │ │ │ │ │ │ ├── RecommendFragment.kt │ │ │ │ │ │ └── RecommendViewModel.kt │ │ │ │ │ └── search │ │ │ │ │ │ ├── SearchActivity.kt │ │ │ │ │ │ ├── SearchContentFragment.kt │ │ │ │ │ │ ├── SearchHistoryChipAdapter.kt │ │ │ │ │ │ └── SearchViewModel.kt │ │ │ │ ├── more │ │ │ │ │ ├── MoreFragment.kt │ │ │ │ │ └── more │ │ │ │ │ │ ├── about │ │ │ │ │ │ ├── AboutActivity.kt │ │ │ │ │ │ └── AboutViewModel.kt │ │ │ │ │ │ ├── account │ │ │ │ │ │ ├── AccountActivity.kt │ │ │ │ │ │ └── AccountViewModel.kt │ │ │ │ │ │ └── setting │ │ │ │ │ │ ├── SettingActivity.kt │ │ │ │ │ │ ├── SettingViewModel.kt │ │ │ │ │ │ └── ThemeListDialogFragment.kt │ │ │ │ └── visit_history │ │ │ │ │ ├── VisitHistoryContentFragment.kt │ │ │ │ │ ├── VisitHistoryFragment.kt │ │ │ │ │ ├── VisitHistoryListAdapter.kt │ │ │ │ │ └── VisitHistoryViewModel.kt │ │ │ ├── other │ │ │ │ ├── CrashActivity.kt │ │ │ │ ├── PhotoViewActivity.kt │ │ │ │ └── StateView.kt │ │ │ ├── read │ │ │ │ ├── SelectColorActivity.kt │ │ │ │ ├── SelectColorViewModel.kt │ │ │ │ ├── horizontal │ │ │ │ │ ├── IPageView.kt │ │ │ │ │ ├── PageImage.kt │ │ │ │ │ ├── PageLoading.kt │ │ │ │ │ ├── PageText.kt │ │ │ │ │ ├── PageView.kt │ │ │ │ │ ├── ReadActivity.kt │ │ │ │ │ └── ReadViewModel.kt │ │ │ │ └── vertical │ │ │ │ │ ├── ReadActivity.kt │ │ │ │ │ ├── ReadAdapter.kt │ │ │ │ │ ├── ReadFragment.kt │ │ │ │ │ └── ReadViewModel.kt │ │ │ └── splash │ │ │ │ ├── GuideFragment.kt │ │ │ │ ├── LoggingInFragment.kt │ │ │ │ ├── LoginActivity.kt │ │ │ │ ├── LoginErrorFragment.kt │ │ │ │ ├── LoginViewModel.kt │ │ │ │ ├── SplashActivity.kt │ │ │ │ └── SplashViewModel.kt │ │ │ └── util │ │ │ ├── Base64Helper.kt │ │ │ ├── Constants.kt │ │ │ ├── Extensions.kt │ │ │ ├── HttpCodeParser.kt │ │ │ ├── LanguageHelper.kt │ │ │ ├── ResourceUtil.kt │ │ │ ├── ThemeHelper.kt │ │ │ ├── TimeUtil.kt │ │ │ └── Wenku8Parser.kt │ └── res │ │ ├── anim │ │ ├── slide_in_left.xml │ │ ├── slide_in_right.xml │ │ ├── slide_out_left.xml │ │ └── slide_out_right.xml │ │ ├── drawable-night │ │ ├── app_logo.xml │ │ └── logo_header.xml │ │ ├── drawable-notnight │ │ ├── app_logo.xml │ │ └── logo_header.xml │ │ ├── drawable │ │ ├── app_logo_day.png │ │ ├── app_logo_night.png │ │ ├── applogo.xml │ │ ├── ic_account.xml │ │ ├── ic_arrow_back.xml │ │ ├── ic_arrow_down.xml │ │ ├── ic_arrow_forward.xml │ │ ├── ic_baseline_collections_bookmark.xml │ │ ├── ic_baseline_favorite.xml │ │ ├── ic_baseline_home.xml │ │ ├── ic_check_circle_fill.xml │ │ ├── ic_close.xml │ │ ├── ic_colorize.xml │ │ ├── ic_comment.xml │ │ ├── ic_contract.xml │ │ ├── ic_dark_mode.xml │ │ ├── ic_delete.xml │ │ ├── ic_delete_forever.xml │ │ ├── ic_delete_history.xml │ │ ├── ic_deselect.xml │ │ ├── ic_done_all.xml │ │ ├── ic_drive_file_move.xml │ │ ├── ic_edit.xml │ │ ├── ic_empty.xml │ │ ├── ic_error.xml │ │ ├── ic_event_available.xml │ │ ├── ic_experiment.xml │ │ ├── ic_filter.xml │ │ ├── ic_fullscreen.xml │ │ ├── ic_github.xml │ │ ├── ic_heat.xml │ │ ├── ic_help.xml │ │ ├── ic_history.xml │ │ ├── ic_info.xml │ │ ├── ic_keyboard_arrow_right.xml │ │ ├── ic_language.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_live_tv.xml │ │ ├── ic_login.xml │ │ ├── ic_logout.xml │ │ ├── ic_more.xml │ │ ├── ic_network_node.xml │ │ ├── ic_outline_collections_bookmark.xml │ │ ├── ic_outline_favorite.xml │ │ ├── ic_outline_home.xml │ │ ├── ic_page_control.xml │ │ ├── ic_palette.xml │ │ ├── ic_person.xml │ │ ├── ic_play.xml │ │ ├── ic_priority_high.xml │ │ ├── ic_reader.xml │ │ ├── ic_recommend.xml │ │ ├── ic_refresh.xml │ │ ├── ic_release_alert.xml │ │ ├── ic_schedule.xml │ │ ├── ic_search.xml │ │ ├── ic_select_all.xml │ │ ├── ic_selector_collections_bookmark.xml │ │ ├── ic_selector_home.xml │ │ ├── ic_setting.xml │ │ ├── ic_shelves.xml │ │ ├── ic_skip_next.xml │ │ ├── ic_skip_previous.xml │ │ ├── ic_sync.xml │ │ ├── ic_telegram.xml │ │ ├── ic_trending.xml │ │ ├── ic_tv_off.xml │ │ ├── ic_update.xml │ │ ├── ic_view.xml │ │ ├── ic_view_list.xml │ │ ├── ic_warning.xml │ │ ├── ic_web.xml │ │ ├── logo_header_day.png │ │ └── logo_header_night.png │ │ ├── layout │ │ ├── activity_about.xml │ │ ├── activity_account.xml │ │ ├── activity_bookshelf_search.xml │ │ ├── activity_comment.xml │ │ ├── activity_crash.xml │ │ ├── activity_horizontal_read.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_novel_info.xml │ │ ├── activity_photo_view.xml │ │ ├── activity_search.xml │ │ ├── activity_select_color.xml │ │ ├── activity_setting.xml │ │ ├── activity_splash.xml │ │ ├── activity_user_bookshelf.xml │ │ ├── activity_vertical_read.xml │ │ ├── fragment_bookshelf.xml │ │ ├── fragment_bookshelf_content.xml │ │ ├── fragment_bookshelf_list.xml │ │ ├── fragment_bookshelf_search.xml │ │ ├── fragment_category.xml │ │ ├── fragment_guide.xml │ │ ├── fragment_home.xml │ │ ├── fragment_logging_in.xml │ │ ├── fragment_login_error.xml │ │ ├── fragment_more.xml │ │ ├── fragment_novel_info_content.xml │ │ ├── fragment_novel_list.xml │ │ ├── fragment_ranking.xml │ │ ├── fragment_recommend.xml │ │ ├── fragment_reply.xml │ │ ├── fragment_vertical_read.xml │ │ ├── fragment_visit_history.xml │ │ ├── item_chapter_ccss.xml │ │ ├── item_chapter_vcss.xml │ │ ├── item_comment.xml │ │ ├── item_novel_cover_grid.xml │ │ ├── item_novel_cover_liner.xml │ │ ├── item_reply.xml │ │ ├── item_search_history.xml │ │ ├── item_simple_novel_cover.xml │ │ ├── item_tag.xml │ │ ├── item_vertical_read_image.xml │ │ ├── item_visit_history.xml │ │ ├── view_empty.xml │ │ ├── view_horizontal_read_config.xml │ │ ├── view_horizontal_read_guide.xml │ │ ├── view_loading.xml │ │ ├── view_message.xml │ │ ├── view_theme_list.xml │ │ └── view_vertical_read_config.xml │ │ ├── menu │ │ ├── menu_act_novel_info.xml │ │ ├── menu_act_v_h_read.xml │ │ ├── menu_act_visit_history.xml │ │ ├── menu_frag_all_novel.xml │ │ ├── menu_frag_bookshelf.xml │ │ ├── menu_frag_bookshelf_selection.xml │ │ ├── menu_frag_home.xml │ │ └── menu_nav_act_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ ├── colors_greenapple.xml │ │ ├── colors_lavender.xml │ │ ├── colors_midnightdusk.xml │ │ ├── colors_nord.xml │ │ ├── colors_strawberry.xml │ │ ├── colors_tako.xml │ │ ├── colors_tealturqoise.xml │ │ ├── colors_tidalwave.xml │ │ ├── colors_yinyang.xml │ │ ├── colors_yotsuba.xml │ │ └── themes.xml │ │ ├── values-v23 │ │ └── themes.xml │ │ ├── values-zh-rTW │ │ └── strings.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── colors_greenapple.xml │ │ ├── colors_lavender.xml │ │ ├── colors_midnightdusk.xml │ │ ├── colors_nord.xml │ │ ├── colors_strawberry.xml │ │ ├── colors_tako.xml │ │ ├── colors_tealturqoise.xml │ │ ├── colors_tidalwave.xml │ │ ├── colors_yinyang.xml │ │ ├── colors_yotsuba.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── cyh128 │ └── hikari_novel │ └── ExampleUnitTest.kt ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── hikari_novel.jks └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | HikariNovel -------------------------------------------------------------------------------- /.idea/AndroidProjectSystem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/appInsightsSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/deploymentTargetSelector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/.idea/icon.png -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.kotlin/errors/errors-1740210508444.log: -------------------------------------------------------------------------------- 1 | kotlin version: 2.0.21 2 | error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output: 3 | 1. Kotlin compile daemon is ready 4 | 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License (for the parts of the project under MIT License) 2 | 3 | Copyright (c) 2024 15dd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- 24 | 25 | Apache License 2.0 (for the parts of the project under Apache License 2.0) 26 | 27 | Copyright 2018 ya-b 28 | 29 | Licensed under the Apache License, Version 2.0 (the "License"); 30 | you may not use this file except in compliance with the License. 31 | You may obtain a copy of the License at 32 | 33 | http://www.apache.org/licenses/LICENSE-2.0 34 | 35 | Unless required by applicable law or agreed to in writing, software 36 | distributed under the License is distributed on an "AS IS" BASIS, 37 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 38 | See the License for the specific language governing permissions and 39 | limitations under the License. 40 | 41 | Modifications by 15dd on 2024 - 增加了图片支持,删除了用不到的函数以及变量,优化了手势检测,优化了分页算法 -------------------------------------------------------------------------------- /README/1d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/README/1d.jpg -------------------------------------------------------------------------------- /README/1n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/README/1n.jpg -------------------------------------------------------------------------------- /README/2d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/README/2d.jpg -------------------------------------------------------------------------------- /README/2n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/README/2n.jpg -------------------------------------------------------------------------------- /README/3d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/README/3d.jpg -------------------------------------------------------------------------------- /README/3n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/README/3n.jpg -------------------------------------------------------------------------------- /README/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/README/logo.png -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /debug 3 | /release 4 | /schemas -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/cyh128/hikari_novel/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("com.cyh128.hikari_novel", appContext.packageName) 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /app/src/debug/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | (DEBUG)Hikari Novel 4 | -------------------------------------------------------------------------------- /app/src/key.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/key.jks -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.base 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.viewbinding.ViewBinding 8 | import com.cyh128.hikari_novel.data.model.Event 9 | import com.cyh128.hikari_novel.util.LanguageHelper 10 | import com.cyh128.hikari_novel.util.ThemeHelper 11 | import com.drake.channel.receiveEvent 12 | import java.lang.reflect.ParameterizedType 13 | 14 | abstract class BaseActivity : AppCompatActivity() { 15 | lateinit var binding: VB 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | LanguageHelper.initLanguage() 19 | ThemeHelper.initActivityThemeAndDarkMode(this) 20 | 21 | receiveEvent("event_theme_changed") { 22 | recreateActivity() 23 | } 24 | 25 | super.onCreate(savedInstanceState) 26 | 27 | val type = javaClass.genericSuperclass as ParameterizedType 28 | val aClass = type.actualTypeArguments[0] as Class<*> 29 | val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java) 30 | @Suppress("UNCHECKED_CAST") 31 | binding = method.invoke(null, layoutInflater) as VB 32 | setContentView(binding.root) 33 | } 34 | 35 | private fun recreateActivity() { 36 | val intent = Intent(this, this::class.java) 37 | startActivity(intent) 38 | finish() 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/base/BaseBottomSheetDialogFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.base 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.viewbinding.ViewBinding 8 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment 9 | import java.lang.reflect.ParameterizedType 10 | 11 | abstract class BaseBottomSheetDialogFragment: BottomSheetDialogFragment() { 12 | private var _binding: VB? = null 13 | val binding get() = _binding!! 14 | 15 | override fun onCreateView( 16 | inflater: LayoutInflater, 17 | container: ViewGroup?, 18 | savedInstanceState: Bundle? 19 | ): View? { 20 | val type = javaClass.genericSuperclass as ParameterizedType 21 | val aClass = type.actualTypeArguments[0] as Class<*> 22 | val method = aClass.getDeclaredMethod( 23 | "inflate", 24 | LayoutInflater::class.java, 25 | ViewGroup::class.java, 26 | Boolean::class.java 27 | ) 28 | @Suppress("UNCHECKED_CAST") 29 | _binding = method.invoke(null, layoutInflater, container, false) as VB 30 | return binding.root 31 | } 32 | 33 | override fun onDestroyView() { 34 | super.onDestroyView() 35 | _binding = null 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.base 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.viewbinding.ViewBinding 9 | import java.lang.reflect.ParameterizedType 10 | 11 | abstract class BaseFragment : Fragment() { 12 | private var _binding: VB? = null 13 | val binding get() = _binding!! 14 | 15 | override fun onCreateView( 16 | inflater: LayoutInflater, 17 | container: ViewGroup?, 18 | savedInstanceState: Bundle? 19 | ): View? { 20 | val type = javaClass.genericSuperclass as ParameterizedType 21 | val aClass = type.actualTypeArguments[0] as Class<*> 22 | val method = aClass.getDeclaredMethod( 23 | "inflate", 24 | LayoutInflater::class.java, 25 | ViewGroup::class.java, 26 | Boolean::class.java 27 | ) 28 | @Suppress("UNCHECKED_CAST") 29 | _binding = method.invoke(null, layoutInflater, container, false) as VB 30 | return binding.root 31 | } 32 | 33 | override fun onDestroyView() { 34 | super.onDestroyView() 35 | _binding = null 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/AppTheme.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class AppTheme { 4 | Dynamic, 5 | GreenApple, 6 | Lavender, 7 | MidnightDusk, 8 | Nord, 9 | StrawberryDaiquiri, 10 | Tako, 11 | TealTurquoise, 12 | TidalWave, 13 | YinYang, 14 | Yotsuba 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/Bookshelf.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class Bookshelf( 4 | val list: List, 5 | val maxNum: Int 6 | ) 7 | 8 | data class BookshelfNovelInfo( 9 | val bid: String, 10 | val aid: String, 11 | val detailUrl: String, 12 | val title: String, 13 | val img: String, 14 | var isSelected: Boolean = false //多选模式用 15 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/Comment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class Comment( 4 | val replyUrl: String, 5 | val content: String, 6 | val viewCount: String, 7 | val replyCount: String, 8 | val userName: String, 9 | val uid: String, 10 | val time: String 11 | ) 12 | 13 | data class Reply( 14 | val content: String, 15 | val userName: String, 16 | val uid: String, 17 | val time: String 18 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/DarkMode.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class DarkMode { 4 | System, 5 | Enable, 6 | Disable 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/DefaultTab.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class DefaultTab { 4 | Home, 5 | Bookshelf, 6 | History, 7 | More 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/Event.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | sealed class Event { 4 | data object LoadSuccessEvent: Event() //加载内容成功 5 | data class NetworkErrorEvent(val msg: String?): Event() //网络错误 6 | data class VoteSuccessEvent(val msg: String?): Event() //投票成功 7 | data object InBookshelfEvent: Event() //此书在书架中 8 | data object NotInBookshelfEvent: Event() //此书不在书架中 9 | data object AddToBookshelfFailure: Event() //添加书架失败 10 | data object SearchInitSuccessEvent: Event() //初始化内容页面成功 11 | data object SearchResultEmptyEvent: Event() //搜索内容为空 12 | data object SearchLoadErrorCauseByInFiveSecondEvent: Event() //加载失败,因为5秒限制 13 | data object SearchInitErrorCauseByInFiveSecondEvent: Event() //初始化内容页面失败,因为5秒限制 14 | data object LogInSuccessEvent: Event() //登录成功 15 | data object LogInFailureEvent: Event() //登录失败 16 | data object AuthFailedEvent: Event() //验证失败事件(用户名或者密码错误) 17 | data object SignInSuccessEvent: Event() //签到成功 18 | data object SignInFailureEvent: Event() //签到失败 19 | data object TempSignInUnableEvent: Event() //临时签到不可用事件 20 | data object RefreshSearchHistoryEvent: Event() //刷新搜索记录事件 21 | 22 | data object RemoveNovelFromListEvent: Event() //从书架批量删除小说事件 23 | data object MoveNovelFromListEvent: Event() //从书架批量移动小说事件 24 | data object SelectAllEvent: Event() //选择全部书籍事件 25 | data object DeselectEvent: Event() //取消选择书籍事件 26 | data object ExitSelectionModeEvent: Event() //退出多选模式事件 27 | data object EditBookshelfEvent: Event() //编辑书架事件 28 | 29 | data class ChangeLineSpacingEvent(val value: Float): Event() //修改行距事件 30 | data class ChangeFontSizeEvent(val value: Float): Event() //修改字体大小事件 31 | 32 | data object HaveAvailableUpdateEvent: Event() //有更新 33 | data object NoAvailableUpdateEvent: Event() //无更新 34 | 35 | data object ThemeChangedEvent: Event() //主题颜色改变事件 36 | data object LanguageChantedEvent: Event() //语言改变事件 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/Exception.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | //网络错误异常 4 | class NetworkException(message: String?): Exception(message) 5 | 6 | //在五秒限制内异常 7 | class InFiveSecondException: Exception() 8 | 9 | //已签到异常 10 | class SignedInException: Exception() 11 | 12 | //临时登录签到异常 13 | class TempSignInException: Exception() -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/HomeBlock.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class HomeBlock( 4 | val title: String, 5 | val list: List 6 | ) 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/HorizontalRead.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class HorizontalRead( 4 | val title: String, 5 | val content: String, 6 | val imageList: List 7 | ) { 8 | companion object { 9 | fun empty() = HorizontalRead( 10 | "", 11 | "", 12 | mutableListOf() 13 | ) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/Language.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class Language { 4 | FOLLOW_SYSTEM, 5 | ZH_CN, 6 | ZH_TW 7 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/ListViewType.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class ListViewType { 4 | Linear, Grid 5 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/LoadMode.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class LoadMode { REFRESH, LOADMORE } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/Novel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | 6 | @Parcelize 7 | data class Chapter( 8 | val chapterTitle: String, 9 | val url: String, 10 | val cid: String 11 | ): Parcelable 12 | 13 | @Parcelize 14 | data class Volume( 15 | var volumeTitle: String, 16 | var chapters: List 17 | ): Parcelable { 18 | companion object { 19 | fun empty() = Volume( 20 | "", 21 | mutableListOf() 22 | ) 23 | } 24 | } 25 | 26 | @Parcelize 27 | data class Novel( 28 | val aid: String, 29 | val volume: List 30 | ): Parcelable -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/NovelCover.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class NovelCover( 4 | val title: String, 5 | val img: String, 6 | val detailUrl: String, 7 | val aid: String 8 | ) 9 | 10 | data class SimpleNovelCover( 11 | val title: String, 12 | val aid: String 13 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/NovelInfo.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class NovelInfo ( 4 | var title: String, 5 | var author: String, 6 | var status: String, 7 | var finUpdate: String, 8 | var imgUrl: String, 9 | var introduce: String, 10 | var tag: List, 11 | var heat: String, 12 | var trending: String, 13 | val isAnimated: Boolean 14 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/ReadChapter.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class ReadChapter( 4 | val volumePos: Int, 5 | val chapterPos: Int, 6 | val progress: String 7 | ) 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/ReadParcel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | import android.os.Parcelable 4 | import kotlinx.parcelize.Parcelize 5 | 6 | @Parcelize 7 | data class ReadParcel( 8 | val novel: Novel, 9 | val curVolumePos: Int, 10 | val curChapterPos: Int, 11 | val goToLatest: Boolean 12 | ): Parcelable -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/ReaderOrientation.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class ReaderOrientation { 4 | Vertical, Horizontal 5 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/Response.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class NovelCoverResponse( 4 | val maxNum: Int, 5 | val curPage: List 6 | ) 7 | 8 | data class ChapterContentResponse( 9 | val content: String, 10 | val image: List 11 | ) 12 | 13 | data class LoginResponse( 14 | var isUsernameCorrect: Boolean, 15 | var isPasswordCorrect: Boolean, 16 | var isCodeCorrect: Boolean, 17 | var isLoginSuccessful: Boolean 18 | ) { 19 | fun isCorrect() = isUsernameCorrect && isPasswordCorrect && isCodeCorrect 20 | 21 | companion object { 22 | fun empty() = LoginResponse( 23 | isUsernameCorrect = false, 24 | isPasswordCorrect = false, 25 | isCodeCorrect = false, 26 | isLoginSuccessful = false 27 | ) 28 | } 29 | } 30 | 31 | data class CommentResponse( 32 | var maxNum: Int, 33 | val list: MutableList 34 | ) { 35 | companion object { 36 | fun empty() = CommentResponse( 37 | -1, 38 | mutableListOf() 39 | ) 40 | } 41 | } 42 | 43 | data class ReplyResponse( 44 | var maxNum: Int, 45 | val curPage: MutableList 46 | ) { 47 | companion object { 48 | fun empty() = ReplyResponse( 49 | -1, 50 | mutableListOf() 51 | ) 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/SearchMode.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | enum class SearchMode { TITLE, AUTHOR } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/model/UserInfo.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.model 2 | 3 | data class UserInfo( 4 | val avatar: String, 5 | val userID: String, 6 | val username: String, 7 | val userLevel: String, 8 | val email: String, 9 | val registerDate: String, 10 | val contribution: String, 11 | val experience: String, 12 | val point: String, 13 | val maxBookshelfNum: String, 14 | val maxRecommendNum: String 15 | ) 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/repository/BookshelfRepository.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.repository 2 | 3 | import com.cyh128.hikari_novel.data.source.local.database.bookshelf.BookshelfDao 4 | import com.cyh128.hikari_novel.data.source.local.database.bookshelf.BookshelfEntity 5 | import com.cyh128.hikari_novel.data.source.local.mmkv.BookshelfInfo 6 | import javax.inject.Inject 7 | import javax.inject.Singleton 8 | 9 | @Singleton 10 | class BookshelfRepository @Inject constructor( 11 | private val bookshelfInfo: BookshelfInfo, 12 | private val bookshelfDao: BookshelfDao 13 | ) { 14 | suspend fun upsert(bookshelfEntity: BookshelfEntity) = bookshelfDao.upsert(bookshelfEntity) 15 | 16 | suspend fun upsertAll(list: List) = bookshelfDao.upsertAll(list) 17 | 18 | suspend fun updateClassId(aid: String, newClassId: Int) = bookshelfDao.updateClassId(aid, newClassId) 19 | 20 | suspend fun delete(aid: String) = bookshelfDao.delete(aid) 21 | 22 | suspend fun deleteAll() = bookshelfDao.deleteAll() 23 | 24 | fun getAll() = bookshelfDao.getAll() 25 | 26 | fun getByClassId(classId: Int) = bookshelfDao.getByClassId(classId) 27 | 28 | fun getByAid(aid: String) = bookshelfDao.getByAid(aid) 29 | 30 | fun setMaxCollection(value: Int) { 31 | bookshelfInfo.maxCollection = value 32 | } 33 | 34 | fun getMaxCollection() = bookshelfInfo.maxCollection 35 | } 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/repository/ReadColorRepository.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.repository 2 | 3 | import com.cyh128.hikari_novel.data.source.local.mmkv.ReadColorConfig 4 | import javax.inject.Inject 5 | import javax.inject.Singleton 6 | 7 | @Singleton 8 | class ReadColorRepository @Inject constructor( 9 | private val readColorConfig: ReadColorConfig 10 | ) { 11 | fun getTextColorDay() = readColorConfig.textColorDay 12 | 13 | fun setTextColorDay(color: String) { 14 | readColorConfig.textColorDay = color 15 | } 16 | 17 | fun getTextColorNight() = readColorConfig.textColorNight 18 | 19 | fun setTextColorNight(color: String) { 20 | readColorConfig.textColorNight = color 21 | } 22 | 23 | fun getBgColorDay() = readColorConfig.bgColorDay 24 | 25 | fun setBgColorDay(color: String) { 26 | readColorConfig.bgColorDay = color 27 | } 28 | 29 | fun getBgColorNight() = readColorConfig.bgColorNight 30 | 31 | fun setBgColorNight(color: String) { 32 | readColorConfig.bgColorNight = color 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/repository/SearchHistoryRepository.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.repository 2 | 3 | import com.cyh128.hikari_novel.data.source.local.database.search_history.SearchHistoryDao 4 | import com.cyh128.hikari_novel.data.source.local.database.search_history.SearchHistoryEntity 5 | import javax.inject.Inject 6 | import javax.inject.Singleton 7 | 8 | @Singleton 9 | class SearchHistoryRepository @Inject constructor( 10 | private val searchHistoryDao: SearchHistoryDao 11 | ) { 12 | suspend fun getAll() = searchHistoryDao.getAll() 13 | 14 | suspend fun addOrReplace(searchHistoryEntity: SearchHistoryEntity) = searchHistoryDao.upsert(searchHistoryEntity) 15 | 16 | suspend fun deleteAll() = searchHistoryDao.deleteAll() 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/repository/VisitHistoryRepository.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.repository 2 | 3 | import com.cyh128.hikari_novel.data.source.local.database.visit_history.VisitHistoryDao 4 | import com.cyh128.hikari_novel.data.source.local.database.visit_history.VisitHistoryEntity 5 | import javax.inject.Inject 6 | import javax.inject.Singleton 7 | 8 | @Singleton 9 | class VisitHistoryRepository @Inject constructor( 10 | private val visitHistoryDao: VisitHistoryDao 11 | ) { 12 | suspend fun add(visitHistoryEntity: VisitHistoryEntity) = visitHistoryDao.upsert(visitHistoryEntity) 13 | 14 | suspend fun delete(aid: String) = visitHistoryDao.delete(aid) 15 | 16 | suspend fun deleteAll() = visitHistoryDao.deleteAll() 17 | 18 | fun getAll() = visitHistoryDao.getAll() 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/bookshelf/BookshelfDao.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.bookshelf 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Insert 5 | import androidx.room.OnConflictStrategy 6 | import androidx.room.Query 7 | import kotlinx.coroutines.flow.Flow 8 | 9 | @Dao 10 | interface BookshelfDao { 11 | @Insert(onConflict = OnConflictStrategy.REPLACE) 12 | suspend fun upsert(bookshelfEntity: BookshelfEntity) 13 | 14 | @Insert(onConflict = OnConflictStrategy.REPLACE) 15 | suspend fun upsertAll(list: List) 16 | 17 | @Query("UPDATE bookshelf SET classid = (:newClassId) WHERE aid = (:aid)") 18 | suspend fun updateClassId(aid: String, newClassId: Int) 19 | 20 | @Query("DELETE FROM bookshelf WHERE aid = (:aid)") 21 | suspend fun delete(aid: String) 22 | 23 | @Query("DELETE FROM bookshelf") 24 | suspend fun deleteAll() 25 | 26 | @Query("SELECT * FROM bookshelf WHERE classid = (:classId)") 27 | fun getByClassId(classId: Int): Flow?> 28 | 29 | @Query("SELECT * FROM bookshelf") 30 | fun getAll(): Flow?> 31 | 32 | @Query("SELECT * FROM bookshelf WHERE aid = (:aid)") 33 | fun getByAid(aid: String): BookshelfEntity? 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/bookshelf/BookshelfDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.bookshelf 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | 6 | @Database(entities = [BookshelfEntity::class], version = 1) 7 | abstract class BookshelfDatabase: RoomDatabase() { 8 | abstract fun bookshelfDao(): BookshelfDao 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/bookshelf/BookshelfEntity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.bookshelf 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | 7 | @Entity(tableName = "bookshelf") 8 | data class BookshelfEntity( 9 | @PrimaryKey 10 | @ColumnInfo(name = "aid") 11 | val aid: String, 12 | 13 | @ColumnInfo(name = "bid") 14 | val bid: String, 15 | 16 | @ColumnInfo(name = "detail_url") 17 | val detailUrl: String, 18 | 19 | @ColumnInfo(name = "title") 20 | val title: String, 21 | 22 | @ColumnInfo(name = "img") 23 | val img: String, 24 | 25 | @ColumnInfo(name = "classid") 26 | val classId: Int 27 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/read_history/BaseReadHistoryEntity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.read_history 2 | 3 | abstract class BaseReadHistoryEntity( 4 | open val cid: String, 5 | open val aid: String, 6 | open val volume: Int, 7 | open val chapter: Int, 8 | open val location: Int, //保存阅读位置 9 | open val progressPercent: Int, 10 | open var isLatest: Boolean //是否为上次阅读的章节 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/read_history/horizontal_read_history/HorizontalReadHistoryDao.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.read_history.horizontal_read_history 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Query 5 | import androidx.room.Transaction 6 | import androidx.room.Upsert 7 | import kotlinx.coroutines.flow.Flow 8 | 9 | @Dao 10 | interface HorizontalReadHistoryDao { 11 | @Query("SELECT * FROM horizontal_read_history WHERE cid = (:cid)") 12 | fun getByCid(cid: String): Flow 13 | 14 | @Query("SELECT * FROM horizontal_read_history WHERE aid = (:aid) AND volume = (:volume)") 15 | fun getByVolume(aid: String, volume: Int): Flow?> 16 | 17 | @Transaction 18 | suspend fun addOrReplace( 19 | aid: String, 20 | horizontalReadHistoryEntity: HorizontalReadHistoryEntity 21 | ) { 22 | cancelLatestChapter(aid) 23 | upsert(horizontalReadHistoryEntity) 24 | } 25 | 26 | @Upsert 27 | suspend fun upsert(horizontalReadHistoryEntity: HorizontalReadHistoryEntity) 28 | 29 | @Query("SELECT * FROM horizontal_read_history WHERE aid = (:aid) AND is_latest = 1") 30 | fun getLatestChapter(aid: String): Flow 31 | 32 | @Query("UPDATE horizontal_read_history SET is_latest = 0 WHERE aid = (:aid) AND is_latest = 1") 33 | suspend fun cancelLatestChapter(aid: String) 34 | 35 | @Query("DELETE FROM horizontal_read_history WHERE cid = (:cid)") 36 | suspend fun delete(cid: String) 37 | 38 | @Query("DELETE FROM horizontal_read_history WHERE aid = (:aid)") 39 | suspend fun deleteAll(aid: String) 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/read_history/horizontal_read_history/HorizontalReadHistoryDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.read_history.horizontal_read_history 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | 6 | //version不要修改,除非做数据迁移Migration,否则数据会丢失 7 | @Database( 8 | entities = [HorizontalReadHistoryEntity::class], 9 | version = 1 10 | ) 11 | abstract class HorizontalReadHistoryDatabase: RoomDatabase() { 12 | abstract fun horizontalReadHistoryDao(): HorizontalReadHistoryDao 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/read_history/horizontal_read_history/HorizontalReadHistoryEntity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.read_history.horizontal_read_history 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import com.cyh128.hikari_novel.data.source.local.database.read_history.BaseReadHistoryEntity 7 | 8 | //名称和表的结构不要修改,除非做数据迁移Migration,否则数据会丢失 9 | @Entity(tableName = "horizontal_read_history") 10 | data class HorizontalReadHistoryEntity ( 11 | @PrimaryKey 12 | @ColumnInfo(name = "cid") 13 | override val cid: String, 14 | 15 | @ColumnInfo(name = "aid") 16 | override val aid: String, 17 | 18 | @ColumnInfo(name = "volume") 19 | override val volume: Int, 20 | 21 | @ColumnInfo(name = "chapter") 22 | override val chapter: Int, 23 | 24 | @ColumnInfo(name = "location") 25 | override val location: Int, //保存阅读位置 26 | 27 | @ColumnInfo(name = "progress_percent") 28 | override val progressPercent: Int, 29 | 30 | @ColumnInfo(name = "is_latest") 31 | override var isLatest: Boolean //是否为上次阅读的章节 32 | ): BaseReadHistoryEntity(cid, aid, volume, chapter, location, progressPercent, isLatest) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/read_history/vertical_read_history/VerticalReadHistoryDao.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.read_history.vertical_read_history 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Query 5 | import androidx.room.Transaction 6 | import androidx.room.Upsert 7 | import kotlinx.coroutines.flow.Flow 8 | 9 | @Dao 10 | interface VerticalReadHistoryDao { 11 | @Query("SELECT * FROM vertical_read_history WHERE cid = (:cid)") 12 | fun getByCid(cid: String): Flow 13 | 14 | @Query("SELECT * FROM vertical_read_history WHERE aid = (:aid) AND volume = (:volume)") 15 | fun getByVolume(aid: String, volume: Int): Flow?> 16 | 17 | @Transaction 18 | suspend fun addOrReplace( 19 | aid: String, 20 | verticalReadHistoryEntity: VerticalReadHistoryEntity 21 | ) { 22 | cancelLatestChapter(aid) 23 | upsert(verticalReadHistoryEntity) 24 | } 25 | 26 | @Upsert 27 | suspend fun upsert(verticalReadHistoryEntity: VerticalReadHistoryEntity) 28 | 29 | @Query("SELECT * FROM vertical_read_history WHERE aid = (:aid) AND is_latest = 1") 30 | fun getLatestChapter(aid: String): Flow 31 | 32 | @Query("UPDATE vertical_read_history SET is_latest = 0 WHERE aid = (:aid) AND is_latest = 1") 33 | suspend fun cancelLatestChapter(aid: String) 34 | 35 | @Query("DELETE FROM vertical_read_history WHERE cid = (:cid)") 36 | suspend fun delete(cid: String) 37 | 38 | @Query("DELETE FROM vertical_read_history WHERE aid = (:aid)") 39 | suspend fun deleteAll(aid: String) 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/read_history/vertical_read_history/VerticalReadHistoryDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.read_history.vertical_read_history 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | 6 | //version不要修改,除非做数据迁移Migration,否则数据会丢失 7 | @Database( 8 | entities = [VerticalReadHistoryEntity::class], 9 | version = 1 10 | ) 11 | abstract class VerticalReadHistoryDatabase: RoomDatabase() { 12 | abstract fun verticalReadHistoryDao(): VerticalReadHistoryDao 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/read_history/vertical_read_history/VerticalReadHistoryEntity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.read_history.vertical_read_history 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | import com.cyh128.hikari_novel.data.source.local.database.read_history.BaseReadHistoryEntity 7 | 8 | //名称和表的结构不要修改,除非做数据迁移Migration,否则数据会丢失 9 | @Entity(tableName = "vertical_read_history") 10 | data class VerticalReadHistoryEntity( 11 | @PrimaryKey 12 | @ColumnInfo(name = "cid") 13 | override val cid: String, 14 | 15 | @ColumnInfo(name = "aid") 16 | override val aid: String, 17 | 18 | @ColumnInfo(name = "volume") 19 | override val volume: Int, 20 | 21 | @ColumnInfo(name = "chapter") 22 | override val chapter: Int, 23 | 24 | @ColumnInfo(name = "location") 25 | override val location: Int, //保存阅读位置 26 | 27 | @ColumnInfo(name = "progress_percent") 28 | override val progressPercent: Int, 29 | 30 | @ColumnInfo(name = "is_latest") 31 | override var isLatest: Boolean //是否为上次阅读的章节 32 | ): BaseReadHistoryEntity(cid, aid, volume, chapter, location, progressPercent, isLatest) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/search_history/SearchHistoryDao.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.search_history 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Query 5 | import androidx.room.Upsert 6 | 7 | @Dao 8 | interface SearchHistoryDao { 9 | @Query("SELECT keyword FROM search_history") 10 | suspend fun getAll(): List? 11 | 12 | @Upsert 13 | suspend fun upsert(searchHistoryEntity: SearchHistoryEntity) 14 | 15 | @Query("DELETE FROM search_history") 16 | suspend fun deleteAll() 17 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/search_history/SearchHistoryDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.search_history 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | 6 | //version不要修改,除非做数据迁移Migration,否则数据会丢失 7 | @Database(entities = [SearchHistoryEntity::class], version = 1) 8 | abstract class SearchHistoryDatabase: RoomDatabase() { 9 | abstract fun searchHistoryDao(): SearchHistoryDao 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/search_history/SearchHistoryEntity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.search_history 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | 7 | //名称和表的结构不要修改,除非做数据迁移Migration,否则数据会丢失 8 | @Entity(tableName = "search_history") 9 | data class SearchHistoryEntity( 10 | @PrimaryKey 11 | @ColumnInfo(name = "keyword") 12 | val keyword: String 13 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/visit_history/VisitHistoryDao.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.visit_history 2 | 3 | import androidx.room.Dao 4 | import androidx.room.Insert 5 | import androidx.room.OnConflictStrategy 6 | import androidx.room.Query 7 | import kotlinx.coroutines.flow.Flow 8 | 9 | @Dao 10 | interface VisitHistoryDao { 11 | @Insert(onConflict = OnConflictStrategy.REPLACE) 12 | suspend fun upsert(vararg visitHistoryEntity: VisitHistoryEntity) 13 | 14 | @Query("DELETE FROM visit_history WHERE aid = (:aid)") 15 | suspend fun delete(aid: String) 16 | 17 | @Query("DELETE FROM visit_history") 18 | suspend fun deleteAll() 19 | 20 | @Query("SELECT * FROM visit_history") 21 | fun getAll(): Flow?> 22 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/visit_history/VisitHistoryDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.visit_history 2 | 3 | import androidx.room.Database 4 | import androidx.room.RoomDatabase 5 | 6 | //version不要修改,除非做数据迁移Migration,否则数据会丢失 7 | @Database(entities = [VisitHistoryEntity::class], version = 1) 8 | abstract class VisitHistoryDatabase: RoomDatabase() { 9 | abstract fun visitHistoryDao(): VisitHistoryDao 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/database/visit_history/VisitHistoryEntity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.database.visit_history 2 | 3 | import androidx.room.ColumnInfo 4 | import androidx.room.Entity 5 | import androidx.room.PrimaryKey 6 | 7 | @Entity(tableName = "visit_history") 8 | data class VisitHistoryEntity( 9 | @PrimaryKey 10 | @ColumnInfo(name = "aid") 11 | val aid: String, 12 | 13 | @ColumnInfo(name = "title") 14 | val title: String, 15 | 16 | @ColumnInfo(name = "img") 17 | val img: String, 18 | 19 | @ColumnInfo(name = "time") 20 | val time: String 21 | ) 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/mmkv/BookshelfInfo.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.mmkv 2 | 3 | import com.tencent.mmkv.MMKV 4 | import javax.inject.Inject 5 | import javax.inject.Singleton 6 | 7 | @Singleton 8 | class BookshelfInfo @Inject constructor() { 9 | private val cursor = MMKV.mmkvWithID("bookshelf_info") 10 | 11 | var maxCollection: Int 12 | get() = cursor.decodeInt("max_collection", -1) 13 | set(value) { 14 | cursor.encode("max_collection", value) 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/mmkv/LoginInfo.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.mmkv 2 | 3 | import com.tencent.mmkv.MMKV 4 | import javax.inject.Inject 5 | import javax.inject.Singleton 6 | 7 | @Singleton 8 | class LoginInfo @Inject constructor() { 9 | private val cursor = MMKV.mmkvWithID("loginInfo") 10 | 11 | var username: String? 12 | get() = cursor.decodeString("username") 13 | set(value) { 14 | cursor.encode("username",value) 15 | } 16 | 17 | var password: String? 18 | get() = cursor.decodeString("password") 19 | set(value) { 20 | cursor.encode("password",value) 21 | } 22 | 23 | var cookie: String? 24 | get() = cursor.decodeString("cookie") 25 | set(value) { 26 | cursor.encode("cookie",value) 27 | } 28 | 29 | //毫秒级时间戳 30 | var expDate: Long? 31 | get() = cursor.decodeLong("exp_date") 32 | set(value) { 33 | if (value != null) { 34 | cursor.encode("exp_date",value) 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/mmkv/ReadColorConfig.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.mmkv 2 | 3 | import com.tencent.mmkv.MMKV 4 | import javax.inject.Inject 5 | import javax.inject.Singleton 6 | 7 | @Singleton 8 | class ReadColorConfig @Inject constructor() { 9 | private val cursor = MMKV.mmkvWithID("read_color_config") 10 | 11 | var textColorDay: String 12 | get() = cursor.decodeString("text_color_day", "000000")!! 13 | set(value) { 14 | cursor.encode("text_color_day",value) 15 | } 16 | 17 | var textColorNight: String 18 | get() = cursor.decodeString("text_color_night","ffffff")!! 19 | set(value) { 20 | cursor.encode("text_color_night",value) 21 | } 22 | 23 | var bgColorDay: String 24 | get() = cursor.decodeString("bg_color_day","ffffff")!! 25 | set(value) { 26 | cursor.encode("bg_color_day",value) 27 | } 28 | 29 | var bgColorNight: String 30 | get() = cursor.decodeString("bg_color_night","000000")!! 31 | set(value) { 32 | cursor.encode("bg_color_night",value) 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/data/source/local/mmkv/VerticalReadConfig.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.data.source.local.mmkv 2 | 3 | import com.tencent.mmkv.MMKV 4 | import javax.inject.Inject 5 | import javax.inject.Singleton 6 | 7 | @Singleton 8 | class VerticalReadConfig @Inject constructor() { 9 | private val cursor = MMKV.mmkvWithID("vertical_read_config") 10 | 11 | var fontSize: Float 12 | get() = cursor.decodeFloat("font_size",16f) 13 | set(value) { 14 | cursor.encode("font_size",value) 15 | } 16 | 17 | var lineSpacing: Float 18 | get() = cursor.decodeFloat("line_spacing",1f) 19 | set(value) { 20 | cursor.encode("line_spacing",value) 21 | } 22 | 23 | var keepScreenOn: Boolean 24 | get() = cursor.decodeBool("keep_screen_on", false) 25 | set(value) { 26 | cursor.encode("keep_screen_on", value) 27 | } 28 | 29 | var isShowChapterReadHistory: Boolean 30 | get() = cursor.decodeBool("is_show_chapter_read_history", true) 31 | set(value) { 32 | cursor.encode("is_show_chapter_read_history", value) 33 | } 34 | 35 | var isShowChapterReadHistoryWithoutConfirm: Boolean 36 | get() = cursor.decodeBool("is_show_chapter_read_history_without_confirm", false) 37 | set(value) { 38 | cursor.encode("is_show_chapter_read_history_without_confirm", value) 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/detail/TagChipAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.detail 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.cyh128.hikari_novel.databinding.ItemTagBinding 7 | 8 | class TagChipAdapter( 9 | val list: List 10 | ): RecyclerView.Adapter() { 11 | inner class ViewHolder(val binding: ItemTagBinding): RecyclerView.ViewHolder(binding.root) 12 | 13 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = 14 | ViewHolder(ItemTagBinding.inflate(LayoutInflater.from(parent.context),parent,false)) 15 | 16 | override fun getItemCount(): Int = list.size 17 | 18 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 19 | holder.binding.cITag.apply { 20 | text = list[position] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/detail/comment/CommentListAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.detail.comment 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.cyh128.hikari_novel.data.model.Comment 7 | import com.cyh128.hikari_novel.databinding.ItemCommentBinding 8 | 9 | class CommentListAdapter( 10 | val list: List, 11 | val onItemClick: (replyUrl: String) -> Unit, 12 | val onUsernameClick: (uid: String) -> Unit 13 | ) : RecyclerView.Adapter() { 14 | inner class ViewHolder(val binding: ItemCommentBinding) : RecyclerView.ViewHolder(binding.root) 15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 16 | return ViewHolder( 17 | ItemCommentBinding.inflate( 18 | LayoutInflater.from(parent.context), 19 | parent, 20 | false 21 | ) 22 | ) 23 | } 24 | 25 | override fun getItemCount(): Int = list.size 26 | 27 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 28 | val item = list[position] 29 | holder.binding.apply { 30 | tvICommentUsername.text = item.userName 31 | tvICommentViewCount.text = item.viewCount 32 | tvICommentReplyCount.text = item.replyCount 33 | tvICommentComment.text = item.content 34 | tvICommentTime.text = item.time 35 | cvICommentUsername.setOnClickListener { 36 | onUsernameClick(item.uid) 37 | } 38 | root.setOnClickListener { 39 | onItemClick(item.replyUrl) 40 | } 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/detail/comment/CommentViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.detail.comment 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.cyh128.hikari_novel.data.model.Comment 6 | import com.cyh128.hikari_novel.data.model.Event 7 | import com.cyh128.hikari_novel.data.model.LoadMode 8 | import com.cyh128.hikari_novel.data.repository.Wenku8Repository 9 | import com.drake.channel.sendEvent 10 | import dagger.hilt.android.lifecycle.HiltViewModel 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.launch 13 | import javax.inject.Inject 14 | 15 | @HiltViewModel 16 | class CommentViewModel @Inject constructor( 17 | private val wenku8Repository: Wenku8Repository 18 | ) : ViewModel() { 19 | var isDialogShown = false 20 | 21 | private var maxNum: Int? = null 22 | val list = mutableListOf() 23 | 24 | lateinit var aid: String 25 | private var currentIndex: Int = 0 26 | 27 | fun getComment(mode: LoadMode) { 28 | viewModelScope.launch(Dispatchers.IO) { 29 | if (mode == LoadMode.REFRESH) { 30 | currentIndex = 0 31 | list.clear() 32 | } 33 | ++currentIndex 34 | wenku8Repository.getComment(aid, currentIndex) 35 | .onSuccess { success -> 36 | list.addAll(success.list) 37 | maxNum = success.maxNum 38 | sendEvent(Event.LoadSuccessEvent, "event_comment_activity") 39 | }.onFailure { failure -> 40 | --currentIndex 41 | sendEvent(Event.NetworkErrorEvent(failure.message), "event_comment_activity") 42 | } 43 | } 44 | } 45 | 46 | fun haveMore() = maxNum == null || currentIndex < maxNum!! 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/detail/comment/reply/ReplyListAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.detail.comment.reply 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.cyh128.hikari_novel.R 7 | import com.cyh128.hikari_novel.data.model.Reply 8 | import com.cyh128.hikari_novel.databinding.ItemReplyBinding 9 | import com.cyh128.hikari_novel.util.ResourceUtil 10 | 11 | class ReplyListAdapter( 12 | private val list: List, 13 | private val onUsernameClick: (uid: String) -> Unit 14 | ) : RecyclerView.Adapter() { 15 | inner class ViewHolder(val binding: ItemReplyBinding) : RecyclerView.ViewHolder(binding.root) 16 | 17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 18 | return ViewHolder( 19 | ItemReplyBinding.inflate( 20 | LayoutInflater.from(parent.context), 21 | parent, 22 | false 23 | ) 24 | ) 25 | } 26 | 27 | override fun getItemCount(): Int = list.size 28 | 29 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 30 | val item = list[position] 31 | holder.binding.apply { 32 | tvIReplyUsername.text = item.userName 33 | tvIReplyComment.text = item.content 34 | tvIReplyTime.text = item.time 35 | tvIReplyFloor.text = (position + 1).let { 36 | if (it == 1) return@let ResourceUtil.getString(R.string.content) 37 | else return@let "${it}${ResourceUtil.getString(R.string.floors)}" 38 | } 39 | cvIReplyUsername.setOnClickListener { 40 | onUsernameClick(item.uid) 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/detail/comment/reply/ReplyViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.detail.comment.reply 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.cyh128.hikari_novel.data.model.Event 6 | import com.cyh128.hikari_novel.data.model.Reply 7 | import com.cyh128.hikari_novel.data.repository.Wenku8Repository 8 | import com.drake.channel.sendEvent 9 | import dagger.hilt.android.lifecycle.HiltViewModel 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.launch 12 | import javax.inject.Inject 13 | 14 | @HiltViewModel 15 | class ReplyViewModel @Inject constructor( 16 | private val wenku8Repository: Wenku8Repository 17 | ) : ViewModel() { 18 | private var currentIndex: Int = 0 19 | var maxNum: Int? = null //总页数 20 | private set 21 | 22 | val pager: MutableList = mutableListOf() 23 | 24 | fun getReply(url: String) { 25 | viewModelScope.launch(Dispatchers.IO) { 26 | ++currentIndex 27 | wenku8Repository.getReply(url, currentIndex) 28 | .onSuccess { success -> 29 | pager.addAll(success.curPage) 30 | maxNum = success.maxNum 31 | sendEvent(Event.LoadSuccessEvent,"event_reply_fragment") 32 | }.onFailure { failure -> 33 | --currentIndex 34 | sendEvent(Event.NetworkErrorEvent(failure.message),"event_reply_fragment") 35 | } 36 | } 37 | } 38 | 39 | fun haveMore() = maxNum == null || currentIndex < maxNum!! 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/detail/user_bookshelf/UserBookshelfListAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.detail.user_bookshelf 2 | 3 | import android.view.LayoutInflater 4 | import android.view.ViewGroup 5 | import androidx.recyclerview.widget.RecyclerView 6 | import com.cyh128.hikari_novel.data.model.SimpleNovelCover 7 | import com.cyh128.hikari_novel.databinding.ItemSimpleNovelCoverBinding 8 | 9 | class UserBookshelfListAdapter( 10 | val list: List, 11 | val onItemClick: (aid: String) -> Unit 12 | ): RecyclerView.Adapter() { 13 | inner class ViewHolder(val binding: ItemSimpleNovelCoverBinding): RecyclerView.ViewHolder(binding.root) 14 | 15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = 16 | ViewHolder( 17 | ItemSimpleNovelCoverBinding.inflate( 18 | LayoutInflater.from(parent.context), 19 | parent, 20 | false 21 | ) 22 | ) 23 | 24 | override fun getItemCount(): Int = list.size 25 | 26 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 27 | val item = list[position] 28 | holder.binding.apply { 29 | tvISimpleNovelCover.text = item.title 30 | 31 | root.setOnClickListener { 32 | onItemClick(item.aid) 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/detail/user_bookshelf/UserBookshelfViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.detail.user_bookshelf 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.cyh128.hikari_novel.data.model.Event 6 | import com.cyh128.hikari_novel.data.model.SimpleNovelCover 7 | import com.cyh128.hikari_novel.data.repository.Wenku8Repository 8 | import com.drake.channel.sendEvent 9 | import dagger.hilt.android.lifecycle.HiltViewModel 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.launch 12 | import javax.inject.Inject 13 | 14 | @HiltViewModel 15 | class UserBookshelfViewModel @Inject constructor( 16 | private val wenku8Repository: Wenku8Repository 17 | ): ViewModel() { 18 | lateinit var uid: String 19 | val list = mutableListOf() 20 | 21 | fun getUserBookshelf() { 22 | viewModelScope.launch(Dispatchers.IO) { 23 | list.clear() 24 | wenku8Repository.getBookshelfFromUser(uid) 25 | .onSuccess { success -> 26 | list.addAll(success) 27 | sendEvent(Event.LoadSuccessEvent, "event_user_bookshelf_activity") 28 | }.onFailure { failure -> 29 | sendEvent(Event.NetworkErrorEvent(failure.message), "event_user_bookshelf_activity") 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.cyh128.hikari_novel.data.model.Event 6 | import com.cyh128.hikari_novel.data.repository.AppRepository 7 | import com.drake.channel.sendEvent 8 | import dagger.hilt.android.lifecycle.HiltViewModel 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.launch 11 | import javax.inject.Inject 12 | 13 | @HiltViewModel 14 | class MainViewModel @Inject constructor( 15 | private val appRepository: AppRepository 16 | ) : ViewModel() { 17 | val isAutoUpdate get() = appRepository.getIsAutoUpdate() 18 | 19 | val defaultTab get() = appRepository.getDefaultTab() 20 | 21 | fun checkUpdate() { 22 | viewModelScope.launch(Dispatchers.IO) { 23 | appRepository.checkUpdate() 24 | .onSuccess { 25 | if (it) sendEvent(Event.HaveAvailableUpdateEvent,"event_main_activity") 26 | else sendEvent(Event.NoAvailableUpdateEvent,"event_main_activity") 27 | }.onFailure { 28 | sendEvent(Event.NetworkErrorEvent(it.message),"event_main_activity") 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/bookshelf/search/BookshelfSearchContentFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.bookshelf.search 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.lifecycle.ViewModelProvider 6 | import androidx.recyclerview.widget.GridLayoutManager 7 | import androidx.recyclerview.widget.LinearLayoutManager 8 | import com.cyh128.hikari_novel.base.BaseFragment 9 | import com.cyh128.hikari_novel.data.model.ListViewType 10 | import com.cyh128.hikari_novel.databinding.FragmentNovelListBinding 11 | import com.cyh128.hikari_novel.ui.detail.NovelInfoActivity 12 | import com.cyh128.hikari_novel.ui.main.NovelCoverListAdapter 13 | import com.cyh128.hikari_novel.util.startActivity 14 | import dagger.hilt.android.AndroidEntryPoint 15 | 16 | @AndroidEntryPoint 17 | class BookshelfSearchContentFragment: BaseFragment() { 18 | private val viewModel by lazy { ViewModelProvider(requireActivity())[BookshelfSearchViewModel::class] } 19 | 20 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 21 | super.onViewCreated(view, savedInstanceState) 22 | 23 | val adapter = NovelCoverListAdapter(viewModel.searchList, viewModel.listViewType) { aid -> 24 | startActivity { 25 | putExtra("aid", aid) 26 | } 27 | } 28 | binding.rvFNovelList.apply { 29 | layoutManager = if (viewModel.listViewType == ListViewType.Linear) LinearLayoutManager(context) else GridLayoutManager(context, 3) 30 | this.adapter = adapter 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/bookshelf/search/BookshelfSearchViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.bookshelf.search 2 | 3 | import androidx.lifecycle.ViewModel 4 | import com.cyh128.hikari_novel.data.model.NovelCover 5 | import com.cyh128.hikari_novel.data.repository.AppRepository 6 | import com.cyh128.hikari_novel.data.repository.BookshelfRepository 7 | import dagger.hilt.android.lifecycle.HiltViewModel 8 | import javax.inject.Inject 9 | 10 | @HiltViewModel 11 | class BookshelfSearchViewModel @Inject constructor( 12 | private val bookshelfRepository: BookshelfRepository, 13 | private val appRepository: AppRepository 14 | ): ViewModel() { 15 | var getAllFlow = bookshelfRepository.getAll() 16 | 17 | val searchList = mutableListOf() 18 | 19 | val listViewType get() = appRepository.getListViewType() 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/home/ranking/RankingFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.home.ranking 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import com.cyh128.hikari_novel.R 6 | import com.cyh128.hikari_novel.base.BaseFragment 7 | import com.cyh128.hikari_novel.databinding.FragmentRankingBinding 8 | import dagger.hilt.android.AndroidEntryPoint 9 | 10 | @AndroidEntryPoint 11 | class RankingFragment: BaseFragment() { 12 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 13 | super.onViewCreated(view, savedInstanceState) 14 | binding.actFRanking.setOnItemClickListener { parent, _, position, _ -> 15 | childFragmentManager.beginTransaction().replace( 16 | R.id.fcv_f_ranking, 17 | RankingContentFragment().apply { 18 | arguments = Bundle().apply { putString("ranking", parent.getItemAtPosition(position) as String) } 19 | } 20 | ).commit() 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/home/recommend/RecommendViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.home.recommend 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.cyh128.hikari_novel.data.model.Event 6 | import com.cyh128.hikari_novel.data.model.HomeBlock 7 | import com.cyh128.hikari_novel.data.repository.AppRepository 8 | import com.cyh128.hikari_novel.data.repository.Wenku8Repository 9 | import com.drake.channel.sendEvent 10 | import dagger.hilt.android.lifecycle.HiltViewModel 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.launch 13 | import javax.inject.Inject 14 | 15 | @HiltViewModel 16 | class RecommendViewModel @Inject constructor( 17 | private val wenku8Repository: Wenku8Repository, 18 | private val appRepository: AppRepository 19 | ) : ViewModel() { 20 | var homeBlockList: List? = null 21 | 22 | val listViewType get() = appRepository.getListViewType() 23 | 24 | fun getData() { 25 | viewModelScope.launch(Dispatchers.IO) { 26 | wenku8Repository.getRecommend() 27 | .onSuccess { success -> 28 | homeBlockList = success 29 | sendEvent(Event.LoadSuccessEvent, "event_recommend_view_model") 30 | }.onFailure { failure -> 31 | sendEvent(Event.NetworkErrorEvent(failure.message), "event_recommend_view_model") 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/home/search/SearchHistoryChipAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.home.search 2 | 3 | import android.content.Context 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.cyh128.hikari_novel.databinding.ItemSearchHistoryBinding 8 | 9 | class SearchHistoryChipAdapter( 10 | val list: MutableList, 11 | val onItemClick: (text: String) -> Unit 12 | ) : RecyclerView.Adapter() { 13 | 14 | inner class ViewHolder( 15 | val context: Context, 16 | val binding: ItemSearchHistoryBinding 17 | ) : RecyclerView.ViewHolder(binding.root) 18 | 19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = 20 | ViewHolder( 21 | parent.context, 22 | ItemSearchHistoryBinding.inflate( 23 | LayoutInflater.from(parent.context), 24 | parent, 25 | false 26 | ) 27 | ) 28 | 29 | override fun getItemCount(): Int = list.size 30 | 31 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 32 | val tempText = list[position] 33 | holder.binding.cISearchHistory.apply { 34 | text = tempText 35 | setOnClickListener { 36 | onItemClick(tempText) 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/more/MoreFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.more 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import com.cyh128.hikari_novel.base.BaseFragment 6 | import com.cyh128.hikari_novel.databinding.FragmentMoreBinding 7 | import com.cyh128.hikari_novel.ui.main.more.more.about.AboutActivity 8 | import com.cyh128.hikari_novel.ui.main.more.more.account.AccountActivity 9 | import com.cyh128.hikari_novel.ui.main.more.more.setting.SettingActivity 10 | import com.cyh128.hikari_novel.util.startActivity 11 | import dagger.hilt.android.AndroidEntryPoint 12 | 13 | @AndroidEntryPoint 14 | class MoreFragment: BaseFragment() { 15 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 16 | super.onViewCreated(view, savedInstanceState) 17 | binding.llFMoreAccount.setOnClickListener { 18 | startActivity() 19 | } 20 | binding.llFMoreSetting.setOnClickListener { 21 | startActivity() 22 | } 23 | binding.llFMoreAbout.setOnClickListener { 24 | startActivity() 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/more/more/about/AboutViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.more.more.about 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.cyh128.hikari_novel.data.model.Event 6 | import com.cyh128.hikari_novel.data.repository.AppRepository 7 | import com.drake.channel.sendEvent 8 | import dagger.hilt.android.lifecycle.HiltViewModel 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.launch 11 | import javax.inject.Inject 12 | 13 | @HiltViewModel 14 | class AboutViewModel @Inject constructor( 15 | private val appRepository: AppRepository 16 | ): ViewModel(){ 17 | fun checkUpdate() { 18 | viewModelScope.launch(Dispatchers.IO) { 19 | appRepository.checkUpdate() 20 | .onSuccess { 21 | if (it) sendEvent(Event.HaveAvailableUpdateEvent,"event_about_activity") 22 | else sendEvent(Event.NoAvailableUpdateEvent, "event_about_activity") 23 | }.onFailure { 24 | sendEvent(Event.NetworkErrorEvent(it.message),"event_about_activity") 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/visit_history/VisitHistoryContentFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.visit_history 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.lifecycle.ViewModelProvider 6 | import androidx.recyclerview.widget.LinearLayoutManager 7 | import com.cyh128.hikari_novel.base.BaseFragment 8 | import com.cyh128.hikari_novel.databinding.FragmentNovelListBinding 9 | import com.cyh128.hikari_novel.util.launchWithLifecycle 10 | import dagger.hilt.android.AndroidEntryPoint 11 | 12 | @AndroidEntryPoint 13 | class VisitHistoryContentFragment: BaseFragment() { 14 | private val viewModel by lazy { ViewModelProvider(requireActivity())[VisitHistoryViewModel::class.java] } 15 | private lateinit var visitHistoryListAdapter: VisitHistoryListAdapter 16 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 17 | super.onViewCreated(view, savedInstanceState) 18 | 19 | visitHistoryListAdapter = VisitHistoryListAdapter { aid -> 20 | viewModel.delete(aid) 21 | } 22 | 23 | binding.rvFNovelList.apply { 24 | adapter = visitHistoryListAdapter 25 | layoutManager = LinearLayoutManager(context) 26 | } 27 | binding.srlFNovelList.isEnabled = false 28 | 29 | launchWithLifecycle { 30 | viewModel.visitHistoryFlow.collect { 31 | visitHistoryListAdapter.updateData(it) 32 | visitHistoryListAdapter.notifyDataSetChanged() 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/main/visit_history/VisitHistoryViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.main.visit_history 2 | 3 | import androidx.lifecycle.ViewModel 4 | import androidx.lifecycle.viewModelScope 5 | import com.cyh128.hikari_novel.data.repository.VisitHistoryRepository 6 | import dagger.hilt.android.lifecycle.HiltViewModel 7 | import kotlinx.coroutines.CoroutineScope 8 | import kotlinx.coroutines.Dispatchers 9 | import kotlinx.coroutines.flow.SharingStarted 10 | import kotlinx.coroutines.flow.shareIn 11 | import kotlinx.coroutines.launch 12 | import javax.inject.Inject 13 | 14 | @HiltViewModel 15 | class VisitHistoryViewModel @Inject constructor( 16 | private val visitHistoryRepository: VisitHistoryRepository 17 | ) : ViewModel() { 18 | val visitHistoryFlow get() = visitHistoryRepository.getAll().shareIn( 19 | scope = CoroutineScope(Dispatchers.IO), 20 | started = SharingStarted.Lazily, 21 | replay = 0 22 | ) 23 | 24 | fun deleteAllHistory() { 25 | viewModelScope.launch(Dispatchers.IO) { 26 | visitHistoryRepository.deleteAll() 27 | } 28 | } 29 | 30 | fun delete(aid: String) { 31 | viewModelScope.launch(Dispatchers.IO) { 32 | visitHistoryRepository.delete(aid) 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/other/CrashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.other 2 | 3 | import android.os.Bundle 4 | import com.cyh128.hikari_novel.base.BaseActivity 5 | import com.cyh128.hikari_novel.databinding.ActivityCrashBinding 6 | import com.cyh128.hikari_novel.ui.main.more.more.setting.SettingActivity 7 | import com.cyh128.hikari_novel.util.openUrl 8 | import com.cyh128.hikari_novel.util.startActivity 9 | import com.developer.crashx.CrashActivity 10 | 11 | class CrashActivity: BaseActivity() { 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | 15 | binding.tvACrashErrorMsg.text = CrashActivity.getAllErrorDetailsFromIntent(this,intent) 16 | binding.bACrashRestart.setOnClickListener { 17 | CrashActivity.restartApplication(this,CrashActivity.getConfigFromIntent(intent)) 18 | } 19 | binding.bACrashReport.setOnClickListener { 20 | openUrl("https://github.com/15dd/wenku8reader/issues") 21 | } 22 | binding.bACrashSetting.setOnClickListener { 23 | startActivity() 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/other/StateView.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.other 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import com.cyh128.hikari_novel.base.BaseFragment 6 | import com.cyh128.hikari_novel.databinding.ViewEmptyBinding 7 | import com.cyh128.hikari_novel.databinding.ViewLoadingBinding 8 | import com.cyh128.hikari_novel.databinding.ViewMessageBinding 9 | 10 | class EmptyView: BaseFragment() 11 | 12 | class LoadingView: BaseFragment() 13 | 14 | class MessageView: BaseFragment() { 15 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 16 | super.onViewCreated(view, savedInstanceState) 17 | binding.tvVMessage.text = requireArguments().getString("msg") 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/read/SelectColorViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.read 2 | 3 | import androidx.lifecycle.ViewModel 4 | import com.cyh128.hikari_novel.data.repository.ReadColorRepository 5 | import dagger.hilt.android.lifecycle.HiltViewModel 6 | import javax.inject.Inject 7 | 8 | @HiltViewModel 9 | class SelectColorViewModel @Inject constructor( 10 | private val readColorRepository: ReadColorRepository 11 | ): ViewModel() { 12 | fun getTextColorDay() = readColorRepository.getTextColorDay() 13 | 14 | fun setTextColorDay(color: String) = readColorRepository.setTextColorDay(color) 15 | 16 | fun getTextColorNight() = readColorRepository.getTextColorNight() 17 | 18 | fun setTextColorNight(color: String) = readColorRepository.setTextColorNight(color) 19 | 20 | fun getBgColorDay() = readColorRepository.getBgColorDay() 21 | 22 | fun setBgColorDay(color: String) = readColorRepository.setBgColorDay(color) 23 | 24 | fun getBgColorNight() = readColorRepository.getBgColorNight() 25 | 26 | fun setBgColorNight(color: String) = readColorRepository.setBgColorNight(color) 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/splash/GuideFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.splash 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.lifecycle.ViewModelProvider 6 | import com.cyh128.hikari_novel.R 7 | import com.cyh128.hikari_novel.base.BaseFragment 8 | import com.cyh128.hikari_novel.databinding.FragmentGuideBinding 9 | import com.cyh128.hikari_novel.util.openUrl 10 | import com.cyh128.hikari_novel.util.startActivity 11 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 12 | import dagger.hilt.android.AndroidEntryPoint 13 | 14 | @AndroidEntryPoint 15 | class GuideFragment: BaseFragment() { 16 | private val viewModel by lazy { ViewModelProvider(requireActivity())[SplashViewModel::class.java] } 17 | 18 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 19 | super.onViewCreated(view, savedInstanceState) 20 | 21 | binding.cbFGuideAccept.setOnCheckedChangeListener { _, isChecked -> 22 | binding.bFGuideGoOn.isEnabled = isChecked 23 | } 24 | 25 | binding.bFGuideGoOn.setOnClickListener { 26 | if (binding.cbFGuideAccept.isChecked) { 27 | startActivity() 28 | viewModel.setIsFirstLaunch(false) 29 | } 30 | } 31 | 32 | binding.bFGuideDisclaimers.setOnClickListener { 33 | MaterialAlertDialogBuilder(requireContext()) 34 | .setIcon(R.drawable.ic_contract) 35 | .setTitle(R.string.disclaimers) 36 | .setMessage(R.string.disclaimers_message) 37 | .setPositiveButton(R.string.ok) { _, _ -> } 38 | .show() 39 | } 40 | 41 | binding.bFGuideUsingHelp.setOnClickListener { 42 | openUrl("https://github.com/15dd/wenku8reader/wiki") 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/splash/LoggingInFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.splash 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.lifecycle.ViewModelProvider 6 | import com.cyh128.hikari_novel.base.BaseFragment 7 | import com.cyh128.hikari_novel.databinding.FragmentLoggingInBinding 8 | import dagger.hilt.android.AndroidEntryPoint 9 | 10 | @AndroidEntryPoint 11 | class LoggingInFragment: BaseFragment() { 12 | private val viewModel by lazy { ViewModelProvider(requireActivity())[SplashViewModel::class.java] } 13 | 14 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 15 | super.onViewCreated(view, savedInstanceState) 16 | 17 | viewModel.loggingInText.observe(viewLifecycleOwner) { 18 | binding.tvFLoggingIn.text = it 19 | } 20 | } 21 | 22 | override fun onDestroyView() { 23 | binding.liFLoggingIn.clearAnimation() //防止内存泄漏 24 | super.onDestroyView() 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/ui/splash/LoginErrorFragment.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.ui.splash 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.lifecycle.ViewModelProvider 6 | import com.cyh128.hikari_novel.R 7 | import com.cyh128.hikari_novel.base.BaseFragment 8 | import com.cyh128.hikari_novel.databinding.FragmentLoginErrorBinding 9 | import com.cyh128.hikari_novel.ui.main.more.more.setting.SettingActivity 10 | import com.cyh128.hikari_novel.util.startActivity 11 | import dagger.hilt.android.AndroidEntryPoint 12 | 13 | @AndroidEntryPoint 14 | class LoginErrorFragment : BaseFragment() { 15 | private val viewModel by lazy { ViewModelProvider(requireActivity())[SplashViewModel::class.java] } 16 | 17 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 18 | super.onViewCreated(view, savedInstanceState) 19 | binding.bFLoginError.setOnClickListener { 20 | viewModel.setLoggingInText(getString(R.string.logging)) 21 | (requireActivity() as SplashActivity).startFragment() 22 | viewModel.isOnline() 23 | } 24 | binding.tvFLoginError.text = requireArguments().getString("msg") 25 | 26 | binding.bFLoginErrorSetting.setOnClickListener { 27 | startActivity() 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/util/Base64Helper.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.util 2 | 3 | import android.util.Base64 4 | import java.nio.charset.Charset 5 | 6 | object Base64Helper { 7 | private fun encodeBase64(b: ByteArray): String { 8 | return Base64.encodeToString(b, Base64.DEFAULT).trim { it <= ' ' } 9 | } 10 | 11 | fun encodeBase64(s: String): String { 12 | return encodeBase64(s.toByteArray(Charset.forName("UTF-8"))) 13 | } 14 | 15 | private fun decodeBase64(s: String): ByteArray { 16 | try { 17 | val b = Base64.decode(s, Base64.DEFAULT) 18 | return b 19 | } catch (e: IllegalArgumentException) { 20 | return ByteArray(0) 21 | } 22 | } 23 | 24 | fun decodeBase64String(s: String): String { 25 | return String(decodeBase64(s), Charset.forName("UTF-8")) 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/util/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.util 2 | 3 | object Constants { 4 | var isUpdateChecked = false 5 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/util/HttpCodeParser.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.util 2 | 3 | import com.cyh128.hikari_novel.HikariApp 4 | import com.cyh128.hikari_novel.R 5 | 6 | object HttpCodeParser { 7 | fun parser(code: Int): String = when { 8 | code == 403 -> HikariApp.application.getString(R.string.http_code_403) 9 | code/100 == 5 -> HikariApp.application.getString(R.string.http_code_5xx) 10 | else -> "http status code:" 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/util/LanguageHelper.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.util 2 | 3 | import androidx.appcompat.app.AppCompatDelegate 4 | import androidx.core.os.LocaleListCompat 5 | import com.cyh128.hikari_novel.data.model.Event 6 | import com.cyh128.hikari_novel.data.model.Language 7 | import com.drake.channel.sendEvent 8 | 9 | object LanguageHelper { 10 | private lateinit var currentLanguage: Language 11 | 12 | fun setCurrentLanguage(language: Language) { 13 | currentLanguage = language 14 | sendEvent(Event.LanguageChantedEvent, "event_language_changed") 15 | } 16 | 17 | fun initLanguage() { 18 | val locale = when (currentLanguage) { 19 | Language.FOLLOW_SYSTEM -> LocaleListCompat.getEmptyLocaleList() 20 | Language.ZH_CN -> LocaleListCompat.forLanguageTags("zh-cn") 21 | Language.ZH_TW -> LocaleListCompat.forLanguageTags("zh-tw") 22 | } 23 | AppCompatDelegate.setApplicationLocales(locale) 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/util/ResourceUtil.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.util 2 | 3 | import androidx.annotation.StringRes 4 | import com.cyh128.hikari_novel.HikariApp 5 | 6 | object ResourceUtil { 7 | fun getString(@StringRes res: Int): String { 8 | return HikariApp.application.getString(res) 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cyh128/hikari_novel/util/TimeUtil.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel.util 2 | 3 | import android.text.format.DateUtils 4 | import java.text.SimpleDateFormat 5 | import java.util.Date 6 | import java.util.Locale 7 | 8 | object TimeUtil { 9 | //20xx-01-01 00:00:00转换成xx天前 10 | fun dateToText1(dateStr: String): String { 11 | val pattern = "yyyy-MM-dd HH:mm:ss" 12 | val simpleDateFormat = SimpleDateFormat(pattern, Locale.getDefault()) 13 | val date = simpleDateFormat.parse(dateStr)!! 14 | return DateUtils.getRelativeTimeSpanString(date.time).toString() 15 | } 16 | 17 | //20xx-01-01转换成xx天前 18 | fun dateToText2(dateStr: String): String { 19 | val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) 20 | val date: Date = dateFormat.parse(dateStr)!! 21 | val timeInMillis: Long = date.time 22 | return DateUtils.getRelativeTimeSpanString( 23 | timeInMillis, 24 | System.currentTimeMillis(), 25 | DateUtils.DAY_IN_MILLIS 26 | ).toString() 27 | } 28 | 29 | fun getTimeToken(): String = SimpleDateFormat( 30 | "yyyy/MM/dd HH:mm:ss", 31 | Locale.getDefault() 32 | ).format(System.currentTimeMillis()) 33 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-night/app_logo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-night/logo_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-notnight/app_logo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-notnight/logo_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_logo_day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/drawable/app_logo_day.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/app_logo_night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/drawable/app_logo_night.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_account.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_forward.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_collections_bookmark.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_favorite.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_home.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check_circle_fill.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_colorize.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_comment.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_contract.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dark_mode.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_forever.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_history.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_deselect.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done_all.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_drive_file_move.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_edit.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_empty.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_error.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_event_available.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_experiment.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_filter.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fullscreen.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_heat.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_help.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_history.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_keyboard_arrow_right.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_language.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_live_tv.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_login.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_logout.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_network_node.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_collections_bookmark.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_favorite.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_outline_home.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_page_control.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_palette.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_priority_high.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reader.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_recommend.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_release_alert.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_schedule.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_select_all.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_selector_collections_bookmark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_selector_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_setting.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_shelves.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_skip_next.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_skip_previous.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sync.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_telegram.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_trending.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tv_off.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_update.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_view.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_view_list.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_web.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo_header_day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/drawable/logo_header_day.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo_header_night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/drawable/logo_header_night.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_comment.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 20 | 21 | 22 | 23 | 28 | 29 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 18 | 19 | 20 | 21 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_user_bookshelf.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 21 | 22 | 27 | 28 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_bookshelf_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 28 | 29 | 30 | 31 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_bookshelf_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_bookshelf_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | 22 | 28 | 29 | 30 | 31 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_logging_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_novel_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_ranking.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_reply.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 20 | 21 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_visit_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 20 | 21 | 22 | 23 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_chapter_vcss.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 17 | 18 | 27 | 28 | 38 | 39 | 40 | 41 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_search_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_simple_novel_cover.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_tag.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_message.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_act_novel_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_act_v_h_read.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_act_visit_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_frag_all_novel.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_frag_bookshelf.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_frag_bookshelf_selection.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 15 | 16 | 21 | 22 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_frag_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_nav_act_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 15 | 20 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors_tako.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | #F3B375 15 | #38294E 16 | #F3B375 17 | #38294E 18 | #84531E 19 | #F3B375 20 | #38294E 21 | #5C4D4B 22 | #F3B375 23 | #66577E 24 | #F3B375 25 | #4E4065 26 | #EDDCFF 27 | #21212E 28 | #E3E0F2 29 | #21212E 30 | #E3E0F2 31 | #2A2A3C 32 | #CBC4CE 33 | #66577E 34 | #E5E1E6 35 | #1B1B1E 36 | #958F99 37 | #20202E 38 | #262636 39 | #2A2A3C 40 | #303044 41 | #36364D 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors_tealturqoise.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #40E0D0 4 | #000000 5 | #40E0D0 6 | #000000 7 | #008080 8 | #40E0D0 9 | #000000 10 | #18544E 11 | #40E0D0 12 | #BF1F2F 13 | #FFFFFF 14 | #200508 15 | #BF1F2F 16 | #202125 17 | #DFDEDA 18 | #202125 19 | #DFDEDA 20 | #233133 21 | #DFDEDA 22 | #40E0D0 23 | #DFDEDA 24 | #202125 25 | #899391 26 | #202C2E 27 | #222F31 28 | #233133 29 | #28383A 30 | #2F4244 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors_yinyang.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | #FFFFFF 9 | #5A5A5A 10 | #FFFFFF 11 | #000000 12 | #CECECE 13 | #FFFFFF 14 | #5A5A5A 15 | #717171 16 | #E4E4E4 17 | #000000 18 | #FFFFFF 19 | #00419E 20 | #D8E2FF 21 | #1E1E1E 22 | #E6E6E6 23 | #1E1E1E 24 | #E6E6E6 25 | #313131 26 | #D1D1D1 27 | #FFFFFF 28 | #E6E6E6 29 | #1E1E1E 30 | #999999 31 | #2A2A2A 32 | #2D2D2D 33 | #313131 34 | #383838 35 | #3F3F3F 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values-v23/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffff 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors_tako.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | #66577E 15 | #F3B375 16 | #66577E 17 | #F3B375 18 | #D6BAFF 19 | #66577E 20 | #F3B375 21 | #C8BED0 22 | #66577E 23 | #F3B375 24 | #574360 25 | #FDD6B0 26 | #221437 27 | #F7F5FF 28 | #1B1B22 29 | #F7F5FF 30 | #1B1B22 31 | #E8E0EB 32 | #49454E 33 | #66577E 34 | #313033 35 | #F3EFF4 36 | #7A757E 37 | #D7D0DA 38 | #DFD8E2 39 | #E8E0EB 40 | #EEE6F1 41 | #F7EEFA 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors_tealturqoise.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008080 4 | #FFFFFF 5 | #008080 6 | #FFFFFF 7 | #40E0D0 8 | #008080 9 | #FFFFFF 10 | #CFE5E4 11 | #008080 12 | #FF7F7F 13 | #000000 14 | #2A1616 15 | #FF7F7F 16 | #FAFAFA 17 | #050505 18 | #FAFAFA 19 | #050505 20 | #EBF3F1 21 | #050505 22 | #BFDFDF 23 | #050505 24 | #FAFAFA 25 | #6F7977 26 | #E1E9E7 27 | #E6EEEC 28 | #EBF3F1 29 | #F0F8F6 30 | #F7FFFD 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors_yinyang.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | #000000 9 | #FFFFFF 10 | #000000 11 | #FFFFFF 12 | #A6A6A6 13 | #000000 14 | #FFFFFF 15 | #DDDDDD 16 | #0C0C0C 17 | #FFFFFF 18 | #000000 19 | #D8E2FF 20 | #001947 21 | #FDFDFD 22 | #222222 23 | #FDFDFD 24 | #222222 25 | #E8E8E8 26 | #515151 27 | #000000 28 | #333333 29 | #F4F4F4 30 | #838383 31 | #CFCFCF 32 | #DADADA 33 | #E8E8E8 34 | #ECECEC 35 | #EFEFEF 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app/src/test/java/com/cyh128/hikari_novel/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.cyh128.hikari_novel 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Test 5 | 6 | /** 7 | * Example local unit test, which will execute on the development machine (host). 8 | * 9 | * See [testing documentation](http://d.android.com/tools/testing). 10 | */ 11 | class ExampleUnitTest { 12 | @Test 13 | fun addition_isCorrect() { 14 | assertEquals(4, 2 + 2) 15 | } 16 | } -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id("com.android.application") version "8.9.1" apply false 4 | id("org.jetbrains.kotlin.android") version "2.1.20" apply false 5 | id("com.google.devtools.ksp") version "2.1.20-1.0.31" apply false 6 | id("com.android.library") version "8.9.1" apply false 7 | id("com.google.dagger.hilt.android") version "2.56" apply false 8 | } 9 | 10 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true 24 | 25 | android.enableJetifier=false -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Jan 27 16:20:12 CST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /hikari_novel.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/15dd/wenku8reader/5a8589f21d25dab3154d853c57b69bf3f5f47b74/hikari_novel.jks -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | maven("https://jitpack.io") 12 | google() 13 | mavenCentral() 14 | } 15 | } 16 | 17 | rootProject.name = "HikariNovel" 18 | include(":app") 19 | --------------------------------------------------------------------------------