Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
Z | 2f55751ef0 | 4 years ago |
Z | b7207b761f | 4 years ago |
@ -1,3 +0,0 @@ |
||||
# Default ignored files |
||||
/shelf/ |
||||
/workspace.xml |
@ -1,6 +0,0 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="CompilerConfiguration"> |
||||
<bytecodeTargetLevel target="1.8" /> |
||||
</component> |
||||
</project> |
@ -1,7 +0,0 @@ |
||||
<component name="ProjectDictionaryState"> |
||||
<dictionary name="Administrator"> |
||||
<words> |
||||
<w>umeng</w> |
||||
</words> |
||||
</dictionary> |
||||
</component> |
@ -0,0 +1,4 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" /> |
||||
</project> |
@ -0,0 +1,86 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="MarkdownProjectSettings" wasCopied="false"> |
||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true" openRemoteLinks="true" replaceUnicodeEmoji="false" lastLayoutSetsDefault="false"> |
||||
<PanelProvider> |
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" /> |
||||
</PanelProvider> |
||||
</PreviewSettings> |
||||
<ParserSettings gitHubSyntaxChange="false" emojiShortcuts="1" emojiImages="0"> |
||||
<PegdownExtensions> |
||||
<option name="ABBREVIATIONS" value="false" /> |
||||
<option name="ANCHORLINKS" value="true" /> |
||||
<option name="ASIDE" value="false" /> |
||||
<option name="ATXHEADERSPACE" value="true" /> |
||||
<option name="AUTOLINKS" value="false" /> |
||||
<option name="DEFINITIONS" value="false" /> |
||||
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" /> |
||||
<option name="FENCED_CODE_BLOCKS" value="true" /> |
||||
<option name="FOOTNOTES" value="false" /> |
||||
<option name="HARDWRAPS" value="false" /> |
||||
<option name="HTML_DEEP_PARSER" value="false" /> |
||||
<option name="INSERTED" value="false" /> |
||||
<option name="QUOTES" value="false" /> |
||||
<option name="RELAXEDHRULES" value="true" /> |
||||
<option name="SMARTS" value="false" /> |
||||
<option name="STRIKETHROUGH" value="true" /> |
||||
<option name="SUBSCRIPT" value="false" /> |
||||
<option name="SUPERSCRIPT" value="false" /> |
||||
<option name="SUPPRESS_HTML_BLOCKS" value="false" /> |
||||
<option name="SUPPRESS_INLINE_HTML" value="false" /> |
||||
<option name="TABLES" value="true" /> |
||||
<option name="TASKLISTITEMS" value="true" /> |
||||
<option name="TOC" value="false" /> |
||||
<option name="WIKILINKS" value="false" /> |
||||
</PegdownExtensions> |
||||
<ParserOptions> |
||||
<option name="ADMONITION_EXT" value="false" /> |
||||
<option name="ATTRIBUTES_EXT" value="false" /> |
||||
<option name="COMMONMARK_LISTS" value="true" /> |
||||
<option name="DUMMY" value="false" /> |
||||
<option name="EMOJI_SHORTCUTS" value="true" /> |
||||
<option name="ENUMERATED_REFERENCES_EXT" value="false" /> |
||||
<option name="FLEXMARK_FRONT_MATTER" value="false" /> |
||||
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" /> |
||||
<option name="GFM_TABLE_RENDERING" value="true" /> |
||||
<option name="GITBOOK_URL_ENCODING" value="false" /> |
||||
<option name="GITHUB_LISTS" value="false" /> |
||||
<option name="GITHUB_WIKI_LINKS" value="false" /> |
||||
<option name="GITLAB_EXT" value="false" /> |
||||
<option name="GITLAB_MATH_EXT" value="false" /> |
||||
<option name="GITLAB_MERMAID_EXT" value="false" /> |
||||
<option name="HEADER_ID_NON_ASCII_TO_LOWERCASE" value="false" /> |
||||
<option name="HEADER_ID_NO_DUPED_DASHES" value="false" /> |
||||
<option name="JEKYLL_FRONT_MATTER" value="false" /> |
||||
<option name="MACROS_EXT" value="false" /> |
||||
<option name="NO_TEXT_ATTRIBUTES" value="false" /> |
||||
<option name="PARSE_HTML_ANCHOR_ID" value="false" /> |
||||
<option name="PLANTUML_FENCED_CODE" value="false" /> |
||||
<option name="PUML_FENCED_CODE" value="false" /> |
||||
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" /> |
||||
</ParserOptions> |
||||
</ParserSettings> |
||||
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true" embedImages="false" embedHttpImages="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" plantUmlConversion="0" mathConversion="0"> |
||||
<GeneratorProvider> |
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" /> |
||||
</GeneratorProvider> |
||||
<headerTop /> |
||||
<headerBottom /> |
||||
<bodyTop /> |
||||
<bodyBottom /> |
||||
</HtmlSettings> |
||||
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true"> |
||||
<StylesheetProvider> |
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" /> |
||||
</StylesheetProvider> |
||||
<ScriptProviders /> |
||||
<cssText /> |
||||
<cssUriHistory /> |
||||
</CssSettings> |
||||
<AnnotatorSettings targetHasSpaces="true" linkCaseMismatch="true" wikiCaseMismatch="true" wikiLinkHasDashes="true" notUnderWikiHome="true" targetNotWikiPageExt="true" notUnderSourceWikiHome="true" targetNameHasAnchor="true" targetPathHasAnchor="true" wikiLinkHasSlash="true" wikiLinkHasSubdir="true" wikiLinkHasOnlyAnchor="true" linkTargetsWikiHasExt="true" linkTargetsWikiHasBadExt="true" notUnderSameRepo="true" targetNotUnderVcs="false" linkNeedsExt="true" linkHasBadExt="true" linkTargetNeedsExt="true" linkTargetHasBadExt="true" wikiLinkNotInWiki="true" imageTargetNotInRaw="true" repoRelativeAcrossVcsRoots="true" multipleWikiTargetsMatch="true" unresolvedLinkReference="true" linkIsIgnored="true" anchorIsIgnored="true" anchorIsUnresolved="true" anchorLineReferenceIsUnresolved="true" anchorLineReferenceFormat="true" anchorHasDuplicates="true" abbreviationDuplicates="true" abbreviationNotUsed="true" attributeIdDuplicateDefinition="true" attributeIdNotUsed="true" footnoteDuplicateDefinition="true" footnoteUnresolved="true" footnoteDuplicates="true" footnoteNotUsed="true" macroDuplicateDefinition="true" macroUnresolved="true" macroDuplicates="true" macroNotUsed="true" referenceDuplicateDefinition="true" referenceUnresolved="true" referenceDuplicates="true" referenceNotUsed="true" referenceUnresolvedNumericId="true" enumRefDuplicateDefinition="true" enumRefUnresolved="true" enumRefDuplicates="true" enumRefNotUsed="true" enumRefLinkUnresolved="true" enumRefLinkDuplicates="true" simTocUpdateNeeded="true" simTocTitleSpaceNeeded="true" /> |
||||
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="css" scriptDir="js" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" /> |
||||
<LinkMapSettings> |
||||
<textMaps /> |
||||
</LinkMapSettings> |
||||
</component> |
||||
</project> |
@ -0,0 +1,3 @@ |
||||
<component name="MarkdownNavigator.ProfileManager"> |
||||
<settings default="" pdf-export="" plain-text-search-scope="Project Files" /> |
||||
</component> |
@ -0,0 +1,12 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="RunConfigurationProducerService"> |
||||
<option name="ignoredProducers"> |
||||
<set> |
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> |
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> |
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> |
||||
</set> |
||||
</option> |
||||
</component> |
||||
</project> |
@ -1,6 +1,7 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="VcsDirectoryMappings"> |
||||
<mapping directory="" vcs="Git" /> |
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" /> |
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> |
||||
</component> |
||||
</project> |
@ -1,160 +1,38 @@ |
||||
plugins { |
||||
id 'com.android.application' |
||||
id 'kotlin-android' |
||||
id 'kotlin-parcelize' |
||||
} |
||||
apply plugin: 'com.android.application' |
||||
|
||||
def name = "reader" |
||||
def code = 1 |
||||
def version = "1.0.0" |
||||
apply plugin: 'kotlin-android' |
||||
|
||||
android { |
||||
compileSdkVersion 30 |
||||
buildToolsVersion "29.0.3" |
||||
apply plugin: 'kotlin-android-extensions' |
||||
|
||||
android { |
||||
compileSdkVersion rootProject.ext.android.compileSdkVersion |
||||
defaultConfig { |
||||
applicationId "com.novel.read" |
||||
minSdkVersion 21 |
||||
targetSdkVersion 30 |
||||
versionCode code |
||||
versionName version |
||||
|
||||
applicationId rootProject.ext.android.applicationId |
||||
minSdkVersion rootProject.ext.android.minSdkVersion |
||||
targetSdkVersion rootProject.ext.android.targetSdkVersion |
||||
versionCode rootProject.ext.android.versionCode |
||||
versionName rootProject.ext.android.versionName |
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" |
||||
|
||||
ndk { |
||||
abiFilters "armeabi" |
||||
} |
||||
multiDexEnabled true |
||||
resConfigs "zh", "zh-rCN" |
||||
resConfigs "zh", "zh-rTW" |
||||
resConfigs "zh", "zh-rHK" |
||||
} |
||||
|
||||
signingConfigs { |
||||
release { |
||||
keyAlias 'key0' |
||||
keyPassword '1qaz@WSX' |
||||
storeFile file('reader.jks') |
||||
storePassword '1qaz@WSX' |
||||
} |
||||
} |
||||
buildFeatures { |
||||
viewBinding true |
||||
} |
||||
buildTypes { |
||||
debug { |
||||
minifyEnabled true |
||||
shrinkResources true |
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
||||
signingConfig signingConfigs.release |
||||
} |
||||
release { |
||||
buildConfigField "boolean", "LOG_DEBUG", "false" //不显示log |
||||
minifyEnabled true |
||||
shrinkResources true |
||||
minifyEnabled false |
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
||||
signingConfig signingConfigs.release |
||||
} |
||||
|
||||
android.applicationVariants.all { variant -> |
||||
variant.outputs.all { |
||||
def flavor = variant.productFlavors[0].name |
||||
outputFileName = "${name}_${flavor}_${defaultConfig.versionName}.apk" |
||||
} |
||||
} |
||||
} |
||||
|
||||
flavorDimensions "mode" |
||||
productFlavors { |
||||
app { |
||||
dimension "mode" |
||||
manifestPlaceholders = [APP_CHANNEL_VALUE: "app"] |
||||
} |
||||
} |
||||
|
||||
compileOptions { |
||||
sourceCompatibility JavaVersion.VERSION_1_8 |
||||
targetCompatibility JavaVersion.VERSION_1_8 |
||||
} |
||||
kotlinOptions { |
||||
jvmTarget = '1.8' |
||||
} |
||||
|
||||
} |
||||
|
||||
dependencies { |
||||
implementation fileTree(dir: 'libs', include: ['*.aar']) |
||||
testImplementation 'junit:junit:4.13.1' |
||||
androidTestImplementation 'androidx.test:runner:1.3.0' |
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' |
||||
implementation "com.android.support:multidex:1.0.3" |
||||
|
||||
//kotlin |
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" |
||||
|
||||
//androidX |
||||
implementation 'androidx.core:core-ktx:1.3.2' |
||||
implementation 'androidx.appcompat:appcompat:1.2.0' |
||||
implementation 'androidx.media:media:1.2.1' |
||||
implementation 'androidx.preference:preference-ktx:1.1.1' |
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4' |
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' |
||||
implementation 'androidx.viewpager2:viewpager2:1.0.0' |
||||
implementation 'com.google.android.material:material:1.2.1' |
||||
implementation 'com.google.android:flexbox:1.1.0' |
||||
implementation 'com.google.code.gson:gson:2.8.6' |
||||
|
||||
//基本的网络框架 |
||||
implementation 'com.squareup.okhttp3:okhttp:3.14.9' |
||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0' |
||||
implementation 'com.squareup.retrofit2:converter-gson:2.7.2' |
||||
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' |
||||
|
||||
//anko |
||||
def anko_version = '0.10.8' |
||||
implementation "org.jetbrains.anko:anko-sdk27:$anko_version" |
||||
implementation "org.jetbrains.anko:anko-sdk27-listeners:$anko_version" |
||||
|
||||
//sql |
||||
implementation 'org.litepal.android:kotlin:3.0.0' |
||||
|
||||
//协程 |
||||
def coroutines_version = '1.3.7' |
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" |
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" |
||||
|
||||
//liveEventBus |
||||
implementation 'com.jeremyliao:live-event-bus-x:1.7.2' |
||||
|
||||
//lifecycle |
||||
def lifecycle_version = '2.2.0' |
||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" |
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" |
||||
|
||||
//Glide |
||||
implementation 'com.github.bumptech.glide:glide:4.11.0' |
||||
|
||||
//MarkDown |
||||
implementation 'io.noties.markwon:core:4.6.0' |
||||
implementation 'io.noties.markwon:image-glide:4.6.0' |
||||
//转换繁体 |
||||
implementation files('libs/ZHConverter.jar') |
||||
//brvah |
||||
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6' |
||||
|
||||
//字符串比较 |
||||
implementation 'net.ricecode:string-similarity:1.0.0' |
||||
|
||||
//epub |
||||
implementation('com.positiondev.epublib:epublib-core:3.1') { |
||||
exclude group: 'org.slf4j' |
||||
exclude group: 'xmlpull' |
||||
} |
||||
|
||||
//flex |
||||
implementation 'com.google.android:flexbox:1.1.0' |
||||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
||||
testImplementation rootProject.ext.dependencies["junit"] |
||||
androidTestImplementation rootProject.ext.dependencies["runner"] |
||||
androidTestImplementation rootProject.ext.dependencies["espresso_core"] |
||||
implementation project(path: ':net_serivce') |
||||
implementation project(path: ':common_lib') |
||||
|
||||
implementation 'com.allenliu.versionchecklib:library:2.2.0' |
||||
|
||||
implementation 'com.permissionx.guolindev:permissionx:1.4.0' |
||||
} |
||||
} |
||||
|
Binary file not shown.
@ -1,18 +0,0 @@ |
||||
{ |
||||
"version": 2, |
||||
"artifactType": { |
||||
"type": "APK", |
||||
"kind": "Directory" |
||||
}, |
||||
"applicationId": "com.novel.read", |
||||
"variantName": "processAppReleaseResources", |
||||
"elements": [ |
||||
{ |
||||
"type": "SINGLE", |
||||
"filters": [], |
||||
"versionCode": 1, |
||||
"versionName": "1.0.0", |
||||
"outputFile": "reader_app_1.0.0.apk" |
||||
} |
||||
] |
||||
} |
Binary file not shown.
Before Width: | Height: | Size: 246 KiB |
@ -1,62 +0,0 @@ |
||||
[ |
||||
{ |
||||
"id": 1598233029304, |
||||
"name": "度小美", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=0&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029305, |
||||
"name": "度小宇", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=1&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029306, |
||||
"name": "度逍遥", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=5003&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029307, |
||||
"name": "度丫丫", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=4&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029308, |
||||
"name": "度小娇", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=5&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029309, |
||||
"name": "度米朵", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=103&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029310, |
||||
"name": "度博文", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=106&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029311, |
||||
"name": "度小童", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=110&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029312, |
||||
"name": "度小萌", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=111&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029313, |
||||
"name": "百度骚男", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=11&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029314, |
||||
"name": "百度评书", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=6&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
}, |
||||
{ |
||||
"id": 1598233029315, |
||||
"name": "百度主持", |
||||
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=9&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||
} |
||||
] |
@ -1,52 +0,0 @@ |
||||
[ |
||||
{ |
||||
"bgStr": "#EFEFF7", |
||||
"bgStrNight": "#212021", |
||||
"textColor": "#383429", |
||||
"textColorNight": "#94969C", |
||||
"bgType": 0, |
||||
"bgTypeNight": 0, |
||||
"darkStatusIcon": true, |
||||
"darkStatusIconNight": false |
||||
}, |
||||
{ |
||||
"bgStr": "#DDC090", |
||||
"bgStrNight": "#3C3F43", |
||||
"textColor": "#3E3422", |
||||
"textColorNight": "#DCDFE1", |
||||
"bgType": 0, |
||||
"bgTypeNight": 0, |
||||
"darkStatusIcon": true, |
||||
"darkStatusIconNight": false |
||||
}, |
||||
{ |
||||
"bgStr": "#C2D8AA", |
||||
"bgStrNight": "#3C3F43", |
||||
"textColor": "#596C44", |
||||
"textColorNight": "#88C16F", |
||||
"bgType": 0, |
||||
"bgTypeNight": 0, |
||||
"darkStatusIcon": false, |
||||
"darkStatusIconNight": false |
||||
}, |
||||
{ |
||||
"bgStr": "#DBB8E2", |
||||
"bgStrNight": "#3C3F43", |
||||
"textColor": "#68516C", |
||||
"textColorNight": "#F6AEAE", |
||||
"bgType": 0, |
||||
"bgTypeNight": 0, |
||||
"darkStatusIcon": false, |
||||
"darkStatusIconNight": false |
||||
}, |
||||
{ |
||||
"bgStr": "#ABCEE0", |
||||
"bgStrNight": "#3C3F43", |
||||
"textColor": "#3D4C54", |
||||
"textColorNight": "#90BFF5", |
||||
"bgType": 0, |
||||
"bgTypeNight": 0, |
||||
"darkStatusIcon": false, |
||||
"darkStatusIconNight": false |
||||
} |
||||
] |
@ -1,26 +0,0 @@ |
||||
[ |
||||
{ |
||||
"themeName": "典雅蓝", |
||||
"isNightTheme": false, |
||||
"primaryColor": "#03A9F4", |
||||
"accentColor": "#AD1457", |
||||
"backgroundColor": "#F5F5F5", |
||||
"bottomBackground": "#EEEEEE" |
||||
}, |
||||
{ |
||||
"themeName": "黑白", |
||||
"isNightTheme": true, |
||||
"primaryColor": "#303030", |
||||
"accentColor": "#E0E0E0", |
||||
"backgroundColor": "#424242", |
||||
"bottomBackground": "#424242" |
||||
}, |
||||
{ |
||||
"themeName": "A屏黑", |
||||
"isNightTheme": true, |
||||
"primaryColor": "#000000", |
||||
"accentColor": "#FFFFFF", |
||||
"backgroundColor": "#000000", |
||||
"bottomBackground": "#000000" |
||||
} |
||||
] |
Binary file not shown.
@ -1,12 +1,23 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<litepal> |
||||
<dbname value="light_book" /> |
||||
<version value="1" /> |
||||
<dbname value="readDb" /> |
||||
|
||||
<version value="9" /> |
||||
|
||||
<list> |
||||
<mapping class="com.novel.read.data.db.entity.Book" /> |
||||
<mapping class="com.novel.read.data.db.entity.BookChapter" /> |
||||
<mapping class="com.novel.read.data.db.entity.Bookmark" /> |
||||
<mapping class="com.novel.read.data.db.entity.ReadRecord" /> |
||||
<mapping class="com.novel.read.data.db.entity.SearchHistory" /> |
||||
<!--搜索记录表--> |
||||
<mapping class="com.novel.read.model.db.SearchListTable"/> |
||||
<!--收藏书籍表--> |
||||
<mapping class="com.novel.read.model.db.CollBookBean"/> |
||||
<!--章节表--> |
||||
<mapping class="com.novel.read.model.db.BookChapterBean"/> |
||||
<!--阅读记录表--> |
||||
<mapping class="com.novel.read.model.db.BookRecordBean"/> |
||||
<!--章节详情表--> |
||||
<mapping class="com.novel.read.model.db.ChapterInfoBean" /> |
||||
<!--章节详情表--> |
||||
<mapping class="com.novel.read.model.db.DownloadTaskBean" /> |
||||
<!--书签表--> |
||||
<mapping class="com.novel.read.model.db.BookSignTable" /> |
||||
</list> |
||||
<storage value="external" /> |
||||
</litepal> |
@ -1,138 +0,0 @@ |
||||
package com.novel.read |
||||
|
||||
import android.app.NotificationChannel |
||||
import android.app.NotificationManager |
||||
import android.content.Context |
||||
import android.content.res.Configuration |
||||
import android.os.Build |
||||
import android.provider.Settings |
||||
import androidx.annotation.RequiresApi |
||||
import androidx.appcompat.app.AppCompatDelegate |
||||
import androidx.multidex.MultiDexApplication |
||||
import com.bumptech.glide.Glide |
||||
import com.jeremyliao.liveeventbus.LiveEventBus |
||||
import com.novel.read.constant.AppConst.channelIdDownload |
||||
import com.novel.read.constant.AppConst.channelIdReadAloud |
||||
import com.novel.read.constant.EventBus |
||||
import com.novel.read.data.db.BookDatabase |
||||
import com.novel.read.help.ActivityHelp |
||||
import com.novel.read.help.AppConfig |
||||
import com.novel.read.help.ReadBookConfig |
||||
import com.novel.read.help.ThemeConfig |
||||
import com.novel.read.utils.LanguageUtils |
||||
import com.novel.read.utils.ext.postEvent |
||||
import org.litepal.LitePal |
||||
|
||||
@Suppress("DEPRECATION") |
||||
class App : MultiDexApplication() { |
||||
|
||||
companion object { |
||||
@JvmStatic |
||||
lateinit var INSTANCE: App |
||||
private set |
||||
|
||||
@JvmStatic |
||||
lateinit var db: BookDatabase |
||||
private set |
||||
|
||||
lateinit var androidId: String |
||||
var versionCode = 0 |
||||
var versionName = "" |
||||
} |
||||
|
||||
override fun onCreate() { |
||||
super.onCreate() |
||||
INSTANCE = this |
||||
androidId = Settings.System.getString(contentResolver, Settings.Secure.ANDROID_ID) |
||||
LanguageUtils.setConfiguration(this) |
||||
LitePal.initialize(this) |
||||
db = BookDatabase.get() |
||||
packageManager.getPackageInfo(packageName, 0)?.let { |
||||
versionCode = it.versionCode |
||||
versionName = it.versionName |
||||
} |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createChannelId() |
||||
applyDayNight() |
||||
LiveEventBus |
||||
.config() |
||||
.lifecycleObserverAlwaysActive(true) |
||||
.autoClear(false) |
||||
registerActivityLifecycleCallbacks(ActivityHelp) |
||||
} |
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) { |
||||
super.onConfigurationChanged(newConfig) |
||||
when (newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK) { |
||||
Configuration.UI_MODE_NIGHT_YES, |
||||
Configuration.UI_MODE_NIGHT_NO -> applyDayNight() |
||||
} |
||||
} |
||||
|
||||
|
||||
fun applyDayNight() { |
||||
AppConfig.upEInkMode() |
||||
ReadBookConfig.upBg() |
||||
ThemeConfig.applyTheme(this) |
||||
initNightMode() |
||||
postEvent(EventBus.RECREATE, "") |
||||
} |
||||
|
||||
|
||||
private fun initNightMode() { |
||||
val targetMode = |
||||
if (AppConfig.isNightTheme) { |
||||
AppCompatDelegate.MODE_NIGHT_YES |
||||
} else { |
||||
AppCompatDelegate.MODE_NIGHT_NO |
||||
} |
||||
AppCompatDelegate.setDefaultNightMode(targetMode) |
||||
} |
||||
|
||||
/** |
||||
* 创建通知ID |
||||
*/ |
||||
@RequiresApi(Build.VERSION_CODES.O) |
||||
private fun createChannelId() { |
||||
(getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager)?.let { |
||||
//用唯一的ID创建渠道对象 |
||||
val downloadChannel = NotificationChannel( |
||||
channelIdDownload, |
||||
getString(R.string.action_download), |
||||
NotificationManager.IMPORTANCE_LOW |
||||
) |
||||
//初始化channel |
||||
downloadChannel.enableLights(false) |
||||
downloadChannel.enableVibration(false) |
||||
downloadChannel.setSound(null, null) |
||||
|
||||
//用唯一的ID创建渠道对象 |
||||
val readAloudChannel = NotificationChannel( |
||||
channelIdReadAloud, |
||||
getString(R.string.read_aloud), |
||||
NotificationManager.IMPORTANCE_LOW |
||||
) |
||||
//初始化channel |
||||
readAloudChannel.enableLights(false) |
||||
readAloudChannel.enableVibration(false) |
||||
readAloudChannel.setSound(null, null) |
||||
|
||||
//向notification manager 提交channel |
||||
it.createNotificationChannels(listOf(downloadChannel, readAloudChannel)) |
||||
} |
||||
} |
||||
|
||||
|
||||
override fun onLowMemory() { |
||||
super.onLowMemory() |
||||
Glide.get(this).clearMemory() |
||||
} |
||||
|
||||
override fun onTrimMemory(level: Int) { |
||||
super.onTrimMemory(level) |
||||
if (level == TRIM_MEMORY_UI_HIDDEN) { |
||||
Glide.get(this).clearMemory() |
||||
} |
||||
Glide.get(this).trimMemory(level) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,22 @@ |
||||
package com.novel.read |
||||
|
||||
import android.content.Context |
||||
import android.widget.ImageView |
||||
import android.widget.Toast |
||||
|
||||
fun Context.showToast(msg:String){ |
||||
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show() |
||||
} |
||||
|
||||
fun Context.getScreenContentWidth(): Int { |
||||
val displayMetrics = this.resources.displayMetrics |
||||
return displayMetrics.widthPixels |
||||
} |
||||
|
||||
fun Context.dp2px(dps: Int): Int { |
||||
return Math.round(dps.toFloat() * getDensityDpiScale(this)) |
||||
} |
||||
|
||||
fun getDensityDpiScale(context: Context): Float { |
||||
return context.resources.displayMetrics.xdpi / 160.0f |
||||
} |
@ -0,0 +1,205 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.app.ProgressDialog |
||||
import android.content.Intent |
||||
import android.util.Log |
||||
import android.view.View |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import com.mango.mangolib.event.EventManager |
||||
import com.novel.read.R |
||||
import com.novel.read.adapter.LoveLyAdapter |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.constants.Constant.RequestCode.Companion.REQUEST_READ |
||||
import com.novel.read.constants.Constant.ResultCode.Companion.RESULT_IS_COLLECTED |
||||
import com.novel.read.event.BookArticleEvent |
||||
import com.novel.read.event.GetBookDetailEvent |
||||
import com.novel.read.event.GetRecommendBookEvent |
||||
import com.novel.read.event.UpdateBookEvent |
||||
import com.novel.read.http.AccountManager |
||||
import com.novel.read.model.db.CollBookBean |
||||
import com.novel.read.model.db.dbManage.BookRepository |
||||
import com.novel.read.model.protocol.RecommendBookResp |
||||
import com.novel.read.showToast |
||||
import com.novel.read.utlis.DateUtli |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
import com.squareup.otto.Subscribe |
||||
import kotlinx.android.synthetic.main.activity_book_detail.* |
||||
import org.litepal.LitePal |
||||
import java.util.* |
||||
|
||||
class NovelBookDetailActivity(override val layoutId: Int = R.layout.activity_book_detail) : NovelBaseActivity(), View.OnClickListener { |
||||
|
||||
private lateinit var mAdapter: LoveLyAdapter |
||||
private val mList = ArrayList<RecommendBookResp.BookBean>() |
||||
private var mBookId: Int = 0 |
||||
private var isCollected = false |
||||
private var mCollBookBean: CollBookBean? = null |
||||
private lateinit var mProgressDialog: ProgressDialog |
||||
|
||||
override fun initView() { |
||||
mBookId = intent.getIntExtra(Constant.Bundle.BookId, 0) |
||||
rlv_lovely.layoutManager = LinearLayoutManager(this) |
||||
mAdapter = LoveLyAdapter(mList) |
||||
rlv_lovely.adapter = mAdapter |
||||
mProgressDialog = ProgressDialog(this) |
||||
} |
||||
|
||||
override fun initData() { |
||||
refresh.showLoading() |
||||
refresh.setOnReloadingListener { getData() } |
||||
getData() |
||||
toolbar.setNavigationOnClickListener { finish() } |
||||
tv_add_book.setOnClickListener(this) |
||||
tv_start_read.setOnClickListener(this) |
||||
} |
||||
|
||||
private fun getData() { |
||||
AccountManager.getInstance().getRecommendBook(mBookId.toString(), "10") |
||||
AccountManager.getInstance().getBookDetail(mBookId.toString()) |
||||
} |
||||
|
||||
override fun onClick(v: View?) { |
||||
when (v?.id) { |
||||
R.id.tv_add_book -> |
||||
//点击存储 |
||||
if (isCollected) { |
||||
//放弃点击 |
||||
BookRepository.getInstance().deleteCollBookInRx(mCollBookBean) |
||||
tv_add_book.text = resources.getString(R.string.add_book) |
||||
isCollected = false |
||||
} else { |
||||
mProgressDialog.setTitle("正在添加到书架中") |
||||
mProgressDialog.show() |
||||
AccountManager.getInstance().getBookArticle(mBookId.toString()) |
||||
|
||||
} |
||||
R.id.tv_start_read -> |
||||
startActivityForResult( |
||||
Intent(this, NovelReadActivity::class.java) |
||||
.putExtra(NovelReadActivity.EXTRA_IS_COLLECTED, isCollected) |
||||
.putExtra(NovelReadActivity.EXTRA_COLL_BOOK, mCollBookBean), REQUEST_READ |
||||
) |
||||
} |
||||
} |
||||
|
||||
@SuppressLint("SetTextI18n") |
||||
@Subscribe |
||||
fun getBookDetail(event: GetBookDetailEvent) { |
||||
refresh.showFinish() |
||||
if (event.isFail) { |
||||
refresh.showError() |
||||
} else { |
||||
val bookBean = event.result!!.book |
||||
GlideImageLoader.displayCornerImage(this, bookBean.cover, iv_book) |
||||
tv_book_name.text = bookBean.title |
||||
|
||||
tv_book_author.text = bookBean.author + " | " |
||||
tv_book_length.text = getString(R.string.book_word, bookBean.words / 10000) |
||||
|
||||
if (event.result!!.last_article != null) { |
||||
tv_new_title.text = |
||||
getString(R.string.new_chapter, event.result!!.last_article.title) |
||||
tv_update_time.text = |
||||
DateUtli.dateConvert(event.result!!.last_article.create_time, 0) |
||||
} |
||||
|
||||
tv_human_num.text = bookBean.hot.toString() + "" |
||||
tv_love_look_num.text = bookBean.like |
||||
tv_Intro.text = bookBean.description |
||||
mCollBookBean = BookRepository.getInstance().getCollBook(bookBean.id.toString()) |
||||
//判断是否收藏 |
||||
if (mCollBookBean != null) { |
||||
isCollected = true |
||||
tv_add_book.text = resources.getString(R.string.already_add) |
||||
tv_start_read.text = resources.getString(R.string.go_read) |
||||
} else { |
||||
mCollBookBean = event.result!!.collBookBean |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Subscribe |
||||
fun getRecommendBook(event: GetRecommendBookEvent) { |
||||
if (event.isFail) { |
||||
Log.e("getRecommendBook", event.er?.msg) |
||||
} else { |
||||
mList.clear() |
||||
mList.addAll(event.result!!.book) |
||||
mAdapter.notifyDataSetChanged() |
||||
} |
||||
} |
||||
|
||||
override fun onResume() { |
||||
super.onResume() |
||||
EventManager.instance.registerSubscriber(this) |
||||
} |
||||
|
||||
override fun onPause() { |
||||
super.onPause() |
||||
EventManager.instance.unregisterSubscriber(this) |
||||
} |
||||
|
||||
@Subscribe |
||||
fun getArticle(event: BookArticleEvent) { |
||||
if (event.isFail) { |
||||
dismiss() |
||||
showToast(getString(R.string.net_error)) |
||||
} else { |
||||
//存储收藏 |
||||
var success = false |
||||
if (mCollBookBean != null) { |
||||
success = mCollBookBean!!.saveOrUpdate("bookId=?", mCollBookBean!!.id) |
||||
} |
||||
if (success) { |
||||
val bookChapterBean = event.result!!.chapterBean |
||||
for (i in bookChapterBean.indices) { |
||||
bookChapterBean[i].collBookBean = mCollBookBean |
||||
} |
||||
LitePal.saveAllAsync(bookChapterBean).listen { success1 -> |
||||
if (success1) { |
||||
if (tv_add_book != null) { |
||||
tv_add_book.text = resources.getString(R.string.already_add) |
||||
} |
||||
isCollected = true |
||||
} else { |
||||
LitePal.deleteAll(CollBookBean::class.java, "bookId =?", mCollBookBean!!.id) |
||||
showToast(getString(R.string.net_error)) |
||||
} |
||||
dismiss() |
||||
} |
||||
} else { |
||||
showToast(getString(R.string.net_error)) |
||||
dismiss() |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
private fun dismiss() { |
||||
mProgressDialog.dismiss() |
||||
} |
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
||||
super.onActivityResult(requestCode, resultCode, data) |
||||
//如果进入阅读页面收藏了,页面结束的时候,就需要返回改变收藏按钮 |
||||
if (requestCode == REQUEST_READ) { |
||||
if (data == null) { |
||||
return |
||||
} |
||||
|
||||
isCollected = data.getBooleanExtra(RESULT_IS_COLLECTED, false) |
||||
|
||||
if (isCollected) { |
||||
tv_add_book.text = resources.getString(R.string.already_add) |
||||
tv_start_read.text = resources.getString(R.string.go_read) |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
EventManager.instance.postEvent(UpdateBookEvent()) |
||||
} |
||||
} |
@ -0,0 +1,89 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import com.mango.mangolib.event.EventManager |
||||
import com.novel.read.R |
||||
import com.novel.read.adapter.BookListAdapter |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.constants.Constant.COMMENT_SIZE |
||||
import com.novel.read.event.SearchListEvent |
||||
import com.novel.read.http.AccountManager |
||||
import com.novel.read.inter.OnLoadMoreListener |
||||
import com.novel.read.model.protocol.SearchResp |
||||
import com.squareup.otto.Subscribe |
||||
import kotlinx.android.synthetic.main.activity_book_type_list.* |
||||
import java.util.* |
||||
|
||||
class NovelBookTypeListActivity(override val layoutId: Int = R.layout.activity_book_type_list) : NovelBaseActivity() { |
||||
|
||||
private var mList: MutableList<SearchResp.BookBean> = ArrayList() |
||||
private lateinit var mAdapter: BookListAdapter |
||||
private var mCategoryId: String? = null |
||||
private var mTitle: String? = null |
||||
private var page: Int = 1 |
||||
private var loadSize: Int = 0 |
||||
|
||||
override fun initView() { |
||||
EventManager.instance.registerSubscriber(this) |
||||
|
||||
mCategoryId = intent.getStringExtra(Constant.Bundle.CategoryId) |
||||
mTitle = intent.getStringExtra(Constant.Bundle.mTitle) |
||||
|
||||
rlv_type_list.layoutManager = LinearLayoutManager(this) |
||||
mAdapter = BookListAdapter(mList, rlv_type_list) |
||||
rlv_type_list.adapter = mAdapter |
||||
|
||||
mAdapter.setOnLoadMoreListener(object : OnLoadMoreListener { |
||||
override fun onLoadMore() { |
||||
if (mAdapter.isLoadingMore) { |
||||
rlv_type_list.stopScroll() |
||||
} else { |
||||
if (loadSize >= COMMENT_SIZE) { |
||||
mAdapter.isLoadingMore = true |
||||
mAdapter.notifyDataSetChanged() |
||||
page++ |
||||
getData() |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
|
||||
override fun initData() { |
||||
refresh.showLoading() |
||||
refresh.setOnReloadingListener { this.getData() } |
||||
getData() |
||||
toolbar.title = mTitle |
||||
toolbar.setNavigationOnClickListener { finish() } |
||||
|
||||
} |
||||
|
||||
private fun getData() { |
||||
mCategoryId?.let { AccountManager.getInstance().getSearchBookList(it, "", page) } |
||||
} |
||||
|
||||
@Subscribe |
||||
fun getSearchList(event: SearchListEvent) { |
||||
refresh.showFinish() |
||||
if (event.isFail) { |
||||
refresh.showError() |
||||
} else { |
||||
loadSize = event.result!!.book.size |
||||
if (mAdapter.isLoadingMore) { |
||||
mAdapter.isLoadingMore = false |
||||
mList.addAll(event.result!!.book) |
||||
mAdapter.notifyDataSetChanged() |
||||
} else { |
||||
mList.clear() |
||||
mList.addAll(event.result!!.book) |
||||
mAdapter.notifyDataSetChanged() |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
EventManager.instance.unregisterSubscriber(this) |
||||
} |
||||
} |
@ -0,0 +1,148 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.os.Bundle |
||||
import android.util.Log |
||||
import android.view.KeyEvent |
||||
import android.view.View |
||||
import androidx.fragment.app.Fragment |
||||
import com.mango.mangolib.event.EventManager |
||||
import com.novel.read.R |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.event.* |
||||
import com.novel.read.fragment.BookFragment |
||||
import com.novel.read.fragment.MoreFragment |
||||
import com.novel.read.fragment.RecommendFragment |
||||
import com.novel.read.fragment.StackFragment |
||||
import com.novel.read.http.AccountManager |
||||
import com.novel.read.model.db.dbManage.BookRepository |
||||
import com.novel.read.showToast |
||||
import com.novel.read.utlis.SpUtil |
||||
import com.squareup.otto.Subscribe |
||||
import kotlinx.android.synthetic.main.activity_main.* |
||||
|
||||
class NovelMainActivity(override val layoutId: Int = R.layout.activity_main) : NovelBaseActivity() { |
||||
|
||||
private lateinit var mCurrentFrag: Fragment |
||||
private lateinit var mMainFragment: BookFragment |
||||
private lateinit var mRecommendFragment: RecommendFragment |
||||
private lateinit var mStackFragment: StackFragment |
||||
private lateinit var mMoreFragment: MoreFragment |
||||
|
||||
//记录用户首次点击返回键的时间 |
||||
private var firstTime: Long = 0 |
||||
|
||||
override fun initView() { |
||||
mCurrentFrag = Fragment() |
||||
mMainFragment = BookFragment.newInstance() |
||||
mRecommendFragment = RecommendFragment.newInstance() |
||||
mStackFragment = StackFragment.newInstance() |
||||
mMoreFragment = MoreFragment.newInstance() |
||||
AccountManager.getInstance().login(this) |
||||
} |
||||
|
||||
override fun initData() { |
||||
bottom_bar.setOnNavigationItemSelectedListener { menuItem -> |
||||
when (menuItem.itemId) { |
||||
R.id.tab_one -> { |
||||
switchFragment(mMainFragment) |
||||
return@setOnNavigationItemSelectedListener true |
||||
} |
||||
R.id.tab_two -> { |
||||
switchFragment(mRecommendFragment) |
||||
return@setOnNavigationItemSelectedListener true |
||||
} |
||||
R.id.tab_three -> { |
||||
switchFragment(mStackFragment) |
||||
return@setOnNavigationItemSelectedListener true |
||||
} |
||||
R.id.tab_four -> { |
||||
switchFragment(mMoreFragment) |
||||
return@setOnNavigationItemSelectedListener true |
||||
} |
||||
} |
||||
false |
||||
} |
||||
|
||||
if (BookRepository.getInstance().collBooks.size > 0) { |
||||
switchFragment(mMainFragment) |
||||
} else { |
||||
bottom_bar.selectedItemId = R.id.tab_two |
||||
} |
||||
} |
||||
|
||||
private fun switchFragment(targetFragment: Fragment) { |
||||
val transaction = supportFragmentManager.beginTransaction() |
||||
if (!targetFragment.isAdded) { |
||||
transaction.hide(mCurrentFrag) |
||||
transaction.add(R.id.fl_content, targetFragment, targetFragment.javaClass.name) |
||||
} else { |
||||
transaction.hide(mCurrentFrag).show(targetFragment) |
||||
} |
||||
mCurrentFrag = targetFragment |
||||
transaction.commit() |
||||
} |
||||
|
||||
override fun onResume() { |
||||
super.onResume() |
||||
EventManager.instance.registerSubscriber(this) |
||||
} |
||||
|
||||
override fun onPause() { |
||||
super.onPause() |
||||
EventManager.instance.unregisterSubscriber(this) |
||||
} |
||||
|
||||
@Subscribe |
||||
fun login(event: LoginEvent) { |
||||
if (event.isFail) { |
||||
Log.e("NovelMainActivity", "login: " + event.er!!.msg) |
||||
} else { |
||||
SpUtil.setStringValue(Constant.Uid, event.result!!.uid.toString()) |
||||
} |
||||
} |
||||
|
||||
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { |
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) { |
||||
if (!isVisible(bottom_bar)) { |
||||
bottom_bar.visibility = View.VISIBLE |
||||
mMainFragment.updateBook(UpdateBookEvent()) |
||||
} else { |
||||
val secondTime = System.currentTimeMillis() |
||||
if (secondTime - firstTime > 1000) { |
||||
firstTime = secondTime |
||||
showToast("再次点击退出界面") |
||||
} else { |
||||
finish() |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
return super.onKeyUp(keyCode, event) |
||||
} |
||||
|
||||
@Subscribe |
||||
fun setBottomBar(event: HideBottomBarEvent) { |
||||
if (event.result!!) { |
||||
bottom_bar.visibility = View.GONE |
||||
} else { |
||||
bottom_bar.visibility = View.VISIBLE |
||||
} |
||||
} |
||||
|
||||
@Subscribe |
||||
fun toRecommendFragment(event: SwitchFragmentEvent) { |
||||
bottom_bar.selectedItemId = R.id.tab_two |
||||
} |
||||
|
||||
companion object { |
||||
fun reStart(context: Context) { |
||||
val intent = Intent(context, NovelMainActivity::class.java) |
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK |
||||
context.startActivity(intent) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,91 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import com.novel.read.R |
||||
import com.novel.read.adapter.RankListAdapter |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.constants.Constant.COMMENT_SIZE |
||||
import com.novel.read.http.AccountManager |
||||
import com.novel.read.inter.OnLoadMoreListener |
||||
import com.novel.read.model.protocol.RankByUpdateResp |
||||
import kotlinx.android.synthetic.main.activity_rank_list.* |
||||
import retrofit2.Call |
||||
import retrofit2.Callback |
||||
import retrofit2.Response |
||||
import java.util.* |
||||
|
||||
/** |
||||
* 推荐fragment中点击更多跳转来的。 |
||||
*/ |
||||
class NovelRankListActivity(override val layoutId: Int= R.layout.activity_rank_list) : NovelBaseActivity() { |
||||
|
||||
private lateinit var mAdapter: RankListAdapter |
||||
private var mList: MutableList<RankByUpdateResp.BookBean> = ArrayList() |
||||
private var page = 1 |
||||
private var loadSize: Int = 0 |
||||
private var type: String = "" |
||||
private var sex: String = "" |
||||
|
||||
override fun initView() { |
||||
rlv_book_list.layoutManager = LinearLayoutManager(this) |
||||
mAdapter = RankListAdapter(mList, rlv_book_list) |
||||
rlv_book_list.adapter = mAdapter |
||||
sex = intent.getStringExtra(Constant.Sex) |
||||
type = intent.getStringExtra(Constant.Type) |
||||
when (type) { |
||||
Constant.ListType.Human -> toolbar.title = getString(R.string.popular_selection) |
||||
Constant.ListType.EditRecommend -> toolbar.title = getString(R.string.edit_recommend) |
||||
Constant.ListType.HotSearch -> toolbar.title = getString(R.string.hot_search) |
||||
} |
||||
getData() |
||||
} |
||||
|
||||
override fun initData() { |
||||
toolbar.setNavigationOnClickListener { finish() } |
||||
|
||||
mAdapter.setOnLoadMoreListener(object : OnLoadMoreListener { |
||||
override fun onLoadMore() { |
||||
if (mAdapter.isLoadingMore) { |
||||
|
||||
} else { |
||||
if (loadSize >= COMMENT_SIZE) { |
||||
mAdapter.isLoadingMore = true |
||||
mAdapter.notifyDataSetChanged() |
||||
page++ |
||||
getData() |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
|
||||
private fun getData() { |
||||
AccountManager.getInstance().getRankList(type, sex, Constant.DateTyp.Week, page.toString(), RankCallBack()) |
||||
} |
||||
|
||||
private inner class RankCallBack : Callback<RankByUpdateResp> { |
||||
|
||||
override fun onResponse(call: Call<RankByUpdateResp>, response: Response<RankByUpdateResp>) { |
||||
if (response.isSuccessful) { |
||||
if (response.body() != null) { |
||||
loadSize = response.body()!!.book.size |
||||
if (mAdapter.isLoadingMore) { |
||||
mAdapter.isLoadingMore = false |
||||
mList.addAll(response.body()!!.book) |
||||
mAdapter.notifyDataSetChanged() |
||||
} else { |
||||
mList.clear() |
||||
mList.addAll(response.body()!!.book) |
||||
mAdapter.notifyDataSetChanged() |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun onFailure(call: Call<RankByUpdateResp>, t: Throwable) { |
||||
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,655 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.app.Activity |
||||
import android.app.Service |
||||
import android.content.* |
||||
import android.os.Build |
||||
import android.os.Handler |
||||
import android.os.IBinder |
||||
import android.os.Message |
||||
import android.util.Log |
||||
import android.view.KeyEvent |
||||
import android.view.View.* |
||||
import android.view.WindowManager |
||||
import android.view.animation.Animation |
||||
import android.view.animation.AnimationUtils |
||||
import android.widget.SeekBar |
||||
import androidx.appcompat.app.AlertDialog |
||||
import androidx.core.content.ContextCompat |
||||
import androidx.core.view.GravityCompat |
||||
import androidx.drawerlayout.widget.DrawerLayout |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import com.mango.mangolib.event.EventManager |
||||
import com.novel.read.R |
||||
import com.novel.read.adapter.CategoryAdapter |
||||
import com.novel.read.adapter.MarkAdapter |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.constants.Constant.ResultCode.Companion.RESULT_IS_COLLECTED |
||||
import com.novel.read.event.BookArticleEvent |
||||
import com.novel.read.event.ErrorChapterEvent |
||||
import com.novel.read.event.FinishChapterEvent |
||||
import com.novel.read.event.RxBus |
||||
import com.novel.read.http.AccountManager |
||||
import com.novel.read.model.db.BookChapterBean |
||||
import com.novel.read.model.db.BookSignTable |
||||
import com.novel.read.model.db.CollBookBean |
||||
import com.novel.read.model.db.DownloadTaskBean |
||||
import com.novel.read.model.db.dbManage.BookRepository |
||||
import com.novel.read.service.DownloadMessage |
||||
import com.novel.read.service.DownloadService |
||||
import com.novel.read.showToast |
||||
import com.novel.read.utlis.BrightnessUtils |
||||
import com.novel.read.utlis.ScreenUtils |
||||
import com.novel.read.utlis.SpUtil |
||||
import com.novel.read.utlis.SystemBarUtils |
||||
import com.novel.read.widget.dialog.ReadSettingDialog |
||||
import com.novel.read.widget.page.PageLoader |
||||
import com.novel.read.widget.page.PageView |
||||
import com.novel.read.widget.page.ReadSettingManager |
||||
import com.novel.read.widget.page.TxtChapter |
||||
import com.squareup.otto.Subscribe |
||||
import kotlinx.android.synthetic.main.activity_read.* |
||||
import kotlinx.android.synthetic.main.layout_download.* |
||||
import kotlinx.android.synthetic.main.layout_light.* |
||||
import kotlinx.android.synthetic.main.layout_read_mark.* |
||||
import java.util.* |
||||
|
||||
/** |
||||
* 阅读页📕 |
||||
*/ |
||||
class NovelReadActivity : NovelBaseActivity(), DownloadService.OnDownloadListener { |
||||
|
||||
private lateinit var mCategoryAdapter: CategoryAdapter |
||||
private val mChapters = ArrayList<TxtChapter>() |
||||
private lateinit var mCurrentChapter: TxtChapter //当前章节 |
||||
private var currentChapter = 0 |
||||
private lateinit var mMarkAdapter: MarkAdapter |
||||
private val mMarks = ArrayList<BookSignTable>() |
||||
private lateinit var mPageLoader: PageLoader |
||||
private var mTopInAnim: Animation? = null |
||||
private var mTopOutAnim: Animation? = null |
||||
private var mBottomInAnim: Animation? = null |
||||
private var mBottomOutAnim: Animation? = null |
||||
|
||||
private lateinit var mSettingDialog: ReadSettingDialog |
||||
private var isCollected = false // isFromSDCard |
||||
private var isNightMode = false |
||||
private var isFullScreen = false |
||||
private val isRegistered = false |
||||
|
||||
private lateinit var mCollBook: CollBookBean |
||||
private lateinit var mBookId: String |
||||
|
||||
@SuppressLint("HandlerLeak") |
||||
private val mHandler = object : Handler() { |
||||
override fun handleMessage(msg: Message) { |
||||
super.handleMessage(msg) |
||||
when (msg.what) { |
||||
WHAT_CATEGORY -> rlv_list.setSelection(mPageLoader.chapterPos) |
||||
WHAT_CHAPTER -> mPageLoader.openChapter() |
||||
} |
||||
} |
||||
} |
||||
|
||||
override val layoutId: Int get() = R.layout.activity_read |
||||
|
||||
// 接收电池信息和时间更新的广播 |
||||
private val mReceiver = object : BroadcastReceiver() { |
||||
override fun onReceive(context: Context, intent: Intent) { |
||||
if (Objects.requireNonNull(intent.action) == Intent.ACTION_BATTERY_CHANGED) { |
||||
val level = intent.getIntExtra("level", 0) |
||||
mPageLoader.updateBattery(level) |
||||
} else if (intent.action == Intent.ACTION_TIME_TICK) { |
||||
mPageLoader.updateTime() |
||||
}// 监听分钟的变化 |
||||
} |
||||
} |
||||
|
||||
private var mService: DownloadService.IDownloadManager? = null |
||||
private var mConn: ServiceConnection? = null |
||||
|
||||
override fun initView() { |
||||
EventManager.instance.registerSubscriber(this) |
||||
mCollBook = intent.getSerializableExtra(EXTRA_COLL_BOOK) as CollBookBean |
||||
isCollected = intent.getBooleanExtra(EXTRA_IS_COLLECTED, false) |
||||
mBookId = mCollBook.id |
||||
initService() |
||||
// 如果 API < 18 取消硬件加速 |
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { |
||||
read_pv_page.setLayerType(LAYER_TYPE_SOFTWARE, null) |
||||
} |
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) |
||||
|
||||
//获取页面加载器 |
||||
mPageLoader = read_pv_page.getPageLoader(mCollBook) |
||||
|
||||
mSettingDialog = ReadSettingDialog(this, mPageLoader) |
||||
//禁止滑动展示DrawerLayout |
||||
read_dl_slide.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) |
||||
//侧边打开后,返回键能够起作用 |
||||
read_dl_slide.isFocusableInTouchMode = false |
||||
//半透明化StatusBar |
||||
SystemBarUtils.transparentStatusBar(this) |
||||
//隐藏StatusBar |
||||
read_pv_page.post { this.hideSystemBar() } |
||||
read_abl_top_menu.setPadding(0, ScreenUtils.statusBarHeight, 0, 0) |
||||
ll_download.setPadding(0, ScreenUtils.statusBarHeight, 0, ScreenUtils.dpToPx(15)) |
||||
|
||||
val lp = window.attributes |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { |
||||
lp.layoutInDisplayCutoutMode = 1 |
||||
} |
||||
window.attributes = lp |
||||
|
||||
//设置当前Activity的Brightness |
||||
if (ReadSettingManager.getInstance().isBrightnessAuto) { |
||||
BrightnessUtils.setDefaultBrightness(this) |
||||
} else { |
||||
BrightnessUtils.setBrightness(this, ReadSettingManager.getInstance().brightness) |
||||
} |
||||
|
||||
//注册广播 |
||||
val intentFilter = IntentFilter() |
||||
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED) |
||||
intentFilter.addAction(Intent.ACTION_TIME_TICK) |
||||
registerReceiver(mReceiver, intentFilter) |
||||
|
||||
if (!SpUtil.getBooleanValue(Constant.BookGuide, false)) { |
||||
iv_guide.visibility = VISIBLE |
||||
toggleMenu(false) |
||||
} |
||||
|
||||
if (isCollected) { |
||||
mPageLoader.collBook.bookChapters = BookRepository.getInstance().getBookChaptersInRx(mBookId) |
||||
// 刷新章节列表 |
||||
mPageLoader.refreshChapterList() |
||||
// 如果是网络小说并被标记更新的,则从网络下载目录 |
||||
if (mCollBook.isUpdate && !mCollBook.isLocal) { |
||||
AccountManager.getInstance().getBookArticle(mBookId) |
||||
} |
||||
} else { |
||||
AccountManager.getInstance().getBookArticle(mBookId) |
||||
} |
||||
|
||||
} |
||||
|
||||
override fun initData() { |
||||
tv_book_name.text = mCollBook.title |
||||
mCategoryAdapter = CategoryAdapter() |
||||
rlv_list.adapter = mCategoryAdapter |
||||
rlv_list.isFastScrollEnabled = true |
||||
rlv_mark.layoutManager = LinearLayoutManager(this) |
||||
mMarkAdapter = MarkAdapter(mMarks) |
||||
rlv_mark.adapter = mMarkAdapter |
||||
isNightMode = ReadSettingManager.getInstance().isNightMode |
||||
//夜间模式按钮的状态 |
||||
toggleNightMode() |
||||
isFullScreen = ReadSettingManager.getInstance().isFullScreen |
||||
toolbar.setNavigationOnClickListener { finish() } |
||||
read_setting_sb_brightness.progress = ReadSettingManager.getInstance().brightness |
||||
mPageLoader.setOnPageChangeListener( |
||||
object : PageLoader.OnPageChangeListener { |
||||
|
||||
override fun onChapterChange(pos: Int) { |
||||
var index: Int = pos |
||||
if (pos >= mChapters.size) { |
||||
index = mChapters.size - 1 |
||||
} |
||||
mCategoryAdapter.setChapter(index) |
||||
mCurrentChapter = mChapters[index] |
||||
currentChapter = index |
||||
} |
||||
|
||||
override fun requestChapters(requestChapters: List<TxtChapter>) { |
||||
AccountManager.getInstance().getBookArticleDetail(mBookId, requestChapters) |
||||
mHandler.sendEmptyMessage(WHAT_CATEGORY) |
||||
} |
||||
|
||||
override fun onCategoryFinish(chapters: List<TxtChapter>) { |
||||
mChapters.clear() |
||||
mChapters.addAll(chapters) |
||||
mCategoryAdapter.refreshItems(mChapters) |
||||
} |
||||
|
||||
override fun onPageCountChange(count: Int) {} |
||||
|
||||
override fun onPageChange(pos: Int) { |
||||
|
||||
} |
||||
} |
||||
) |
||||
read_pv_page.setTouchListener(object : PageView.TouchListener { |
||||
override fun onTouch(): Boolean { |
||||
return !hideReadMenu() |
||||
} |
||||
|
||||
override fun center() { |
||||
toggleMenu(true) |
||||
} |
||||
|
||||
override fun prePage() {} |
||||
|
||||
override fun nextPage() {} |
||||
|
||||
override fun cancel() {} |
||||
}) |
||||
read_tv_category.setOnClickListener { |
||||
//移动到指定位置 |
||||
if (mCategoryAdapter.count > 0) { |
||||
rlv_list.setSelection(mPageLoader.chapterPos) |
||||
} |
||||
//切换菜单 |
||||
toggleMenu(true) |
||||
//打开侧滑动栏 |
||||
read_dl_slide.openDrawer(GravityCompat.START) |
||||
} |
||||
tv_light.setOnClickListener { |
||||
ll_light.visibility = GONE |
||||
rlReadMark.visibility = GONE |
||||
if (isVisible(ll_light)) { |
||||
ll_light.visibility = GONE |
||||
} else { |
||||
ll_light.visibility = VISIBLE |
||||
} |
||||
} |
||||
tv_setting.setOnClickListener { |
||||
ll_light.visibility = GONE |
||||
rlReadMark.visibility = GONE |
||||
toggleMenu(false) |
||||
mSettingDialog.show() |
||||
} |
||||
|
||||
read_setting_sb_brightness.setOnSeekBarChangeListener(object : |
||||
SeekBar.OnSeekBarChangeListener { |
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { |
||||
|
||||
} |
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) { |
||||
|
||||
} |
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) { |
||||
val progress = seekBar.progress |
||||
//设置当前 Activity 的亮度 |
||||
BrightnessUtils.setBrightness(this@NovelReadActivity, progress) |
||||
//存储亮度的进度条 |
||||
ReadSettingManager.getInstance().brightness = progress |
||||
} |
||||
}) |
||||
|
||||
tvBookReadMode.setOnClickListener { |
||||
isNightMode = !isNightMode |
||||
mPageLoader.setNightMode(isNightMode) |
||||
toggleNightMode() |
||||
} |
||||
|
||||
read_tv_brief.setOnClickListener { |
||||
val intent = Intent(this, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, Integer.valueOf(mBookId)) |
||||
startActivity(intent) |
||||
} |
||||
|
||||
read_tv_community.setOnClickListener { |
||||
if (isVisible(read_ll_bottom_menu)) { |
||||
if (isVisible(rlReadMark)) { |
||||
gone(rlReadMark) |
||||
} else { |
||||
gone(ll_light) |
||||
updateMark() |
||||
visible(rlReadMark) |
||||
} |
||||
} |
||||
} |
||||
|
||||
tvAddMark.setOnClickListener { |
||||
mMarkAdapter.edit = false |
||||
if (BookRepository.getInstance().getSignById(mCurrentChapter.chapterId)) { |
||||
showToast(getString(R.string.sign_exist)) |
||||
return@setOnClickListener |
||||
} |
||||
BookRepository.getInstance().addSign(mBookId, mCurrentChapter.chapterId, mCurrentChapter.title) |
||||
updateMark() |
||||
} |
||||
|
||||
tvClear.setOnClickListener { |
||||
if (mMarkAdapter.edit) { |
||||
val sign = mMarkAdapter.selectList |
||||
if (sign != "") { |
||||
BookRepository.getInstance().deleteSign(sign) |
||||
updateMark() |
||||
} |
||||
mMarkAdapter.edit = false |
||||
} else { |
||||
mMarkAdapter.edit = true |
||||
} |
||||
} |
||||
|
||||
tv_cache.setOnClickListener { |
||||
if (!isCollected) { //没有收藏 先收藏 然后弹框 |
||||
//设置为已收藏 |
||||
isCollected = true |
||||
//设置阅读时间 |
||||
mCollBook.lastRead = System.currentTimeMillis().toString() |
||||
BookRepository.getInstance().saveCollBookWithAsync(mCollBook) |
||||
} |
||||
showDownLoadDialog() |
||||
|
||||
} |
||||
rlv_list.setOnItemClickListener { _, _, position, _ -> |
||||
read_dl_slide.closeDrawer(GravityCompat.START) |
||||
mPageLoader.skipToChapter(position) |
||||
} |
||||
iv_guide.setOnClickListener { |
||||
iv_guide.visibility = GONE |
||||
SpUtil.setBooleanValue(Constant.BookGuide, true) |
||||
} |
||||
} |
||||
|
||||
private fun showDownLoadDialog() { |
||||
val builder = AlertDialog.Builder(this) |
||||
builder.setTitle(getString(R.string.d_cache_num)) |
||||
.setItems( |
||||
arrayOf( |
||||
getString(R.string.d_cache_last_50), |
||||
getString(R.string.d_cache_last_all), |
||||
getString(R.string.d_cache_all) |
||||
) |
||||
) { _, which -> |
||||
when (which) { |
||||
0 -> { |
||||
//50章 |
||||
val last = currentChapter + 50 |
||||
if (last > mCollBook.bookChapters.size) { |
||||
downLoadCache(mCollBook.bookChapters, mCollBook.bookChapters.size) |
||||
} else { |
||||
downLoadCache(mCollBook.bookChapters, last) |
||||
} |
||||
} |
||||
1 -> { |
||||
//后面所有 |
||||
val lastBeans = ArrayList<BookChapterBean>() |
||||
for (i in currentChapter until mCollBook.bookChapters.size) { |
||||
lastBeans.add(mCollBook.bookChapters[i]) |
||||
} |
||||
downLoadCache(lastBeans, mCollBook.bookChapters.size - currentChapter) |
||||
} |
||||
2 -> downLoadCache(mCollBook.bookChapters, mCollBook.bookChapters.size) //所有 |
||||
else -> { |
||||
} |
||||
} |
||||
toggleMenu(true) |
||||
} |
||||
builder.show() |
||||
} |
||||
|
||||
private fun downLoadCache(beans: List<BookChapterBean>, size: Int) { |
||||
val task = DownloadTaskBean() |
||||
task.taskName = mCollBook.title |
||||
task.bookId = mCollBook.id |
||||
task.bookChapters = beans //计算要缓存的章节 |
||||
task.currentChapter = currentChapter |
||||
task.lastChapter = size |
||||
|
||||
RxBus.getInstance().post(task) |
||||
startService(Intent(this, DownloadService::class.java)) |
||||
} |
||||
|
||||
private fun toggleNightMode() { |
||||
if (isNightMode) { |
||||
tvBookReadMode.text = resources.getString(R.string.book_read_mode_day) |
||||
val drawable = ContextCompat.getDrawable(this, R.drawable.ic_read_menu_moring) |
||||
tvBookReadMode.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null) |
||||
cl_layout.setBackgroundColor(ContextCompat.getColor(this, R.color.read_bg_night)) |
||||
} else { |
||||
tvBookReadMode.text = resources.getString(R.string.book_read_mode_day) |
||||
val drawable = ContextCompat.getDrawable(this, R.drawable.ic_read_menu_night) |
||||
tvBookReadMode.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null) |
||||
cl_layout.setBackgroundColor( |
||||
ContextCompat.getColor( |
||||
this, |
||||
ReadSettingManager.getInstance().pageStyle.bgColor |
||||
) |
||||
) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 隐藏阅读界面的菜单显示 |
||||
* |
||||
* @return 是否隐藏成功 |
||||
*/ |
||||
private fun hideReadMenu(): Boolean { |
||||
hideSystemBar() |
||||
if (read_abl_top_menu.visibility == VISIBLE) { |
||||
toggleMenu(true) |
||||
return true |
||||
} else if (mSettingDialog.isShowing) { |
||||
mSettingDialog.dismiss() |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
private fun showSystemBar() { |
||||
//显示 |
||||
SystemBarUtils.showUnStableStatusBar(this) |
||||
if (isFullScreen) { |
||||
SystemBarUtils.showUnStableNavBar(this) |
||||
} |
||||
} |
||||
|
||||
private fun hideSystemBar() { |
||||
//隐藏 |
||||
SystemBarUtils.hideStableStatusBar(this) |
||||
if (isFullScreen) { |
||||
SystemBarUtils.hideStableNavBar(this) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 切换菜单栏的可视状态 |
||||
* 默认是隐藏的 |
||||
*/ |
||||
private fun toggleMenu(hideStatusBar: Boolean) { |
||||
initMenuAnim() |
||||
gone(ll_light, rlReadMark) |
||||
if (read_abl_top_menu.visibility == VISIBLE) { |
||||
//关闭 |
||||
read_abl_top_menu.startAnimation(mTopOutAnim) |
||||
read_ll_bottom_menu.startAnimation(mBottomOutAnim) |
||||
read_abl_top_menu.visibility = GONE |
||||
read_ll_bottom_menu.visibility = GONE |
||||
|
||||
if (hideStatusBar) { |
||||
hideSystemBar() |
||||
} |
||||
} else { |
||||
read_abl_top_menu.visibility = VISIBLE |
||||
read_ll_bottom_menu.visibility = VISIBLE |
||||
read_abl_top_menu.startAnimation(mTopInAnim) |
||||
read_ll_bottom_menu.startAnimation(mBottomInAnim) |
||||
|
||||
showSystemBar() |
||||
} |
||||
} |
||||
|
||||
//初始化菜单动画 |
||||
private fun initMenuAnim() { |
||||
if (mTopInAnim != null) return |
||||
mTopInAnim = AnimationUtils.loadAnimation(this, R.anim.slide_top_in) |
||||
mTopOutAnim = AnimationUtils.loadAnimation(this, R.anim.slide_top_out) |
||||
mBottomInAnim = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_in) |
||||
mBottomOutAnim = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_out) |
||||
//退出的速度要快 |
||||
mTopOutAnim!!.duration = 200 |
||||
mBottomOutAnim!!.duration = 200 |
||||
} |
||||
|
||||
@Subscribe |
||||
fun getBookArticle(event: BookArticleEvent) { |
||||
if (event.isFail) { |
||||
//获取章节失败处理 |
||||
Log.e(TAG, event.er!!.msg) |
||||
} else { |
||||
val chapterBeans = event.result!!.chapterBean |
||||
mPageLoader.collBook.bookChapters = chapterBeans |
||||
mPageLoader.refreshChapterList() |
||||
|
||||
// 如果是目录更新的情况,那么就需要存储更新数据 |
||||
if (mCollBook.isUpdate && isCollected) { |
||||
BookRepository.getInstance().saveBookChaptersWithAsync(chapterBeans, mCollBook) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Subscribe |
||||
fun finishChapter(event: FinishChapterEvent) { |
||||
if (mPageLoader.pageStatus == PageLoader.STATUS_LOADING) { |
||||
mHandler.sendEmptyMessage(WHAT_CHAPTER) |
||||
} |
||||
// 当完成章节的时候,刷新列表 |
||||
mCategoryAdapter.notifyDataSetChanged() |
||||
} |
||||
|
||||
@Subscribe |
||||
fun errorChapter(event: ErrorChapterEvent) { |
||||
if (mPageLoader.pageStatus == PageLoader.STATUS_LOADING) { |
||||
mPageLoader.chapterError() |
||||
} |
||||
} |
||||
|
||||
private fun updateMark() { |
||||
mMarks.clear() |
||||
mMarks.addAll(BookRepository.getInstance().getSign(mBookId)) |
||||
mMarkAdapter.notifyDataSetChanged() |
||||
} |
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { |
||||
when (keyCode) { |
||||
KeyEvent.KEYCODE_VOLUME_UP -> return mPageLoader.skipToPrePage() |
||||
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN -> return mPageLoader.skipToNextPage() |
||||
} |
||||
return super.onKeyDown(keyCode, event) |
||||
} |
||||
|
||||
override fun onBackPressed() { |
||||
if (read_abl_top_menu.visibility == VISIBLE) { |
||||
// 非全屏下才收缩,全屏下直接退出 |
||||
if (!ReadSettingManager.getInstance().isFullScreen) { |
||||
toggleMenu(true) |
||||
return |
||||
} |
||||
} else if (mSettingDialog.isShowing) { |
||||
mSettingDialog.dismiss() |
||||
return |
||||
} else if (read_dl_slide.isDrawerOpen(GravityCompat.START)) { |
||||
read_dl_slide.closeDrawer(GravityCompat.START) |
||||
return |
||||
} |
||||
Log.e(TAG, "onBackPressed: " + mCollBook.bookChapters.isEmpty()) |
||||
|
||||
if (!mCollBook.isLocal && !isCollected && mCollBook.bookChapters.isNotEmpty()) { |
||||
val alertDialog = AlertDialog.Builder(this) |
||||
.setTitle(getString(R.string.add_book)) |
||||
.setMessage(getString(R.string.like_book)) |
||||
.setPositiveButton(getString(R.string.sure)) { dialog, which -> |
||||
//设置为已收藏 |
||||
isCollected = true |
||||
//设置阅读时间 |
||||
mCollBook.lastRead = System.currentTimeMillis().toString() |
||||
|
||||
BookRepository.getInstance().saveCollBookWithAsync(mCollBook) |
||||
|
||||
exit() |
||||
} |
||||
.setNegativeButton(getString(R.string.cancel)) { dialog, which -> exit() }.create() |
||||
alertDialog.show() |
||||
} else { |
||||
exit() |
||||
} |
||||
} |
||||
|
||||
// 退出 |
||||
private fun exit() { |
||||
// 返回给BookDetail。 |
||||
val result = Intent() |
||||
result.putExtra(RESULT_IS_COLLECTED, isCollected) |
||||
setResult(Activity.RESULT_OK, result) |
||||
super.onBackPressed() |
||||
} |
||||
|
||||
override fun onPause() { |
||||
super.onPause() |
||||
if (isCollected) { |
||||
mPageLoader.saveRecord() |
||||
} |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
EventManager.instance.unregisterSubscriber(this) |
||||
mPageLoader.closeBook() |
||||
unbindService(mConn) |
||||
unregisterReceiver(mReceiver) |
||||
} |
||||
|
||||
private fun initService() { |
||||
|
||||
mConn = object : ServiceConnection { |
||||
override fun onServiceConnected(name: ComponentName, service: IBinder) { |
||||
mService = service as DownloadService.IDownloadManager |
||||
mService!!.setOnDownloadListener(this@NovelReadActivity) |
||||
} |
||||
|
||||
override fun onServiceDisconnected(name: ComponentName) {} |
||||
} |
||||
//绑定 |
||||
bindService(Intent(this, DownloadService::class.java), mConn, Service.BIND_AUTO_CREATE) |
||||
} |
||||
|
||||
override fun onDownloadChange(pos: Int, status: Int, msg: String) { |
||||
Log.e(TAG, "onDownloadChange: $pos $status $msg") |
||||
|
||||
if (msg == getString(R.string.download_success) || msg == getString(R.string.download_error)) { |
||||
//下载成功或失败后隐藏下载视图 |
||||
if (ll_download != null) { |
||||
ll_download.visibility = GONE |
||||
showToast(msg) |
||||
} |
||||
} else { |
||||
if (ll_download != null) { |
||||
ll_download.visibility = VISIBLE |
||||
tv_progress.text = getString( |
||||
R.string.download_loading, |
||||
mService!!.downloadTaskList[pos].currentChapter, |
||||
mService!!.downloadTaskList[pos].lastChapter |
||||
) |
||||
pb_loading.max = mService!!.downloadTaskList[pos].lastChapter |
||||
pb_loading.progress = mService!!.downloadTaskList[pos].currentChapter |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
override fun onDownloadResponse(pos: Int, status: Int) { |
||||
Log.e(TAG, "onDownloadResponse: $pos $status") |
||||
} |
||||
|
||||
@Subscribe |
||||
fun onDownLoadEvent(message: DownloadMessage) { |
||||
showToast(message.message) |
||||
} |
||||
|
||||
companion object { |
||||
|
||||
private const val TAG = "NovelReadActivity" |
||||
const val EXTRA_COLL_BOOK = "extra_coll_book" |
||||
const val EXTRA_IS_COLLECTED = "extra_is_collected" |
||||
private const val WHAT_CATEGORY = 1 |
||||
private const val WHAT_CHAPTER = 2 |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import android.view.View |
||||
import androidx.fragment.app.Fragment |
||||
import androidx.viewpager.widget.ViewPager |
||||
import com.novel.read.R |
||||
import com.novel.read.adapter.ViewPageAdapter |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.fragment.BookListFragment |
||||
import com.novel.read.widget.VpTabLayout |
||||
import kotlinx.android.synthetic.main.activity_recommend_book_list.* |
||||
import java.util.* |
||||
|
||||
class NovelRecommendBookListActivity(override val layoutId: Int= R.layout.activity_recommend_book_list) : NovelBaseActivity() { |
||||
|
||||
override fun initView() { |
||||
val fragmentList = ArrayList<Fragment>() |
||||
val sex = intent.getStringExtra(Constant.Sex) |
||||
val type = intent.getStringExtra(Constant.Type) |
||||
when (type) { |
||||
Constant.ListType.Human -> toolbar.title = getString(R.string.popular_selection) |
||||
Constant.ListType.EditRecommend -> toolbar.title = getString(R.string.edit_recommend) |
||||
Constant.ListType.HotSearch -> toolbar.title = getString(R.string.hot_search) |
||||
} |
||||
val generalFragment = BookListFragment.newInstance(type, Constant.DateTyp.General, sex) |
||||
val monthFragment = BookListFragment.newInstance(type, Constant.DateTyp.Month, sex) |
||||
val weekFragment = BookListFragment.newInstance(type, Constant.DateTyp.Week, sex) |
||||
fragmentList.add(generalFragment) |
||||
fragmentList.add(monthFragment) |
||||
fragmentList.add(weekFragment) |
||||
val pageAdapter = ViewPageAdapter(supportFragmentManager, fragmentList) |
||||
vp_recommend_type.adapter = pageAdapter |
||||
vp_recommend_type.offscreenPageLimit = 2 |
||||
vp_recommend_type.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { |
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { |
||||
|
||||
} |
||||
|
||||
override fun onPageSelected(position: Int) { |
||||
vp_tab.setAnim(position, vp_recommend_type) |
||||
} |
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {} |
||||
}) |
||||
} |
||||
|
||||
override fun initData() { |
||||
toolbar!!.setNavigationOnClickListener { finish() } |
||||
|
||||
vp_tab.setOnTabBtnClickListener(object : VpTabLayout.OnTabClickListener { |
||||
override fun onTabBtnClick(var1: VpTabLayout.CommonTabBtn, var2: View) { |
||||
when (var1) { |
||||
VpTabLayout.CommonTabBtn.ONE -> vp_tab.setAnim(0, vp_recommend_type) |
||||
VpTabLayout.CommonTabBtn.TWO -> vp_tab.setAnim(1, vp_recommend_type) |
||||
VpTabLayout.CommonTabBtn.THREE -> vp_tab.setAnim(2, vp_recommend_type) |
||||
} |
||||
} |
||||
}) |
||||
|
||||
} |
||||
} |
@ -0,0 +1,255 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import android.content.DialogInterface |
||||
import android.text.Editable |
||||
import android.text.TextUtils |
||||
import android.text.TextWatcher |
||||
import android.view.KeyEvent |
||||
import android.view.View |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import com.google.android.flexbox.AlignItems |
||||
import com.google.android.flexbox.FlexDirection |
||||
import com.google.android.flexbox.FlexWrap |
||||
import com.google.android.flexbox.FlexboxLayoutManager |
||||
import com.mango.mangolib.event.EventManager |
||||
import com.novel.read.R |
||||
import com.novel.read.adapter.HistoryAdapter |
||||
import com.novel.read.adapter.HotAdapter |
||||
import com.novel.read.adapter.SearchAdapter |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant.COMMENT_SIZE |
||||
import com.novel.read.event.HotSearchEvent |
||||
import com.novel.read.event.SearchListEvent |
||||
import com.novel.read.http.AccountManager |
||||
import com.novel.read.inter.OnLoadMoreListener |
||||
import com.novel.read.model.db.SearchListTable |
||||
import com.novel.read.model.protocol.SearchResp |
||||
import com.novel.read.utlis.DialogUtils |
||||
import com.spreada.utils.chinese.ZHConverter |
||||
import com.squareup.otto.Subscribe |
||||
import kotlinx.android.synthetic.main.activity_search.* |
||||
import kotlinx.android.synthetic.main.title_search.* |
||||
import org.litepal.LitePal |
||||
import java.util.* |
||||
|
||||
class NovelSearchActivity(override val layoutId: Int= R.layout.activity_search) : NovelBaseActivity() { |
||||
|
||||
private val mHotList = ArrayList<String>() |
||||
private lateinit var mHotAdapter: HotAdapter |
||||
|
||||
private var mHisList: MutableList<SearchListTable> = ArrayList() |
||||
private lateinit var mHisAdapter: HistoryAdapter |
||||
|
||||
private val mSearchList = ArrayList<SearchResp.BookBean>() |
||||
private lateinit var mSearchAdapter: SearchAdapter |
||||
|
||||
private var page = 1 |
||||
private var loadSize: Int = 0 |
||||
|
||||
override fun initView() { |
||||
EventManager.instance.registerSubscriber(this) |
||||
|
||||
val manager = FlexboxLayoutManager(this) |
||||
//设置主轴排列方式 |
||||
manager.flexDirection = FlexDirection.ROW |
||||
//设置是否换行 |
||||
manager.flexWrap = FlexWrap.WRAP |
||||
manager.alignItems = AlignItems.STRETCH |
||||
rlv_hot.layoutManager = manager |
||||
mHotAdapter = HotAdapter(mHotList) |
||||
rlv_hot.adapter = mHotAdapter |
||||
|
||||
mHisList = LitePal.order("saveTime desc").limit(5).find(SearchListTable::class.java) |
||||
val manager2 = FlexboxLayoutManager(this) |
||||
//设置主轴排列方式 |
||||
manager2.flexDirection = FlexDirection.ROW |
||||
//设置是否换行 |
||||
manager2.flexWrap = FlexWrap.WRAP |
||||
manager2.alignItems = AlignItems.STRETCH |
||||
mHisAdapter = HistoryAdapter(mHisList) |
||||
rlv_history.layoutManager = manager2 |
||||
rlv_history.adapter = mHisAdapter |
||||
|
||||
rlv_search.layoutManager = LinearLayoutManager(this) |
||||
mSearchAdapter = SearchAdapter(mSearchList, rlv_search) |
||||
rlv_search.adapter = mSearchAdapter |
||||
|
||||
mSearchAdapter.setOnLoadMoreListener(object : OnLoadMoreListener { |
||||
override fun onLoadMore() { |
||||
if (mSearchAdapter.isLoadingMore) { |
||||
|
||||
} else { |
||||
if (loadSize >= COMMENT_SIZE) { |
||||
mSearchAdapter.isLoadingMore = true |
||||
mSearchAdapter.notifyDataSetChanged() |
||||
page++ |
||||
getData() |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
|
||||
AccountManager.getInstance().getHotSearch() |
||||
} |
||||
|
||||
private fun getData() { |
||||
val str = convertCC(tv_search.text.toString().trim { it <= ' ' }) |
||||
AccountManager.getInstance().getSearchBookList("", str, page) |
||||
} |
||||
|
||||
//繁簡轉換 |
||||
fun convertCC(input: String): String { |
||||
return if (TextUtils.isEmpty(input) || input.isEmpty()) "" else ZHConverter.getInstance( |
||||
ZHConverter.SIMPLIFIED |
||||
).convert(input) |
||||
} |
||||
|
||||
override fun initData() { |
||||
//输入框 |
||||
tv_search.addTextChangedListener(object : TextWatcher { |
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { |
||||
|
||||
} |
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { |
||||
if (s.toString().trim { it <= ' ' } == "") { |
||||
refresh.visibility = View.GONE |
||||
head_hot.visibility = View.VISIBLE |
||||
head_history.visibility = View.VISIBLE |
||||
rlv_hot.visibility = View.VISIBLE |
||||
rlv_history.visibility = View.VISIBLE |
||||
} else { |
||||
refresh.visibility = View.VISIBLE |
||||
head_hot.visibility = View.GONE |
||||
head_history.visibility = View.GONE |
||||
rlv_hot.visibility = View.GONE |
||||
rlv_history.visibility = View.GONE |
||||
refresh.showLoading() |
||||
page = 1 |
||||
getData() |
||||
} |
||||
|
||||
} |
||||
|
||||
override fun afterTextChanged(s: Editable) { |
||||
|
||||
} |
||||
}) |
||||
|
||||
//键盘的搜索 |
||||
tv_search.setOnKeyListener { v, keyCode, event -> |
||||
//修改回车键功能 |
||||
if (keyCode == KeyEvent.KEYCODE_ENTER) { |
||||
mSearchAdapter.setHolderType(true) |
||||
saveKey() |
||||
return@setOnKeyListener true |
||||
} |
||||
false |
||||
} |
||||
|
||||
mHotAdapter.setOnItemClickListener(object :HotAdapter.OnItemClickListener{ |
||||
override fun onItemClick(view: View, pos: Int) { |
||||
mSearchAdapter.setHolderType(true) |
||||
refresh.visibility = View.VISIBLE |
||||
tv_search.setText(mHotList[pos]) |
||||
saveKey() |
||||
} |
||||
}) |
||||
|
||||
mHisAdapter.setOnItemClickListener(object :HistoryAdapter.OnItemClickListener{ |
||||
override fun onItemClick(view: View, pos: Int) { |
||||
mSearchAdapter.setHolderType(true) |
||||
refresh.visibility = View.VISIBLE |
||||
tv_search.setText(mHisList[pos].key) |
||||
saveKey() |
||||
} |
||||
}) |
||||
|
||||
mSearchAdapter.setOnItemClickListener(object :SearchAdapter.OnItemClickListener{ |
||||
override fun onItemClick(view: View, pos: Int) { |
||||
mSearchAdapter.setHolderType(true) |
||||
tv_search.setText(mSearchList[pos].title) |
||||
saveKey() |
||||
} |
||||
}) |
||||
|
||||
head_history.setOnClickListener { view -> |
||||
|
||||
DialogUtils.getInstance().showAlertDialog( |
||||
this, |
||||
getString(R.string.clear_search), |
||||
dialogListener = DialogInterface.OnClickListener { dialog, which -> |
||||
LitePal.deleteAll(SearchListTable::class.java) |
||||
mHisList.clear() |
||||
mHisList.addAll(LitePal.order("saveTime desc").limit(5).find(SearchListTable::class.java)) |
||||
mHisAdapter.notifyDataSetChanged() |
||||
}) |
||||
} |
||||
|
||||
tv_cancel.setOnClickListener { |
||||
onBackPressed() |
||||
} |
||||
|
||||
refresh.setOnReloadingListener { getData() } |
||||
|
||||
} |
||||
|
||||
private fun saveKey() { |
||||
if (tv_search.text.toString().trim { it <= ' ' } == "") { |
||||
return |
||||
} |
||||
val searchListTable = SearchListTable() |
||||
searchListTable.key = tv_search.text.toString().trim { it <= ' ' } |
||||
searchListTable.saveTime = System.currentTimeMillis() |
||||
searchListTable.saveOrUpdate("key=?", tv_search.text.toString().trim { it <= ' ' }) |
||||
mHisList.clear() |
||||
mHisList.addAll(LitePal.order("saveTime desc").limit(5).find(SearchListTable::class.java)) |
||||
mHisAdapter.notifyDataSetChanged() |
||||
} |
||||
|
||||
override fun onBackPressed() { |
||||
if (refresh.visibility == View.VISIBLE) { |
||||
tv_search.setText("") |
||||
mSearchAdapter.setHolderType(false) |
||||
page = 1 |
||||
} else { |
||||
super.onBackPressed() |
||||
overridePendingTransition(R.anim.message_fade_in, R.anim.message_fade_out) |
||||
} |
||||
} |
||||
|
||||
@Subscribe |
||||
fun getHotSearch(event: HotSearchEvent) { |
||||
if (event.isFail) { |
||||
|
||||
} else { |
||||
mHotList.clear() |
||||
mHotList.addAll(event.result!!.key) |
||||
mHotAdapter.notifyDataSetChanged() |
||||
} |
||||
} |
||||
|
||||
@Subscribe |
||||
fun getSearchList(event: SearchListEvent) { |
||||
refresh.showFinish() |
||||
if (event.isFail) { |
||||
refresh.showError() |
||||
} else { |
||||
loadSize = event.result!!.book.size |
||||
if (mSearchAdapter.isLoadingMore) { |
||||
mSearchAdapter.isLoadingMore = false |
||||
mSearchList.addAll(event.result!!.book) |
||||
mSearchAdapter.notifyDataSetChanged() |
||||
} else { |
||||
mSearchList.clear() |
||||
mSearchList.addAll(event.result!!.book) |
||||
mSearchAdapter.notifyDataSetChanged() |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
EventManager.instance.unregisterSubscriber(this) |
||||
} |
||||
} |
@ -0,0 +1,152 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.app.AlertDialog |
||||
import android.text.TextUtils |
||||
import android.view.View |
||||
import com.allenliu.versionchecklib.v2.AllenVersionChecker |
||||
import com.allenliu.versionchecklib.v2.builder.UIData |
||||
import com.mango.mangolib.event.EventManager |
||||
import com.novel.read.R |
||||
import com.novel.read.base.NovelBaseActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.event.UpdateBookEvent |
||||
import com.novel.read.event.VersionEvent |
||||
import com.novel.read.http.AccountManager |
||||
import com.novel.read.model.protocol.VersionResp |
||||
import com.novel.read.utlis.CleanCacheUtils |
||||
import com.novel.read.utlis.LocalManageUtil |
||||
import com.novel.read.utlis.SpUtil |
||||
import com.novel.read.utlis.VersionUtil |
||||
import com.squareup.otto.Subscribe |
||||
import kotlinx.android.synthetic.main.activity_setting.* |
||||
|
||||
class NovelSettingActivity(override val layoutId: Int = R.layout.activity_setting) : NovelBaseActivity(), View.OnClickListener { |
||||
|
||||
private var resp: VersionResp? = null |
||||
|
||||
override fun initView() { |
||||
EventManager.instance.registerSubscriber(this) |
||||
} |
||||
|
||||
@SuppressLint("SetTextI18n") |
||||
override fun initData() { |
||||
tv_language.text = |
||||
resources.getStringArray(R.array.setting_dialog_language_choice)[SpUtil.getIntValue( |
||||
Constant.Language, |
||||
1 |
||||
)] |
||||
tv_version.text = "V" + VersionUtil.getPackageName(this)!! |
||||
try { |
||||
val cacheSize = |
||||
CleanCacheUtils.getInstance().getTotalCacheSize(this@NovelSettingActivity) |
||||
tv_cache_num.text = cacheSize |
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} |
||||
toolbar.setNavigationOnClickListener { finish() } |
||||
AccountManager.getInstance().checkVersion(VersionUtil.getPackageCode(this)) |
||||
|
||||
ll_choose_language.setOnClickListener(this) |
||||
ll_clear_cache.setOnClickListener(this) |
||||
tv_check.setOnClickListener(this) |
||||
} |
||||
|
||||
override fun onClick(v: View?) { |
||||
when (v?.id) { |
||||
R.id.ll_choose_language -> showLanguageDialog() |
||||
R.id.ll_clear_cache -> { |
||||
//默认不勾选清空书架列表,防手抖!! |
||||
val selected = booleanArrayOf(true, false) |
||||
AlertDialog.Builder(this) |
||||
.setTitle(getString(R.string.clear_cache)) |
||||
.setCancelable(true) |
||||
.setMultiChoiceItems(arrayOf(getString(R.string.clear_cache), getString(R.string.clear_book)), selected) { _, which, isChecked -> selected[which] = isChecked } |
||||
.setPositiveButton(getString(R.string.sure)) { dialog, _ -> |
||||
Thread { |
||||
CleanCacheUtils.getInstance() |
||||
.clearCache(selected[0], selected[1], this@NovelSettingActivity) |
||||
var cacheSize = "" |
||||
try { |
||||
cacheSize = |
||||
CleanCacheUtils.getInstance() |
||||
.getTotalCacheSize(this@NovelSettingActivity) |
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} |
||||
val finalCacheSize = cacheSize |
||||
runOnUiThread { |
||||
EventManager.instance.postEvent(UpdateBookEvent()) |
||||
tv_cache_num.text = finalCacheSize |
||||
} |
||||
}.start() |
||||
dialog.dismiss() |
||||
} |
||||
.setNegativeButton(getString(R.string.cancel)) { dialog, _ -> dialog.dismiss() } |
||||
.create().show() |
||||
} |
||||
R.id.tv_check -> |
||||
//版本大小不为空 去更新。 |
||||
updateApk(resp!!) |
||||
} |
||||
} |
||||
|
||||
private fun showLanguageDialog() { |
||||
AlertDialog.Builder(this) |
||||
.setTitle(getString(R.string.choose_language)) |
||||
.setSingleChoiceItems( |
||||
resources.getStringArray(R.array.setting_dialog_language_choice), |
||||
SpUtil.getIntValue(Constant.Language, 1) |
||||
) { dialog, which -> |
||||
val language = |
||||
resources.getStringArray(R.array.setting_dialog_language_choice)[which] |
||||
tv_language.text = language |
||||
SpUtil.setIntValue(Constant.Language, which) |
||||
dialog.dismiss() |
||||
|
||||
if (which == 0) { |
||||
selectLanguage(0) |
||||
} else { |
||||
selectLanguage(1) |
||||
} |
||||
} |
||||
.create().show() |
||||
} |
||||
|
||||
private fun selectLanguage(select: Int) { |
||||
LocalManageUtil.saveSelectLanguage(this, select) |
||||
NovelMainActivity.reStart(this) |
||||
} |
||||
|
||||
@Subscribe |
||||
fun checkVersion(event: VersionEvent) { |
||||
if (event.isFail) { |
||||
|
||||
} else { |
||||
if (TextUtils.isEmpty(event.result!!.version.size)) { |
||||
return |
||||
} |
||||
resp = event.result |
||||
tv_check.visibility = View.VISIBLE |
||||
|
||||
} |
||||
} |
||||
|
||||
private fun updateApk(resp: VersionResp) { |
||||
val versionBean = resp.version |
||||
val builder = AllenVersionChecker |
||||
.getInstance() |
||||
.downloadOnly( |
||||
UIData.create() |
||||
.setTitle(getString(R.string.new_version, versionBean.version)) |
||||
.setContent(versionBean.content) |
||||
.setDownloadUrl(versionBean.download) |
||||
) |
||||
builder.executeMission(this) |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
EventManager.instance.unregisterSubscriber(this) |
||||
} |
||||
} |
@ -0,0 +1,69 @@ |
||||
package com.novel.read.activity |
||||
|
||||
import android.content.Intent |
||||
import android.os.Bundle |
||||
import androidx.appcompat.app.AppCompatActivity |
||||
import com.novel.read.R |
||||
import com.novel.read.utlis.PermissionUtil |
||||
import com.novel.read.utlis.StatusBarUtil |
||||
import kotlinx.android.synthetic.main.activity_splash.* |
||||
|
||||
class NovelSplashActivity : AppCompatActivity(), PermissionUtil.PermissionCallBack { |
||||
|
||||
private var flag = false |
||||
private var runnable: Runnable? = null |
||||
|
||||
private var mPermissionUtil: PermissionUtil = PermissionUtil.getInstance() |
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
super.onCreate(savedInstanceState) |
||||
StatusBarUtil.setBarsStyle(this, R.color.colorPrimary, true) |
||||
setContentView(R.layout.activity_splash) |
||||
mPermissionUtil.requestPermissions(this, PERMISSION_CODE, this) |
||||
} |
||||
|
||||
override fun onRequestPermissionsResult( |
||||
requestCode: Int, |
||||
permissions: Array<String>, |
||||
grantResults: IntArray |
||||
) { |
||||
mPermissionUtil.requestResult(this, permissions, grantResults, this) |
||||
} |
||||
|
||||
private fun init() { |
||||
runnable = Runnable { goHome() } |
||||
tvSkip.postDelayed(runnable, 2000) |
||||
tvSkip.setOnClickListener { goHome() } |
||||
} |
||||
|
||||
@Synchronized |
||||
private fun goHome() { |
||||
if (!flag) { |
||||
flag = true |
||||
startActivity(Intent(this, NovelMainActivity::class.java)) |
||||
finish() |
||||
} |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
flag = true |
||||
tvSkip.removeCallbacks(runnable) |
||||
} |
||||
|
||||
override fun onPermissionSuccess() { |
||||
init() |
||||
} |
||||
|
||||
override fun onPermissionReject(strMessage: String) { |
||||
finish() |
||||
} |
||||
|
||||
override fun onPermissionFail() { |
||||
mPermissionUtil.requestPermissions(this, PERMISSION_CODE, this) |
||||
} |
||||
|
||||
companion object { |
||||
private val PERMISSION_CODE = 999 |
||||
} |
||||
} |
@ -0,0 +1,163 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.Button |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelReadActivity |
||||
import com.novel.read.model.db.CollBookBean |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
|
||||
import java.util.ArrayList |
||||
|
||||
class BookAdapter(private val mList: List<CollBookBean>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { |
||||
private lateinit var mContext: Context |
||||
|
||||
private var mClickListener: OnItemClickListener? = null |
||||
private var mEdit: Boolean = false |
||||
|
||||
val selectList: List<CollBookBean> |
||||
get() { |
||||
val collBookBeans = ArrayList<CollBookBean>() |
||||
for (i in mList.indices) { |
||||
if (mList[i].isSelect) { |
||||
collBookBeans.add(mList[i]) |
||||
} |
||||
} |
||||
return collBookBeans |
||||
} |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder { |
||||
mContext = viewGroup.context |
||||
val view: View |
||||
if (i == VALUE_ITEM) { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} else if (i == EMPTY_ITEM) { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_add_book, viewGroup, false) |
||||
return EmptyHolder(view) |
||||
} |
||||
throw IllegalArgumentException() |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) { |
||||
if (viewHolder is ViewHolder) { |
||||
if (mEdit) { //编辑模式 |
||||
viewHolder.mIvCheck.isSelected = mList[i].isSelect |
||||
viewHolder.mIvCheck.visibility = View.VISIBLE |
||||
viewHolder.mTvBookName.text = mList[i].title |
||||
viewHolder.mTvBookAuthor.text = mList[i].author |
||||
if (mList[i].isUpdate) { |
||||
viewHolder.mIvGeng.visibility = View.VISIBLE |
||||
} else { |
||||
viewHolder.mIvGeng.visibility = View.GONE |
||||
} |
||||
GlideImageLoader.displayCornerImage(mContext, mList[i].cover, viewHolder.mIvBook) |
||||
viewHolder.itemView.setOnClickListener { |
||||
viewHolder.mIvCheck.isSelected = !mList[i].isSelect |
||||
mList[i].isSelect = !mList[i].isSelect |
||||
} |
||||
} else { //正常模式 |
||||
viewHolder.mIvCheck.visibility = View.GONE |
||||
if (mList.size == i) { //最后的条目 |
||||
viewHolder.mTvBookName.text = "" |
||||
viewHolder.mTvBookAuthor.text = "" |
||||
viewHolder.mIvBook.setImageResource(R.drawable.ic_book_add) |
||||
viewHolder.mIvGeng.visibility = View.GONE |
||||
viewHolder.itemView.setOnClickListener { view -> |
||||
mClickListener!!.onItemClick( |
||||
view, |
||||
i |
||||
) |
||||
} |
||||
} else { |
||||
viewHolder.mTvBookName.text = mList[i].title |
||||
viewHolder.mTvBookAuthor.text = mList[i].author |
||||
if (mList[i].isUpdate) { |
||||
viewHolder.mIvGeng.visibility = View.VISIBLE |
||||
} else { |
||||
viewHolder.mIvGeng.visibility = View.GONE |
||||
} |
||||
GlideImageLoader.displayCornerImage( |
||||
mContext, |
||||
mList[i].cover, |
||||
viewHolder.mIvBook |
||||
) |
||||
viewHolder.itemView.setOnClickListener { |
||||
val intent = Intent(mContext, NovelReadActivity::class.java) |
||||
intent.putExtra(NovelReadActivity.EXTRA_IS_COLLECTED, true) |
||||
intent.putExtra(NovelReadActivity.EXTRA_COLL_BOOK, mList[i]) |
||||
mContext.startActivity(intent) |
||||
} |
||||
} |
||||
} |
||||
} else if (viewHolder is EmptyHolder) { //空条目 |
||||
viewHolder.mBtnAdd.setOnClickListener { view -> mClickListener!!.onItemClick(view, i) } |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
if (mList.isEmpty()) { |
||||
return 1 |
||||
} |
||||
return if (mEdit) { |
||||
mList.size |
||||
} else { |
||||
mList.size + 1 |
||||
} |
||||
} |
||||
|
||||
override fun getItemViewType(position: Int): Int { |
||||
return if (mList.isEmpty()) { |
||||
EMPTY_ITEM |
||||
} else { |
||||
VALUE_ITEM |
||||
} |
||||
|
||||
} |
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mIvBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var mTvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var mTvBookAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
var mIvCheck: ImageView = itemView.findViewById(R.id.iv_check) |
||||
var mIvGeng: ImageView = itemView.findViewById(R.id.iv_geng) |
||||
|
||||
} |
||||
|
||||
internal class EmptyHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mBtnAdd: Button = itemView.findViewById(R.id.btn_add) |
||||
|
||||
} |
||||
|
||||
fun setOnItemClickListener(mListener: OnItemClickListener) { |
||||
this.mClickListener = mListener |
||||
} |
||||
|
||||
|
||||
interface OnItemClickListener { |
||||
fun onItemClick(view: View, pos: Int) |
||||
} |
||||
|
||||
fun setEdit(edit: Boolean) { //开启编辑模式 |
||||
mEdit = edit |
||||
notifyDataSetChanged() |
||||
} |
||||
|
||||
|
||||
companion object { |
||||
|
||||
private const val VALUE_ITEM = 100 //正常item |
||||
|
||||
private const val EMPTY_ITEM = 101 //空白item |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,126 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookDetailActivity |
||||
import com.novel.read.adapter.holder.EmptyHolder |
||||
import com.novel.read.adapter.holder.MoreHolder |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.constants.Constant.COMMENT_SIZE |
||||
import com.novel.read.inter.OnLoadMoreListener |
||||
import com.novel.read.model.protocol.SearchResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
|
||||
class BookListAdapter(private val mList: List<SearchResp.BookBean>, recyclerView: RecyclerView) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { |
||||
private var mContext: Context? = null |
||||
|
||||
var isLoadingMore: Boolean = false |
||||
private var lastVisibleItem: Int = 0 |
||||
private var totalItemCount: Int = 0 |
||||
private val visibleThreshold = 1 |
||||
private var mOnLoadMoreListener: OnLoadMoreListener? = null |
||||
|
||||
init { |
||||
if (recyclerView.layoutManager is LinearLayoutManager) { |
||||
val manager = recyclerView.layoutManager as LinearLayoutManager? |
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { |
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { |
||||
super.onScrolled(recyclerView, dx, dy) |
||||
totalItemCount = manager!!.itemCount |
||||
lastVisibleItem = manager.findLastVisibleItemPosition() |
||||
if (!isLoadingMore && totalItemCount == lastVisibleItem + visibleThreshold && totalItemCount >= COMMENT_SIZE) { |
||||
if (mOnLoadMoreListener != null) { |
||||
mOnLoadMoreListener!!.onLoadMore() |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
|
||||
} |
||||
} |
||||
|
||||
fun setOnLoadMoreListener(listener: OnLoadMoreListener) { |
||||
this.mOnLoadMoreListener = listener |
||||
} |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view: View |
||||
return when (viewType) { |
||||
VALUE_ITEM -> { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book_list, viewGroup, false) |
||||
ViewHolder(view) |
||||
} |
||||
EMPTY_ITEM -> { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_view, viewGroup, false) |
||||
EmptyHolder(view) |
||||
} |
||||
PROCESS_ITEM -> { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.load_more_layout, viewGroup, false) |
||||
MoreHolder(view) |
||||
} |
||||
else -> throw IllegalArgumentException() |
||||
} |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) { |
||||
if (viewHolder is ViewHolder) { |
||||
val bookBean = mList[i] |
||||
viewHolder.tvBookName.text = bookBean.title |
||||
viewHolder.tvBookAuthor.text = bookBean.author |
||||
viewHolder.tvBookDescription.text = bookBean.description |
||||
GlideImageLoader.displayCornerImage(mContext!!, bookBean.cover!!, viewHolder.ivBook) |
||||
viewHolder.itemView.setOnClickListener { |
||||
val intent = Intent(mContext, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, bookBean.id) |
||||
mContext!!.startActivity(intent) |
||||
} |
||||
}else if (viewHolder is MoreHolder){ |
||||
viewHolder.bindModule(isLoadingMore) |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return if (mList.isEmpty()) { |
||||
1 |
||||
} else mList.size + 1 |
||||
} |
||||
|
||||
override fun getItemViewType(position: Int): Int { |
||||
if (mList.isNotEmpty() &&position == itemCount - 1) { |
||||
return PROCESS_ITEM |
||||
} |
||||
return when { |
||||
mList.isEmpty() -> EMPTY_ITEM |
||||
else -> VALUE_ITEM |
||||
} |
||||
|
||||
} |
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var ivBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var tvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var tvBookAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
var tvBookDescription: TextView = itemView.findViewById(R.id.tv_book_description) |
||||
} |
||||
|
||||
companion object { |
||||
|
||||
private const val VALUE_ITEM = 100 //正常item |
||||
|
||||
private const val EMPTY_ITEM = 101 //空白item |
||||
|
||||
private const val PROCESS_ITEM = 102 |
||||
} |
||||
|
||||
} |
@ -0,0 +1,34 @@ |
||||
package com.novel.read.adapter; |
||||
|
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
|
||||
import com.novel.read.adapter.holder.CategoryHolder; |
||||
import com.novel.read.widget.page.TxtChapter; |
||||
|
||||
public class CategoryAdapter extends EasyAdapter<TxtChapter> { |
||||
private int currentSelected = 0; |
||||
|
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
View view = super.getView(position, convertView, parent); |
||||
CategoryHolder holder = (CategoryHolder) view.getTag(); |
||||
|
||||
if (position == currentSelected){ |
||||
holder.setSelectedChapter(); |
||||
} |
||||
|
||||
return view; |
||||
} |
||||
|
||||
@Override |
||||
protected IViewHolder<TxtChapter> onCreateViewHolder(int viewType) { |
||||
return new CategoryHolder(); |
||||
} |
||||
|
||||
public void setChapter(int pos){ |
||||
currentSelected = pos; |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,87 @@ |
||||
package com.novel.read.adapter; |
||||
|
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
public abstract class EasyAdapter<T> extends BaseAdapter { |
||||
|
||||
private List<T> mList = new ArrayList<T>(); |
||||
|
||||
@Override |
||||
public int getCount() { |
||||
return mList.size(); |
||||
} |
||||
|
||||
@Override |
||||
public T getItem(int position) { |
||||
return mList.get(position); |
||||
} |
||||
|
||||
@Override |
||||
public long getItemId(int position) { |
||||
return position; |
||||
} |
||||
|
||||
public void addItem(T value){ |
||||
mList.add(value); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
public void addItem(int index,T value){ |
||||
mList.add(index, value); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
public void addItems(List<T> values){ |
||||
mList.addAll(values); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
public void removeItem(T value){ |
||||
mList.remove(value); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
public List<T> getItems(){ |
||||
return Collections.unmodifiableList(mList); |
||||
} |
||||
|
||||
public int getItemSize(){ |
||||
return mList.size(); |
||||
} |
||||
|
||||
public void refreshItems(List<T> list){ |
||||
mList.clear(); |
||||
mList.addAll(list); |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
public void clear(){ |
||||
mList.clear(); |
||||
} |
||||
|
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
IViewHolder holder; |
||||
if (convertView == null){ |
||||
holder = onCreateViewHolder(getItemViewType(position)); |
||||
convertView = holder.createItemView(parent); |
||||
convertView.setTag(holder); |
||||
//初始化
|
||||
holder.initView(); |
||||
} |
||||
else { |
||||
holder = (IViewHolder)convertView.getTag(); |
||||
} |
||||
//执行绑定
|
||||
holder.onBind(getItem(position),position); |
||||
return convertView; |
||||
} |
||||
|
||||
protected abstract IViewHolder<T> onCreateViewHolder(int viewType); |
||||
} |
@ -0,0 +1,62 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookDetailActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.model.protocol.RecommendListResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
|
||||
/** |
||||
* create by zlj on 2019/6/19 |
||||
* describe: |
||||
*/ |
||||
class EditRecommendAdapter(private val mList: List<RecommendListResp.ListBean>) : RecyclerView.Adapter<EditRecommendAdapter.ViewHolder>() { |
||||
|
||||
private var mContext: Context? = null |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view = LayoutInflater.from(mContext) |
||||
.inflate(R.layout.rlv_edit_recommend_item, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { |
||||
val listBean = mList[i] |
||||
viewHolder.mTvBookName.text = listBean.book_title |
||||
viewHolder.mTvAuthor.text = listBean.author |
||||
viewHolder.mTvDescription.text = listBean.description |
||||
viewHolder.mTvHumanNum.text = listBean.getHot() |
||||
viewHolder.mTvLoveNum.text = listBean.getLike() |
||||
GlideImageLoader.displayCornerImage(mContext!!, listBean.book_cover!!, viewHolder.mIvBook) |
||||
viewHolder.itemView.setOnClickListener { |
||||
val intent = Intent(mContext, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, listBean.book_id) |
||||
mContext!!.startActivity(intent) |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mIvBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var mTvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var mTvAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
var mTvDescription: TextView = itemView.findViewById(R.id.tv_book_description) |
||||
var mTvHumanNum: TextView = itemView.findViewById(R.id.tv_human_num) |
||||
var mTvLoveNum: TextView = itemView.findViewById(R.id.tv_love_look_num) |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.model.db.SearchListTable |
||||
|
||||
/** |
||||
* create by zlj on 2019/6/17 |
||||
* describe: |
||||
*/ |
||||
class HistoryAdapter(private val mList: List<SearchListTable>) : |
||||
RecyclerView.Adapter<HistoryAdapter.ViewHolder>() { |
||||
private var mContext: Context? = null |
||||
|
||||
private lateinit var mClickListener: OnItemClickListener |
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mTvLabel: TextView = itemView.findViewById(R.id.tv_label) |
||||
} |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view = LayoutInflater.from(mContext).inflate(R.layout.item_label, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { |
||||
viewHolder.mTvLabel.text = mList[i].key |
||||
viewHolder.itemView.setOnClickListener { view -> mClickListener.onItemClick(view, i) } |
||||
} |
||||
|
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
|
||||
fun setOnItemClickListener(mListener: OnItemClickListener) { |
||||
this.mClickListener = mListener |
||||
} |
||||
|
||||
|
||||
interface OnItemClickListener { |
||||
fun onItemClick(view: View, pos: Int) |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.constants.Constant |
||||
|
||||
/** |
||||
* create by 赵利君 on 2019/6/17 |
||||
* describe: |
||||
*/ |
||||
class HotAdapter(private val mList: List<String>) : RecyclerView.Adapter<HotAdapter.ViewHolder>() { |
||||
private var mContext: Context? = null |
||||
private lateinit var mClickListener: OnItemClickListener |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view = LayoutInflater.from(mContext).inflate(R.layout.item_label, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { |
||||
viewHolder.mTvLabel.text = mList[i] |
||||
viewHolder.mTvLabel.setBackgroundColor(Constant.tagColors[i]) |
||||
viewHolder.itemView.setOnClickListener { view -> mClickListener.onItemClick(view, i) } |
||||
|
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return if (mList.size > 8) { |
||||
8 |
||||
} else mList.size |
||||
} |
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mTvLabel: TextView = itemView.findViewById(R.id.tv_label) |
||||
} |
||||
|
||||
fun setOnItemClickListener(mListener: OnItemClickListener) { |
||||
this.mClickListener = mListener |
||||
} |
||||
|
||||
|
||||
interface OnItemClickListener { |
||||
fun onItemClick(view: View, pos: Int) |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
|
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookDetailActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.dp2px |
||||
import com.novel.read.getScreenContentWidth |
||||
import com.novel.read.model.protocol.RecommendListResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
import kotlinx.android.synthetic.main.rlv_human_item.view.* |
||||
|
||||
/** |
||||
* create by zlj on 2019/6/19 |
||||
* describe: |
||||
*/ |
||||
class HumanAdapter(private val mList: List<RecommendListResp.ListBean>) : RecyclerView.Adapter<HumanAdapter.ViewHolder>() { |
||||
private lateinit var mContext: Context |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { |
||||
mContext = viewGroup.context |
||||
val view = LayoutInflater.from(mContext).inflate(R.layout.rlv_human_item, viewGroup, false) |
||||
val ivSize = (mContext.getScreenContentWidth() - mContext.dp2px(10) * 4) / 3 |
||||
view.cl_layout.layoutParams.width = ivSize |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { |
||||
viewHolder.mTvBookName.text = mList[i].book_title |
||||
viewHolder.mTvAuthor.text = mList[i].author |
||||
GlideImageLoader.displayCornerImage(mContext, mList[i].book_cover!!, viewHolder.mIvBook) |
||||
viewHolder.itemView.setOnClickListener { |
||||
val intent = Intent(mContext, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, mList[i].book_id) |
||||
mContext.startActivity(intent) |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mIvBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var mTvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var mTvAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
|
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
|
||||
/** |
||||
* Created by zlj |
||||
*/ |
||||
|
||||
interface IViewHolder<T> { |
||||
fun createItemView(parent: ViewGroup): View |
||||
fun initView() |
||||
fun onBind(data: T, pos: Int) |
||||
fun onClick() |
||||
} |
@ -0,0 +1,59 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookDetailActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.model.protocol.RecommendBookResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
|
||||
/** |
||||
* 猜你喜欢adapter |
||||
*/ |
||||
class LoveLyAdapter(private val mList: List<RecommendBookResp.BookBean>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { |
||||
|
||||
private var mContext: Context? = null |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view: View = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_lovely, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) { |
||||
if (viewHolder is ViewHolder) { |
||||
val bookBean = mList[i] |
||||
GlideImageLoader.displayCornerImage(mContext!!, bookBean.cover!!, viewHolder.mIvBook) |
||||
viewHolder.mTvBookName.text = bookBean.title |
||||
viewHolder.mTvBookAuthor.text = |
||||
mContext!!.getString(R.string.author_zhu, bookBean.author) |
||||
viewHolder.mTvDescription.text = bookBean.description |
||||
viewHolder.itemView.setOnClickListener { |
||||
val intent = Intent(mContext, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, bookBean.id) |
||||
mContext!!.startActivity(intent) |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mIvBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var mTvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var mTvBookAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
var mTvDescription: TextView = itemView.findViewById(R.id.tv_book_description) |
||||
} |
||||
} |
@ -0,0 +1,71 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.CheckBox |
||||
import android.widget.CompoundButton |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.model.db.BookSignTable |
||||
import com.novel.read.model.protocol.MarkResp |
||||
|
||||
class MarkAdapter(private val mList: List<BookSignTable>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { |
||||
|
||||
private var mContext: Context? = null |
||||
var edit: Boolean = false |
||||
set(edit) { |
||||
field = edit |
||||
notifyDataSetChanged() |
||||
} |
||||
|
||||
val selectList: String |
||||
get() { |
||||
val signs = StringBuilder() |
||||
for (i in mList.indices) { |
||||
if (mList[i].edit) { |
||||
if (signs.toString() == "") { |
||||
signs.append(mList[i].articleId) |
||||
} else { |
||||
signs.append(",").append(mList[i].articleId) |
||||
} |
||||
} |
||||
} |
||||
return signs.toString() |
||||
} |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view: View = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_mark, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) { |
||||
if (viewHolder is ViewHolder) { |
||||
if (this.edit) { |
||||
viewHolder.mCheck.visibility = View.VISIBLE |
||||
viewHolder.mCheck.setOnCheckedChangeListener { compoundButton, b -> |
||||
mList[i].edit = b |
||||
} |
||||
} else { |
||||
viewHolder.mCheck.visibility = View.GONE |
||||
} |
||||
viewHolder.mTvMark.text = mList[i].content |
||||
viewHolder.mCheck.isChecked = mList[i].edit |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mTvMark: TextView = itemView.findViewById(R.id.tvMarkItem) |
||||
var mCheck: CheckBox = itemView.findViewById(R.id.checkbox) |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.graphics.drawable.Drawable |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
import com.mango.mangolib.event.EventManager |
||||
import com.novel.read.R |
||||
import com.novel.read.widget.page.PageLoader |
||||
import com.novel.read.widget.page.PageStyle |
||||
|
||||
class PageStyleAdapter(val mList: List<Drawable>, private val mPageLoader: PageLoader) : |
||||
RecyclerView.Adapter<PageStyleAdapter.PageHolder>() { |
||||
private var mContext: Context? = null |
||||
private var currentChecked: Int = 0 |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): PageHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view = LayoutInflater.from(mContext).inflate(R.layout.item_read_bg, viewGroup, false) |
||||
return PageHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(pageHolder: PageHolder, i: Int) { |
||||
pageHolder.mReadBg.background = mList[i] |
||||
pageHolder.mIvChecked.visibility = View.GONE |
||||
if (currentChecked == i) { |
||||
pageHolder.mIvChecked.visibility = View.VISIBLE |
||||
} |
||||
pageHolder.itemView.setOnClickListener { |
||||
currentChecked = i |
||||
notifyDataSetChanged() |
||||
mPageLoader.setPageStyle(PageStyle.values()[i]) |
||||
} |
||||
} |
||||
|
||||
fun setPageStyleChecked(pageStyle: PageStyle) { |
||||
currentChecked = pageStyle.ordinal |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
class PageHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
val mReadBg: View = itemView.findViewById(R.id.read_bg_view) |
||||
val mIvChecked: ImageView = itemView.findViewById(R.id.read_bg_iv_checked) |
||||
|
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
|
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookDetailActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.dp2px |
||||
import com.novel.read.getScreenContentWidth |
||||
import com.novel.read.model.protocol.RecommendListResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
import kotlinx.android.synthetic.main.rlv_human_item.view.* |
||||
|
||||
/** |
||||
* create by zlj on 2019/6/20 |
||||
* describe: |
||||
*/ |
||||
class RankAdapter(private val mList: List<RecommendListResp.ListBean>) : |
||||
RecyclerView.Adapter<RankAdapter.ViewHolder>() { |
||||
private lateinit var mContext: Context |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { |
||||
mContext = viewGroup.context |
||||
val view = LayoutInflater.from(mContext).inflate(R.layout.rlv_human_item, viewGroup, false) |
||||
val ivSize = (mContext.getScreenContentWidth() - mContext.dp2px(10) * 4) / 3 |
||||
view.cl_layout.layoutParams.width = ivSize |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { |
||||
viewHolder.mTvBookName.text = mList[i].book_title |
||||
viewHolder.mTvAuthor.text = mList[i].author |
||||
GlideImageLoader.displayCornerImage(mContext, mList[i].book_cover!!, viewHolder.mIvBook) |
||||
viewHolder.itemView.setOnClickListener { |
||||
val intent = Intent(mContext, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, mList[i].book_id) |
||||
mContext.startActivity(intent) |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mIvBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var mTvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var mTvAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
|
||||
} |
||||
} |
@ -0,0 +1,125 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookDetailActivity |
||||
import com.novel.read.adapter.holder.EmptyHolder |
||||
import com.novel.read.adapter.holder.MoreHolder |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.inter.OnLoadMoreListener |
||||
import com.novel.read.model.protocol.RankByUpdateResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
import com.novel.read.constants.Constant.COMMENT_SIZE |
||||
|
||||
class RankListAdapter( val mList: List<RankByUpdateResp.BookBean>, recyclerView: RecyclerView) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { |
||||
|
||||
private lateinit var mContext: Context |
||||
var isLoadingMore: Boolean = false |
||||
private var lastVisibleItem: Int = 0 |
||||
private var totalItemCount: Int = 0 |
||||
private val visibleThreshold = 1 |
||||
private var mOnLoadMoreListener: OnLoadMoreListener? = null |
||||
|
||||
init { |
||||
if (recyclerView.layoutManager is LinearLayoutManager) { |
||||
val manager = recyclerView.layoutManager as LinearLayoutManager? |
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { |
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { |
||||
super.onScrolled(recyclerView, dx, dy) |
||||
totalItemCount = manager!!.itemCount |
||||
lastVisibleItem = manager.findLastVisibleItemPosition() |
||||
if (!isLoadingMore && totalItemCount == lastVisibleItem + visibleThreshold && totalItemCount >= COMMENT_SIZE) { |
||||
if (mOnLoadMoreListener != null) { |
||||
mOnLoadMoreListener!!.onLoadMore() |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
|
||||
fun setOnLoadMoreListener(listener: OnLoadMoreListener) { |
||||
this.mOnLoadMoreListener = listener |
||||
} |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder { |
||||
mContext = viewGroup.context |
||||
|
||||
val view: View |
||||
when (viewType) { |
||||
VALUE_ITEM -> { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book_list, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
EMPTY_ITEM -> { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_view, viewGroup, false) |
||||
return EmptyHolder(view) |
||||
} |
||||
PROCESS_ITEM -> { |
||||
view = LayoutInflater.from(mContext).inflate(R.layout.load_more_layout, viewGroup, false) |
||||
return MoreHolder(view) |
||||
} |
||||
} |
||||
throw IllegalArgumentException() |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) { |
||||
if (viewHolder is ViewHolder) { |
||||
val bookBean = mList[i] |
||||
viewHolder.tvBookName.text = bookBean.title |
||||
viewHolder.tvBookAuthor.text = bookBean.author |
||||
viewHolder.tvBookDescription.text = bookBean.description |
||||
GlideImageLoader.displayCornerImage(mContext, bookBean.cover, viewHolder.ivBook) |
||||
viewHolder.itemView.setOnClickListener { |
||||
val intent = Intent(mContext, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, bookBean.id) |
||||
mContext.startActivity(intent) |
||||
} |
||||
}else if (viewHolder is MoreHolder){ |
||||
viewHolder.bindModule(isLoadingMore) |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return if (mList.isEmpty()) { |
||||
1 |
||||
} else mList.size + 1 |
||||
} |
||||
|
||||
override fun getItemViewType(position: Int): Int { |
||||
if (mList.isNotEmpty() && position == itemCount - 1) { |
||||
return PROCESS_ITEM |
||||
} |
||||
return when { |
||||
mList.isEmpty() -> EMPTY_ITEM |
||||
else -> VALUE_ITEM |
||||
} |
||||
} |
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var ivBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var tvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var tvBookAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
var tvBookDescription: TextView = itemView.findViewById(R.id.tv_book_description) |
||||
|
||||
} |
||||
|
||||
companion object { |
||||
|
||||
private const val VALUE_ITEM = 100 //正常item |
||||
|
||||
private const val EMPTY_ITEM = 101 //空白item |
||||
|
||||
private const val PROCESS_ITEM = 102 |
||||
} |
||||
|
||||
} |
@ -0,0 +1,173 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookDetailActivity |
||||
import com.novel.read.adapter.holder.EmptyHolder |
||||
import com.novel.read.adapter.holder.MoreHolder |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.constants.Constant.COMMENT_SIZE |
||||
import com.novel.read.inter.OnLoadMoreListener |
||||
import com.novel.read.model.protocol.SearchResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
|
||||
class SearchAdapter(private val mList: List<SearchResp.BookBean>, recyclerView: RecyclerView) : |
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() { |
||||
|
||||
private var mContext: Context? = null |
||||
|
||||
private var book = false |
||||
private var mClickListener: OnItemClickListener? = null |
||||
|
||||
var isLoadingMore: Boolean = false |
||||
private var lastVisibleItem: Int = 0 |
||||
private var totalItemCount: Int = 0 |
||||
private val visibleThreshold = 1 |
||||
private var mOnLoadMoreListener: OnLoadMoreListener? = null |
||||
|
||||
init { |
||||
if (recyclerView.layoutManager is LinearLayoutManager) { |
||||
val manager = recyclerView.layoutManager as LinearLayoutManager? |
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { |
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { |
||||
super.onScrolled(recyclerView, dx, dy) |
||||
totalItemCount = manager!!.itemCount |
||||
lastVisibleItem = manager.findLastVisibleItemPosition() |
||||
if (!isLoadingMore && totalItemCount == lastVisibleItem + visibleThreshold && totalItemCount >= COMMENT_SIZE) { |
||||
if (mOnLoadMoreListener != null) { |
||||
mOnLoadMoreListener!!.onLoadMore() |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
|
||||
} |
||||
} |
||||
|
||||
fun setOnLoadMoreListener(listener: OnLoadMoreListener) { |
||||
this.mOnLoadMoreListener = listener |
||||
} |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view: View |
||||
when (i) { |
||||
VALUE_ITEM -> { |
||||
view = LayoutInflater.from(mContext) |
||||
.inflate(R.layout.rlv_item_search, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
BOOK_ITEM -> { |
||||
view = LayoutInflater.from(mContext) |
||||
.inflate(R.layout.rlv_item_book_list_search, viewGroup, false) |
||||
return BookHolder(view) |
||||
} |
||||
EMPTY_ITEM -> { |
||||
view = |
||||
LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_view, viewGroup, false) |
||||
return EmptyHolder(view) |
||||
} |
||||
PROCESS_ITEM -> { |
||||
view = LayoutInflater.from(mContext) |
||||
.inflate(R.layout.load_more_layout, viewGroup, false) |
||||
return MoreHolder(view) |
||||
} |
||||
else -> throw IllegalArgumentException() |
||||
} |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) { |
||||
when (viewHolder) { |
||||
is ViewHolder -> { |
||||
val bookBean = mList[i] |
||||
viewHolder.mTvBookName.text = bookBean.title |
||||
viewHolder.itemView.setOnClickListener { view -> |
||||
mClickListener!!.onItemClick(view, i) |
||||
} |
||||
} |
||||
is BookHolder -> { |
||||
val bookBean = mList[i] |
||||
viewHolder.tvBookName.text = bookBean.title |
||||
viewHolder.tvBookAuthor.text = bookBean.author |
||||
viewHolder.tvBookDescription.text = bookBean.description |
||||
GlideImageLoader.displayCornerImage(mContext!!, bookBean.cover!!, viewHolder.ivBook) |
||||
viewHolder.itemView.setOnClickListener { view -> |
||||
val intent = Intent(mContext, NovelBookDetailActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.BookId, bookBean.id) |
||||
mContext!!.startActivity(intent) |
||||
} |
||||
} |
||||
is MoreHolder -> viewHolder.bindModule(isLoadingMore) |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return if (mList.isEmpty()) { |
||||
1 |
||||
} else mList.size + 1 |
||||
} |
||||
|
||||
override fun getItemViewType(position: Int): Int { |
||||
if (mList.isNotEmpty() && position == itemCount - 1) { |
||||
return PROCESS_ITEM |
||||
} |
||||
|
||||
return if (mList.isEmpty()) { |
||||
EMPTY_ITEM |
||||
} else { |
||||
if (book) { |
||||
BOOK_ITEM |
||||
} else { |
||||
VALUE_ITEM |
||||
} |
||||
} |
||||
} |
||||
|
||||
fun setHolderType(book: Boolean) { |
||||
this.book = book |
||||
notifyDataSetChanged() |
||||
} |
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mTvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
|
||||
} |
||||
|
||||
internal class BookHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var ivBook: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var tvBookName: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
var tvBookAuthor: TextView = itemView.findViewById(R.id.tv_book_author) |
||||
var tvBookDescription: TextView = itemView.findViewById(R.id.tv_book_description) |
||||
|
||||
} |
||||
|
||||
fun setOnItemClickListener(mListener: OnItemClickListener) { |
||||
this.mClickListener = mListener |
||||
} |
||||
|
||||
interface OnItemClickListener { |
||||
fun onItemClick(view: View, pos: Int) |
||||
} |
||||
|
||||
companion object { |
||||
|
||||
private const val VALUE_ITEM = 100 //正常item |
||||
|
||||
private const val EMPTY_ITEM = 101 //空白item |
||||
|
||||
private const val BOOK_ITEM = 102 //书本item |
||||
|
||||
private const val PROCESS_ITEM = 103 |
||||
} |
||||
|
||||
} |
@ -0,0 +1,61 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.ImageView |
||||
import android.widget.TextView |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
import com.novel.read.activity.NovelBookTypeListActivity |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.model.protocol.CategoryTypeResp |
||||
import com.novel.read.utlis.GlideImageLoader |
||||
|
||||
class StackAdapter(private val mList: List<CategoryTypeResp.CategoryBean>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { |
||||
|
||||
private var mContext: Context? = null |
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): RecyclerView.ViewHolder { |
||||
if (mContext == null) { |
||||
mContext = viewGroup.context |
||||
} |
||||
val view: View = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book_type, viewGroup, false) |
||||
return ViewHolder(view) |
||||
} |
||||
|
||||
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, i: Int) { |
||||
if (viewHolder is ViewHolder) { |
||||
|
||||
var input = mList[i].title |
||||
val regex = "(.{2})" |
||||
input = input.replace(regex.toRegex(), "$1\n") |
||||
viewHolder.mTvType.text = input |
||||
viewHolder.itemView.setOnClickListener { view -> |
||||
val intent = Intent(mContext, NovelBookTypeListActivity::class.java) |
||||
intent.putExtra(Constant.Bundle.CategoryId, mList[i].id.toString()) |
||||
intent.putExtra(Constant.Bundle.mTitle, mList[i].title) |
||||
mContext!!.startActivity(intent) |
||||
} |
||||
GlideImageLoader.displayCornerImage( |
||||
mContext!!, |
||||
mList[i].cover, |
||||
viewHolder.mIvType, |
||||
R.drawable.ic_type_default |
||||
) |
||||
} |
||||
} |
||||
|
||||
override fun getItemCount(): Int { |
||||
return mList.size |
||||
} |
||||
|
||||
internal class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
var mIvType: ImageView = itemView.findViewById(R.id.iv_book) |
||||
var mTvType: TextView = itemView.findViewById(R.id.tv_book_name) |
||||
|
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
package com.novel.read.adapter; |
||||
|
||||
import android.content.Context; |
||||
import android.view.LayoutInflater; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
|
||||
import org.jetbrains.annotations.NotNull; |
||||
|
||||
public abstract class ViewHolderImpl<T> implements IViewHolder<T> { |
||||
private View view; |
||||
private Context context; |
||||
|
||||
protected abstract int getItemLayoutId(); |
||||
|
||||
@NotNull |
||||
@Override |
||||
public View createItemView(ViewGroup parent) { |
||||
view = LayoutInflater.from(parent.getContext()) |
||||
.inflate(getItemLayoutId(), parent, false); |
||||
context = parent.getContext(); |
||||
return view; |
||||
} |
||||
|
||||
protected <V extends View> V findById(int id){ |
||||
return (V) view.findViewById(id); |
||||
} |
||||
|
||||
protected Context getContext(){ |
||||
return context; |
||||
} |
||||
|
||||
protected View getItemView(){ |
||||
return view; |
||||
} |
||||
|
||||
@Override |
||||
public void onClick() { |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
package com.novel.read.adapter |
||||
|
||||
import androidx.fragment.app.Fragment |
||||
import androidx.fragment.app.FragmentManager |
||||
import androidx.fragment.app.FragmentPagerAdapter |
||||
|
||||
/** |
||||
* Created by Administrator on 2017/2/24. |
||||
*/ |
||||
|
||||
class ViewPageAdapter(fm: FragmentManager, private val fragmentList: List<Fragment>) : |
||||
FragmentPagerAdapter(fm) { |
||||
|
||||
override fun getItem(position: Int): Fragment { |
||||
return fragmentList[position] |
||||
} |
||||
|
||||
override fun getCount(): Int { |
||||
return fragmentList.size |
||||
} |
||||
|
||||
} |
@ -0,0 +1,50 @@ |
||||
package com.novel.read.adapter.holder; |
||||
|
||||
import android.graphics.drawable.Drawable; |
||||
import android.widget.TextView; |
||||
|
||||
import androidx.core.content.ContextCompat; |
||||
|
||||
import com.novel.read.R; |
||||
import com.novel.read.adapter.ViewHolderImpl; |
||||
import com.novel.read.model.db.dbManage.BookManager; |
||||
import com.novel.read.utlis.StringUtils; |
||||
import com.novel.read.widget.page.TxtChapter; |
||||
|
||||
public class CategoryHolder extends ViewHolderImpl<TxtChapter> { |
||||
|
||||
private TextView mTvChapter; |
||||
|
||||
@Override |
||||
public void initView() { |
||||
mTvChapter = findById(R.id.category_tv_chapter); |
||||
} |
||||
|
||||
@Override |
||||
public void onBind(TxtChapter value, int pos){ |
||||
//首先判断是否该章已下载
|
||||
Drawable drawable = null; |
||||
if (value.getBookId() != null && BookManager.isChapterCached(value.getBookId(),value.getTitle())){ |
||||
drawable = ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load); |
||||
} |
||||
else { |
||||
drawable = ContextCompat.getDrawable(getContext(), R.drawable.selector_category_unload); |
||||
} |
||||
|
||||
mTvChapter.setSelected(false); |
||||
mTvChapter.setTextColor(ContextCompat.getColor(getContext(),R.color.colorTitle)); |
||||
mTvChapter.setCompoundDrawablesWithIntrinsicBounds(drawable,null,null,null); |
||||
mTvChapter.setText(StringUtils.INSTANCE.convertCC(value.getTitle())); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
protected int getItemLayoutId() { |
||||
return R.layout.rlv_item_category; |
||||
} |
||||
|
||||
public void setSelectedChapter(){ |
||||
mTvChapter.setTextColor(ContextCompat.getColor(getContext(),R.color.light_red)); |
||||
mTvChapter.setSelected(true); |
||||
} |
||||
} |
@ -0,0 +1,6 @@ |
||||
package com.novel.read.adapter.holder |
||||
|
||||
import android.view.View |
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
class EmptyHolder(itemView: View) : RecyclerView.ViewHolder(itemView) |
@ -0,0 +1,34 @@ |
||||
package com.novel.read.adapter.holder |
||||
|
||||
import android.view.View |
||||
import android.widget.ProgressBar |
||||
import android.widget.TextView |
||||
|
||||
import androidx.recyclerview.widget.RecyclerView |
||||
|
||||
import com.novel.read.R |
||||
|
||||
/** |
||||
* @author: LiJun 390057892@qq.com |
||||
* @date: 2018/4/4 9:28 |
||||
*/ |
||||
|
||||
class MoreHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { |
||||
|
||||
private val mProgressBar: ProgressBar = itemView.findViewById(R.id.progressBar) |
||||
private val mTvName: TextView = itemView.findViewById(R.id.tv_name) |
||||
private val mTvEnd: TextView = itemView.findViewById(R.id.tv_end) |
||||
|
||||
fun bindModule(loadMore: Boolean) { |
||||
if (loadMore) { |
||||
mTvName.visibility = View.VISIBLE |
||||
mProgressBar.visibility = View.VISIBLE |
||||
mTvEnd.visibility = View.GONE |
||||
} else { |
||||
mTvName.visibility = View.GONE |
||||
mProgressBar.visibility = View.GONE |
||||
mTvEnd.visibility = View.VISIBLE |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,178 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.content.Context |
||||
import android.content.res.Configuration |
||||
import android.os.Bundle |
||||
import android.util.AttributeSet |
||||
import android.view.Menu |
||||
import android.view.MenuItem |
||||
import android.view.View |
||||
import android.view.WindowManager |
||||
import android.widget.FrameLayout |
||||
import androidx.appcompat.app.AppCompatActivity |
||||
import androidx.viewbinding.ViewBinding |
||||
import com.novel.read.R |
||||
import com.novel.read.constant.AppConst |
||||
import com.novel.read.constant.Theme |
||||
import com.novel.read.lib.* |
||||
import com.novel.read.ui.widget.TitleBar |
||||
import com.novel.read.utils.ColorUtils |
||||
import com.novel.read.utils.LanguageUtils |
||||
import com.novel.read.utils.ext.disableAutoFill |
||||
import com.novel.read.utils.ext.* |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.MainScope |
||||
import kotlinx.coroutines.cancel |
||||
|
||||
abstract class BaseActivity<VB : ViewBinding>( |
||||
val fullScreen: Boolean = true, |
||||
private val theme: Theme = Theme.Auto, |
||||
private val toolBarTheme: Theme = Theme.Auto, |
||||
private val transparent: Boolean = false |
||||
) : AppCompatActivity(), |
||||
CoroutineScope by MainScope() { |
||||
|
||||
protected val binding: VB by lazy { getViewBinding() } |
||||
|
||||
val isInMultiWindow: Boolean |
||||
get() { |
||||
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { |
||||
isInMultiWindowMode |
||||
} else { |
||||
false |
||||
} |
||||
} |
||||
|
||||
override fun attachBaseContext(newBase: Context) { |
||||
super.attachBaseContext(LanguageUtils.setConfiguration(newBase)) |
||||
} |
||||
|
||||
protected abstract fun getViewBinding(): VB |
||||
|
||||
override fun onCreateView( |
||||
parent: View?, |
||||
name: String, |
||||
context: Context, |
||||
attrs: AttributeSet |
||||
): View? { |
||||
if (AppConst.menuViewNames.contains(name) && parent?.parent is FrameLayout) { |
||||
(parent.parent as View).setBackgroundColor(backgroundColor) |
||||
} |
||||
return super.onCreateView(parent, name, context, attrs) |
||||
} |
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
window.decorView.disableAutoFill() |
||||
initTheme() |
||||
super.onCreate(savedInstanceState) |
||||
setContentView(binding.root) |
||||
setupSystemBar() |
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { |
||||
findViewById<TitleBar>(R.id.title_bar) |
||||
?.onMultiWindowModeChanged(isInMultiWindowMode, fullScreen) |
||||
} |
||||
onActivityCreated(savedInstanceState) |
||||
observeLiveBus() |
||||
} |
||||
|
||||
override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean, newConfig: Configuration?) { |
||||
super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig) |
||||
findViewById<TitleBar>(R.id.title_bar) |
||||
?.onMultiWindowModeChanged(isInMultiWindowMode, fullScreen) |
||||
setupSystemBar() |
||||
} |
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) { |
||||
super.onConfigurationChanged(newConfig) |
||||
findViewById<TitleBar>(R.id.title_bar) |
||||
?.onMultiWindowModeChanged(isInMultiWindow, fullScreen) |
||||
setupSystemBar() |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
cancel() |
||||
} |
||||
|
||||
abstract fun onActivityCreated(savedInstanceState: Bundle?) |
||||
|
||||
final override fun onCreateOptionsMenu(menu: Menu?): Boolean { |
||||
return menu?.let { |
||||
val bool = onCompatCreateOptionsMenu(it) |
||||
it.applyTint(this, toolBarTheme) |
||||
bool |
||||
} ?: super.onCreateOptionsMenu(menu) |
||||
} |
||||
|
||||
override fun onMenuOpened(featureId: Int, menu: Menu): Boolean { |
||||
menu.applyOpenTint(this) |
||||
return super.onMenuOpened(featureId, menu) |
||||
} |
||||
|
||||
open fun onCompatCreateOptionsMenu(menu: Menu) = super.onCreateOptionsMenu(menu) |
||||
|
||||
final override fun onOptionsItemSelected(item: MenuItem): Boolean { |
||||
item.let { |
||||
if (it.itemId == android.R.id.home) { |
||||
supportFinishAfterTransition() |
||||
return true |
||||
} |
||||
} |
||||
return onCompatOptionsItemSelected(item) |
||||
} |
||||
|
||||
open fun onCompatOptionsItemSelected(item: MenuItem) = super.onOptionsItemSelected(item) |
||||
|
||||
private fun initTheme() { |
||||
when (theme) { |
||||
Theme.Transparent -> setTheme(R.style.AppTheme_Transparent) |
||||
Theme.Dark -> { |
||||
setTheme(R.style.AppTheme_Dark) |
||||
ATH.applyBackgroundTint(window.decorView) |
||||
} |
||||
Theme.Light -> { |
||||
setTheme(R.style.AppTheme_Light) |
||||
ATH.applyBackgroundTint(window.decorView) |
||||
} |
||||
else -> { |
||||
if (ColorUtils.isColorLight(primaryColor)) { |
||||
setTheme(R.style.AppTheme_Light) |
||||
} else { |
||||
setTheme(R.style.AppTheme_Dark) |
||||
} |
||||
ATH.applyBackgroundTint(window.decorView) |
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun setupSystemBar() { |
||||
if (fullScreen && !isInMultiWindow) { |
||||
window.clearFlags( |
||||
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS |
||||
or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION |
||||
) |
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) |
||||
window.decorView.systemUiVisibility = |
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
||||
} |
||||
ATH.setStatusBarColorAuto(this, fullScreen) |
||||
if (toolBarTheme == Theme.Dark) { |
||||
ATH.setLightStatusBar(window, false) |
||||
} else if (toolBarTheme == Theme.Light) { |
||||
ATH.setLightStatusBar(window, true) |
||||
} |
||||
upNavigationBarColor() |
||||
} |
||||
|
||||
open fun upNavigationBarColor() { |
||||
ATH.setNavigationBarColorAuto(this) |
||||
} |
||||
|
||||
open fun observeLiveBus() { |
||||
} |
||||
|
||||
override fun finish() { |
||||
currentFocus?.hideSoftInput() |
||||
super.finish() |
||||
} |
||||
} |
@ -1,41 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import androidx.viewbinding.ViewBinding |
||||
import com.chad.library.adapter.base.BaseQuickAdapter |
||||
import com.chad.library.adapter.base.BaseSectionQuickAdapter |
||||
import com.chad.library.adapter.base.entity.SectionEntity |
||||
import com.chad.library.adapter.base.viewholder.BaseViewHolder |
||||
|
||||
abstract class BaseBindingAdapter<T, VB : ViewBinding>(data: MutableList<T>? = null) : |
||||
BaseQuickAdapter<T, VBViewHolder<VB>>(0, data) { |
||||
|
||||
abstract fun createViewBinding(inflater: LayoutInflater, parent: ViewGroup): VB |
||||
|
||||
override fun onCreateDefViewHolder(parent: ViewGroup, viewType: Int): VBViewHolder<VB> { |
||||
val viewBinding = createViewBinding(LayoutInflater.from(parent.context), parent) |
||||
return VBViewHolder(viewBinding, viewBinding.root) |
||||
} |
||||
|
||||
} |
||||
|
||||
class VBViewHolder<VB : ViewBinding>(val vb: VB, view: View) : BaseViewHolder(view) |
||||
|
||||
|
||||
@JvmName("bind") |
||||
fun <VB : ViewBinding> BaseViewHolder.withBinding(bind: (View) -> VB): BaseViewHolder = |
||||
BaseViewHolderWithBinding(bind(itemView)) |
||||
|
||||
@JvmName("getBinding") |
||||
@Suppress("UNCHECKED_CAST") |
||||
fun <VB : ViewBinding> BaseViewHolder.getViewBinding(): VB { |
||||
if (this is BaseViewHolderWithBinding<*>) { |
||||
return binding as VB |
||||
} else { |
||||
throw IllegalStateException("The binding could not be found.") |
||||
} |
||||
} |
||||
|
||||
class BaseViewHolderWithBinding<VB : ViewBinding>(val binding: VB) : BaseViewHolder(binding.root) |
@ -1,58 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.os.Bundle |
||||
import android.view.View |
||||
import androidx.fragment.app.DialogFragment |
||||
import androidx.fragment.app.FragmentManager |
||||
import com.novel.read.lib.ThemeStore |
||||
import com.novel.read.help.coroutine.Coroutine |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.Dispatchers |
||||
import kotlinx.coroutines.Job |
||||
import kotlin.coroutines.CoroutineContext |
||||
|
||||
|
||||
abstract class BaseDialogFragment : DialogFragment(), CoroutineScope { |
||||
override val coroutineContext: CoroutineContext |
||||
get() = job + Dispatchers.Main |
||||
private lateinit var job: Job |
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
super.onCreate(savedInstanceState) |
||||
job = Job() |
||||
} |
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||
super.onViewCreated(view, savedInstanceState) |
||||
view.setBackgroundColor(ThemeStore.backgroundColor()) |
||||
onFragmentCreated(view, savedInstanceState) |
||||
observeLiveBus() |
||||
} |
||||
|
||||
abstract fun onFragmentCreated(view: View, savedInstanceState: Bundle?) |
||||
|
||||
override fun show(manager: FragmentManager, tag: String?) { |
||||
try { |
||||
//在每个add事务前增加一个remove事务,防止连续的add |
||||
manager.beginTransaction().remove(this).commit() |
||||
super.show(manager, tag) |
||||
} catch (e: Exception) { |
||||
//同一实例使用不同的tag会异常,这里捕获一下 |
||||
e.printStackTrace() |
||||
} |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
job.cancel() |
||||
} |
||||
|
||||
fun <T> execute( |
||||
scope: CoroutineScope = this, |
||||
context: CoroutineContext = Dispatchers.IO, |
||||
block: suspend CoroutineScope.() -> T |
||||
) = Coroutine.async(scope, context) { block() } |
||||
|
||||
open fun observeLiveBus() { |
||||
} |
||||
} |
@ -1,96 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.content.res.Configuration |
||||
import android.os.Bundle |
||||
import android.view.* |
||||
import androidx.appcompat.view.SupportMenuInflater |
||||
import androidx.appcompat.widget.Toolbar |
||||
import androidx.fragment.app.Fragment |
||||
import com.novel.read.R |
||||
import com.novel.read.ui.widget.TitleBar |
||||
import com.novel.read.utils.ext.* |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.Dispatchers |
||||
import kotlinx.coroutines.Job |
||||
import kotlin.coroutines.CoroutineContext |
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate") |
||||
abstract class BaseFragment(layoutID: Int) : Fragment(layoutID), |
||||
CoroutineScope { |
||||
lateinit var job: Job |
||||
var supportToolbar: Toolbar? = null |
||||
private set |
||||
|
||||
val menuInflater: MenuInflater |
||||
@SuppressLint("RestrictedApi") |
||||
get() = SupportMenuInflater(requireContext()) |
||||
|
||||
override val coroutineContext: CoroutineContext |
||||
get() = job + Dispatchers.Main |
||||
|
||||
override fun onCreateView( |
||||
inflater: LayoutInflater, |
||||
container: ViewGroup?, |
||||
savedInstanceState: Bundle? |
||||
): View? { |
||||
job = Job() |
||||
return super.onCreateView(inflater, container, savedInstanceState) |
||||
} |
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||
super.onViewCreated(view, savedInstanceState) |
||||
onMultiWindowModeChanged() |
||||
onFragmentCreated(view, savedInstanceState) |
||||
observeLiveBus() |
||||
} |
||||
|
||||
abstract fun onFragmentCreated(view: View, savedInstanceState: Bundle?) |
||||
|
||||
override fun onMultiWindowModeChanged(isInMultiWindowMode: Boolean) { |
||||
super.onMultiWindowModeChanged(isInMultiWindowMode) |
||||
onMultiWindowModeChanged() |
||||
} |
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) { |
||||
super.onConfigurationChanged(newConfig) |
||||
onMultiWindowModeChanged() |
||||
} |
||||
|
||||
private fun onMultiWindowModeChanged() { |
||||
(activity as? BaseActivity<*>)?.let { |
||||
view?.findViewById<TitleBar>(R.id.title_bar) |
||||
?.onMultiWindowModeChanged(it.isInMultiWindow, it.fullScreen) |
||||
} |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
job.cancel() |
||||
} |
||||
|
||||
fun setSupportToolbar(toolbar: Toolbar) { |
||||
supportToolbar = toolbar |
||||
supportToolbar?.let { |
||||
it.menu.apply { |
||||
onCompatCreateOptionsMenu(this) |
||||
applyTint(requireContext()) |
||||
} |
||||
|
||||
it.setOnMenuItemClickListener { item -> |
||||
onCompatOptionsItemSelected(item) |
||||
true |
||||
} |
||||
} |
||||
} |
||||
|
||||
open fun observeLiveBus() { |
||||
} |
||||
|
||||
open fun onCompatCreateOptionsMenu(menu: Menu) { |
||||
} |
||||
|
||||
open fun onCompatOptionsItemSelected(item: MenuItem) { |
||||
} |
||||
|
||||
} |
@ -1,60 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.annotation.SuppressLint |
||||
import androidx.fragment.app.DialogFragment |
||||
import androidx.preference.* |
||||
import com.novel.read.ui.widget.prefs.EditTextPreferenceDialog |
||||
import com.novel.read.ui.widget.prefs.ListPreferenceDialog |
||||
import com.novel.read.ui.widget.prefs.MultiSelectListPreferenceDialog |
||||
|
||||
abstract class BasePreferenceFragment : PreferenceFragmentCompat() { |
||||
|
||||
private val dialogFragmentTag = "androidx.preference.PreferenceFragment.DIALOG" |
||||
|
||||
@SuppressLint("RestrictedApi") |
||||
override fun onDisplayPreferenceDialog(preference: Preference) { |
||||
|
||||
var handled = false |
||||
if (callbackFragment is OnPreferenceDisplayDialogCallback) { |
||||
handled = |
||||
(callbackFragment as OnPreferenceDisplayDialogCallback) |
||||
.onPreferenceDisplayDialog(this, preference) |
||||
} |
||||
if (!handled && activity is OnPreferenceDisplayDialogCallback) { |
||||
handled = (activity as OnPreferenceDisplayDialogCallback) |
||||
.onPreferenceDisplayDialog(this, preference) |
||||
} |
||||
|
||||
if (handled) { |
||||
return |
||||
} |
||||
|
||||
// check if dialog is already showing |
||||
if (parentFragmentManager.findFragmentByTag(dialogFragmentTag) != null) { |
||||
return |
||||
} |
||||
|
||||
val f: DialogFragment = when (preference) { |
||||
is EditTextPreference -> { |
||||
EditTextPreferenceDialog.newInstance(preference.getKey()) |
||||
} |
||||
is ListPreference -> { |
||||
ListPreferenceDialog.newInstance(preference.getKey()) |
||||
} |
||||
is MultiSelectListPreference -> { |
||||
MultiSelectListPreferenceDialog.newInstance(preference.getKey()) |
||||
} |
||||
else -> { |
||||
throw IllegalArgumentException( |
||||
"Cannot display dialog for an unknown Preference type: " |
||||
+ preference.javaClass.simpleName |
||||
+ ". Make sure to implement onPreferenceDisplayDialog() to handle " |
||||
+ "displaying a custom dialog for this Preference." |
||||
) |
||||
} |
||||
} |
||||
f.setTargetFragment(this, 0) |
||||
f.show(parentFragmentManager, dialogFragmentTag) |
||||
} |
||||
|
||||
} |
@ -1,26 +1,25 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.app.Service |
||||
import android.content.Intent |
||||
import com.novel.read.help.coroutine.Coroutine |
||||
import kotlinx.coroutines.CoroutineScope |
||||
import kotlinx.coroutines.Dispatchers |
||||
import kotlinx.coroutines.MainScope |
||||
import kotlinx.coroutines.cancel |
||||
import kotlin.coroutines.CoroutineContext |
||||
|
||||
abstract class BaseService : Service(), CoroutineScope by MainScope() { |
||||
import io.reactivex.disposables.CompositeDisposable |
||||
import io.reactivex.disposables.Disposable |
||||
|
||||
fun <T> execute( |
||||
scope: CoroutineScope = this, |
||||
context: CoroutineContext = Dispatchers.IO, |
||||
block: suspend CoroutineScope.() -> T |
||||
) = Coroutine.async(scope, context) { block() } |
||||
abstract class BaseService : Service() { |
||||
|
||||
override fun onBind(intent: Intent?) = null |
||||
private var mDisposable: CompositeDisposable? = null |
||||
|
||||
protected fun addDisposable(disposable: Disposable) { |
||||
if (mDisposable == null) { |
||||
mDisposable = CompositeDisposable() |
||||
} |
||||
mDisposable!!.add(disposable) |
||||
} |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
cancel() |
||||
if (mDisposable != null) { |
||||
mDisposable!!.dispose() |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
@ -1,154 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.app.Application |
||||
import android.content.Context |
||||
import androidx.annotation.CallSuper |
||||
import androidx.lifecycle.AndroidViewModel |
||||
import androidx.lifecycle.viewModelScope |
||||
import com.novel.read.App |
||||
import com.novel.read.R |
||||
import com.novel.read.network.api.ApiException |
||||
import com.novel.read.help.coroutine.Coroutine |
||||
import kotlinx.coroutines.* |
||||
import org.jetbrains.anko.AnkoLogger |
||||
import org.jetbrains.anko.toast |
||||
import retrofit2.HttpException |
||||
import java.net.ConnectException |
||||
import java.net.SocketTimeoutException |
||||
import java.net.UnknownHostException |
||||
import kotlin.coroutines.CoroutineContext |
||||
|
||||
typealias Block<T> = suspend (CoroutineScope) -> T |
||||
typealias Error = suspend (Exception) -> Unit |
||||
typealias Cancel = suspend (Exception) -> Unit |
||||
|
||||
open class BaseViewModel(application: Application) : AndroidViewModel(application), |
||||
CoroutineScope by MainScope(), |
||||
AnkoLogger { |
||||
|
||||
val context: Context by lazy { this.getApplication<App>() } |
||||
|
||||
fun <T> execute( |
||||
scope: CoroutineScope = this, |
||||
context: CoroutineContext = Dispatchers.IO, |
||||
block: suspend CoroutineScope.() -> T |
||||
): Coroutine<T> { |
||||
return Coroutine.async(scope, context) { block() } |
||||
} |
||||
|
||||
fun <R> submit( |
||||
scope: CoroutineScope = this, |
||||
context: CoroutineContext = Dispatchers.IO, |
||||
block: suspend CoroutineScope.() -> Deferred<R> |
||||
): Coroutine<R> { |
||||
return Coroutine.async(scope, context) { block().await() } |
||||
} |
||||
|
||||
@CallSuper |
||||
override fun onCleared() { |
||||
super.onCleared() |
||||
cancel() |
||||
} |
||||
|
||||
open fun toast(message: Int) { |
||||
launch { |
||||
context.toast(message) |
||||
} |
||||
} |
||||
|
||||
open fun toast(message: CharSequence?) { |
||||
launch { |
||||
context.toast(message ?: toString()) |
||||
} |
||||
} |
||||
|
||||
open fun longToast(message: Int) { |
||||
launch { |
||||
context.toast(message) |
||||
} |
||||
} |
||||
|
||||
open fun longToast(message: CharSequence?) { |
||||
launch { |
||||
context.toast(message ?: toString()) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 创建并执行协程 |
||||
* @param block 协程中执行 |
||||
* @param error 错误时执行 |
||||
* @param cancel 取消时只需 |
||||
* @param showErrorToast 是否弹出错误吐司 |
||||
* @return Job |
||||
*/ |
||||
protected fun launch( |
||||
block: Block<Unit>, |
||||
error: Error? = null, |
||||
cancel: Cancel? = null, |
||||
showErrorToast: Boolean = true |
||||
): Job { |
||||
return viewModelScope.launch { |
||||
try { |
||||
block.invoke(this) |
||||
} catch (e: Exception) { |
||||
when (e) { |
||||
is CancellationException -> { |
||||
cancel?.invoke(e) |
||||
} |
||||
else -> { |
||||
onError(e, showErrorToast) |
||||
error?.invoke(e) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 创建并执行协程 |
||||
* @param block 协程中执行 |
||||
* @return Deferred<T> |
||||
*/ |
||||
protected fun <T> async(block: Block<T>): Deferred<T> { |
||||
return viewModelScope.async { block.invoke(this) } |
||||
} |
||||
|
||||
/** |
||||
* 取消协程 |
||||
* @param job 协程job |
||||
*/ |
||||
protected fun cancelJob(job: Job?) { |
||||
if (job != null && job.isActive && !job.isCompleted && !job.isCancelled) { |
||||
job.cancel() |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 统一处理错误 |
||||
* @param e 异常 |
||||
* @param showErrorToast 是否显示错误吐司 |
||||
*/ |
||||
private fun onError(e: Exception, showErrorToast: Boolean) { |
||||
when (e) { |
||||
is ApiException -> { |
||||
when (e.code) { |
||||
-1001 -> { |
||||
// 登录失效,清除用户信息、清除cookie/token |
||||
} |
||||
// 其他api错误 |
||||
-1 -> if (showErrorToast) toast(e.message) |
||||
// 其他错误 |
||||
else -> if (showErrorToast) toast(e.message) |
||||
} |
||||
} |
||||
// 网络请求失败 |
||||
is ConnectException, is SocketTimeoutException, is UnknownHostException, is HttpException -> |
||||
if (showErrorToast) toast(R.string.network_request_failed) |
||||
// 其他错误 |
||||
else -> |
||||
if (showErrorToast) toast(e.message ?: return) |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,63 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.app.Application |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.content.res.Configuration |
||||
import android.util.Log |
||||
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate |
||||
|
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.service.DownloadService |
||||
import com.novel.read.utlis.LocalManageUtil |
||||
import com.novel.read.utlis.SpUtil |
||||
|
||||
|
||||
import org.litepal.LitePal |
||||
import kotlin.properties.Delegates |
||||
|
||||
/** |
||||
* create by zlj on 2019/6/10 |
||||
*/ |
||||
class MyApp : Application() { |
||||
|
||||
override fun onCreate() { |
||||
super.onCreate() |
||||
context = applicationContext |
||||
LitePal.initialize(this) |
||||
setNight() |
||||
LocalManageUtil.setApplicationLanguage(this) |
||||
startService(Intent(context, DownloadService::class.java)) |
||||
} |
||||
|
||||
private fun setNight() { |
||||
if (SpUtil.getBooleanValue(Constant.NIGHT, false)) { |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) |
||||
} else { |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) |
||||
} |
||||
} |
||||
|
||||
|
||||
override fun attachBaseContext(base: Context) { |
||||
SpUtil.init(base) |
||||
//保存系统选择语言 |
||||
LocalManageUtil.saveSystemCurrentLanguage(base) |
||||
super.attachBaseContext(LocalManageUtil.setLocal(base)) |
||||
} |
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) { |
||||
super.onConfigurationChanged(newConfig) |
||||
//保存系统选择语言 |
||||
LocalManageUtil.onConfigurationChanged(applicationContext) |
||||
} |
||||
|
||||
companion object { |
||||
var context: Context by Delegates.notNull() |
||||
private set |
||||
} |
||||
|
||||
} |
@ -0,0 +1,78 @@ |
||||
package com.novel.read.base |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.os.Bundle |
||||
import android.view.View |
||||
import androidx.appcompat.app.AppCompatActivity |
||||
import androidx.appcompat.app.AppCompatDelegate |
||||
import com.novel.read.R |
||||
import com.novel.read.constants.Constant |
||||
import com.novel.read.utlis.LocalManageUtil |
||||
import com.novel.read.utlis.SpUtil |
||||
import com.novel.read.utlis.StatusBarUtil |
||||
|
||||
/** |
||||
* create by 赵利君 on 2019/6/10 |
||||
* describe: |
||||
*/ |
||||
abstract class NovelBaseActivity : AppCompatActivity() { |
||||
|
||||
private var mNowMode: Boolean = false |
||||
|
||||
protected abstract val layoutId: Int |
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
super.onCreate(savedInstanceState) |
||||
StatusBarUtil.setBarsStyle(this, R.color.colorPrimary, true) |
||||
mNowMode = SpUtil.getBooleanValue(Constant.NIGHT) |
||||
setContentView(layoutId) |
||||
initView() |
||||
initData() |
||||
|
||||
} |
||||
|
||||
private fun setTheme() { |
||||
if (SpUtil.getBooleanValue(Constant.NIGHT) != mNowMode) { |
||||
if (SpUtil.getBooleanValue(Constant.NIGHT)) { |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) |
||||
} else { |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) |
||||
} |
||||
recreate() |
||||
} |
||||
} |
||||
|
||||
protected abstract fun initView() |
||||
|
||||
protected abstract fun initData() |
||||
|
||||
override fun onResume() { |
||||
super.onResume() |
||||
setTheme() |
||||
} |
||||
|
||||
protected fun gone(vararg views: View) { |
||||
if (views.isNotEmpty()) { |
||||
for (view in views) { |
||||
view.visibility = View.GONE |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected fun visible(vararg views: View) { |
||||
if (views.isNotEmpty()) { |
||||
for (view in views) { |
||||
view.visibility = View.VISIBLE |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected fun isVisible(view: View): Boolean { |
||||
return view.visibility == View.VISIBLE |
||||
} |
||||
|
||||
override fun attachBaseContext(newBase: Context) { |
||||
super.attachBaseContext(LocalManageUtil.setLocal(newBase)) |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
package com.novel.read.base |
||||
|
||||
|
||||
import android.content.Intent |
||||
import android.os.Bundle |
||||
|
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import androidx.annotation.LayoutRes |
||||
import androidx.fragment.app.Fragment |
||||
|
||||
|
||||
abstract class NovelBaseFragment : Fragment() { |
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
||||
return inflater.inflate(getLayoutId(),null) |
||||
} |
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||
super.onViewCreated(view, savedInstanceState) |
||||
initView() |
||||
initData() |
||||
} |
||||
|
||||
/** |
||||
* 加载布局 |
||||
*/ |
||||
@LayoutRes |
||||
abstract fun getLayoutId():Int |
||||
|
||||
abstract fun initView() |
||||
|
||||
abstract fun initData() |
||||
|
||||
fun toActivity(toClsActivity: Class<*>) { |
||||
this.toActivity(toClsActivity, null as Bundle?) |
||||
} |
||||
|
||||
fun toActivity(toClsActivity: Class<*>, bundle: Bundle?) { |
||||
val intent = Intent(this.context, toClsActivity) |
||||
if (bundle != null) { |
||||
intent.putExtras(bundle) |
||||
} |
||||
|
||||
this.startActivity(intent) |
||||
} |
||||
|
||||
fun toActivityForResult(toClsActivity: Class<*>, bundle: Bundle?, requestCode: Int) { |
||||
val intent = Intent(this.context, toClsActivity) |
||||
if (bundle != null) { |
||||
intent.putExtras(bundle) |
||||
} |
||||
|
||||
startActivityForResult(intent, requestCode) |
||||
} |
||||
|
||||
|
||||
} |
@ -1,15 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import androidx.lifecycle.ViewModel |
||||
import androidx.viewbinding.ViewBinding |
||||
import com.novel.read.constant.Theme |
||||
|
||||
abstract class VMBaseActivity<VB : ViewBinding,VM : ViewModel>( |
||||
fullScreen: Boolean = true, |
||||
theme: Theme = Theme.Auto, |
||||
toolBarTheme: Theme = Theme.Auto |
||||
) : BaseActivity<VB>(fullScreen, theme, toolBarTheme) { |
||||
|
||||
protected abstract val viewModel: VM |
||||
|
||||
} |
@ -1,9 +0,0 @@ |
||||
package com.novel.read.base |
||||
|
||||
import androidx.lifecycle.ViewModel |
||||
|
||||
abstract class VMBaseFragment<VM : ViewModel>(layoutID: Int) : BaseFragment(layoutID) { |
||||
|
||||
protected abstract val viewModel: VM |
||||
|
||||
} |
@ -1,73 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.graphics.Color |
||||
import java.text.SimpleDateFormat |
||||
|
||||
@SuppressLint("SimpleDateFormat") |
||||
object AppConst { |
||||
|
||||
const val APP_TAG = "TuZi" |
||||
const val AppId = "20210306161" |
||||
const val AppSecret = "c14f6a2b3dcah893a31b9i4f40f5cc08" |
||||
|
||||
const val channelIdDownload = "channel_download" |
||||
const val channelIdReadAloud = "channel_read_aloud" |
||||
|
||||
val timeFormat: SimpleDateFormat by lazy { |
||||
SimpleDateFormat("HH:mm") |
||||
} |
||||
|
||||
val dateFormat: SimpleDateFormat by lazy { |
||||
SimpleDateFormat("yyyy/MM/dd HH:mm") |
||||
} |
||||
|
||||
val fileNameFormat: SimpleDateFormat by lazy { |
||||
SimpleDateFormat("yy-MM-dd-HH-mm-ss") |
||||
} |
||||
|
||||
val keyboardToolChars: List<String> by lazy { |
||||
arrayListOf( |
||||
"※", "@", "&", "|", "%", "/", ":", "[", "]", "{", "}", "<", ">", "\\", |
||||
"$", "#", "!", ".", "href", "src", "textNodes", "xpath", "json", "css", |
||||
"id", "class", "tag" |
||||
) |
||||
} |
||||
|
||||
const val notificationIdRead = 1144771 |
||||
const val notificationIdDownload = 1144774 |
||||
|
||||
|
||||
const val refresh = 1 |
||||
const val loading = 2 |
||||
const val complete = 3 |
||||
const val error = 4 |
||||
const val loadMore = 5 |
||||
const val loadComplete = 6 |
||||
const val loadMoreFail = 7 |
||||
const val noMore = 8 |
||||
|
||||
@kotlin.jvm.JvmField |
||||
val tagColors = intArrayOf( |
||||
Color.parseColor("#90C5F0"), |
||||
Color.parseColor("#91CED5"), |
||||
Color.parseColor("#F88F55"), |
||||
Color.parseColor("#C0AFD0"), |
||||
Color.parseColor("#E78F8F"), |
||||
Color.parseColor("#67CCB7"), |
||||
Color.parseColor("#F6BC7E"), |
||||
Color.parseColor("#90C5F0"), |
||||
Color.parseColor("#91CED5") |
||||
) |
||||
|
||||
const val home = 0 |
||||
const val man = 1 |
||||
const val woman = 2 |
||||
|
||||
const val shellName = "001" |
||||
|
||||
val menuViewNames = arrayOf( |
||||
"com.android.internal.view.menu.ListMenuItemView", |
||||
"androidx.appcompat.view.menu.ListMenuItemView" |
||||
) |
||||
} |
@ -1,16 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
import java.util.regex.Pattern |
||||
|
||||
object AppPattern { |
||||
val JS_PATTERN: Pattern = |
||||
Pattern.compile("(<js>[\\w\\W]*?</js>|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE) |
||||
val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") |
||||
val imgPattern: Pattern = |
||||
Pattern.compile("<img .*?src.*?=.*?\"(.*?(?:,\\{.*\\})?)\".*?>", Pattern.CASE_INSENSITIVE) |
||||
|
||||
val nameRegex = Regex("\\s+作\\s*者.*") |
||||
val authorRegex = Regex(".*?作\\s*?者[::]") |
||||
val fileNameRegex = Regex("[\\\\/:*?\"<>|.]") |
||||
val splitGroupRegex = Regex("[,;,;]") |
||||
} |
@ -1,13 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
object BookType { |
||||
const val default = 0 // 0 文本 |
||||
const val audio = 1 // 1 音频 |
||||
const val local = "loc_book" |
||||
const val net = "net_book" |
||||
|
||||
|
||||
const val serial="01" |
||||
const val stop="02" |
||||
const val complete="03" |
||||
} |
@ -1,28 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
object EventBus { |
||||
const val MEDIA_BUTTON = "mediaButton" |
||||
const val RECREATE = "RECREATE" |
||||
const val UP_BOOK = "upBookToc" |
||||
const val UPDATE_BOOK = "UPDATE_BOOK" |
||||
const val ALOUD_STATE = "aloud_state" |
||||
const val TTS_PROGRESS = "ttsStart" |
||||
const val TTS_DS = "ttsDs" |
||||
const val BATTERY_CHANGED = "batteryChanged" |
||||
const val TIME_CHANGED = "timeChanged" |
||||
const val UP_CONFIG = "upConfig" |
||||
const val OPEN_CHAPTER = "openChapter" |
||||
const val AUDIO_SUB_TITLE = "audioSubTitle" |
||||
const val AUDIO_STATE = "audioState" |
||||
const val AUDIO_PROGRESS = "audioProgress" |
||||
const val AUDIO_SIZE = "audioSize" |
||||
const val AUDIO_SPEED = "audioSpeed" |
||||
const val SHOW_RSS = "showRss" |
||||
const val SHOW_AD = "showAd" |
||||
const val WEB_SERVICE = "webService" |
||||
const val UP_DOWNLOAD = "upDownload" |
||||
const val SAVE_CONTENT = "saveContent" |
||||
const val CHECK_SOURCE = "checkSource" |
||||
const val CHECK_SOURCE_DONE = "checkSourceDone" |
||||
const val REPLACE_RULE_SAVE = "replaceRuleSave" |
||||
} |
@ -1,30 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
object IntentAction { |
||||
const val start = "start" |
||||
const val play = "play" |
||||
const val stop = "stop" |
||||
const val resume = "resume" |
||||
const val pause = "pause" |
||||
const val addTimer = "addTimer" |
||||
const val setTimer = "setTimer" |
||||
const val prevParagraph = "prevParagraph" |
||||
const val nextParagraph = "nextParagraph" |
||||
const val upTtsSpeechRate = "upTtsSpeechRate" |
||||
const val adjustProgress = "adjustProgress" |
||||
const val adjustSpeed = "adjustSpeed" |
||||
const val prev = "prev" |
||||
const val next = "next" |
||||
const val moveTo = "moveTo" |
||||
const val init = "init" |
||||
const val remove = "remove" |
||||
|
||||
|
||||
//page skip use |
||||
const val bookTypeId = "bookTypeId" |
||||
const val channelName = "channelName" |
||||
const val bookId = "bookId" |
||||
const val rankType = "rankType" |
||||
const val homeType = "homeType" |
||||
|
||||
} |
@ -1,23 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
object LayoutType { |
||||
const val HOT = 1 |
||||
const val CLICK = 2 |
||||
const val RECOMMEND= 3 |
||||
const val END = 4 |
||||
|
||||
const val BOY_HOT = 6 |
||||
const val BOY_END = 7 |
||||
const val BOY_SEARCH = 8 |
||||
|
||||
const val GIRL_HOT = 9 |
||||
const val GIRL_END = 10 |
||||
const val GIRL_SEARCH = 11 |
||||
|
||||
const val HEAD = 100 |
||||
const val OTHER = 101 |
||||
|
||||
|
||||
const val INIT_BOOK = 102 |
||||
const val SEARCH_BOOK = 103 |
||||
} |
@ -1,69 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
object PreferKey { |
||||
const val versionCode = "versionCode" |
||||
const val language = "language" |
||||
const val themeMode = "themeMode" |
||||
const val hideStatusBar = "hideStatusBar" |
||||
const val clickTurnPage = "clickTurnPage" |
||||
const val clickAllNext = "clickAllNext" |
||||
const val hideNavigationBar = "hideNavigationBar" |
||||
const val precisionSearch = "precisionSearch" |
||||
const val speakEngine = "speakEngine" |
||||
const val readAloudByPage = "readAloudByPage" |
||||
const val ttsSpeechRate = "ttsSpeechRate" |
||||
const val prevKeys = "prevKeyCodes" |
||||
const val nextKeys = "nextKeyCodes" |
||||
const val bookshelfLayout = "bookshelfLayout" |
||||
const val bookshelfSort = "bookshelfSort" |
||||
const val recordLog = "recordLog" |
||||
const val processText = "process_text" |
||||
const val cleanCache = "cleanCache" |
||||
const val saveTabPosition = "saveTabPosition" |
||||
const val fontFolder = "fontFolder" |
||||
const val backupPath = "backupUri" |
||||
const val restoreIgnore = "restoreIgnore" |
||||
const val threadCount = "threadCount" |
||||
const val webPort = "webPort" |
||||
const val keepLight = "keep_light" |
||||
const val webService = "webService" |
||||
const val webDavUrl = "web_dav_url" |
||||
const val webDavAccount = "web_dav_account" |
||||
const val webDavPassword = "web_dav_password" |
||||
const val webDavCreateDir = "webDavCreateDir" |
||||
const val webDavCacheBackup = "webDavCacheBackup" |
||||
const val changeSourceLoadToc = "changeSourceLoadToc" |
||||
const val changeSourceLoadInfo = "changeSourceLoadInfo" |
||||
const val chineseConverterType = "chineseConverterType" |
||||
const val launcherIcon = "launcherIcon" |
||||
const val textSelectAble = "selectText" |
||||
const val lastBackup = "lastBackup" |
||||
const val shareLayout = "shareLayout" |
||||
const val readStyleSelect = "readStyleSelect" |
||||
const val systemTypefaces = "system_typefaces" |
||||
const val readBodyToLh = "readBodyToLh" |
||||
const val textFullJustify = "textFullJustify" |
||||
const val textBottomJustify = "textBottomJustify" |
||||
const val autoReadSpeed = "autoReadSpeed" |
||||
const val barElevation = "barElevation" |
||||
const val transparentStatusBar = "transparentStatusBar" |
||||
const val defaultCover = "defaultCover" |
||||
const val replaceEnableDefault = "replaceEnableDefault" |
||||
const val showBrightnessView = "showBrightnessView" |
||||
const val autoClearExpired = "autoClearExpired" |
||||
|
||||
const val cPrimary = "colorPrimary" |
||||
const val cAccent = "colorAccent" |
||||
const val cBackground = "colorBackground" |
||||
const val cBBackground = "colorBottomBackground" |
||||
|
||||
const val cNPrimary = "colorPrimaryNight" |
||||
const val cNAccent = "colorAccentNight" |
||||
const val cNBackground = "colorBackgroundNight" |
||||
const val cNBBackground = "colorBottomBackgroundNight" |
||||
|
||||
const val installCount = "installCount" |
||||
const val installTime = "installTime" |
||||
const val appraiseShow = "appraiseShow" |
||||
|
||||
} |
@ -1,7 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
object Status { |
||||
const val STOP = 0 |
||||
const val PLAY = 1 |
||||
const val PAUSE = 3 |
||||
} |
@ -1,20 +0,0 @@ |
||||
package com.novel.read.constant |
||||
|
||||
import com.novel.read.help.AppConfig |
||||
import com.novel.read.utils.ColorUtils |
||||
|
||||
|
||||
enum class Theme { |
||||
Dark, Light, Auto, Transparent; |
||||
|
||||
companion object { |
||||
fun getTheme() = |
||||
if (AppConfig.isNightTheme) Dark |
||||
else Light |
||||
|
||||
fun getTheme(backgroundColor: Int) = |
||||
if (ColorUtils.isColorLight(backgroundColor)) Light |
||||
else Dark |
||||
|
||||
} |
||||
} |
@ -1,17 +0,0 @@ |
||||
# 存储数据用 |
||||
* dao 数据操作 |
||||
* entities 数据模型 |
||||
* \Book 书籍信息 |
||||
* \BookChapter 目录信息 |
||||
* \BookGroup 书籍分组 |
||||
* \Bookmark 书签 |
||||
* \BookSource 书源 |
||||
* \Cookie http cookie |
||||
* \ReplaceRule 替换规则 |
||||
* \RssArticle rss条目 |
||||
* \RssReadRecord rss阅读记录 |
||||
* \RssSource rss源 |
||||
* \RssStar rss收藏 |
||||
* \SearchBook 搜索结果 |
||||
* \SearchKeyword 搜索关键字 |
||||
* \TxtTocRule txt文件目录规则 |
@ -1,50 +0,0 @@ |
||||
package com.novel.read.data.db |
||||
|
||||
import android.content.ContentValues |
||||
import com.novel.read.data.db.entity.Book |
||||
import org.litepal.LitePal |
||||
|
||||
|
||||
class BookDao { |
||||
|
||||
fun getAllBooks(): MutableList<Book> = LitePal.findAll(Book::class.java) |
||||
|
||||
fun lastReadBook(): Book = LitePal.order("durChapterTime desc").findFirst(Book::class.java) |
||||
|
||||
fun update(book: Book) { |
||||
val values = ContentValues() |
||||
values.put("authorPenname", book.authorPenname) |
||||
values.put("bookName", book.bookName) |
||||
values.put("bookStatus", book.bookStatus) |
||||
values.put("categoryName", book.categoryName) |
||||
values.put("channelName", book.channelName) |
||||
values.put("cName", book.cName) |
||||
values.put("coverImageUrl", book.coverImageUrl) |
||||
values.put("introduction", book.introduction) |
||||
values.put("keyWord", book.keyWord) |
||||
values.put("lastUpdateChapterDate", book.lastUpdateChapterDate) |
||||
values.put("status", book.status) |
||||
values.put("wordCount", book.wordCount) |
||||
values.put("durChapterTime", book.durChapterTime) |
||||
values.put("durChapterIndex", book.durChapterIndex) |
||||
values.put("durChapterPos", book.durChapterPos) |
||||
values.put("durChapterTitle", book.durChapterTitle) |
||||
values.put("totalChapterNum", book.totalChapterNum) |
||||
LitePal.updateAll(Book::class.java, values, "bookId=?", book.bookId.toString()) |
||||
} |
||||
|
||||
fun getBook(bookId: String): Book? = |
||||
LitePal.where("bookId=?", bookId).findFirst(Book::class.java) |
||||
|
||||
fun insert(book: Book) = book.saveOrUpdate("bookId=?", book.bookId.toString()) |
||||
|
||||
fun delete(book: Book): Int = |
||||
LitePal.deleteAll(Book::class.java, "bookId=?", book.bookId.toString()) |
||||
|
||||
fun saveBook(book: List<Book>?) { |
||||
if (book != null && book.isNotEmpty()) { |
||||
LitePal.saveAll(book) |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,60 +0,0 @@ |
||||
package com.novel.read.data.db |
||||
|
||||
class BookDatabase private constructor() { |
||||
|
||||
companion object { |
||||
private var instance: BookDatabase? = null |
||||
get() { |
||||
if (field == null) { |
||||
field = BookDatabase() |
||||
} |
||||
return field |
||||
} |
||||
|
||||
fun get(): BookDatabase { |
||||
return instance!! |
||||
} |
||||
} |
||||
|
||||
private var chapterDao: ChapterDao? = null |
||||
private var bookDao: BookDao? = null |
||||
private var readRecordDao: ReadRecordDao? = null |
||||
private var bookMarkDao: BookMarkDao? = null |
||||
private var searchHistoryDao: SearchHistoryDao? = null |
||||
|
||||
fun getChapterDao(): ChapterDao { |
||||
if (chapterDao == null) { |
||||
chapterDao = ChapterDao() |
||||
} |
||||
return chapterDao!! |
||||
} |
||||
|
||||
fun getBookDao(): BookDao { |
||||
if (bookDao == null) { |
||||
bookDao = BookDao() |
||||
} |
||||
return bookDao!! |
||||
} |
||||
|
||||
fun getReadRecordDao(): ReadRecordDao { |
||||
if (readRecordDao == null) { |
||||
readRecordDao = ReadRecordDao() |
||||
} |
||||
return readRecordDao!! |
||||
} |
||||
|
||||
fun getBookMarkDao(): BookMarkDao { |
||||
if (bookMarkDao == null) { |
||||
bookMarkDao = BookMarkDao() |
||||
} |
||||
return bookMarkDao!! |
||||
} |
||||
|
||||
fun getSearchDao(): SearchHistoryDao { |
||||
if (searchHistoryDao == null) { |
||||
searchHistoryDao = SearchHistoryDao() |
||||
} |
||||
return searchHistoryDao!! |
||||
} |
||||
|
||||
} |
@ -1,39 +0,0 @@ |
||||
package com.novel.read.data.db |
||||
|
||||
import com.novel.read.data.db.entity.Bookmark |
||||
import org.litepal.LitePal |
||||
|
||||
class BookMarkDao { |
||||
|
||||
fun observeByBook(bookId: Long): List<Bookmark>? = |
||||
LitePal.where("bookId=?", bookId.toString()).find(Bookmark::class.java) |
||||
|
||||
fun liveDataSearch(bookId: String, key: String): List<Bookmark>? = |
||||
LitePal.where( |
||||
"bookId=? and (chapterName like ? or content like ?)", |
||||
bookId.toString(), |
||||
"%${key}%", "%${key}%" |
||||
) |
||||
.find(Bookmark::class.java) |
||||
|
||||
fun insert(bookmark: Bookmark) { |
||||
bookmark.saveOrUpdate( |
||||
"bookId=? and chapterIndex=?", |
||||
bookmark.bookId.toString(), |
||||
bookmark.chapterIndex.toString() |
||||
) |
||||
} |
||||
|
||||
fun update(bookmark: Bookmark) { |
||||
bookmark.saveOrUpdate( |
||||
"bookId=? and chapterIndex=?", |
||||
bookmark.bookId.toString(), |
||||
bookmark.chapterIndex.toString() |
||||
) |
||||
} |
||||
|
||||
fun delete(bookmark: Bookmark) { |
||||
bookmark.delete() |
||||
} |
||||
|
||||
} |
@ -1,48 +0,0 @@ |
||||
package com.novel.read.data.db |
||||
|
||||
import com.novel.read.data.db.entity.BookChapter |
||||
import org.litepal.LitePal |
||||
|
||||
class ChapterDao { |
||||
|
||||
fun observeByBook(bookId: String): List<BookChapter>? = |
||||
LitePal.where("bookId=?", bookId.toString()).find(BookChapter::class.java) |
||||
|
||||
fun liveDataSearch(bookId: String, key: String): List<BookChapter>? = |
||||
LitePal.where("bookId=? and chapterName like ?", bookId, "%${key}%") |
||||
.find(BookChapter::class.java) |
||||
|
||||
fun getChapter(chapterId: Long): BookChapter? = |
||||
LitePal.where("chapterId =?", chapterId.toString()).findFirst(BookChapter::class.java) |
||||
|
||||
fun getChapter(bookId: Long, chapterIndex: Int): BookChapter? = |
||||
LitePal.where("bookId=? and chapterIndex =?", bookId.toString(), chapterIndex.toString()) |
||||
.findFirst(BookChapter::class.java) |
||||
|
||||
fun getChapterList(bookId: Long): List<BookChapter>? = |
||||
LitePal.where("bookId=?", bookId.toString()).find(BookChapter::class.java) |
||||
|
||||
fun getChapterList(bookId: Long, start: Int, end: Int): List<BookChapter> = |
||||
LitePal.where( |
||||
"bookId=? and chapterIndex >=? and chapterIndex <=?", |
||||
bookId.toString(), |
||||
start.toString(), |
||||
end.toString() |
||||
).order("chapterIndex desc").find(BookChapter::class.java) |
||||
|
||||
fun getChapterCount(bookId: Long): Int { |
||||
return LitePal.where("bookId=?", bookId.toString()).count(BookChapter::class.java) |
||||
} |
||||
|
||||
fun insert(bookChapters: Array<BookChapter>) { |
||||
if (bookChapters.isNotEmpty()) { |
||||
LitePal.deleteAll( |
||||
BookChapter::class.java, |
||||
"bookId=?", |
||||
bookChapters[0].bookId.toString() |
||||
) |
||||
} |
||||
LitePal.saveAll(bookChapters.toList()) |
||||
} |
||||
|
||||
} |
@ -1,23 +0,0 @@ |
||||
package com.novel.read.data.db |
||||
|
||||
import com.novel.read.data.db.entity.ReadRecord |
||||
import org.litepal.LitePal |
||||
|
||||
class ReadRecordDao { |
||||
|
||||
fun getReadTime(bookName: String): Long? = |
||||
LitePal.where("bookName =?", bookName).findFirst(ReadRecord::class.java)?.readTime |
||||
|
||||
fun insert(readRecord: ReadRecord) { |
||||
readRecord.saveOrUpdate("bookId=?", readRecord.bookId.toString()) |
||||
} |
||||
|
||||
fun delete(readRecord: ReadRecord) { |
||||
readRecord.delete() |
||||
} |
||||
|
||||
fun getAll(): List<ReadRecord> { |
||||
return LitePal.findAll(ReadRecord::class.java) |
||||
} |
||||
|
||||
} |
@ -1,19 +0,0 @@ |
||||
package com.novel.read.data.db |
||||
|
||||
import com.novel.read.data.db.entity.SearchHistory |
||||
import org.litepal.LitePal |
||||
|
||||
class SearchHistoryDao { |
||||
|
||||
fun getListByTime(): MutableList<SearchHistory>? = |
||||
LitePal.order("saveTime desc").limit(5).find(SearchHistory::class.java) |
||||
|
||||
fun insert(searchHistory: SearchHistory, key: String) { |
||||
searchHistory.saveOrUpdate("key=?", key) |
||||
} |
||||
|
||||
fun deleteAll() { |
||||
LitePal.deleteAll(SearchHistory::class.java) |
||||
} |
||||
|
||||
} |
@ -1,52 +0,0 @@ |
||||
package com.novel.read.data.db.entity |
||||
|
||||
import com.google.gson.annotations.SerializedName |
||||
import com.novel.read.constant.AppPattern |
||||
import com.novel.read.constant.BookType |
||||
import com.novel.read.utils.MD5Utils |
||||
import org.litepal.crud.LitePalSupport |
||||
import kotlin.math.max |
||||
|
||||
data class Book( |
||||
val authorPenname: String, |
||||
val bookId: Long, |
||||
val bookName: String, |
||||
val bookStatus: String, |
||||
val categoryName: String?, |
||||
val channelName: String?, |
||||
@SerializedName("className") |
||||
val cName: String?, |
||||
val coverImageUrl: String, |
||||
val introduction: String, |
||||
val keyWord: String, |
||||
var lastUpdateChapterDate: String, |
||||
val status: Int, |
||||
val wordCount: Long, |
||||
var totalChapterNum: Int = 0, // 书籍目录总数 |
||||
var durChapterTitle: String? = null, // 当前章节名称 |
||||
var durChapterIndex: Int = 0, // 当前章节索引 |
||||
var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置) |
||||
var durChapterTime: Long = System.currentTimeMillis(), // 最近一次阅读书籍的时间(打开正文的时间) |
||||
var origin: String = BookType.net, |
||||
var originName: String = "", |
||||
var bookTypeId: Int = 0 |
||||
) : LitePalSupport() { |
||||
|
||||
fun isLocalBook(): Boolean { |
||||
return origin == BookType.local |
||||
} |
||||
|
||||
fun getFolderName(): String { |
||||
return bookName.replace(AppPattern.fileNameRegex, "") + MD5Utils.md5Encode16(coverImageUrl) |
||||
} |
||||
|
||||
fun isEpub(): Boolean { |
||||
return originName.endsWith(".epub", true) |
||||
} |
||||
|
||||
fun canUpdate(): Boolean { |
||||
return bookStatus == BookType.serial |
||||
} |
||||
|
||||
fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0) |
||||
} |
@ -1,19 +0,0 @@ |
||||
package com.novel.read.data.db.entity |
||||
|
||||
import org.litepal.crud.LitePalSupport |
||||
|
||||
data class BookChapter( |
||||
// val bookId: Int, |
||||
// val chapterList: List<Chapter>, |
||||
// val volumeId: Int, |
||||
// val volumeName: String |
||||
|
||||
val chapterId: Long, |
||||
val bookId: Long, |
||||
val chapterIndex: Int, |
||||
var chapterName: String, |
||||
val createTimeValue: Long, |
||||
val updateDate: String, |
||||
val updateTimeValue: Long, |
||||
val chapterUrl: String?, |
||||
) : LitePalSupport() |
@ -1,16 +0,0 @@ |
||||
package com.novel.read.data.db.entity |
||||
|
||||
import org.litepal.crud.LitePalSupport |
||||
import java.io.Serializable |
||||
|
||||
data class Bookmark( |
||||
var time: Long = System.currentTimeMillis(), |
||||
var bookId: Long = 0, |
||||
var bookName: String = "", |
||||
val bookAuthor: String = "", |
||||
var chapterIndex: Int = 0, |
||||
var pageIndex: Int = 0, |
||||
var chapterName: String = "", |
||||
var content: String = "" |
||||
|
||||
) : LitePalSupport(), Serializable |
@ -1,10 +0,0 @@ |
||||
package com.novel.read.data.db.entity |
||||
|
||||
data class ChapterDetailEntity( |
||||
val chapterContent: String, |
||||
val chapterIndex: Int, |
||||
val chapterName: String, |
||||
val isRecommend: String, |
||||
val isVIP: String, |
||||
val wordCount: Int |
||||
) |
@ -1,9 +0,0 @@ |
||||
package com.novel.read.data.db.entity |
||||
|
||||
import org.litepal.crud.LitePalSupport |
||||
|
||||
data class HttpTTS( |
||||
val id: Long = System.currentTimeMillis(), |
||||
var name: String = "", |
||||
var url: String = "" |
||||
) : LitePalSupport() |
@ -1,15 +0,0 @@ |
||||
package com.novel.read.data.db.entity |
||||
|
||||
import org.litepal.crud.LitePalSupport |
||||
|
||||
import java.io.Serializable |
||||
|
||||
/** |
||||
* Created by zlj |
||||
*/ |
||||
class ReadRecord( |
||||
var androidId: String = "", |
||||
var bookName: String = "", |
||||
var bookId: Long = 0L, |
||||
var readTime: Long = 0L |
||||
) : LitePalSupport(), Serializable |
@ -1,20 +0,0 @@ |
||||
package com.novel.read.data.model |
||||
|
||||
data class AppUpdateResp( |
||||
val appEdition: AppEdition |
||||
) |
||||
|
||||
data class AppEdition( |
||||
val createTime: String, |
||||
val editionCode: String, |
||||
val editionId: Int, |
||||
val fileUrl: String, |
||||
val forceUpdate: Int, |
||||
val insideEditionCode: Int, |
||||
val isDel: Int, |
||||
val packageSize: String, |
||||
val pushTime: String, |
||||
val shellName: String, |
||||
val status: Int, |
||||
val upgradeContent: String |
||||
) |
@ -1,33 +0,0 @@ |
||||
package com.novel.read.data.model |
||||
|
||||
data class BookInfoResp( |
||||
val book: BookResp |
||||
) |
||||
|
||||
data class BookResp( |
||||
val authorInformation: Any, |
||||
val authorName: String, |
||||
val authorUserId: Long, |
||||
val bookClass: Any, |
||||
val bookId: Long, |
||||
val bookName: String, |
||||
val bookSId: String, |
||||
val bookStatus: Any, |
||||
val bookTypeId: Int, |
||||
val categoryName: String?, |
||||
val channelName: Any?, |
||||
val coverImageUrl: String, |
||||
val createTime: Long, |
||||
val endStatus: Int, |
||||
val extBookId: Any, |
||||
val hits: Any, |
||||
val hotStatus: Any, |
||||
val introduction: String, |
||||
val keyWord: String, |
||||
val lastUpdateChapterDate: String, |
||||
val rankNumber: Any, |
||||
val rankType: Any, |
||||
val recommendStatus: Any, |
||||
val validFlag: Int, |
||||
val wordCount: Long |
||||
) |
@ -1,52 +0,0 @@ |
||||
package com.novel.read.data.model |
||||
|
||||
import com.novel.read.utils.StringUtils |
||||
|
||||
data class BookListResp( |
||||
val authorInformation: String, |
||||
var authorName: String?, |
||||
val authorUserId: Long, |
||||
val bookClass: Int, |
||||
val bookId: Long, |
||||
val bookName: String, |
||||
val bookSId: String, |
||||
val bookStatus: Int, |
||||
val bookTypeId: Int, |
||||
val categoryName: String?, |
||||
val channelName: String?, |
||||
val coverImageUrl: String, |
||||
val createTime: Long, |
||||
val endStatus: Int, |
||||
val hotStatus: Int, |
||||
val introduction: String?, |
||||
val keyWord: String, |
||||
val lastUpdateChapterDate: String?, |
||||
val recommendStatus: Int, |
||||
val validFlag: Int, |
||||
val wordCount: Long |
||||
|
||||
) { |
||||
fun getBAuthorName(): String { |
||||
return StringUtils.convertCC(authorName!!) |
||||
} |
||||
|
||||
fun getBBookName(): String { |
||||
return StringUtils.convertCC(bookName) |
||||
} |
||||
|
||||
fun getBCategoryName(): String { |
||||
return StringUtils.convertCC(categoryName ?: "") |
||||
} |
||||
|
||||
fun getBChannel(): String { |
||||
return StringUtils.convertCC(channelName!!) |
||||
} |
||||
|
||||
fun getBIntroduction(): String { |
||||
return StringUtils.convertCC(introduction!!) |
||||
} |
||||
|
||||
fun getBKeyWord(): String { |
||||
return StringUtils.convertCC(keyWord) |
||||
} |
||||
} |
@ -1,51 +0,0 @@ |
||||
package com.novel.read.data.model |
||||
|
||||
import com.chad.library.adapter.base.entity.MultiItemEntity |
||||
import com.novel.read.constant.LayoutType |
||||
import com.novel.read.utils.StringUtils |
||||
|
||||
data class BoyEndRank( |
||||
val authorInformation: String, |
||||
val authorName: String, |
||||
val authorUserId: Long, |
||||
val bookChannelId: Long, |
||||
val bookClass: Int, |
||||
val bookId: Long, |
||||
val bookName: String, |
||||
val bookSId: String, |
||||
val bookStatus: Int, |
||||
val bookTypeId: Long, |
||||
val categoryName: String, |
||||
val channelName: String, |
||||
val coverImageUrl: String, |
||||
val createTime: Long, |
||||
val endStatus: Int, |
||||
val extBookId: Int, |
||||
val hits: String, |
||||
val hotStatus: Int, |
||||
val introduction: String, |
||||
val keyWord: String, |
||||
val lastUpdateChapterDate: String, |
||||
val rankNumber: String, |
||||
val rankType: String, |
||||
val recommendStatus: Int, |
||||
val validFlag: Int, |
||||
val wordCount: Long |
||||
){ |
||||
fun getBAuthorName(): String { |
||||
return StringUtils.convertCC(authorName) |
||||
} |
||||
|
||||
fun getBBookName(): String { |
||||
return StringUtils.convertCC(bookName) |
||||
} |
||||
|
||||
fun getBCategoryName(): String { |
||||
return StringUtils.convertCC(categoryName) |
||||
} |
||||
} |
||||
|
||||
data class BoyEndRankEntity(val boyEndRanks:List<BoyEndRank>):MultiItemEntity{ |
||||
override val itemType: Int |
||||
get() = LayoutType.BOY_END |
||||
} |
@ -1,50 +0,0 @@ |
||||
package com.novel.read.data.model |
||||
|
||||
import com.chad.library.adapter.base.entity.MultiItemEntity |
||||
import com.novel.read.constant.LayoutType |
||||
import com.novel.read.utils.StringUtils |
||||
|
||||
data class BoyHotRank( |
||||
val authorInformation: String, |
||||
val authorName: String, |
||||
val authorUserId: Long, |
||||
val bookChannelId: Long, |
||||
val bookClass: Int, |
||||
val bookId: Long, |
||||
val bookName: String, |
||||
val bookSId: String, |
||||
val bookStatus: Int, |
||||
val bookTypeId: Long, |
||||
val categoryName: String, |
||||
val channelName: String, |
||||
val coverImageUrl: String, |
||||
val createTime: Long, |
||||
val endStatus: Int, |
||||
val extBookId: Int, |
||||
val hits: String, |
||||
val hotStatus: Int, |
||||
val introduction: String, |
||||
val keyWord: String, |
||||
val lastUpdateChapterDate: String, |
||||
val rankNumber: String, |
||||
val rankType: String, |
||||
val recommendStatus: Int, |
||||
val validFlag: Int |
||||
) { |
||||
fun getBAuthorName(): String { |
||||
return StringUtils.convertCC(authorName) |
||||
} |
||||
|
||||
fun getBBookName(): String { |
||||
return StringUtils.convertCC(bookName) |
||||
} |
||||
|
||||
fun getBCategoryName(): String { |
||||
return StringUtils.convertCC(categoryName) |
||||
} |
||||
} |
||||
|
||||
data class BoyHotRankEntity(val boyHotRanks: List<BoyHotRank>) : MultiItemEntity { |
||||
override val itemType: Int |
||||
get() = LayoutType.BOY_HOT |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue