diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8e48145
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,90 @@
+# Built application files
+#*.apk
+*.aar
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+# Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+/.idea
+app/debug/
+app/release/
+app/sampledata/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ef91bcc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,126 @@
+# Eyepetizer
+基于 [Kotlin][1] 语言仿写「[开眼 Eyepetizer][2]」的一个短视频 Android 客户端项目,采用 [Jetpack][3] + [协程][30]实现的 MVVM 架构。
+
+## 简介
+这是一个高仿「[开眼 Eyepetizer][2]」的短视频 Android 客户端项目,个人觉得这款 App 的 UI 设计风格很好看,界面简洁清新,通过此项目,进行相关技术的学习与整合。
+
+整个项目没有复杂的封装,同时项目开发规范参考了 [Kotlin 官方文档][4] 与第三方 [AndroidStandardDevelop][5]。个人认为代码还是比较容易阅读理解的,因此也非常适合新手入门 Kotlin 语言,同时更快地掌握 Jetpack 组件的使用。
+
+另外值得一提的是,所有 UI 都是经过标注工具测量后的,无论是字体颜色、大小、间距等几乎都是**像素级**模仿的「开眼 Eyepetizer」Android 客户端 App,对应的 v6.3.1 版本(目前最新版)。
+
+## 屏幕截图
+
+
+
+
+
+
+
+
+
+
+
+图片加载不出来?附上[博客地址][6]
+
+
+## 下载体验
+- 扫描二维码安装:
+
+
+- [点击下载 eyepetizer.apk][7]
+
+## 主要功能
+- 观看优质高清短视频与评论。
+- 浏览社区图文与视频创作。
+- 查看每日新鲜资讯与热搜关键词。
+- 分享精彩短视频与新鲜资讯等。
+
+## 使用工具
+- [Vector Asset Studio][8] 图标制作
+- [iconfont][9] 图标/设计
+- [Postman][10] API 调试工具
+- [Charles][11] API 数据抓包
+- [PxCook][12] 标注工具
+- [开发助手][13] 反编译应用、提取应用 Apk 等
+
+## 关于我
+- RealName : 殷志威
+- NickName : vipyinzhiwei
+- Email : vipyinzhiwei@gmail.com
+- Blog :
+
+## 鼓励
+通过这个项目希望能够帮助大家更好地学习 Jetpack 与 MVVM 架构。如果你喜欢 Eyepetizer 的设计,感觉本项目的源代码对你的学习有所帮助,可以点右上角 **"Star"** 支持一下,谢谢!^_^
+
+## 致谢
+- [Retrofit][14] 网络请求框架封装
+- [Glide][15] 图片加载
+- [OkHttp][16] 网络请求
+- [Gson][17] Gson 解析
+- [Glide Transformations][18] 图像转换
+- [Eventbus][19] 事件总线
+- [Permissionx][20] 动态请求权限封装
+- [FlycoTabLayout][21] TabLayout封装
+- [SmartRefreshLayout][22] 下拉刷新框架
+- [BannerViewPager][23] Banner轮播图
+- [Immersionbar][24] 状态栏管理
+- [PhotoView][25] 支持手势缩放图片
+- [Circleimageview][26] 圆形图像
+- [GSYVideoPlayer][27] 视频播放器
+- [VasSonic][28] 提升H5首屏加载速度
+- [Leakcanary][29] 内存泄漏检测
+- [Kotlinx Coroutines][30] 简化代码管理后台线程与回调
+
+
+## License
+
+**所有数据来源于开眼,仅供学习和交流使用,严禁用于任何商业用途,原作公司拥有所有权利。**
+
+```
+Copyright (c) 2020. vipyinzhiwei
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+```
+
+[1]:https://kotlinlang.org
+[2]:https://www.kaiyanapp.com
+[3]:https://developer.android.com/jetpack
+[4]:https://www.kotlincn.net/docs/reference/coding-conventions.html
+[5]:https://github.com/Blankj/AndroidStandardDevelop
+[6]:https://www.vipyinzhiwei.com/2020/06/19/pager05/#more
+[7]:https://github.com/VIPyinzhiwei/Eyepetizer/raw/master/eyepetizer.apk
+[8]:https://developer.android.com/studio/write/vector-asset-studio?hl=zh-cn
+[9]:https://www.iconfont.cn
+[10]:https://www.postman.com
+[11]:https://www.charlesproxy.com
+[12]:https://www.fancynode.com.cn/pxcook
+[13]:https://github.com/Trinea/android-open-project/issues/314
+[14]:https://github.com/square/retrofit
+[15]:https://github.com/bumptech/glide
+[16]:https://github.com/square/okhttp
+[17]:https://github.com/google/gson
+[18]:https://github.com/wasabeef/glide-transformations
+[19]:https://github.com/greenrobot/EventBus
+[20]:https://github.com/guolindev/PermissionX
+[21]:https://github.com/H07000223/FlycoTabLayout
+[22]:https://github.com/scwang90/SmartRefreshLayout
+[23]:https://github.com/zhpanvip/BannerViewPager
+[24]:https://github.com/gyf-dev/ImmersionBar
+[25]:https://github.com/chrisbanes/PhotoView
+[26]:https://github.com/hdodenhof/CircleImageView
+[27]:https://github.com/CarGuo/GSYVideoPlayer
+[28]:https://github.com/Tencent/VasSonic
+[29]:https://github.com/square/leakcanary
+[30]:https://github.com/Kotlin/kotlinx.coroutines
+
+
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..3fe82fd
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,3 @@
+/build
+/src/test
+/src/androidTest
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..dc0b620
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,117 @@
+apply plugin: 'com.android.application'
+
+apply plugin: 'kotlin-android'
+
+apply plugin: 'kotlin-android-extensions'
+
+apply plugin: 'kotlin-kapt'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.3"
+
+ defaultConfig {
+ applicationId "com.eyepetizer.android"
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0.0"
+ multiDexEnabled true
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ ndk {
+ abiFilters 'armeabi', 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
+ }
+ }
+
+ sourceSets {
+ main {
+ jniLibs.srcDirs = ['libs']
+ }
+ }
+
+ signingConfigs {
+ releaseConfig {
+ storeFile file(STORE_FILE)
+ storePassword STORE_PASSWORD
+ keyAlias KEY_ALIAS
+ keyPassword KEY_PASSWORD
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ signingConfig signingConfigs.releaseConfig
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ debug {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ lintOptions {
+ abortOnError false
+ disable 'ContentDescription'
+ disable 'SmallSp'
+ disable 'RtlSymmetry'
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'androidx.appcompat:appcompat:1.3.0-alpha01'
+ implementation 'androidx.core:core-ktx:1.3.0'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+
+ //常用依赖库
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7'
+ implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha03'
+ implementation 'com.google.android.material:material:1.1.0'
+ implementation 'com.squareup.retrofit2:retrofit:2.6.1'
+ implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'
+ implementation 'com.github.bumptech.glide:glide:4.9.0'
+ kapt 'com.github.bumptech.glide:compiler:4.9.0'
+ implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0'
+ implementation 'jp.wasabeef:glide-transformations:4.1.0'
+ implementation 'org.greenrobot:eventbus:3.1.1'
+ implementation 'androidx.viewpager2:viewpager2:1.0.0'
+ implementation 'com.permissionx.guolindev:permissionx:1.2.2'
+
+ //Android Jetpack 组件
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
+ implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
+ implementation 'androidx.work:work-runtime:2.3.4'
+
+ //特定功能依赖库
+ debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
+ implementation 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar'
+ implementation 'com.scwang.smart:refresh-header-material:2.0.0'
+ implementation 'com.scwang.smart:refresh-layout-kernel:2.0.0'
+ implementation 'com.github.zhpanvip:BannerViewPager:3.1.2'
+ implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
+ implementation 'com.github.chrisbanes:PhotoView:2.3.0'
+ implementation 'de.hdodenhof:circleimageview:3.1.0'
+ implementation 'com.android.support:multidex:1.0.3'
+ implementation 'com.shuyu:GSYVideoPlayer:7.1.3'
+ implementation 'com.tencent.sonic:sdk:3.1.0'
+ implementation 'com.umeng.umsdk:analytics:8.1.3'
+ implementation 'com.umeng.umsdk:common:2.1.0'
+
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..acad71c
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/assets/fonts/DIN-Condensed-Bold.ttf b/app/src/main/assets/fonts/DIN-Condensed-Bold.ttf
new file mode 100644
index 0000000..f05a1a9
Binary files /dev/null and b/app/src/main/assets/fonts/DIN-Condensed-Bold.ttf differ
diff --git a/app/src/main/assets/fonts/FZLanTingHeiS-DB1-GB-Regular.TTF b/app/src/main/assets/fonts/FZLanTingHeiS-DB1-GB-Regular.TTF
new file mode 100644
index 0000000..16dfb67
Binary files /dev/null and b/app/src/main/assets/fonts/FZLanTingHeiS-DB1-GB-Regular.TTF differ
diff --git a/app/src/main/assets/fonts/FZLanTingHeiS-L-GB-Regular.TTF b/app/src/main/assets/fonts/FZLanTingHeiS-L-GB-Regular.TTF
new file mode 100644
index 0000000..e3c7f7c
Binary files /dev/null and b/app/src/main/assets/fonts/FZLanTingHeiS-L-GB-Regular.TTF differ
diff --git a/app/src/main/assets/fonts/Futura-CondensedMedium.ttf b/app/src/main/assets/fonts/Futura-CondensedMedium.ttf
new file mode 100644
index 0000000..40a322c
Binary files /dev/null and b/app/src/main/assets/fonts/Futura-CondensedMedium.ttf differ
diff --git a/app/src/main/assets/fonts/Lobster-1.4.otf b/app/src/main/assets/fonts/Lobster-1.4.otf
new file mode 100644
index 0000000..86effca
Binary files /dev/null and b/app/src/main/assets/fonts/Lobster-1.4.otf differ
diff --git a/app/src/main/ic_launcher_playstore.png b/app/src/main/ic_launcher_playstore.png
new file mode 100644
index 0000000..2073ccf
Binary files /dev/null and b/app/src/main/ic_launcher_playstore.png differ
diff --git a/app/src/main/java/com/eyepetizer/android/Const.kt b/app/src/main/java/com/eyepetizer/android/Const.kt
new file mode 100644
index 0000000..a186cfe
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/Const.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android
+
+/**
+ * 项目所有全局通用常量的管理类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/31
+ */
+interface Const {
+
+ interface ItemViewType {
+
+ companion object {
+
+ const val UNKNOWN = -1 //未知类型,使用EmptyViewHolder容错处理。
+
+ const val CUSTOM_HEADER = 0 //自定义头部类型。
+
+ const val TEXT_CARD_HEADER1 = 1
+
+ const val TEXT_CARD_HEADER2 = 2
+
+ const val TEXT_CARD_HEADER3 = 3
+
+ const val TEXT_CARD_HEADER4 = 4 //type:textCard -> dataType:TextCard,type:header4
+
+ const val TEXT_CARD_HEADER5 = 5 //type:textCard -> dataType:TextCard -> type:header5
+
+ const val TEXT_CARD_HEADER6 = 6
+
+ const val TEXT_CARD_HEADER7 = 7 //type:textCard -> dataType:TextCardWithRightAndLeftTitle,type:header7
+
+ const val TEXT_CARD_HEADER8 = 8 //type:textCard -> dataType:TextCardWithRightAndLeftTitle,type:header8
+
+ const val TEXT_CARD_FOOTER1 = 9
+
+ const val TEXT_CARD_FOOTER2 = 10 //type:textCard -> dataType:TextCard,type:footer2
+
+ const val TEXT_CARD_FOOTER3 = 11 //type:textCard -> dataType:TextCardWithTagId,type:footer3
+
+ const val BANNER = 12 //type:banner -> dataType:Banner
+
+ const val BANNER3 = 13 //type:banner3-> dataType:Banner
+
+ const val FOLLOW_CARD = 14 //type:followCard -> dataType:FollowCard -> type:video -> dataType:VideoBeanForClient
+
+ const val TAG_BRIEFCARD = 15 //type:briefCard -> dataType:TagBriefCard
+
+ const val TOPIC_BRIEFCARD = 16 //type:briefCard -> dataType:TopicBriefCard
+
+ const val COLUMN_CARD_LIST = 17 //type:columnCardList -> dataType:ItemCollection
+
+ const val VIDEO_SMALL_CARD = 18 //type:videoSmallCard -> dataType:VideoBeanForClient
+
+ const val INFORMATION_CARD = 19 //type:informationCard -> dataType:InformationCard
+
+ const val AUTO_PLAY_VIDEO_AD = 20 //type:autoPlayVideoAd -> dataType:AutoPlayVideoAdDetail
+
+ const val HORIZONTAL_SCROLL_CARD = 21 //type:horizontalScrollCard -> dataType:HorizontalScrollCard
+
+ const val SPECIAL_SQUARE_CARD_COLLECTION = 22 //type:specialSquareCardCollection -> dataType:ItemCollection
+
+ const val UGC_SELECTED_CARD_COLLECTION = 23 //type:ugcSelectedCardCollection -> dataType:ItemCollection
+
+ const val MAX = 100 //避免外部其他类型与此处包含的某个类型重复。
+ }
+ }
+
+ interface ActionUrl {
+ companion object {
+
+ const val TAG = "eyepetizer://tag/"
+
+ const val DETAIL = "eyepetizer://detail/"
+
+ const val RANKLIST = "eyepetizer://ranklist/"
+
+ const val WEBVIEW = "eyepetizer://webview/?title="
+
+ const val REPLIES_HOT = "eyepetizer://replies/hot?"
+
+ const val TOPIC_DETAIL = "eyepetizer://topic/detail?"
+
+ const val COMMON_TITLE = "eyepetizer://common/?title"
+
+ const val LT_DETAIL = "eyepetizer://lightTopic/detail/"
+
+ const val CM_TOPIC_SQUARE = "eyepetizer://community/topicSquare"
+
+ const val HP_NOTIFI_TAB_ZERO = "eyepetizer://homepage/notification?tabIndex=0"
+
+ const val CM_TAGSQUARE_TAB_ZERO = "eyepetizer://community/tagSquare?tabIndex=0"
+
+ const val CM_TOPIC_SQUARE_TAB_ZERO = "eyepetizer://community/tagSquare?tabIndex=0"
+
+ const val HP_SEL_TAB_TWO_NEWTAB_MINUS_THREE = "eyepetizer://homepage/selected?tabIndex=2&newTabIndex=-3"
+ }
+ }
+
+ interface Toast {
+
+ companion object {
+
+ const val BIND_VIEWHOLDER_TYPE_WARN = "bindViewHolder Type Unprocessed"
+ }
+ }
+
+ interface Url {
+
+ companion object {
+
+ const val AUTHOR_LOGIN = "http://open.eyepetizer.net/#!/login"
+
+ const val AUTHOR_REGISTER = "http://open.eyepetizer.net/#!/register"
+
+ const val FORGET_PASSWORD = "http://open.eyepetizer.net/#!/forget"
+
+ const val USER_AGREEMENT = "http://www.eyepetizer.net/agreement.html"
+
+ const val VIDEO_FUNCTION_STATEMENT = "http://www.eyepetizer.net/right.html"
+
+ const val LEGAL_NOTICES = "http://www.kaiyanapp.com/legal_notices.html"
+
+ const val AUTHOR_OPEN = "http://open.eyepetizer.net/#!/landing"
+ }
+ }
+
+ interface Mobclick {
+
+ companion object {
+
+ const val EVENT1 = "10001"
+
+ const val EVENT2 = "10002"
+
+ const val EVENT3 = "10003"
+
+ const val EVENT4 = "10004"
+
+ const val EVENT5 = "10005"
+
+ const val EVENT6 = "10006"
+
+ const val EVENT7 = "10007"
+
+ const val EVENT8 = "10008"
+
+ const val EVENT9 = "10009"
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/EyepetizerApplication.kt b/app/src/main/java/com/eyepetizer/android/EyepetizerApplication.kt
new file mode 100644
index 0000000..5fa121e
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/EyepetizerApplication.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android
+
+import android.app.Application
+import android.content.Context
+import androidx.multidex.MultiDex
+import androidx.work.WorkManager
+import com.eyepetizer.android.extension.logD
+import com.eyepetizer.android.extension.preCreateSession
+import com.eyepetizer.android.ui.SplashActivity
+import com.eyepetizer.android.ui.common.ui.WebViewActivity
+import com.eyepetizer.android.ui.common.view.NoStatusFooter
+import com.eyepetizer.android.util.DialogAppraiseTipsWorker
+import com.google.gson.Gson
+import com.scwang.smart.refresh.header.MaterialHeader
+import com.scwang.smart.refresh.layout.SmartRefreshLayout
+import com.shuyu.gsyvideoplayer.player.IjkPlayerManager
+import com.umeng.commonsdk.UMConfigure
+import tv.danmaku.ijk.media.player.IjkMediaPlayer
+
+/**
+ * Eyepetizer自定义Application,在这里进行全局的初始化操作。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/4/28
+ */
+class EyepetizerApplication : Application() {
+
+ init {
+ SmartRefreshLayout.setDefaultRefreshInitializer { context, layout ->
+ layout.setEnableLoadMore(true)
+ layout.setEnableLoadMoreWhenContentNotFull(true)
+ }
+
+ SmartRefreshLayout.setDefaultRefreshHeaderCreator { context, layout ->
+ layout.setEnableHeaderTranslationContent(true)
+ MaterialHeader(context).setColorSchemeResources(R.color.blue, R.color.blue, R.color.blue)
+ }
+
+ SmartRefreshLayout.setDefaultRefreshFooterCreator { context, layout ->
+ layout.setEnableFooterFollowWhenNoMoreData(true)
+ layout.setEnableFooterTranslationContent(true)
+ layout.setFooterHeight(153f)
+ layout.setFooterTriggerRate(0.6f)
+ NoStatusFooter.REFRESH_FOOTER_NOTHING = "- The End -"
+ NoStatusFooter(context).apply {
+ setAccentColorId(R.color.colorTextPrimary)
+ setTextTitleSize(16f)
+ }
+ }
+ }
+
+ override fun attachBaseContext(base: Context) {
+ super.attachBaseContext(base)
+ MultiDex.install(this)
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ context = this
+ UMConfigure.init(this, null, null, UMConfigure.DEVICE_TYPE_PHONE, null)
+ UMConfigure.setLogEnabled(BuildConfig.DEBUG)
+ IjkPlayerManager.setLogLevel(if (BuildConfig.DEBUG) IjkMediaPlayer.IJK_LOG_WARN else IjkMediaPlayer.IJK_LOG_SILENT)
+ WebViewActivity.DEFAULT_URL.preCreateSession()
+ if (!SplashActivity.isFirstEntryApp && DialogAppraiseTipsWorker.isNeedShowDialog) {
+ WorkManager.getInstance(this).enqueue(DialogAppraiseTipsWorker.showDialogWorkRequest)
+ }
+ }
+
+ companion object {
+ lateinit var context: Context
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/event/MessageEvent.kt b/app/src/main/java/com/eyepetizer/android/event/MessageEvent.kt
new file mode 100644
index 0000000..51521bf
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/event/MessageEvent.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.event
+
+/**
+ * EventBus所有消息的基类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/4/29
+ */
+open class MessageEvent
diff --git a/app/src/main/java/com/eyepetizer/android/event/RefreshEvent.kt b/app/src/main/java/com/eyepetizer/android/event/RefreshEvent.kt
new file mode 100644
index 0000000..76e4437
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/event/RefreshEvent.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.event
+
+/**
+ * EventBus通知刷新界面消息。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/19
+ */
+open class RefreshEvent(var activityClass: Class<*>? = null) : MessageEvent()
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/event/SwitchPagesEvent.kt b/app/src/main/java/com/eyepetizer/android/event/SwitchPagesEvent.kt
new file mode 100644
index 0000000..590068b
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/event/SwitchPagesEvent.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.event
+
+/**
+ * EventBus通知Tab页切换界面。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/19
+ */
+open class SwitchPagesEvent(var activityClass: Class<*>? = null) : MessageEvent()
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/extension/CharSequence.kt b/app/src/main/java/com/eyepetizer/android/extension/CharSequence.kt
new file mode 100644
index 0000000..7c55fc3
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/CharSequence.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.widget.Toast
+import com.eyepetizer.android.EyepetizerApplication
+import com.eyepetizer.android.ui.common.ui.vassonic.SonicRuntimeImpl
+import com.tencent.sonic.sdk.SonicConfig
+import com.tencent.sonic.sdk.SonicEngine
+import com.tencent.sonic.sdk.SonicSessionConfig
+
+/**
+ * 弹出Toast提示。
+ *
+ * @param duration 显示消息的时间 Either {@link #LENGTH_SHORT} or {@link #LENGTH_LONG}
+ */
+fun CharSequence.showToast(duration: Int = Toast.LENGTH_SHORT) {
+ Toast.makeText(EyepetizerApplication.context, this, duration).show()
+}
+
+/**
+ * VasSonic预加载session。
+ *
+ * @param CharSequence 预加载url
+ */
+fun CharSequence.preCreateSession(): Boolean {
+ if (!SonicEngine.isGetInstanceAllowed()) {
+ SonicEngine.createInstance(SonicRuntimeImpl(EyepetizerApplication.context), SonicConfig.Builder().build())
+ }
+ val sessionConfigBuilder = SonicSessionConfig.Builder().apply { setSupportLocalServer(true) }
+ val preloadSuccess = SonicEngine.getInstance().preCreateSession(this.toString(), sessionConfigBuilder.build())
+ logD("preCreateSession()", "${this}\t:${if (preloadSuccess) "Preload start up success!" else "Preload start up fail!"}")
+ return preloadSuccess
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/extension/Density.kt b/app/src/main/java/com/eyepetizer/android/extension/Density.kt
new file mode 100644
index 0000000..53aedf4
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/Density.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) guolin, Suzhou Quxiang Inc. Open source codes for study only.
+ * Do not use for commercial purpose.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import com.eyepetizer.android.EyepetizerApplication
+
+
+/**
+ * 根据手机的分辨率将dp转成为px。
+ */
+fun dp2px(dp: Float): Int {
+ val scale = EyepetizerApplication.context.resources.displayMetrics.density
+ return (dp * scale + 0.5f).toInt()
+}
+
+/**
+ * 根据手机的分辨率将px转成dp。
+ */
+fun px2dp(px: Float): Int {
+ val scale = EyepetizerApplication.context.resources.displayMetrics.density
+ return (px / scale + 0.5f).toInt()
+}
+
+/**
+ * 获取屏幕宽值。
+ */
+val screenWidth
+ get() = EyepetizerApplication.context.resources.displayMetrics.widthPixels
+
+/**
+ * 获取屏幕高值。
+ */
+val screenHeight
+ get() = EyepetizerApplication.context.resources.displayMetrics.heightPixels
+
+/**
+ * 获取屏幕像素:对获取的宽高进行拼接。例:1080X2340。
+ */
+fun screenPixel(): String {
+ EyepetizerApplication.context.resources.displayMetrics.run {
+ return "${widthPixels}X${heightPixels}"
+ }
+}
diff --git a/app/src/main/java/com/eyepetizer/android/extension/Global.kt b/app/src/main/java/com/eyepetizer/android/extension/Global.kt
new file mode 100644
index 0000000..9142f36
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/Global.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.app.Activity
+import android.content.Context
+import android.content.SharedPreferences
+import android.view.View
+import androidx.appcompat.app.AppCompatActivity
+import com.eyepetizer.android.EyepetizerApplication
+import com.eyepetizer.android.ui.common.ui.ShareDialogFragment
+import com.eyepetizer.android.util.GlobalUtil
+import com.eyepetizer.android.util.ShareUtil
+
+/**
+ * 获取SharedPreferences实例。
+ */
+val sharedPreferences: SharedPreferences = EyepetizerApplication.context.getSharedPreferences(GlobalUtil.appPackage + "_preferences", Context.MODE_PRIVATE)
+
+/**
+ * 批量设置控件点击事件。
+ *
+ * @param v 点击的控件
+ * @param block 处理点击事件回调代码块
+ */
+fun setOnClickListener(vararg v: View?, block: View.() -> Unit) {
+ val listener = View.OnClickListener { it.block() }
+ v.forEach { it?.setOnClickListener(listener) }
+}
+
+/**
+ * 批量设置控件点击事件。
+ *
+ * @param v 点击的控件
+ * @param listener 处理点击事件监听器
+ */
+fun setOnClickListener(vararg v: View?, listener: View.OnClickListener) {
+ v.forEach { it?.setOnClickListener(listener) }
+}
+
+/**
+ * 调用系统原生分享。
+ *
+ * @param activity 上下文
+ * @param shareContent 分享内容
+ * @param shareType SHARE_MORE=0,SHARE_QQ=1,SHARE_WECHAT=2,SHARE_WEIBO=3,SHARE_QQZONE=4
+ */
+fun share(activity: Activity, shareContent: String, shareType: Int) {
+ ShareUtil.share(activity, shareContent, shareType)
+}
+
+/**
+ * 弹出分享对话框。
+ *
+ * @param activity 上下文
+ * @param shareContent 分享内容
+ */
+fun showDialogShare(activity: Activity, shareContent: String) {
+ if (activity is AppCompatActivity) {
+ ShareDialogFragment().showDialog(activity, shareContent)
+ }
+}
+
+
diff --git a/app/src/main/java/com/eyepetizer/android/extension/ImageView.kt b/app/src/main/java/com/eyepetizer/android/extension/ImageView.kt
new file mode 100644
index 0000000..efa3318
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/ImageView.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.widget.ImageView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.RequestOptions
+import com.eyepetizer.android.R
+import jp.wasabeef.glide.transformations.RoundedCornersTransformation
+
+/**
+ * Glide加载图片,可以指定圆角弧度。
+ *
+ * @param url 图片地址
+ * @param round 圆角,单位dp
+ * @param cornerType 圆角角度
+ */
+fun ImageView.load(url: String, round: Float = 0f, cornerType: RoundedCornersTransformation.CornerType = RoundedCornersTransformation.CornerType.ALL) {
+ if (round == 0f) {
+ Glide.with(this.context).load(url).into(this)
+ } else {
+ val option = RequestOptions.bitmapTransform(RoundedCornersTransformation(dp2px(round), 0, cornerType)).placeholder(R.drawable.shape_album_loading_bg)
+ Glide.with(this.context).load(url).apply(option).into(this)
+ }
+}
+
+/**
+ * Glide加载图片,可以定义配置参数。
+ *
+ * @param url 图片地址
+ * @param options 配置参数
+ */
+fun ImageView.load(url: String, options: RequestOptions.() -> RequestOptions) {
+ Glide.with(this.context).load(url).apply(RequestOptions().options()).into(this)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/extension/Int.kt b/app/src/main/java/com/eyepetizer/android/extension/Int.kt
new file mode 100644
index 0000000..3e275b1
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/Int.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import com.eyepetizer.android.EyepetizerApplication
+
+/**
+ * 弹出Toast提示。
+ *
+ * @param duration 显示消息的时间 Either {@link #LENGTH_SHORT} or {@link #LENGTH_LONG}
+ */
+fun Int.showToast(duration: Int = Toast.LENGTH_SHORT) {
+ Toast.makeText(EyepetizerApplication.context, this, duration).show()
+}
+
+/**
+ * 解析xml布局
+ *
+ * @param parent 父布局
+ * @param attachToRoot 是否依附到父布局
+ */
+fun Int.inflate(parent: ViewGroup, attachToRoot: Boolean = false): View {
+ return LayoutInflater.from(parent.context).inflate(this, parent, attachToRoot)
+}
+
+/**
+ * 获取转换后的时间样式。
+ *
+ * @return 处理后的时间样式,示例:06:50
+ */
+fun Int.conversionVideoDuration(): String {
+ val minute = 1 * 60
+ val hour = 60 * minute
+ val day = 24 * hour
+
+ return when {
+ this < day -> {
+ String.format("%02d:%02d", this / minute, this % 60)
+ }
+ else -> {
+ String.format("%02d:%02d:%02d", this / hour, (this % hour) / minute, this % 60)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/extension/Log.kt b/app/src/main/java/com/eyepetizer/android/extension/Log.kt
new file mode 100644
index 0000000..14c0afb
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/Log.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.util.Log
+import com.eyepetizer.android.BuildConfig
+
+/**
+ * 日志调试工具类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/4/29
+ */
+private const val VERBOSE = 1
+private const val DEBUG = 2
+private const val INFO = 3
+private const val WARN = 4
+private const val ERROR = 5
+
+private val level = if (BuildConfig.DEBUG) VERBOSE else WARN
+
+fun logV(tag: String, msg: String?) {
+ if (level <= VERBOSE) {
+ Log.v(tag, msg.toString())
+ }
+}
+
+fun logD(tag: String, msg: String?) {
+ if (level <= DEBUG) {
+ Log.d(tag, msg.toString())
+ }
+}
+
+fun logI(tag: String, msg: String?) {
+ if (level <= INFO) {
+ Log.i(tag, msg.toString())
+ }
+}
+
+fun logW(tag: String, msg: String?, tr: Throwable? = null) {
+ if (level <= WARN) {
+ if (tr == null) {
+ Log.w(tag, msg.toString())
+ } else {
+ Log.w(tag, msg.toString(), tr)
+ }
+ }
+}
+
+fun logE(tag: String, msg: String?, tr: Throwable) {
+ if (level <= ERROR) {
+ Log.e(tag, msg.toString(), tr)
+ }
+}
+
diff --git a/app/src/main/java/com/eyepetizer/android/extension/SharedPreferences.kt b/app/src/main/java/com/eyepetizer/android/extension/SharedPreferences.kt
new file mode 100644
index 0000000..bbf7a84
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/SharedPreferences.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.content.SharedPreferences
+
+/**
+ * 简化SharedPreferences调用。
+ *
+ * @param action 拥有SharedPreferences.Editor对象上下文的回调代码块
+ */
+fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit) {
+ val editor = edit()
+ action(editor)
+ editor.apply()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/extension/TextView.kt b/app/src/main/java/com/eyepetizer/android/extension/TextView.kt
new file mode 100644
index 0000000..35f7114
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/TextView.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.graphics.drawable.Drawable
+import android.widget.TextView
+
+/**
+ * 设置TextView图标
+ *
+ * @param drawable 图标
+ * @param iconWidth 图标宽dp:默认自动根据图标大小
+ * @param iconHeight 图标高dp:默认自动根据图标大小
+ * @param direction 图标方向,0左 1上 2右 3下 默认图标位于左侧0
+ */
+fun TextView.setDrawable(drawable: Drawable?, iconWidth: Float? = null, iconHeight: Float? = null, direction: Int = 0) {
+ if (iconWidth != null && iconHeight != null) {
+ //第一个0是距左边距离,第二个0是距上边距离,iconWidth、iconHeight 分别是长宽
+ drawable?.setBounds(0, 0, dp2px(iconWidth), dp2px(iconHeight))
+ }
+ when (direction) {
+ 0 -> setCompoundDrawables(drawable, null, null, null)
+ 1 -> setCompoundDrawables(null, drawable, null, null)
+ 2 -> setCompoundDrawables(null, null, drawable, null)
+ 3 -> setCompoundDrawables(null, null, null, drawable)
+ else -> throw NoSuchMethodError()
+ }
+}
+
+/**
+ * 设置TextView图标
+ *
+ * @param lDrawable 左边图标
+ * @param rDrawable 右边图标
+ * @param lIconWidth 图标宽dp:默认自动根据图标大小
+ * @param lIconHeight 图标高dp:默认自动根据图标大小
+ * @param rIconWidth 图标宽dp:默认自动根据图标大小
+ * @param rIconHeight 图标高dp:默认自动根据图标大小
+ */
+fun TextView.setDrawables(lDrawable: Drawable?, rDrawable: Drawable?, lIconWidth: Float? = null, lIconHeight: Float? = null, rIconWidth: Float? = null, rIconHeight: Float? = null) {
+ if (lIconWidth != null && lIconHeight != null) {
+ lDrawable?.setBounds(0, 0, dp2px(lIconWidth), dp2px(lIconHeight))
+ }
+ if (rIconWidth != null && rIconHeight != null) {
+ rDrawable?.setBounds(0, 0, dp2px(rIconWidth), dp2px(rIconHeight))
+ }
+ setCompoundDrawables(lDrawable, null, rDrawable, null)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/extension/View.kt b/app/src/main/java/com/eyepetizer/android/extension/View.kt
new file mode 100644
index 0000000..0bc2a73
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/extension/View.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.extension
+
+import android.view.View
+import android.view.animation.AlphaAnimation
+
+/**
+ * 显示view
+ */
+fun View?.visible() {
+ this?.visibility = View.VISIBLE
+}
+
+/**
+ * 显示view,带有渐显动画效果。
+ *
+ * @param duration 毫秒,动画持续时长,默认500毫秒。
+ */
+fun View?.visibleAlphaAnimation(duration: Long = 500L) {
+ this?.visibility = View.VISIBLE
+ this?.startAnimation(AlphaAnimation(0f, 1f).apply {
+ this.duration = duration
+ fillAfter = true
+ })
+}
+
+/**
+ * 隐藏view
+ */
+fun View?.gone() {
+ this?.visibility = View.GONE
+}
+
+/**
+ * 隐藏view,带有渐隐动画效果。
+ *
+ * @param duration 毫秒,动画持续时长,默认500毫秒。
+ */
+fun View?.goneAlphaAnimation(duration: Long = 500L) {
+ this?.visibility = View.GONE
+ this?.startAnimation(AlphaAnimation(1f, 0f).apply {
+ this.duration = duration
+ fillAfter = true
+ })
+}
+
+/**
+ * 占位隐藏view
+ */
+fun View?.invisible() {
+ this?.visibility = View.INVISIBLE
+}
+
+/**
+ * 占位隐藏view,带有渐隐动画效果。
+ *
+ * @param duration 毫秒,动画持续时长,默认500毫秒。
+ */
+fun View?.invisibleAlphaAnimation(duration: Long = 500L) {
+ this?.visibility = View.INVISIBLE
+ this?.startAnimation(AlphaAnimation(1f, 0f).apply {
+ this.duration = duration
+ fillAfter = true
+ })
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/logic/MainPageRepository.kt b/app/src/main/java/com/eyepetizer/android/logic/MainPageRepository.kt
new file mode 100644
index 0000000..14af7d2
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/MainPageRepository.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic
+
+import com.eyepetizer.android.logic.dao.MainPageDao
+import com.eyepetizer.android.logic.network.EyepetizerNetwork
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+/**
+ * 主页界面,主要包含:(首页,社区,通知,我的),对应的仓库数据管理。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/2
+ */
+class MainPageRepository private constructor(private val mainPageDao: MainPageDao, private val eyepetizerNetwork: EyepetizerNetwork) {
+
+ suspend fun refreshDiscovery(url: String) = requestDiscovery(url)
+
+ suspend fun refreshHomePageRecommend(url: String) = requestHomePageRecommend(url)
+
+ suspend fun refreshDaily(url: String) = requestDaily(url)
+
+ suspend fun refreshCommunityRecommend(url: String) = requestCommunityRecommend(url)
+
+ suspend fun refreshFollow(url: String) = requestFollow(url)
+
+ suspend fun refreshPushMessage(url: String) = requestPushMessage(url)
+
+ suspend fun refreshHotSearch() = requestHotSearch()
+
+ private suspend fun requestDiscovery(url: String) = withContext(Dispatchers.IO) {
+ val response = eyepetizerNetwork.fetchDiscovery(url)
+ mainPageDao.cacheDiscovery(response)
+ response
+ }
+
+ private suspend fun requestHomePageRecommend(url: String) = withContext(Dispatchers.IO) {
+ val response = eyepetizerNetwork.fetchHomePageRecommend(url)
+ mainPageDao.cacheHomePageRecommend(response)
+ response
+ }
+
+ private suspend fun requestDaily(url: String) = withContext(Dispatchers.IO) {
+ val response = eyepetizerNetwork.fetchDaily(url)
+ mainPageDao.cacheDaily(response)
+ response
+ }
+
+ private suspend fun requestCommunityRecommend(url: String) = withContext(Dispatchers.IO) {
+ val response = eyepetizerNetwork.fetchCommunityRecommend(url)
+ mainPageDao.cacheCommunityRecommend(response)
+ response
+ }
+
+ private suspend fun requestFollow(url: String) = withContext(Dispatchers.IO) {
+ val response = eyepetizerNetwork.fetchFollow(url)
+ mainPageDao.cacheFollow(response)
+ response
+ }
+
+ private suspend fun requestPushMessage(url: String) = withContext(Dispatchers.IO) {
+ val response = eyepetizerNetwork.fetchPushMessage(url)
+ mainPageDao.cachePushMessageInfo(response)
+ response
+ }
+
+ private suspend fun requestHotSearch() = withContext(Dispatchers.IO) {
+ val response = eyepetizerNetwork.fetchHotSearch()
+ mainPageDao.cacheHotSearch(response)
+ response
+ }
+
+ companion object {
+
+ private var repository: MainPageRepository? = null
+
+ fun getInstance(dao: MainPageDao, network: EyepetizerNetwork): MainPageRepository {
+ if (repository == null) {
+ synchronized(MainPageRepository::class.java) {
+ if (repository == null) {
+ repository = MainPageRepository(dao, network)
+ }
+ }
+ }
+
+ return repository!!
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/logic/VideoRepository.kt b/app/src/main/java/com/eyepetizer/android/logic/VideoRepository.kt
new file mode 100644
index 0000000..9491a00
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/VideoRepository.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic
+
+import com.eyepetizer.android.logic.dao.VideoDao
+import com.eyepetizer.android.logic.model.VideoDetail
+import com.eyepetizer.android.logic.network.EyepetizerNetwork
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.withContext
+
+/**
+ * 视频相关,对应的仓库数据管理。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/15
+ */
+class VideoRepository(private val dao: VideoDao, private val network: EyepetizerNetwork) {
+
+ suspend fun refreshVideoReplies(repliesUrl: String) = requestVideoReplies(repliesUrl)
+
+ suspend fun refreshVideoRelatedAndVideoReplies(videoId: Long, repliesUrl: String) = requestVideoRelatedAndVideoReplies(videoId, repliesUrl)
+
+ suspend fun refreshVideoDetail(videoId: Long, repliesUrl: String) = requestVideoDetail(videoId, repliesUrl)
+
+ private suspend fun requestVideoReplies(url: String) = withContext(Dispatchers.IO) {
+ coroutineScope {
+ val deferredVideoReplies = async { network.fetchVideoReplies(url) }
+ val videoReplies = deferredVideoReplies.await()
+ videoReplies
+ }
+ }
+
+ private suspend fun requestVideoRelatedAndVideoReplies(videoId: Long, repliesUrl: String) = withContext(Dispatchers.IO) {
+ coroutineScope {
+ val deferredVideoRelated = async { network.fetchVideoRelated(videoId) }
+ val deferredVideoReplies = async { network.fetchVideoReplies(repliesUrl) }
+ val videoRelated = deferredVideoRelated.await()
+ val videoReplies = deferredVideoReplies.await()
+ val videoDetail = VideoDetail(null, videoRelated, videoReplies)
+ videoDetail
+ }
+ }
+
+ private suspend fun requestVideoDetail(videoId: Long, repliesUrl: String) = withContext(Dispatchers.IO) {
+ coroutineScope {
+ val deferredVideoRelated = async { network.fetchVideoRelated(videoId) }
+ val deferredVideoReplies = async { network.fetchVideoReplies(repliesUrl) }
+ val deferredVideoBeanForClient = async { network.fetchVideoBeanForClient(videoId) }
+ val videoBeanForClient = deferredVideoBeanForClient.await()
+ val videoRelated = deferredVideoRelated.await()
+ val videoReplies = deferredVideoReplies.await()
+ val videoDetail = VideoDetail(videoBeanForClient, videoRelated, videoReplies)
+
+ if (videoDetail.videoBeanForClient != null && videoDetail.videoRelated?.count ?: 0 > 0 && videoDetail.videoReplies.count > 0) {
+ dao.cacheVideoDetail(videoDetail)
+ }
+ videoDetail
+ }
+ }
+
+ companion object {
+
+ private var repository: VideoRepository? = null
+
+ fun getInstance(dao: VideoDao, network: EyepetizerNetwork): VideoRepository {
+ if (repository == null) {
+ synchronized(VideoRepository::class.java) {
+ if (repository == null) {
+ repository = VideoRepository(dao, network)
+ }
+ }
+ }
+
+ return repository!!
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/logic/dao/EyepetizerDatabase.kt b/app/src/main/java/com/eyepetizer/android/logic/dao/EyepetizerDatabase.kt
new file mode 100644
index 0000000..fd7efc2
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/dao/EyepetizerDatabase.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic.dao
+
+/**
+ * 应用程序所有Dao操作管理类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/2
+ */
+object EyepetizerDatabase {
+
+ private var mainPageDao: MainPageDao? = null
+
+ private var videoDao: VideoDao? = null
+
+ fun getMainPageDao(): MainPageDao {
+ if (mainPageDao == null) {
+ mainPageDao = MainPageDao()
+ }
+ return mainPageDao!!
+ }
+
+ fun getVideoDao(): VideoDao {
+ if (videoDao == null) {
+ videoDao = VideoDao()
+ }
+ return videoDao!!
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/logic/dao/MainPageDao.kt b/app/src/main/java/com/eyepetizer/android/logic/dao/MainPageDao.kt
new file mode 100644
index 0000000..190b792
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/dao/MainPageDao.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic.dao
+
+import com.eyepetizer.android.logic.model.*
+
+/**
+ * 主页界面(主要包含:首页,社区,通知,我的),对应的Dao操作类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/15
+ */
+class MainPageDao {
+
+ /*----------------------------首页相关----------------------------*/
+
+ fun cacheDiscovery(bean: Discovery?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedDiscovery(): Discovery? {
+ TODO("获取本地存储的数据")
+ }
+
+ fun cacheHomePageRecommend(bean: HomePageRecommend?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedHomePageRecommend(): HomePageRecommend? {
+ TODO("获取本地存储的数据")
+ }
+
+ fun cacheDaily(bean: Daily?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedDaily(): Daily? {
+ TODO("获取本地存储的数据")
+ }
+
+ /*----------------------------社区相关----------------------------*/
+
+ fun cacheCommunityRecommend(bean: CommunityRecommend?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedCommunityRecommend(): CommunityRecommend? {
+ TODO("获取本地存储的数据")
+ }
+
+ fun cacheFollow(bean: Follow?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedFollow(): Follow? {
+ TODO("获取本地存储的数据")
+ }
+
+ /*----------------------------通知相关----------------------------*/
+
+ fun cachePushMessageInfo(bean: PushMessage?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedPushMessageInfo(): PushMessage? {
+ TODO("获取本地存储的数据")
+ }
+
+ /*----------------------------搜索相关----------------------------*/
+
+ fun cacheHotSearch(bean: List?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getHotSearch(): List? {
+ TODO("获取本地存储的数据")
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/logic/dao/VideoDao.kt b/app/src/main/java/com/eyepetizer/android/logic/dao/VideoDao.kt
new file mode 100644
index 0000000..01a2ea0
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/dao/VideoDao.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic.dao
+
+import com.eyepetizer.android.logic.model.VideoBeanForClient
+import com.eyepetizer.android.logic.model.VideoDetail
+import com.eyepetizer.android.logic.model.VideoRelated
+import com.eyepetizer.android.logic.model.VideoReplies
+
+/**
+ * 视频相关,对应的Dao操作类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/15
+ */
+class VideoDao {
+
+ fun cacheVideoDetail(bean: VideoDetail?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedVideoDetail(): VideoDetail? {
+ TODO("获取本地存储的数据")
+ }
+
+ fun cacheVideoBeanForClient(bean: VideoBeanForClient?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedVideoBeanForClient(): VideoBeanForClient? {
+ TODO("获取本地存储的数据")
+ }
+
+ fun cacheVideoRelated(bean: VideoRelated?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedVideoRelated(): VideoRelated? {
+ TODO("获取本地存储的数据")
+ }
+
+ fun cacheVideoReplies(bean: VideoReplies?) {
+ //TODO("存储数据到本地")
+ }
+
+ fun getCachedVideoReplies(): VideoReplies? {
+ TODO("获取本地存储的数据")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/logic/model/CommunityRecommend.kt b/app/src/main/java/com/eyepetizer/android/logic/model/CommunityRecommend.kt
new file mode 100644
index 0000000..82bfc7f
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/model/CommunityRecommend.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic.model
+
+/**
+ * 社区-推荐列表,响应实体类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/6
+ */
+data class CommunityRecommend(val itemList: List, val count: Int, val total: Int, val nextPageUrl: String?, val adExist: Boolean) : Model() {
+
+ data class Item(val `data`: Data, val type: String, val tag: Any?, val id: Int = 0, val adIndex: Int)
+
+ data class Data(val adTrack: Any, val content: Content, val count: Int, val dataType: String, val footer: Any, val header: Header?, val itemList: List)
+
+ data class Header(
+ val actionUrl: String,
+ val followType: String,
+ val icon: String,
+ val iconType: String,
+ val id: Int,
+ val issuerName: String,
+ val labelList: Any,
+ val showHateVideo: Boolean,
+ val tagId: Int,
+ val tagName: Any,
+ val time: Long,
+ val topShow: Boolean
+ )
+
+ data class Content(val adIndex: Int, val `data`: DataX, val id: Int, val tag: Any, val type: String)
+
+ data class ItemX(val `data`: DataXX, val type: String, val tag: Any?, val id: Int = 0, val adIndex: Int)
+
+ data class DataX(
+ val addWatermark: Boolean,
+ val area: String,
+ val checkStatus: String,
+ val city: String,
+ val collected: Boolean,
+ val consumption: Consumption,
+ val cover: Cover,
+ val createTime: Long,
+ val dataType: String,
+ val description: String,
+ val duration: Int,
+ val height: Int,
+ val id: Long,
+ val ifMock: Boolean,
+ val latitude: Double,
+ val library: String,
+ val longitude: Double,
+ val owner: Owner,
+ val playUrl: String,
+ val playUrlWatermark: String,
+ val privateMessageActionUrl: String,
+ val reallyCollected: Boolean,
+ val recentOnceReply: RecentOnceReply,
+ val releaseTime: Long,
+ val resourceType: String,
+ val selectedTime: Long,
+ val status: Any,
+ val tags: List?,
+ val title: String,
+ val transId: Any,
+ val type: String,
+ val uid: Int,
+ val updateTime: Long,
+ val url: String,
+ val urls: List?,
+ val urlsWithWatermark: List,
+ val validateResult: String,
+ val validateStatus: String,
+ val validateTaskId: String,
+ val width: Int
+ )
+
+ data class Owner(
+ val actionUrl: String,
+ val area: Any,
+ val avatar: String,
+ val birthday: Long,
+ val city: String,
+ val country: String,
+ val cover: String,
+ val description: String,
+ val expert: Boolean,
+ val followed: Boolean,
+ val gender: String,
+ val ifPgc: Boolean,
+ val job: String,
+ val library: String,
+ val limitVideoOpen: Boolean,
+ val nickname: String,
+ val registDate: Long,
+ val releaseDate: Long,
+ val uid: Int,
+ val university: String,
+ val userType: String
+ )
+
+ data class RecentOnceReply(
+ val actionUrl: String,
+ val contentType: Any,
+ val dataType: String,
+ val message: String,
+ val nickname: String
+ )
+
+ data class DataXX(
+ val actionUrl: String?,
+ val adTrack: List,
+ val autoPlay: Boolean,
+ val bgPicture: String,
+ val dataType: String,
+ val description: String,
+ val header: HeaderX?,
+ val id: Int,
+ val image: String,
+ val label: Label?,
+ val labelList: List,
+ val shade: Boolean,
+ val subTitle: String,
+ val title: String
+ )
+
+ data class HeaderX(
+ val actionUrl: Any,
+ val cover: Any,
+ val description: Any,
+ val font: Any,
+ val icon: Any,
+ val id: Int,
+ val label: Any,
+ val labelList: Any,
+ val rightText: Any,
+ val subTitle: Any,
+ val subTitleFont: Any,
+ val textAlign: String,
+ val title: Any
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/eyepetizer/android/logic/model/Daily.kt b/app/src/main/java/com/eyepetizer/android/logic/model/Daily.kt
new file mode 100644
index 0000000..7920234
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/model/Daily.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic.model
+
+/**
+ * 首页-日报列表,响应实体类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/9
+ */
+data class Daily(val itemList: List, val count: Int, val total: Int, val nextPageUrl: String?, val adExist: Boolean) : Model() {
+
+ data class Item(val `data`: Data, val type: String, val tag: Any?, val id: Int = 0, val adIndex: Int)
+
+ data class Data(
+ val actionUrl: String?,
+ val adTrack: Any,
+ val backgroundImage: String,
+ val content: Content,
+ val dataType: String,
+ val follow: Author.Follow?,
+ val header: Header,
+ val id: Int,
+ val rightText: String,
+ val subTitle: Any,
+ val text: String,
+ val titleList: List,
+ val type: String,
+ val image: String,
+ val label: Label?
+ )
+
+ data class Header(
+ val actionUrl: String?,
+ val cover: Any,
+ val description: String,
+ val font: Any,
+ val icon: String,
+ val iconType: String,
+ val id: Int,
+ val label: Any,
+ val labelList: Any,
+ val rightText: Any,
+ val showHateVideo: Boolean,
+ val subTitle: Any,
+ val subTitleFont: Any,
+ val textAlign: String,
+ val time: Long,
+ val title: String
+ )
+}
diff --git a/app/src/main/java/com/eyepetizer/android/logic/model/Discovery.kt b/app/src/main/java/com/eyepetizer/android/logic/model/Discovery.kt
new file mode 100644
index 0000000..6c10418
--- /dev/null
+++ b/app/src/main/java/com/eyepetizer/android/logic/model/Discovery.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2020. vipyinzhiwei
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.eyepetizer.android.logic.model
+
+/**
+ * 首页-发现列表,响应实体类。
+ *
+ * @author vipyinzhiwei
+ * @since 2020/5/9
+ */
+data class Discovery(val itemList: List, val count: Int, val total: Int, val nextPageUrl: String?, val adExist: Boolean) : Model() {
+
+ data class Item(val `data`: Data, val type: String, val tag: Any?, val id: Int = 0, val adIndex: Int)
+
+ data class Data(
+ val actionUrl: String?,
+ val ad: Boolean,
+ val adTrack: Any,
+ val author: Author,
+ val content: Content,
+ val autoPlay: Boolean,
+ val brandWebsiteInfo: Any,
+ val campaign: Any,
+ val category: String,
+ val collected: Boolean,
+ val consumption: Consumption,
+ val count: Int,
+ val cover: Cover,
+ val dataType: String,
+ val date: Long,
+ val description: String,
+ val descriptionEditor: String,
+ val descriptionPgc: Any,
+ val duration: Int,
+ val expert: Boolean,
+ val favoriteAdTrack: Any,
+ val follow: Author.Follow?,
+ val footer: Any,
+ val haveReward: Boolean,
+ val header: Header,
+ val icon: String,
+ val iconType: String,
+ val id: Long,
+ val idx: Int,
+ val ifLimitVideo: Boolean,
+ val ifNewest: Boolean,
+ val ifPgc: Boolean,
+ val ifShowNotificationIcon: Boolean,
+ val image: String,
+ val itemList: List,
+ val label: Label?,
+ val labelList: List