├── .circleci
└── config.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README-en.md
├── README.md
├── _config.yml
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── hazz
│ │ └── kotlinmvp
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── fonts
│ │ │ ├── FZLanTingHeiS-DB1-GB-Regular.TTF
│ │ │ ├── FZLanTingHeiS-L-GB-Regular.TTF
│ │ │ └── Lobster-1.4.otf
│ ├── java
│ │ └── com
│ │ │ └── hazz
│ │ │ └── kotlinmvp
│ │ │ ├── Constants.kt
│ │ │ ├── Extensions.kt
│ │ │ ├── MyApplication.kt
│ │ │ ├── api
│ │ │ ├── ApiService.kt
│ │ │ ├── Eyepetizer.md
│ │ │ ├── UriConstant.kt
│ │ │ └── api
│ │ │ ├── base
│ │ │ ├── BaseActivity.kt
│ │ │ ├── BaseFragment.kt
│ │ │ ├── BaseFragmentAdapter.kt
│ │ │ ├── BasePresenter.kt
│ │ │ ├── IBaseView.kt
│ │ │ └── IPresenter.kt
│ │ │ ├── glide
│ │ │ ├── CustomAppGlideModule.kt
│ │ │ ├── CustomBaseGlideUrlLoader.kt
│ │ │ ├── GlideRoundTransform.kt
│ │ │ └── ImageLoaderUtils.kt
│ │ │ ├── mvp
│ │ │ ├── contract
│ │ │ │ ├── CategoryContract.kt
│ │ │ │ ├── CategoryDetailContract.kt
│ │ │ │ ├── FollowContract.kt
│ │ │ │ ├── HomeContract.kt
│ │ │ │ ├── HotTabContract.kt
│ │ │ │ ├── RankContract.kt
│ │ │ │ ├── SearchContract.kt
│ │ │ │ └── VideoDetailContract.kt
│ │ │ ├── model
│ │ │ │ ├── CategoryDetailModel.kt
│ │ │ │ ├── CategoryModel.kt
│ │ │ │ ├── FollowModel.kt
│ │ │ │ ├── HomeModel.kt
│ │ │ │ ├── HotTabModel.kt
│ │ │ │ ├── RankModel.kt
│ │ │ │ ├── SearchModel.kt
│ │ │ │ ├── VideoDetailModel.kt
│ │ │ │ └── bean
│ │ │ │ │ ├── AuthorInfoBean.kt
│ │ │ │ │ ├── CategoryBean.kt
│ │ │ │ │ ├── HomeBean.kt
│ │ │ │ │ ├── TabEntity.kt
│ │ │ │ │ └── TabInfoBean.kt
│ │ │ └── presenter
│ │ │ │ ├── CategoryDetailPresenter.kt
│ │ │ │ ├── CategoryPresenter.kt
│ │ │ │ ├── FollowPresenter.kt
│ │ │ │ ├── HomePresenter.kt
│ │ │ │ ├── HotTabPresenter.kt
│ │ │ │ ├── RankPresenter.kt
│ │ │ │ ├── SearchPresenter.kt
│ │ │ │ └── VideoDetailPresenter.kt
│ │ │ ├── net
│ │ │ ├── BaseResponse.kt
│ │ │ ├── RetrofitManager.kt
│ │ │ └── exception
│ │ │ │ ├── ApiException.kt
│ │ │ │ ├── ErrorStatus.kt
│ │ │ │ └── ExceptionHandle.kt
│ │ │ ├── rx
│ │ │ └── scheduler
│ │ │ │ ├── BaseScheduler.kt
│ │ │ │ ├── ComputationMainScheduler.kt
│ │ │ │ ├── IoMainScheduler.kt
│ │ │ │ ├── NewThreadMainScheduler.kt
│ │ │ │ ├── SchedulerUtils.kt
│ │ │ │ ├── SingleMainScheduler.kt
│ │ │ │ └── TrampolineMainScheduler.kt
│ │ │ ├── ui
│ │ │ ├── activity
│ │ │ │ ├── AboutActivity.kt
│ │ │ │ ├── CategoryDetailActivity.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── ProfileHomePageActivity.kt
│ │ │ │ ├── SearchActivity.kt
│ │ │ │ ├── SplashActivity.kt
│ │ │ │ ├── VideoDetailActivity.kt
│ │ │ │ └── WatchHistoryActivity.kt
│ │ │ ├── adapter
│ │ │ │ ├── CategoryAdapter.kt
│ │ │ │ ├── CategoryDetailAdapter.kt
│ │ │ │ ├── FollowAdapter.kt
│ │ │ │ ├── FollowHorizontalAdapter.kt
│ │ │ │ ├── HomeAdapter.kt
│ │ │ │ ├── HotKeywordsAdapter.kt
│ │ │ │ ├── VideoDetailAdapter.kt
│ │ │ │ └── WatchHistoryAdapter.kt
│ │ │ └── fragment
│ │ │ │ ├── CategoryFragment.kt
│ │ │ │ ├── DiscoveryFragment.kt
│ │ │ │ ├── FollowFragment.kt
│ │ │ │ ├── HomeFragment.kt
│ │ │ │ ├── HotFragment.kt
│ │ │ │ ├── MineFragment.kt
│ │ │ │ └── RankFragment.kt
│ │ │ ├── utils
│ │ │ ├── AppUtils.kt
│ │ │ ├── CleanLeakUtils.kt
│ │ │ ├── DisplayManager.kt
│ │ │ ├── NetworkUtil.kt
│ │ │ ├── Preference.kt
│ │ │ ├── StatusBarUtil.kt
│ │ │ └── WatchHistoryUtils.kt
│ │ │ └── view
│ │ │ ├── CircleImageView.kt
│ │ │ ├── ClearEditText.kt
│ │ │ ├── ExpandableTextView.kt
│ │ │ ├── LoadingView.java
│ │ │ ├── TabLayoutHelper.kt
│ │ │ ├── VideoListener.kt
│ │ │ ├── ViewAnimUtils.kt
│ │ │ └── recyclerview
│ │ │ ├── MultipleType.kt
│ │ │ ├── ViewHolder.kt
│ │ │ └── adapter
│ │ │ ├── CommonAdapter.kt
│ │ │ ├── OnItemClickListener.kt
│ │ │ └── OnItemLongClickListener.kt
│ └── res
│ │ ├── anim
│ │ ├── anim_in.xml
│ │ ├── anim_out.xml
│ │ ├── push_bottom_in.xml
│ │ └── push_bottom_out.xml
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xxhdpi
│ │ └── placeholder_banner.png
│ │ ├── drawable
│ │ ├── bc_background_panel.xml
│ │ ├── btn_radius_black_border_bg.xml
│ │ ├── btn_radius_normal_bg.xml
│ │ ├── btn_radius_theme_bg.xml
│ │ ├── btn_radius_theme_border_bg.xml
│ │ ├── et_cursor.xml
│ │ ├── et_round_bg.xml
│ │ ├── gradient_bg.xml
│ │ ├── ic_launcher.png
│ │ ├── progressbar.xml
│ │ ├── shape_bg_white.xml
│ │ ├── shape_btn_blue.xml
│ │ ├── shape_corner_bg.xml
│ │ ├── shape_corner_bg_small.xml
│ │ └── shape_number_indicator_background.xml
│ │ ├── layout
│ │ ├── activity_about.xml
│ │ ├── activity_category_detail.xml
│ │ ├── activity_main.xml
│ │ ├── activity_profile_homepage.xml
│ │ ├── activity_search.xml
│ │ ├── activity_splash.xml
│ │ ├── activity_video_detail.xml
│ │ ├── fragment_category.xml
│ │ ├── fragment_home.xml
│ │ ├── fragment_hot.xml
│ │ ├── fragment_mine.xml
│ │ ├── fragment_rank.xml
│ │ ├── item_cardview.xml
│ │ ├── item_category.xml
│ │ ├── item_category_detail.xml
│ │ ├── item_flow_text.xml
│ │ ├── item_follow.xml
│ │ ├── item_follow_horizontal.xml
│ │ ├── item_home_banner.xml
│ │ ├── item_home_content.xml
│ │ ├── item_home_header.xml
│ │ ├── item_video_detail_info.xml
│ │ ├── item_video_footer.xml
│ │ ├── item_video_small_card.xml
│ │ ├── item_video_text_card.xml
│ │ ├── layout_about_me.xml
│ │ ├── layout_empty_view.xml
│ │ ├── layout_error_view.xml
│ │ ├── layout_load_footer_view.xml
│ │ ├── layout_loading_view.xml
│ │ ├── layout_network_view.xml
│ │ ├── layout_recyclerview.xml
│ │ ├── layout_refresh_header_view.xml
│ │ ├── layout_video_tag_item.xml
│ │ └── layout_watch_history.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── default_avatar.png
│ │ ├── ic_about.png
│ │ ├── ic_action_clear.png
│ │ ├── ic_action_collection.png
│ │ ├── ic_action_comment.png
│ │ ├── ic_action_down_white.png
│ │ ├── ic_action_favorites.png
│ │ ├── ic_action_more_arrow.png
│ │ ├── ic_action_more_black.png
│ │ ├── ic_action_offline.png
│ │ ├── ic_action_reply.png
│ │ ├── ic_action_search_black.png
│ │ ├── ic_action_search_small.png
│ │ ├── ic_action_search_white.png
│ │ ├── ic_action_share.png
│ │ ├── ic_action_up_white.png
│ │ ├── ic_discovery_normal.png
│ │ ├── ic_discovery_selected.png
│ │ ├── ic_error.png
│ │ ├── ic_home_normal.png
│ │ ├── ic_home_selected.png
│ │ ├── ic_hot_normal.png
│ │ ├── ic_hot_selected.png
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ ├── ic_mine_normal.png
│ │ ├── ic_mine_selected.png
│ │ ├── ic_no_data.png
│ │ ├── ic_no_network.png
│ │ ├── img_avatar.png
│ │ ├── img_profile_head.png
│ │ ├── img_splash.png
│ │ ├── list_load_more.png
│ │ └── web_hi_res_512.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── transition-v21
│ │ └── arc_motion.xml
│ │ ├── values-v19
│ │ └── styles.xml
│ │ ├── values-v21
│ │ └── styles.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── hazz
│ └── kotlinmvp
│ └── ExampleUnitTest.kt
├── build.gradle
├── config.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ktmp.jks
├── multiple-status-view
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── classic
│ │ └── common
│ │ └── MultipleStatusView.java
│ └── res
│ ├── layout
│ ├── empty_view.xml
│ ├── error_view.xml
│ ├── loading_view.xml
│ └── no_network_view.xml
│ └── values
│ ├── attrs.xml
│ ├── ids.xml
│ ├── strings.xml
│ └── styles.xml
├── screenshot
├── 01.png
├── 02.png
├── 03.png
├── 04.png
├── 05.png
├── 06.png
├── 07.png
├── 08.png
├── 09.png
├── 10.png
└── kotlin-mvp-1.gif
└── settings.gradle
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | working_directory: ~/code
5 | docker:
6 | - image: circleci/android:api-27-alpha
7 | environment:
8 | JVM_OPTS: -Xmx3200m
9 | steps:
10 | - checkout
11 | - restore_cache:
12 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
13 | - run:
14 | name: Download Dependencies
15 | command: ./gradlew androidDependencies
16 | - save_cache:
17 | paths:
18 | - ~/.gradle
19 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }}
20 | - run:
21 | name: Run Tests
22 | command: ./gradlew lint test
23 | - store_artifacts:
24 | path: app/build/reports
25 | destination: reports
26 | - store_test_results:
27 | path: app/build/test-results
28 |
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 | sudo: false
4 |
5 | android:
6 | components:
7 | - tools
8 | - build-tools-27.0.3
9 | - android-27
10 | - extra-android-m2repository
11 | - extra-android-support
12 | licenses:
13 | - android-sdk-license-.+
14 | - '.+'
15 |
16 | before_install:
17 | - chmod +x gradlew
18 | - mkdir "$ANDROID_HOME/licenses" || true
19 | - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license"
20 | - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license"
21 |
22 | script:
23 | - ./gradlew assembleRelease
24 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | #Glide的混淆规则
24 | -keep public class * implements com.bumptech.glide.module.GlideModule
25 | -keep public class * extends com.bumptech.glide.AppGlideModule
26 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
27 | **[] $VALUES;
28 | public *;
29 | }
30 |
31 | # Platform calls Class.forName on types which do not exist on Android to determine platform.
32 | -dontnote retrofit2.Platform
33 | # Platform used when running on Java 8 VMs. Will not be used at runtime.
34 | -dontwarn retrofit2.Platform$Java8
35 | # Retain generic type information for use by reflection by converters and adapters.
36 | -keepattributes Signature
37 | # Retain declared checked exceptions for use by a Proxy instance.
38 | -keepattributes Exceptions
39 | -dontwarn org.xmlpull.v1.**
40 | -dontwarn okhttp3.**
41 | -keep class okhttp3.** { *; }
42 | -dontwarn okio.**
43 | -dontwarn javax.annotation.Nullable
44 | -dontwarn javax.annotation.ParametersAreNonnullByDefault
45 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/hazz/kotlinmvp/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp
2 |
3 | import android.support.test.InstrumentationRegistry
4 | import android.support.test.runner.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getTargetContext()
22 | assertEquals("com.hazz.kotlinmvp", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
48 |
51 |
52 |
53 |
56 |
57 |
58 |
62 |
63 |
64 |
67 |
68 |
69 |
72 |
73 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/FZLanTingHeiS-DB1-GB-Regular.TTF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/assets/fonts/FZLanTingHeiS-DB1-GB-Regular.TTF
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/FZLanTingHeiS-L-GB-Regular.TTF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/assets/fonts/FZLanTingHeiS-L-GB-Regular.TTF
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/Lobster-1.4.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/assets/fonts/Lobster-1.4.otf
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp
2 |
3 | // ┏┓ ┏┓
4 | //┏┛┻━━━┛┻┓
5 | //┃ ┃
6 | //┃ ━ ┃
7 | //┃ ┳┛ ┗┳ ┃
8 | //┃ ┃
9 | //┃ ┻ ┃
10 | //┃ ┃
11 | //┗━┓ ┏━┛
12 | // ┃ ┃ 神兽保佑
13 | // ┃ ┃ 代码无BUG!
14 | // ┃ ┗━━━┓
15 | // ┃ ┣┓
16 | // ┃ ┏┛
17 | // ┗┓┓┏━┳┓┏┛
18 | // ┃┫┫ ┃┫┫
19 | // ┗┻┛ ┗┻┛
20 | /**
21 | * Created by xuhao on 2017/11/27.
22 | * desc: 常量
23 | */
24 | class Constants private constructor() {
25 |
26 | companion object {
27 |
28 | val BUNDLE_VIDEO_DATA = "video_data"
29 | val BUNDLE_CATEGORY_DATA = "category_data"
30 |
31 | //腾讯 Bugly APP id
32 | val BUGLY_APPID = "176aad0d9e"
33 |
34 |
35 | //sp 存储的文件名
36 | val FILE_WATCH_HISTORY_NAME = "watch_history_file" //观看记录
37 |
38 | val FILE_COLLECTION_NAME = "collection_file" //收藏视屏缓存的文件名
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/Extensions.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp
2 |
3 | import android.content.Context
4 | import android.support.v4.app.Fragment
5 | import android.view.View
6 | import android.widget.ImageView
7 | import android.widget.Toast
8 | import com.bumptech.glide.Glide
9 | import com.bumptech.glide.request.RequestOptions
10 | import java.net.URL
11 |
12 | /**
13 | * Created by xuhao on 2017/11/14.
14 | */
15 |
16 | fun Fragment.showToast(content: String): Toast {
17 | val toast = Toast.makeText(this.activity?.applicationContext, content, Toast.LENGTH_SHORT)
18 | toast.show()
19 | return toast
20 | }
21 |
22 | fun Context.showToast(content: String): Toast {
23 | val toast = Toast.makeText(MyApplication.context, content, Toast.LENGTH_SHORT)
24 | toast.show()
25 | return toast
26 | }
27 |
28 |
29 | fun View.dip2px(dipValue: Float): Int {
30 | val scale = this.resources.displayMetrics.density
31 | return (dipValue * scale + 0.5f).toInt()
32 | }
33 |
34 | fun View.px2dip(pxValue: Float): Int {
35 | val scale = this.resources.displayMetrics.density
36 | return (pxValue / scale + 0.5f).toInt()
37 | }
38 |
39 | fun durationFormat(duration: Long?): String {
40 | val minute = duration!! / 60
41 | val second = duration % 60
42 | return if (minute <= 9) {
43 | if (second <= 9) {
44 | "0$minute' 0$second''"
45 | } else {
46 | "0$minute' $second''"
47 | }
48 | } else {
49 | if (second <= 9) {
50 | "$minute' 0$second''"
51 | } else {
52 | "$minute' $second''"
53 | }
54 | }
55 | }
56 |
57 | /**
58 | * 数据流量格式化
59 | */
60 | fun Context.dataFormat(total: Long): String {
61 | var result: String
62 | var speedReal: Int = (total / (1024)).toInt()
63 | result = if (speedReal < 512) {
64 | speedReal.toString() + " KB"
65 | } else {
66 | val mSpeed = speedReal / 1024.0
67 | (Math.round(mSpeed * 100) / 100.0).toString() + " MB"
68 | }
69 | return result
70 | }
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/MyApplication.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp
2 |
3 | import android.app.Activity
4 | import android.app.Application
5 | import android.content.Context
6 | import android.os.Bundle
7 | import android.util.Log
8 | import com.hazz.kotlinmvp.utils.DisplayManager
9 | import com.orhanobut.logger.AndroidLogAdapter
10 | import com.orhanobut.logger.Logger
11 | import com.orhanobut.logger.PrettyFormatStrategy
12 | import com.squareup.leakcanary.LeakCanary
13 | import com.squareup.leakcanary.RefWatcher
14 | import com.tencent.bugly.crashreport.CrashReport
15 | import kotlin.properties.Delegates
16 |
17 |
18 | /**
19 | * Created by xuhao on 2017/11/16.
20 | *
21 | */
22 |
23 | class MyApplication : Application(){
24 |
25 | private var refWatcher: RefWatcher? = null
26 |
27 | companion object {
28 |
29 | private val TAG = "MyApplication"
30 |
31 | var context: Context by Delegates.notNull()
32 | private set
33 |
34 | fun getRefWatcher(context: Context): RefWatcher? {
35 | val myApplication = context.applicationContext as MyApplication
36 | return myApplication.refWatcher
37 | }
38 |
39 | }
40 |
41 | override fun onCreate() {
42 | super.onCreate()
43 | context = applicationContext
44 | // refWatcher = setupLeakCanary()
45 | initConfig()
46 | DisplayManager.init(this)
47 | registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks)
48 |
49 |
50 | }
51 |
52 | private fun setupLeakCanary(): RefWatcher {
53 | return if (LeakCanary.isInAnalyzerProcess(this)) {
54 | RefWatcher.DISABLED
55 | } else LeakCanary.install(this)
56 | }
57 |
58 |
59 | /**
60 | * 初始化配置
61 | */
62 | private fun initConfig() {
63 |
64 | val formatStrategy = PrettyFormatStrategy.newBuilder()
65 | .showThreadInfo(false) // 隐藏线程信息 默认:显示
66 | .methodCount(0) // 决定打印多少行(每一行代表一个方法)默认:2
67 | .methodOffset(7) // (Optional) Hides internal method calls up to offset. Default 5
68 | .tag("hao_zz") // (Optional) Global tag for every log. Default PRETTY_LOGGER
69 | .build()
70 | Logger.addLogAdapter(object : AndroidLogAdapter(formatStrategy) {
71 | override fun isLoggable(priority: Int, tag: String?): Boolean {
72 | return BuildConfig.DEBUG
73 | }
74 | })
75 | }
76 |
77 |
78 | private val mActivityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks {
79 | override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
80 | Log.d(TAG, "onCreated: " + activity.componentName.className)
81 | }
82 |
83 | override fun onActivityStarted(activity: Activity) {
84 | Log.d(TAG, "onStart: " + activity.componentName.className)
85 | }
86 |
87 | override fun onActivityResumed(activity: Activity) {
88 |
89 | }
90 |
91 | override fun onActivityPaused(activity: Activity) {
92 |
93 | }
94 |
95 | override fun onActivityStopped(activity: Activity) {
96 |
97 | }
98 |
99 | override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
100 |
101 | }
102 |
103 | override fun onActivityDestroyed(activity: Activity) {
104 | Log.d(TAG, "onDestroy: " + activity.componentName.className)
105 | }
106 | }
107 |
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/api/ApiService.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.api
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.AuthorInfoBean
4 | import com.hazz.kotlinmvp.mvp.model.bean.CategoryBean
5 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
6 | import com.hazz.kotlinmvp.mvp.model.bean.TabInfoBean
7 | import io.reactivex.Observable
8 | import retrofit2.http.GET
9 | import retrofit2.http.Query
10 | import retrofit2.http.Url
11 |
12 | /**
13 | * Created by xuhao on 2017/11/16.
14 | * Api 接口
15 | */
16 |
17 | interface ApiService{
18 |
19 | /**
20 | * 首页精选
21 | */
22 | @GET("v2/feed?")
23 | fun getFirstHomeData(@Query("num") num:Int): Observable
24 |
25 | /**
26 | * 根据 nextPageUrl 请求数据下一页数据
27 | */
28 | @GET
29 | fun getMoreHomeData(@Url url: String): Observable
30 |
31 | /**
32 | * 根据item id获取相关视频
33 | */
34 | @GET("v4/video/related?")
35 | fun getRelatedData(@Query("id") id: Long): Observable
36 |
37 | /**
38 | * 获取分类
39 | */
40 | @GET("v4/categories")
41 | fun getCategory(): Observable>
42 |
43 | /**
44 | * 获取分类详情List
45 | */
46 | @GET("v4/categories/videoList?")
47 | fun getCategoryDetailList(@Query("id") id: Long): Observable
48 |
49 | /**
50 | * 获取更多的 Issue
51 | */
52 | @GET
53 | fun getIssueData(@Url url: String): Observable
54 |
55 | /**
56 | * 获取全部排行榜的Info(包括,title 和 Url)
57 | */
58 | @GET("v4/rankList")
59 | fun getRankList():Observable
60 |
61 | /**
62 | * 获取搜索信息
63 | */
64 | @GET("v1/search?&num=10&start=10")
65 | fun getSearchData(@Query("query") query :String) : Observable
66 |
67 | /**
68 | * 热门搜索词
69 | */
70 | @GET("v3/queries/hot")
71 | fun getHotWord():Observable>
72 |
73 | /**
74 | * 关注
75 | */
76 | @GET("v4/tabs/follow")
77 | fun getFollowInfo():Observable
78 |
79 | /**
80 | * 作者信息
81 | */
82 | @GET("v4/pgcs/detail/tab?")
83 | fun getAuthorInfo(@Query("id") id: Long):Observable
84 |
85 |
86 |
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/api/UriConstant.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.api
2 |
3 | /**
4 | * Created by xuhao on 2017/11/16.
5 | */
6 | object UrlConstant{
7 | const val BASE_URL = "http://baobab.kaiyanapp.com/api/"
8 |
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/api/api:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | //首页精选
5 | http://baobab.kaiyanapp.com/api/v2/feed?
6 |
7 | //相关视频
8 | http://baobab.kaiyanapp.com/api/v4/video/related?id=xxx
9 |
10 | //获取分类
11 | http://baobab.kaiyanapp.com/api/v4/categories
12 |
13 | //获取分类详情List
14 | http://baobab.kaiyanapp.com/api/v4/categories/videoList?id=xxx&udid=xxx
15 |
16 | //获取排行榜的 Info
17 | http://baobab.kaiyanapp.com/api/v4/rankList
18 |
19 | //获取搜索信息
20 | http://baobab.kaiyanapp.com/api/v1/search?&num=10&start=10&query=xxx
21 |
22 | //热门搜索关键词
23 | http://baobab.kaiyanapp.com/api/v3/queries/hot
24 |
25 | //关注
26 | http://baobab.kaiyanapp.com/api/v4/tabs/follow
27 |
28 | //热门搜索词
29 | http://baobab.kaiyanapp.com/api/v3/queries/hot
30 | ["阅后即瞎","日食记","复仇者联盟","励志","谷阿莫","复仇者联盟3","美食","广告","爱情","舞蹈","搞笑","漫威","动画","日本","电影相关","健身","VR","滑板","脱口秀","寻梦环游记"]
31 |
32 | 作者信息
33 | http://baobab.kaiyanapp.com/api/v4/pgcs/detail/tab?id=571
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/base/BaseFragmentAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.base
2 |
3 | import android.annotation.SuppressLint
4 | import android.support.v4.app.Fragment
5 | import android.support.v4.app.FragmentManager
6 | import android.support.v4.app.FragmentPagerAdapter
7 |
8 |
9 | /**
10 | * Created by xuhao on 2017/11/30.
11 | * 该类内的每一个生成的 Fragment 都将保存在内存之中,
12 | * 因此适用于那些相对静态的页,数量也比较少的那种;
13 | * 如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,
14 | * 应该使用FragmentStatePagerAdapter。
15 | */
16 | class BaseFragmentAdapter : FragmentPagerAdapter {
17 |
18 | private var fragmentList: List? = ArrayList()
19 | private var mTitles: List? = null
20 |
21 | constructor(fm: FragmentManager, fragmentList: List) : super(fm) {
22 | this.fragmentList = fragmentList
23 | }
24 |
25 | constructor(fm: FragmentManager, fragmentList: List, mTitles: List) : super(fm) {
26 | this.mTitles = mTitles
27 | setFragments(fm, fragmentList, mTitles)
28 | }
29 |
30 | //刷新fragment
31 | @SuppressLint("CommitTransaction")
32 | private fun setFragments(fm: FragmentManager, fragments: List, mTitles: List) {
33 | this.mTitles = mTitles
34 | if (this.fragmentList != null) {
35 | val ft = fm.beginTransaction()
36 | fragmentList?.forEach {
37 | ft.remove(it)
38 | }
39 | ft?.commitAllowingStateLoss()
40 | fm.executePendingTransactions()
41 | }
42 | this.fragmentList = fragments
43 | notifyDataSetChanged()
44 | }
45 |
46 | override fun getPageTitle(position: Int): CharSequence {
47 | return if (null != mTitles) mTitles!![position] else ""
48 | }
49 |
50 | override fun getItem(position: Int): Fragment {
51 | return fragmentList!![position]
52 | }
53 |
54 | override fun getCount(): Int {
55 | return fragmentList!!.size
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/base/BasePresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.base
2 |
3 | import io.reactivex.disposables.CompositeDisposable
4 | import io.reactivex.disposables.Disposable
5 |
6 |
7 |
8 | /**
9 | * Created by xuhao on 2017/11/16.
10 | *
11 | */
12 | open class BasePresenter : IPresenter {
13 |
14 | var mRootView: T? = null
15 | private set
16 |
17 | private var compositeDisposable = CompositeDisposable()
18 |
19 |
20 | override fun attachView(mRootView: T) {
21 | this.mRootView = mRootView
22 | }
23 |
24 | override fun detachView() {
25 | mRootView = null
26 |
27 | //保证activity结束时取消所有正在执行的订阅
28 | if (!compositeDisposable.isDisposed) {
29 | compositeDisposable.clear()
30 | }
31 |
32 | }
33 |
34 | private val isViewAttached: Boolean
35 | get() = mRootView != null
36 |
37 | fun checkViewAttached() {
38 | if (!isViewAttached) throw MvpViewNotAttachedException()
39 | }
40 |
41 | fun addSubscription(disposable: Disposable) {
42 | compositeDisposable.add(disposable)
43 | }
44 |
45 | private class MvpViewNotAttachedException internal constructor() : RuntimeException("Please call IPresenter.attachView(IBaseView) before" + " requesting data to the IPresenter")
46 |
47 |
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/base/IBaseView.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.base
2 |
3 | /**
4 | * @author Jake.Ho
5 | * created: 2017/10/25
6 | * desc:
7 | */
8 | interface IBaseView {
9 |
10 | fun showLoading()
11 |
12 | fun dismissLoading()
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/base/IPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.base
2 |
3 |
4 |
5 | /**
6 | * @author Jake.Ho
7 | * created: 2017/10/25
8 | * desc: Presenter 基类
9 | */
10 |
11 |
12 | interface IPresenter {
13 |
14 | fun attachView(mRootView: V)
15 |
16 | fun detachView()
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/glide/CustomAppGlideModule.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.glide
2 |
3 | import android.content.Context
4 |
5 | import com.bumptech.glide.Glide
6 | import com.bumptech.glide.GlideBuilder
7 | import com.bumptech.glide.Registry
8 | import com.bumptech.glide.annotation.GlideModule
9 | import com.bumptech.glide.load.engine.cache.LruResourceCache
10 | import com.bumptech.glide.module.AppGlideModule
11 |
12 | import java.io.InputStream
13 |
14 | /**
15 | * Created by xuhao on 2017/12/1.
16 | * desc:
17 | */
18 | @GlideModule
19 | class CustomAppGlideModule : AppGlideModule() {
20 |
21 | /**
22 | * 通过GlideBuilder设置默认的结构(Engine,BitmapPool ,ArrayPool,MemoryCache等等).
23 | *
24 | * @param context
25 | * @param builder
26 | */
27 | override fun applyOptions(context: Context, builder: GlideBuilder) {
28 |
29 | //重新设置内存限制
30 | builder.setMemoryCache(LruResourceCache(10 * 1024 * 1024))
31 |
32 | }
33 |
34 |
35 | /**
36 | * 清单解析的开启
37 | *
38 | *
39 | * 这里不开启,避免添加相同的modules两次
40 | *
41 | * @return
42 | */
43 | override fun isManifestParsingEnabled(): Boolean {
44 | return false
45 | }
46 |
47 | /**
48 | *
49 | * 为App注册一个自定义的String类型的BaseGlideUrlLoader
50 | * @param context
51 | * @param glide
52 | * @param registry
53 | */
54 | override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
55 | registry.append(String::class.java, InputStream::class.java, CustomBaseGlideUrlLoader.Factory())
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/glide/CustomBaseGlideUrlLoader.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.glide
2 |
3 | import com.bumptech.glide.load.Options
4 | import com.bumptech.glide.load.model.*
5 | import com.bumptech.glide.load.model.stream.BaseGlideUrlLoader
6 | import java.io.InputStream
7 | import java.util.regex.Pattern
8 |
9 | /**
10 | * Created by xuhao on 2017/12/1.
11 | * desc:
12 | */
13 |
14 | class CustomBaseGlideUrlLoader(concreteLoader: ModelLoader, modelCache: ModelCache) : BaseGlideUrlLoader(concreteLoader, modelCache) {
15 |
16 | /**
17 | * If the URL contains a special variable width indicator (eg "__w-200-400-800__")
18 | * we get the buckets from the URL (200, 400 and 800 in the example) and replace
19 | * the URL with the best bucket for the requested width (the bucket immediately
20 | * larger than the requested width).
21 | *
22 | * 控制加载的图片的大小
23 | */
24 | override fun getUrl(model: String, width: Int, height: Int, options: Options): String {
25 | val m = PATTERN.matcher(model)
26 | var bestBucket: Int
27 | if (m.find()) {
28 | val found = m.group(1).split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
29 | for (bucketStr in found) {
30 | bestBucket = Integer.parseInt(bucketStr)
31 | if (bestBucket >= width) {
32 | // the best bucket is the first immediately bigger than the requested width
33 | break
34 | }
35 | }
36 |
37 | }
38 | return model
39 | }
40 |
41 | override fun handles(s: String): Boolean {
42 | return true
43 | }
44 |
45 | /**
46 | * 工厂来构建CustomBaseGlideUrlLoader对象
47 | */
48 | class Factory : ModelLoaderFactory {
49 | override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader {
50 | return CustomBaseGlideUrlLoader(multiFactory.build(GlideUrl::class.java, InputStream::class.java), urlCache)
51 | }
52 |
53 | override fun teardown() {
54 |
55 | }
56 | }
57 |
58 | companion object {
59 |
60 | private val urlCache = ModelCache(150)
61 | /**
62 | * Url的匹配规则
63 | */
64 | private val PATTERN = Pattern.compile("__w-((?:-?\\d+)+)__")
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/glide/GlideRoundTransform.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("DEPRECATION")
2 |
3 | package com.hazz.kotlinmvp.glide
4 |
5 | import android.content.res.Resources
6 | import android.graphics.Bitmap
7 | import android.graphics.BitmapShader
8 | import android.graphics.Canvas
9 | import android.graphics.Paint
10 | import android.graphics.RectF
11 | import android.graphics.Shader
12 |
13 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
14 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
15 |
16 | import java.security.MessageDigest
17 |
18 | /**
19 | * Created by xuhao on 2017/11/29.
20 | * desc:
21 | * 1.永远不要把transform()传给你的原始resource或原始Bitmap给recycle()了,更不要放回BitmapPool,因为这些都自动完成了。值得注意的是,任何从BitmapPool取出的用于自定义图片变换的辅助Bitmap,如果不经过transform()方法返回,就必须主动放回BitmapPool或者调用recycle()回收。
22 | * 2.如果你从BitmapPool拿出多个Bitmap或不使用你从BitmapPool拿出的一个Bitmap,一定要返回extras给BitmapPool。
23 | * 3.如果你的图片处理没有替换原始resource(例如由于一张图片已经匹配了你想要的尺寸,你需要提前返回), transform()`方法就返回原始resource或原始Bitmap。
24 | *
25 | *
26 | */
27 |
28 | class GlideRoundTransform @JvmOverloads constructor(dp: Int = 4) : BitmapTransformation() {
29 |
30 | private var radius = 0f
31 |
32 | init {
33 | this.radius = Resources.getSystem().displayMetrics.density * dp
34 | }
35 |
36 | override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap? {
37 | return roundCrop(pool, toTransform)
38 | }
39 |
40 |
41 | override fun updateDiskCacheKey(messageDigest: MessageDigest) {
42 |
43 | }
44 |
45 |
46 | private fun roundCrop(pool: BitmapPool, source: Bitmap?): Bitmap? {
47 | if (source == null) return null
48 |
49 | var result: Bitmap? = pool.get(source.width, source.height, Bitmap.Config.ARGB_8888)
50 | if (result == null) {
51 | result = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
52 | }
53 |
54 | val canvas = Canvas(result!!)
55 | val paint = Paint()
56 | paint.shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
57 | paint.isAntiAlias = true
58 | val rectF = RectF(0f, 0f, source.width.toFloat(), source.height.toFloat())
59 | canvas.drawRoundRect(rectF, radius, radius, paint)
60 | return result
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/glide/ImageLoaderUtils.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.glide
2 |
3 | /**
4 | * Created by xuhao on 2017/11/27.
5 | * desc:
6 | */
7 | object ImageLoaderUtils{
8 | init {
9 |
10 | }
11 |
12 |
13 |
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/CategoryContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.CategoryBean
6 |
7 | /**
8 | * Created by xuhao on 2017/11/29.
9 | * desc: 分类 契约类
10 | */
11 | interface CategoryContract {
12 |
13 | interface View : IBaseView {
14 | /**
15 | * 显示分类的信息
16 | */
17 | fun showCategory(categoryList: ArrayList)
18 |
19 | /**
20 | * 显示错误信息
21 | */
22 | fun showError(errorMsg:String,errorCode:Int)
23 | }
24 |
25 | interface Presenter:IPresenter{
26 | /**
27 | * 获取分类的信息
28 | */
29 | fun getCategoryData()
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/CategoryDetailContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
6 |
7 | /**
8 | * Created by xuhao on 2017/11/30.
9 | * desc: 分类详情契约类
10 | */
11 | interface CategoryDetailContract {
12 |
13 | interface View:IBaseView{
14 | /**
15 | * 设置列表数据
16 | */
17 | fun setCateDetailList(itemList:ArrayList)
18 |
19 | fun showError(errorMsg:String)
20 |
21 |
22 |
23 |
24 | }
25 |
26 | interface Presenter:IPresenter{
27 |
28 | fun getCategoryDetailList(id:Long)
29 |
30 | fun loadMoreData()
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/FollowContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
6 |
7 | /**
8 | * Created by xuhao on 2017/11/30.
9 | * desc: 契约类
10 | */
11 | interface FollowContract {
12 |
13 | interface View : IBaseView {
14 | /**
15 | * 设置关注信息数据
16 | */
17 | fun setFollowInfo(issue: HomeBean.Issue)
18 |
19 | fun showError(errorMsg: String, errorCode: Int)
20 | }
21 |
22 |
23 | interface Presenter : IPresenter {
24 | /**
25 | * 获取List
26 | */
27 | fun requestFollowList()
28 |
29 | /**
30 | * 加载更多
31 | */
32 | fun loadMoreData()
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/HomeContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
6 |
7 | /**
8 | * Created by xuhao on 2017/11/8.
9 | * 契约类
10 | */
11 |
12 | interface HomeContract {
13 |
14 | interface View : IBaseView {
15 |
16 | /**
17 | * 设置第一次请求的数据
18 | */
19 | fun setHomeData(homeBean: HomeBean)
20 |
21 | /**
22 | * 设置加载更多的数据
23 | */
24 | fun setMoreData(itemList:ArrayList)
25 |
26 | /**
27 | * 显示错误信息
28 | */
29 | fun showError(msg: String,errorCode:Int)
30 |
31 |
32 | }
33 |
34 | interface Presenter {
35 |
36 | /**
37 | * 获取首页精选数据
38 | */
39 | fun requestHomeData(num: Int)
40 |
41 | /**
42 | * 加载更多数据
43 | */
44 | fun loadMoreData()
45 |
46 |
47 | }
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/HotTabContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.TabInfoBean
6 |
7 | /**
8 | * Created by xuhao on 2017/11/30.
9 | * desc: 契约类
10 | */
11 | interface HotTabContract {
12 |
13 | interface View:IBaseView{
14 | /**
15 | * 设置 TabInfo
16 | */
17 | fun setTabInfo(tabInfoBean: TabInfoBean)
18 |
19 | fun showError(errorMsg:String,errorCode:Int)
20 | }
21 |
22 |
23 | interface Presenter:IPresenter{
24 | /**
25 | * 获取 TabInfo
26 | */
27 | fun getTabInfo()
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/RankContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
6 | import com.hazz.kotlinmvp.mvp.model.bean.TabInfoBean
7 |
8 | /**
9 | * Created by xuhao on 2017/11/30.
10 | * desc: 契约类
11 | */
12 | interface RankContract {
13 |
14 | interface View:IBaseView{
15 | /**
16 | * 设置排行榜的数据
17 | */
18 | fun setRankList(itemList: ArrayList)
19 |
20 | fun showError(errorMsg:String,errorCode:Int)
21 | }
22 |
23 |
24 | interface Presenter:IPresenter{
25 | /**
26 | * 获取 TabInfo
27 | */
28 | fun requestRankList(apiUrl:String)
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/SearchContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
6 |
7 | /**
8 | * Created by xuhao on 2017/11/30.
9 | * desc: 搜索契约类
10 | */
11 | interface SearchContract {
12 |
13 | interface View : IBaseView {
14 | /**
15 | * 设置热门关键词数据
16 | */
17 | fun setHotWordData(string: ArrayList)
18 |
19 | /**
20 | * 设置搜索关键词返回的结果
21 | */
22 | fun setSearchResult(issue:HomeBean.Issue)
23 | /**
24 | * 关闭软件盘
25 | */
26 | fun closeSoftKeyboard()
27 |
28 | /**
29 | * 设置空 View
30 | */
31 | fun setEmptyView()
32 |
33 |
34 | fun showError(errorMsg: String,errorCode:Int)
35 | }
36 |
37 |
38 | interface Presenter : IPresenter {
39 | /**
40 | * 获取热门关键字的数据
41 | */
42 | fun requestHotWordData()
43 |
44 | /**
45 | * 查询搜索
46 | */
47 | fun querySearchData(words:String)
48 |
49 | /**
50 | * 加载更多
51 | */
52 | fun loadMoreData()
53 | }
54 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/contract/VideoDetailContract.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.contract
2 |
3 | import com.hazz.kotlinmvp.base.IBaseView
4 | import com.hazz.kotlinmvp.base.IPresenter
5 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
6 |
7 | /**
8 | * Created by xuhao on 2017/11/25.
9 | * desc: 视频详情契约类
10 | */
11 | interface VideoDetailContract {
12 |
13 | interface View : IBaseView {
14 |
15 | /**
16 | * 设置视频播放源
17 | */
18 | fun setVideo(url: String)
19 |
20 | /**
21 | * 设置视频信息
22 | */
23 | fun setVideoInfo(itemInfo: HomeBean.Issue.Item)
24 |
25 | /**
26 | * 设置背景
27 | */
28 | fun setBackground(url: String)
29 |
30 | /**
31 | * 设置最新相关视频
32 | */
33 | fun setRecentRelatedVideo(itemList: ArrayList)
34 |
35 | /**
36 | * 设置错误信息
37 | */
38 | fun setErrorMsg(errorMsg: String)
39 |
40 |
41 | }
42 |
43 | interface Presenter : IPresenter {
44 |
45 | /**
46 | * 加载视频信息
47 | */
48 | fun loadVideoInfo(itemInfo: HomeBean.Issue.Item)
49 |
50 | /**
51 | * 请求相关的视频数据
52 | */
53 | fun requestRelatedVideo(id: Long)
54 |
55 | }
56 |
57 |
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/CategoryDetailModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
4 | import com.hazz.kotlinmvp.net.RetrofitManager
5 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
6 | import io.reactivex.Observable
7 | import java.util.*
8 |
9 | /**
10 | * Created by xuhao on 2017/11/30.
11 | * desc: 分类详情的 Model
12 | */
13 | class CategoryDetailModel {
14 |
15 | /**
16 | * 获取分类下的 List 数据
17 | */
18 | fun getCategoryDetailList(id: Long): Observable {
19 | return RetrofitManager.service.getCategoryDetailList(id)
20 | .compose(SchedulerUtils.ioToMain())
21 | }
22 |
23 | /**
24 | * 加载更多数据
25 | */
26 | fun loadMoreData(url: String): Observable {
27 | return RetrofitManager.service.getIssueData(url)
28 | .compose(SchedulerUtils.ioToMain())
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/CategoryModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.CategoryBean
4 | import com.hazz.kotlinmvp.net.RetrofitManager
5 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
6 | import io.reactivex.Observable
7 |
8 | /**
9 | * Created by xuhao on 2017/11/29.
10 | * desc: 分类数据模型
11 | */
12 | class CategoryModel {
13 |
14 |
15 | /**
16 | * 获取分类信息
17 | */
18 | fun getCategoryData(): Observable> {
19 | return RetrofitManager.service.getCategory()
20 | .compose(SchedulerUtils.ioToMain())
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/FollowModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
4 | import com.hazz.kotlinmvp.mvp.model.bean.TabInfoBean
5 | import com.hazz.kotlinmvp.net.RetrofitManager
6 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
7 | import io.reactivex.Observable
8 |
9 | /**
10 | * Created by xuhao on 2017/11/30.
11 | * desc: 关注Model
12 | */
13 | class FollowModel {
14 |
15 | /**
16 | * 获取关注信息
17 | */
18 | fun requestFollowList(): Observable {
19 |
20 | return RetrofitManager.service.getFollowInfo()
21 | .compose(SchedulerUtils.ioToMain())
22 | }
23 |
24 | /**
25 | * 加载更多
26 | */
27 | fun loadMoreData(url:String):Observable{
28 | return RetrofitManager.service.getIssueData(url)
29 | .compose(SchedulerUtils.ioToMain())
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/HomeModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
4 | import com.hazz.kotlinmvp.net.RetrofitManager
5 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
6 | import io.reactivex.Observable
7 |
8 | /**
9 | * Created by xuhao on 2017/11/21.
10 | * desc: 首页精选 model
11 | */
12 |
13 | class HomeModel{
14 |
15 | /**
16 | * 获取首页 Banner 数据
17 | */
18 | fun requestHomeData(num:Int):Observable{
19 | return RetrofitManager.service.getFirstHomeData(num)
20 | .compose(SchedulerUtils.ioToMain())
21 | }
22 |
23 | /**
24 | * 加载更多
25 | */
26 | fun loadMoreData(url:String):Observable{
27 |
28 | return RetrofitManager.service.getMoreHomeData(url)
29 | .compose(SchedulerUtils.ioToMain())
30 | }
31 |
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/HotTabModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
4 | import com.hazz.kotlinmvp.mvp.model.bean.TabInfoBean
5 | import com.hazz.kotlinmvp.net.RetrofitManager
6 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
7 | import io.reactivex.Observable
8 |
9 | /**
10 | * Created by xuhao on 2017/11/30.
11 | * desc: 热门 Model
12 | */
13 | class HotTabModel {
14 |
15 | /**
16 | * 获取 TabInfo
17 | */
18 | fun getTabInfo(): Observable {
19 |
20 | return RetrofitManager.service.getRankList()
21 | .compose(SchedulerUtils.ioToMain())
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/RankModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
4 | import com.hazz.kotlinmvp.mvp.model.bean.TabInfoBean
5 | import com.hazz.kotlinmvp.net.RetrofitManager
6 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
7 | import io.reactivex.Observable
8 |
9 | /**
10 | * Created by xuhao on 2017/11/30.
11 | * desc: 排行榜 Model
12 | */
13 | class RankModel {
14 |
15 | /**
16 | * 获取排行榜
17 | */
18 | fun requestRankList(apiUrl:String): Observable {
19 |
20 | return RetrofitManager.service.getIssueData(apiUrl)
21 | .compose(SchedulerUtils.ioToMain())
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/SearchModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
4 | import com.hazz.kotlinmvp.net.RetrofitManager
5 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
6 | import io.reactivex.Observable
7 |
8 | /**
9 | * Created by xuhao on 2017/11/30.
10 | * desc: 搜索 Model
11 | */
12 | class SearchModel {
13 |
14 | /**
15 | * 请求热门关键词的数据
16 | */
17 | fun requestHotWordData(): Observable> {
18 |
19 | return RetrofitManager.service.getHotWord()
20 | .compose(SchedulerUtils.ioToMain())
21 | }
22 |
23 |
24 | /**
25 | * 搜索关键词返回的结果
26 | */
27 | fun getSearchResult(words: String):Observable{
28 | return RetrofitManager.service.getSearchData(words)
29 | .compose(SchedulerUtils.ioToMain())
30 | }
31 |
32 | /**
33 | * 加载更多数据
34 | */
35 | fun loadMoreData(url: String): Observable {
36 | return RetrofitManager.service.getIssueData(url)
37 | .compose(SchedulerUtils.ioToMain())
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/VideoDetailModel.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model
2 |
3 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
4 | import com.hazz.kotlinmvp.net.RetrofitManager
5 | import com.hazz.kotlinmvp.rx.scheduler.SchedulerUtils
6 | import io.reactivex.Observable
7 |
8 | /**
9 | * Created by xuhao on 2017/11/25.
10 | * desc:
11 | */
12 | class VideoDetailModel {
13 |
14 | fun requestRelatedData(id:Long):Observable{
15 |
16 | return RetrofitManager.service.getRelatedData(id)
17 | .compose(SchedulerUtils.ioToMain())
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/bean/AuthorInfoBean.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model.bean
2 |
3 | import java.io.Serializable
4 |
5 | data class AuthorInfoBean(val tabInfo: TabInfo,
6 | val pgcInfo: PgcInfo) : Serializable {
7 |
8 | data class TabInfo(val tabList: List,
9 | val defaultIdx: Int) : Serializable
10 |
11 | data class TabList(val id: Int,
12 | val name: String,
13 | val apiUrl: String) : Serializable
14 |
15 |
16 | data class PgcInfo(val dataType: String,
17 | val id: Int,
18 | val icon: String,
19 | val name: String,
20 | val brief: String,
21 | val description: String,
22 | val actionUrl: String,
23 | val area: String,
24 | val gender: String,
25 | val registDate: Int,
26 | val followCount: Int,
27 | val follow: Follow,
28 | val self: Boolean,
29 | val cover: String,
30 | val videoCount: Int,
31 | val shareCount: Int,
32 | val collectCount: Int,
33 | val shield: Shield) : Serializable
34 |
35 |
36 | data class Follow(val itemType: String,
37 | val itemId: Int,
38 | val followed: Boolean) : Serializable
39 |
40 | data class Shield(val itemType: String,
41 | val itemId: Int,
42 | val shielded: Boolean) : Serializable
43 | }
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/bean/CategoryBean.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model.bean
2 |
3 | import java.io.Serializable
4 |
5 | /**
6 | * Created by xuhao on 2017/11/29.
7 | * desc:分类 Bean
8 | */
9 | data class CategoryBean(val id: Long, val name: String, val description: String, val bgPicture: String, val bgColor: String, val headerImage: String) : Serializable
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/bean/TabEntity.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model.bean
2 |
3 | import com.flyco.tablayout.listener.CustomTabEntity
4 |
5 |
6 |
7 | /**
8 | * Created by xuhao on 2017/11/8.
9 | */
10 | class TabEntity(var title: String, private var selectedIcon: Int, private var unSelectedIcon: Int) : CustomTabEntity {
11 |
12 | override fun getTabTitle(): String {
13 | return title
14 | }
15 |
16 | override fun getTabSelectedIcon(): Int {
17 | return selectedIcon
18 | }
19 |
20 | override fun getTabUnselectedIcon(): Int {
21 | return unSelectedIcon
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/model/bean/TabInfoBean.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.model.bean
2 |
3 | /**
4 | * Created by xuhao on 2017/11/30.
5 | * desc: 热门的 tabInfo
6 | */
7 |
8 | data class TabInfoBean(val tabInfo: TabInfo) {
9 | data class TabInfo(val tabList: ArrayList)
10 |
11 | data class Tab(val id: Long, val name: String, val apiUrl: String)
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/presenter/CategoryDetailPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.presenter
2 |
3 | import com.hazz.kotlinmvp.base.BasePresenter
4 | import com.hazz.kotlinmvp.mvp.contract.CategoryDetailContract
5 | import com.hazz.kotlinmvp.mvp.model.CategoryDetailModel
6 |
7 | /**
8 | * Created by xuhao on 2017/11/30.
9 | * desc:
10 | */
11 | class CategoryDetailPresenter:BasePresenter(),CategoryDetailContract.Presenter{
12 |
13 | private val categoryDetailModel by lazy {
14 | CategoryDetailModel()
15 | }
16 |
17 | private var nextPageUrl:String?=null
18 |
19 | /**
20 | * 获取分类详情的列表信息
21 | */
22 | override fun getCategoryDetailList(id: Long) {
23 | checkViewAttached()
24 | val disposable= categoryDetailModel.getCategoryDetailList(id)
25 | .subscribe({
26 | issue ->
27 | mRootView?.apply {
28 | nextPageUrl = issue.nextPageUrl
29 | setCateDetailList(issue.itemList)
30 | }
31 | },{
32 | throwable ->
33 | mRootView?.apply {
34 | showError(throwable.toString())
35 | }
36 | })
37 |
38 | addSubscription(disposable)
39 | }
40 |
41 | /**
42 | * 加载更多数据
43 | */
44 | override fun loadMoreData() {
45 | val disposable = nextPageUrl?.let {
46 | categoryDetailModel.loadMoreData(it)
47 | .subscribe({ issue ->
48 | mRootView?.apply {
49 | nextPageUrl = issue.nextPageUrl
50 | setCateDetailList(issue.itemList)
51 | }
52 | }, { throwable ->
53 | mRootView?.apply {
54 | showError(throwable.toString())
55 | }
56 | })
57 | }
58 |
59 | disposable?.let { addSubscription(it) }
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/presenter/CategoryPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.presenter
2 |
3 | import com.hazz.kotlinmvp.base.BasePresenter
4 | import com.hazz.kotlinmvp.mvp.contract.CategoryContract
5 | import com.hazz.kotlinmvp.mvp.model.CategoryModel
6 | import com.hazz.kotlinmvp.net.exception.ExceptionHandle
7 |
8 | /**
9 | * Created by xuhao on 2017/11/29.
10 | * desc:分类的 Presenter
11 | */
12 | class CategoryPresenter : BasePresenter(), CategoryContract.Presenter {
13 |
14 | private val categoryModel: CategoryModel by lazy {
15 | CategoryModel()
16 | }
17 |
18 | /**
19 | * 获取分类
20 | */
21 | override fun getCategoryData() {
22 | checkViewAttached()
23 | mRootView?.showLoading()
24 | val disposable = categoryModel.getCategoryData()
25 | .subscribe({ categoryList ->
26 | mRootView?.apply {
27 | dismissLoading()
28 | showCategory(categoryList)
29 | }
30 | }, { t ->
31 | mRootView?.apply {
32 | //处理异常
33 | showError(ExceptionHandle.handleException(t),ExceptionHandle.errorCode)
34 | }
35 |
36 | })
37 |
38 | addSubscription(disposable)
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/presenter/FollowPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.presenter
2 |
3 | import com.hazz.kotlinmvp.base.BasePresenter
4 | import com.hazz.kotlinmvp.mvp.contract.FollowContract
5 | import com.hazz.kotlinmvp.mvp.contract.RankContract
6 | import com.hazz.kotlinmvp.mvp.model.FollowModel
7 | import com.hazz.kotlinmvp.mvp.model.RankModel
8 | import com.hazz.kotlinmvp.net.exception.ExceptionHandle
9 |
10 | /**
11 | * Created by xuhao on 2017/11/30.
12 | * desc: 获取 TabInfo Presenter
13 | */
14 | class FollowPresenter : BasePresenter(), FollowContract.Presenter {
15 |
16 | private val followModel by lazy { FollowModel() }
17 |
18 | private var nextPageUrl:String?=null
19 |
20 | /**
21 | * 请求关注数据
22 | */
23 | override fun requestFollowList() {
24 | checkViewAttached()
25 | mRootView?.showLoading()
26 | val disposable = followModel.requestFollowList()
27 | .subscribe({ issue ->
28 | mRootView?.apply {
29 | dismissLoading()
30 | nextPageUrl = issue.nextPageUrl
31 | setFollowInfo(issue)
32 | }
33 | }, { throwable ->
34 | mRootView?.apply {
35 | //处理异常
36 | showError(ExceptionHandle.handleException(throwable),ExceptionHandle.errorCode)
37 | }
38 | })
39 | addSubscription(disposable)
40 | }
41 |
42 | /**
43 | * 加载更多
44 | */
45 | override fun loadMoreData(){
46 | val disposable = nextPageUrl?.let {
47 | followModel.loadMoreData(it)
48 | .subscribe({ issue->
49 | mRootView?.apply {
50 | nextPageUrl = issue.nextPageUrl
51 | setFollowInfo(issue)
52 | }
53 |
54 | },{ t ->
55 | mRootView?.apply {
56 | showError(ExceptionHandle.handleException(t),ExceptionHandle.errorCode)
57 | }
58 | })
59 |
60 |
61 | }
62 | if (disposable != null) {
63 | addSubscription(disposable)
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/presenter/HotTabPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.presenter
2 |
3 | import com.hazz.kotlinmvp.base.BasePresenter
4 | import com.hazz.kotlinmvp.mvp.contract.HotTabContract
5 | import com.hazz.kotlinmvp.mvp.model.HotTabModel
6 | import com.hazz.kotlinmvp.net.exception.ExceptionHandle
7 |
8 | /**
9 | * Created by xuhao on 2017/11/30.
10 | * desc: 获取 TabInfo Presenter
11 | */
12 | class HotTabPresenter:BasePresenter(),HotTabContract.Presenter {
13 |
14 | private val hotTabModel by lazy { HotTabModel() }
15 |
16 |
17 | override fun getTabInfo() {
18 | checkViewAttached()
19 | mRootView?.showLoading()
20 | val disposable = hotTabModel.getTabInfo()
21 | .subscribe({
22 | tabInfo->
23 | mRootView?.setTabInfo(tabInfo)
24 | },{
25 | throwable->
26 | //处理异常
27 | mRootView?.showError(ExceptionHandle.handleException(throwable), ExceptionHandle.errorCode)
28 | })
29 | addSubscription(disposable)
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/presenter/RankPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.presenter
2 |
3 | import com.hazz.kotlinmvp.base.BasePresenter
4 | import com.hazz.kotlinmvp.mvp.contract.RankContract
5 | import com.hazz.kotlinmvp.mvp.model.RankModel
6 | import com.hazz.kotlinmvp.net.exception.ExceptionHandle
7 |
8 | /**
9 | * Created by xuhao on 2017/11/30.
10 | * desc: 获取 TabInfo Presenter
11 | */
12 | class RankPresenter : BasePresenter(), RankContract.Presenter {
13 |
14 | private val rankModel by lazy { RankModel() }
15 |
16 |
17 | /**
18 | * 请求排行榜数据
19 | */
20 | override fun requestRankList(apiUrl: String) {
21 | checkViewAttached()
22 | mRootView?.showLoading()
23 | val disposable = rankModel.requestRankList(apiUrl)
24 | .subscribe({ issue ->
25 | mRootView?.apply {
26 | dismissLoading()
27 | setRankList(issue.itemList)
28 | }
29 | }, { throwable ->
30 | mRootView?.apply {
31 | //处理异常
32 | showError(ExceptionHandle.handleException(throwable),ExceptionHandle.errorCode)
33 | }
34 | })
35 | addSubscription(disposable)
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/presenter/SearchPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.presenter
2 |
3 | import com.hazz.kotlinmvp.base.BasePresenter
4 | import com.hazz.kotlinmvp.mvp.contract.SearchContract
5 | import com.hazz.kotlinmvp.mvp.model.SearchModel
6 | import com.hazz.kotlinmvp.net.exception.ExceptionHandle
7 |
8 | /**
9 | * Created by xuhao on 2017/12/4.
10 | * desc: 搜索的 Presenter
11 | */
12 | class SearchPresenter : BasePresenter(), SearchContract.Presenter {
13 |
14 | private var nextPageUrl: String? = null
15 |
16 | private val searchModel by lazy { SearchModel() }
17 |
18 |
19 | /**
20 | * 获取热门关键词
21 | */
22 | override fun requestHotWordData() {
23 | checkViewAttached()
24 | checkViewAttached()
25 | mRootView?.apply {
26 | closeSoftKeyboard()
27 | showLoading()
28 | }
29 | addSubscription(disposable = searchModel.requestHotWordData()
30 | .subscribe({ string ->
31 | mRootView?.apply {
32 | setHotWordData(string)
33 | }
34 | }, { throwable ->
35 | mRootView?.apply {
36 | //处理异常
37 | showError(ExceptionHandle.handleException(throwable),ExceptionHandle.errorCode)
38 | }
39 | }))
40 | }
41 |
42 | /**
43 | * 查询关键词
44 | */
45 | override fun querySearchData(words: String) {
46 | checkViewAttached()
47 | mRootView?.apply {
48 | closeSoftKeyboard()
49 | showLoading()
50 | }
51 | addSubscription(disposable = searchModel.getSearchResult(words)
52 | .subscribe({ issue ->
53 | mRootView?.apply {
54 | dismissLoading()
55 | if (issue.count > 0 && issue.itemList.size > 0) {
56 | nextPageUrl = issue.nextPageUrl
57 | setSearchResult(issue)
58 | } else
59 | setEmptyView()
60 | }
61 | }, { throwable ->
62 | mRootView?.apply {
63 | dismissLoading()
64 | //处理异常
65 | showError(ExceptionHandle.handleException(throwable),ExceptionHandle.errorCode)
66 | }
67 | })
68 | )
69 |
70 | }
71 |
72 | /**
73 | * 加载更多数据
74 | */
75 | override fun loadMoreData() {
76 | checkViewAttached()
77 | nextPageUrl?.let {
78 | addSubscription(disposable = searchModel.loadMoreData(it)
79 | .subscribe({ issue ->
80 | mRootView?.apply {
81 | nextPageUrl = issue.nextPageUrl
82 | setSearchResult(issue)
83 | }
84 | }, { throwable ->
85 | mRootView?.apply {
86 | //处理异常
87 | showError(ExceptionHandle.handleException(throwable),ExceptionHandle.errorCode)
88 | }
89 | }))
90 | }
91 |
92 | }
93 |
94 |
95 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/mvp/presenter/VideoDetailPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.mvp.presenter
2 |
3 | import android.app.Activity
4 | import com.hazz.kotlinmvp.MyApplication
5 | import com.hazz.kotlinmvp.base.BasePresenter
6 | import com.hazz.kotlinmvp.dataFormat
7 | import com.hazz.kotlinmvp.mvp.contract.VideoDetailContract
8 | import com.hazz.kotlinmvp.mvp.model.VideoDetailModel
9 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
10 | import com.hazz.kotlinmvp.net.exception.ExceptionHandle
11 | import com.hazz.kotlinmvp.showToast
12 | import com.hazz.kotlinmvp.utils.DisplayManager
13 | import com.hazz.kotlinmvp.utils.NetworkUtil
14 |
15 | /**
16 | * Created by xuhao on 2017/11/25.
17 | * desc:
18 | */
19 | class VideoDetailPresenter : BasePresenter(), VideoDetailContract.Presenter {
20 |
21 | private val videoDetailModel: VideoDetailModel by lazy {
22 |
23 | VideoDetailModel()
24 | }
25 |
26 | /**
27 | * 加载视频相关的数据
28 | */
29 | override fun loadVideoInfo(itemInfo: HomeBean.Issue.Item) {
30 |
31 | val playInfo = itemInfo.data?.playInfo
32 |
33 | val netType = NetworkUtil.isWifi(MyApplication.context)
34 | // 检测是否绑定 View
35 | checkViewAttached()
36 | if (playInfo!!.size > 1) {
37 | // 当前网络是 Wifi环境下选择高清的视频
38 | if (netType) {
39 | for (i in playInfo) {
40 | if (i.type == "high") {
41 | val playUrl = i.url
42 | mRootView?.setVideo(playUrl)
43 | break
44 | }
45 | }
46 | } else {
47 | //否则就选标清的视频
48 | for (i in playInfo) {
49 | if (i.type == "normal") {
50 | val playUrl = i.url
51 | mRootView?.setVideo(playUrl)
52 | //Todo 待完善
53 | (mRootView as Activity).showToast("本次消耗${(mRootView as Activity)
54 | .dataFormat(i.urlList[0].size)}流量")
55 | break
56 | }
57 | }
58 | }
59 | } else {
60 | mRootView?.setVideo(itemInfo.data.playUrl)
61 | }
62 |
63 | //设置背景
64 | val backgroundUrl = itemInfo.data.cover.blurred + "/thumbnail/${DisplayManager.getScreenHeight()!! - DisplayManager.dip2px(250f)!!}x${DisplayManager.getScreenWidth()}"
65 | backgroundUrl.let { mRootView?.setBackground(it) }
66 |
67 | mRootView?.setVideoInfo(itemInfo)
68 |
69 |
70 | }
71 |
72 |
73 | /**
74 | * 请求相关的视频数据
75 | */
76 | override fun requestRelatedVideo(id: Long) {
77 | mRootView?.showLoading()
78 | val disposable = videoDetailModel.requestRelatedData(id)
79 | .subscribe({ issue ->
80 | mRootView?.apply {
81 | dismissLoading()
82 | setRecentRelatedVideo(issue.itemList)
83 | }
84 | }, { t ->
85 | mRootView?.apply {
86 | dismissLoading()
87 | setErrorMsg(ExceptionHandle.handleException(t))
88 | }
89 | })
90 |
91 | addSubscription(disposable)
92 |
93 | }
94 |
95 |
96 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/net/BaseResponse.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.net
2 |
3 | /**
4 | * Created by xuhao on 2017/11/16.
5 | * 封装返回的数据
6 | */
7 | class BaseResponse(val code :Int,
8 | val msg:String,
9 | val data:T)
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/net/exception/ApiException.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.net.exception
2 |
3 | /**
4 | * Created by xuhao on 2017/12/5.
5 | * desc:
6 | */
7 | class ApiException : RuntimeException {
8 |
9 | private var code: Int? = null
10 |
11 |
12 | constructor(throwable: Throwable, code: Int) : super(throwable) {
13 | this.code = code
14 | }
15 |
16 | constructor(message: String) : super(Throwable(message))
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/net/exception/ErrorStatus.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.net.exception
2 |
3 | /**
4 | * Created by xuhao on 2017/12/5.
5 | * desc:
6 | */
7 | object ErrorStatus {
8 | /**
9 | * 响应成功
10 | */
11 | @JvmField
12 | val SUCCESS = 0
13 |
14 | /**
15 | * 未知错误
16 | */
17 | @JvmField
18 | val UNKNOWN_ERROR = 1002
19 |
20 | /**
21 | * 服务器内部错误
22 | */
23 | @JvmField
24 | val SERVER_ERROR = 1003
25 |
26 | /**
27 | * 网络连接超时
28 | */
29 | @JvmField
30 | val NETWORK_ERROR = 1004
31 |
32 | /**
33 | * API解析异常(或者第三方数据结构更改)等其他异常
34 | */
35 | @JvmField
36 | val API_ERROR = 1005
37 |
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/net/exception/ExceptionHandle.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.net.exception
2 |
3 | import com.google.gson.JsonParseException
4 | import com.orhanobut.logger.Logger
5 |
6 | import org.json.JSONException
7 |
8 | import java.net.ConnectException
9 |
10 | import java.net.SocketTimeoutException
11 | import java.net.UnknownHostException
12 | import java.text.ParseException
13 |
14 | /**
15 | * Created by xuhao on 2017/12/5.
16 | * desc: 异常处理类
17 | */
18 |
19 | class ExceptionHandle {
20 |
21 |
22 | companion object {
23 | var errorCode = ErrorStatus.UNKNOWN_ERROR
24 | var errorMsg = "请求失败,请稍后重试"
25 |
26 | fun handleException(e: Throwable): String {
27 | e.printStackTrace()
28 | if (e is SocketTimeoutException) {//网络超时
29 | Logger.e("TAG", "网络连接异常: " + e.message)
30 | errorMsg = "网络连接异常"
31 | errorCode = ErrorStatus.NETWORK_ERROR
32 | } else if (e is ConnectException) { //均视为网络错误
33 | Logger.e("TAG", "网络连接异常: " + e.message)
34 | errorMsg = "网络连接异常"
35 | errorCode = ErrorStatus.NETWORK_ERROR
36 | } else if (e is JsonParseException
37 | || e is JSONException
38 | || e is ParseException) { //均视为解析错误
39 | Logger.e("TAG", "数据解析异常: " + e.message)
40 | errorMsg = "数据解析异常"
41 | errorCode = ErrorStatus.SERVER_ERROR
42 | } else if (e is ApiException) {//服务器返回的错误信息
43 | errorMsg = e.message.toString()
44 | errorCode = ErrorStatus.SERVER_ERROR
45 | } else if (e is UnknownHostException) {
46 | Logger.e("TAG", "网络连接异常: " + e.message)
47 | errorMsg = "网络连接异常"
48 | errorCode = ErrorStatus.NETWORK_ERROR
49 | } else if (e is IllegalArgumentException) {
50 | errorMsg = "参数错误"
51 | errorCode = ErrorStatus.SERVER_ERROR
52 | } else {//未知错误
53 | try {
54 | Logger.e("TAG", "错误: " + e.message)
55 | } catch (e1: Exception) {
56 | Logger.e("TAG", "未知错误Debug调试 ")
57 | }
58 |
59 | errorMsg = "未知错误,可能抛锚了吧~"
60 | errorCode = ErrorStatus.UNKNOWN_ERROR
61 | }
62 | return errorMsg
63 | }
64 |
65 | }
66 |
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/rx/scheduler/BaseScheduler.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.rx.scheduler
2 |
3 | import io.reactivex.*
4 | import org.reactivestreams.Publisher
5 |
6 | /**
7 | * Created by xuhao on 2017/11/17.
8 | * desc:RxJava2.x 5中基础相应类型
9 | */
10 |
11 |
12 |
13 | abstract class BaseScheduler protected constructor(private val subscribeOnScheduler: Scheduler,
14 | private val observeOnScheduler: Scheduler) : ObservableTransformer,
15 | SingleTransformer,
16 | MaybeTransformer,
17 | CompletableTransformer,
18 | FlowableTransformer {
19 |
20 | override fun apply(upstream: Completable): CompletableSource {
21 | return upstream.subscribeOn(subscribeOnScheduler)
22 | .observeOn(observeOnScheduler)
23 | }
24 |
25 | override fun apply(upstream: Flowable): Publisher {
26 | return upstream.subscribeOn(subscribeOnScheduler)
27 | .observeOn(observeOnScheduler)
28 | }
29 |
30 | override fun apply(upstream: Maybe): MaybeSource {
31 | return upstream.subscribeOn(subscribeOnScheduler)
32 | .observeOn(observeOnScheduler)
33 | }
34 |
35 | override fun apply(upstream: Observable): ObservableSource {
36 | return upstream.subscribeOn(subscribeOnScheduler)
37 | .observeOn(observeOnScheduler)
38 | }
39 |
40 | override fun apply(upstream: Single): SingleSource {
41 | return upstream.subscribeOn(subscribeOnScheduler)
42 | .observeOn(observeOnScheduler)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/rx/scheduler/ComputationMainScheduler.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.rx.scheduler
2 |
3 | import io.reactivex.android.schedulers.AndroidSchedulers
4 | import io.reactivex.schedulers.Schedulers
5 | /**
6 | * Created by xuhao on 2017/11/17.
7 | * desc:
8 | */
9 |
10 |
11 | class ComputationMainScheduler private constructor() : BaseScheduler(Schedulers.computation(), AndroidSchedulers.mainThread())
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/rx/scheduler/IoMainScheduler.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.rx.scheduler
2 |
3 | import io.reactivex.android.schedulers.AndroidSchedulers
4 | import io.reactivex.schedulers.Schedulers
5 |
6 | /**
7 | * Created by xuhao on 2017/11/17.
8 | * desc:
9 | */
10 | class IoMainScheduler : BaseScheduler(Schedulers.io(), AndroidSchedulers.mainThread())
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/rx/scheduler/NewThreadMainScheduler.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.rx.scheduler
2 |
3 | import io.reactivex.android.schedulers.AndroidSchedulers
4 | import io.reactivex.schedulers.Schedulers
5 |
6 | /**
7 | * Created by xuhao on 2017/11/17.
8 | * desc:
9 | */
10 |
11 |
12 | class NewThreadMainScheduler private constructor() : BaseScheduler(Schedulers.newThread(), AndroidSchedulers.mainThread())
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/rx/scheduler/SchedulerUtils.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.rx.scheduler
2 |
3 | /**
4 | * Created by xuhao on 2017/11/17.
5 | * desc:
6 | */
7 |
8 | object SchedulerUtils {
9 |
10 | fun ioToMain(): IoMainScheduler {
11 | return IoMainScheduler()
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/rx/scheduler/SingleMainScheduler.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.rx.scheduler
2 |
3 | import io.reactivex.android.schedulers.AndroidSchedulers
4 | import io.reactivex.schedulers.Schedulers
5 |
6 | /**
7 | * Created by xuhao on 2017/11/17.
8 | * desc:
9 | */
10 |
11 |
12 | class SingleMainScheduler private constructor() : BaseScheduler(Schedulers.single(), AndroidSchedulers.mainThread())
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/rx/scheduler/TrampolineMainScheduler.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.rx.scheduler
2 |
3 | import io.reactivex.android.schedulers.AndroidSchedulers
4 | import io.reactivex.schedulers.Schedulers
5 |
6 | /**
7 | * Created by xuhao on 2017/11/17.
8 | * desc:
9 | */
10 |
11 |
12 | class TrampolineMainScheduler private constructor() : BaseScheduler(Schedulers.trampoline(), AndroidSchedulers.mainThread())
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/activity/AboutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.activity
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Intent
5 | import android.net.Uri
6 | import com.hazz.kotlinmvp.MyApplication
7 | import com.hazz.kotlinmvp.R
8 | import com.hazz.kotlinmvp.R.id.toolbar
9 | import com.hazz.kotlinmvp.base.BaseActivity
10 | import com.hazz.kotlinmvp.utils.AppUtils
11 | import com.hazz.kotlinmvp.utils.StatusBarUtil
12 | import kotlinx.android.synthetic.main.activity_about.*
13 |
14 | /**
15 | * Created by xuhao on 2017/12/6.
16 | * desc: 关于
17 | */
18 | class AboutActivity : BaseActivity() {
19 | override fun layoutId(): Int = R.layout.activity_about
20 |
21 | override fun initData() {
22 | }
23 |
24 | @SuppressLint("SetTextI18n")
25 | override fun initView() {
26 | StatusBarUtil.darkMode(this)
27 | StatusBarUtil.setPaddingSmart(this, toolbar)
28 |
29 | tv_version_name.text ="v${AppUtils.getVerName(MyApplication.context)}"
30 | //返回
31 | toolbar.setNavigationOnClickListener { finish() }
32 | //访问 GitHub
33 | relayout_gitHub.setOnClickListener {
34 | val uri = Uri.parse("https://github.com/git-xuhao/KotlinMvp")
35 | val intent = Intent(Intent.ACTION_VIEW, uri)
36 | startActivity(intent)
37 | }
38 | }
39 |
40 | override fun start() {
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/activity/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.activity
2 |
3 | import android.Manifest
4 | import android.annotation.SuppressLint
5 | import android.content.Intent
6 | import android.graphics.Typeface
7 | import android.view.animation.AlphaAnimation
8 | import android.view.animation.Animation
9 | import android.view.animation.Animation.AnimationListener
10 | import com.hazz.kotlinmvp.MyApplication
11 | import com.hazz.kotlinmvp.R
12 | import com.hazz.kotlinmvp.base.BaseActivity
13 | import com.hazz.kotlinmvp.utils.AppUtils
14 | import kotlinx.android.synthetic.main.activity_splash.*
15 | import pub.devrel.easypermissions.EasyPermissions
16 |
17 |
18 | /**
19 | * Created by xuhao on 2017/12/5.
20 | * desc: 启动页
21 | */
22 |
23 | class SplashActivity : BaseActivity() {
24 |
25 |
26 | private var textTypeface: Typeface?=null
27 |
28 | private var descTypeFace: Typeface?=null
29 |
30 | private var alphaAnimation:AlphaAnimation?=null
31 |
32 | init {
33 | textTypeface = Typeface.createFromAsset(MyApplication.context.assets, "fonts/Lobster-1.4.otf")
34 | descTypeFace = Typeface.createFromAsset(MyApplication.context.assets, "fonts/FZLanTingHeiS-L-GB-Regular.TTF")
35 | }
36 |
37 |
38 | override fun layoutId(): Int = R.layout.activity_splash
39 |
40 | override fun initData() {
41 |
42 | }
43 |
44 | @SuppressLint("SetTextI18n")
45 | override fun initView() {
46 |
47 | tv_app_name.typeface = textTypeface
48 | tv_splash_desc.typeface = descTypeFace
49 | tv_version_name.text = "v${AppUtils.getVerName(MyApplication.context)}"
50 |
51 | //渐变展示启动屏
52 | alphaAnimation= AlphaAnimation(0.3f, 1.0f)
53 | alphaAnimation?.duration = 2000
54 | alphaAnimation?.setAnimationListener(object : AnimationListener {
55 | override fun onAnimationEnd(arg0: Animation) {
56 | redirectTo()
57 | }
58 |
59 | override fun onAnimationRepeat(animation: Animation) {}
60 |
61 | override fun onAnimationStart(animation: Animation) {}
62 |
63 | })
64 |
65 | checkPermission()
66 | }
67 |
68 | override fun start() {
69 |
70 | }
71 |
72 |
73 | fun redirectTo() {
74 | val intent = Intent(this, MainActivity::class.java)
75 | startActivity(intent)
76 | finish()
77 | }
78 |
79 | /**
80 | * 6.0以下版本(系统自动申请) 不会弹框
81 | * 有些厂商修改了6.0系统申请机制,他们修改成系统自动申请权限了
82 | */
83 | private fun checkPermission(){
84 | val perms = arrayOf(Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
85 | EasyPermissions.requestPermissions(this, "KotlinMvp应用需要以下权限,请允许", 0, *perms)
86 |
87 | }
88 |
89 |
90 | override fun onPermissionsGranted(requestCode: Int, perms: List) {
91 | if (requestCode == 0) {
92 | if (perms.isNotEmpty()) {
93 | if (perms.contains(Manifest.permission.READ_PHONE_STATE)
94 | && perms.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
95 | if (alphaAnimation != null) {
96 | iv_web_icon.startAnimation(alphaAnimation)
97 | }
98 | }
99 | }
100 | }
101 | }
102 |
103 |
104 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/activity/WatchHistoryActivity.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.activity
2 |
3 | import android.support.v7.widget.LinearLayoutManager
4 | import com.hazz.kotlinmvp.Constants
5 | import com.hazz.kotlinmvp.MyApplication
6 | import com.hazz.kotlinmvp.R
7 | import com.hazz.kotlinmvp.base.BaseActivity
8 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
9 | import com.hazz.kotlinmvp.ui.adapter.WatchHistoryAdapter
10 | import com.hazz.kotlinmvp.utils.Preference
11 | import com.hazz.kotlinmvp.utils.StatusBarUtil
12 | import com.hazz.kotlinmvp.utils.WatchHistoryUtils
13 | import kotlinx.android.synthetic.main.activity_about.*
14 | import kotlinx.android.synthetic.main.layout_recyclerview.*
15 | import java.util.*
16 | import kotlin.collections.ArrayList
17 |
18 |
19 | /**
20 | * Created by xuhao on 2017/12/11.
21 | * desc: 观看记录
22 | */
23 |
24 | class WatchHistoryActivity : BaseActivity() {
25 |
26 | private var itemListData = ArrayList()
27 |
28 | companion object {
29 | private const val HISTORY_MAX = 20
30 | }
31 |
32 | override fun layoutId(): Int = R.layout.layout_watch_history
33 |
34 | override fun initData() {
35 | multipleStatusView.showLoading()
36 | itemListData = queryWatchHistory()
37 |
38 | }
39 |
40 | override fun initView() {
41 | //返回
42 | toolbar.setNavigationOnClickListener { finish() }
43 |
44 | val mAdapter = WatchHistoryAdapter(this, itemListData, R.layout.item_video_small_card)
45 | mRecyclerView.layoutManager = LinearLayoutManager(this)
46 | mRecyclerView.adapter = mAdapter
47 |
48 | if (itemListData.size > 0) {
49 | multipleStatusView.showContent()
50 | } else {
51 | multipleStatusView.showEmpty()
52 | }
53 |
54 | //状态栏透明和间距处理
55 | StatusBarUtil.darkMode(this)
56 | StatusBarUtil.setPaddingSmart(this, toolbar)
57 | StatusBarUtil.setPaddingSmart(this, mRecyclerView)
58 |
59 | }
60 |
61 | override fun start() {
62 |
63 | }
64 |
65 | /**
66 | * 查询观看的历史记录
67 | */
68 | private fun queryWatchHistory(): ArrayList {
69 | val watchList = ArrayList()
70 | val hisAll = WatchHistoryUtils.getAll(Constants.FILE_WATCH_HISTORY_NAME, MyApplication.context) as Map<*, *>
71 | //将key排序升序
72 | val keys = hisAll.keys.toTypedArray()
73 | Arrays.sort(keys)
74 | val keyLength = keys.size
75 | //这里计算 如果历史记录条数是大于 可以显示的最大条数,则用最大条数做循环条件,防止历史记录条数-最大条数为负值,数组越界
76 | val hisLength = if (keyLength > HISTORY_MAX) HISTORY_MAX else keyLength
77 | // 反序列化和遍历 添加观看的历史记录
78 | (1..hisLength).mapTo(watchList) {
79 | WatchHistoryUtils.getObject(Constants.FILE_WATCH_HISTORY_NAME, MyApplication.context,
80 | keys[keyLength - it] as String) as HomeBean.Issue.Item
81 | }
82 |
83 | return watchList
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/adapter/CategoryAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.adapter
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.graphics.Typeface
7 | import android.view.View
8 | import android.widget.ImageView
9 | import android.widget.TextView
10 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
11 | import com.hazz.kotlinmvp.Constants
12 | import com.hazz.kotlinmvp.MyApplication
13 | import com.hazz.kotlinmvp.R
14 | import com.hazz.kotlinmvp.glide.GlideApp
15 | import com.hazz.kotlinmvp.mvp.model.bean.CategoryBean
16 | import com.hazz.kotlinmvp.ui.activity.CategoryDetailActivity
17 | import com.hazz.kotlinmvp.view.recyclerview.ViewHolder
18 | import com.hazz.kotlinmvp.view.recyclerview.adapter.CommonAdapter
19 |
20 | /**
21 | * Created by xuhao on 2017/11/29.
22 | * desc: 分类的 Adapter
23 | */
24 |
25 | class CategoryAdapter(mContext: Context, categoryList: ArrayList, layoutId: Int) :
26 | CommonAdapter(mContext, categoryList, layoutId) {
27 |
28 |
29 |
30 | private var textTypeface:Typeface?=null
31 |
32 | init {
33 | textTypeface = Typeface.createFromAsset(MyApplication.context.assets, "fonts/FZLanTingHeiS-DB1-GB-Regular.TTF")
34 | }
35 | /**
36 | * 设置新数据
37 | */
38 | fun setData(categoryList: ArrayList){
39 | mData.clear()
40 | mData = categoryList
41 | notifyDataSetChanged()
42 | }
43 | /**
44 | * 绑定数据
45 | */
46 | override fun bindData(holder: ViewHolder, data: CategoryBean, position: Int) {
47 | holder.setText(R.id.tv_category_name, "#${data.name}")
48 | //设置方正兰亭细黑简体
49 | holder.getView(R.id.tv_category_name).typeface = textTypeface
50 |
51 | holder.setImagePath(R.id.iv_category, object : ViewHolder.HolderImageLoader(data.bgPicture) {
52 | override fun loadImage(iv: ImageView, path: String) {
53 | GlideApp.with(mContext)
54 | .load(path)
55 | .placeholder(R.color.color_darker_gray)
56 | .transition(DrawableTransitionOptions().crossFade())
57 | .thumbnail(0.5f)
58 | .into(iv)
59 | }
60 | })
61 |
62 | holder.setOnItemClickListener(object :View.OnClickListener{
63 | override fun onClick(p0: View?) {
64 | val intent = Intent(mContext as Activity,CategoryDetailActivity::class.java)
65 | intent.putExtra(Constants.BUNDLE_CATEGORY_DATA,data)
66 | mContext.startActivity(intent)
67 | }
68 | })
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/adapter/CategoryDetailAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.adapter
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.support.v4.app.ActivityCompat
7 | import android.support.v4.app.ActivityOptionsCompat
8 | import android.support.v4.util.Pair
9 | import android.view.View
10 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
11 | import com.bumptech.glide.request.RequestOptions
12 | import com.hazz.kotlinmvp.Constants
13 | import com.hazz.kotlinmvp.R
14 | import com.hazz.kotlinmvp.durationFormat
15 | import com.hazz.kotlinmvp.glide.GlideApp
16 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
17 | import com.hazz.kotlinmvp.ui.activity.VideoDetailActivity
18 | import com.hazz.kotlinmvp.view.recyclerview.ViewHolder
19 | import com.hazz.kotlinmvp.view.recyclerview.adapter.CommonAdapter
20 |
21 | /**
22 | * Created by xuhao on 2017/11/30.
23 | * desc:分类详情Adapter
24 | */
25 | class CategoryDetailAdapter(context: Context, dataList: ArrayList, layoutId: Int)
26 | : CommonAdapter(context, dataList, layoutId) {
27 |
28 |
29 | fun addData(dataList: ArrayList) {
30 | this.mData.addAll(dataList)
31 | notifyDataSetChanged()
32 | }
33 |
34 |
35 | override fun bindData(holder: ViewHolder, data: HomeBean.Issue.Item, position: Int) {
36 | setVideoItem(holder, data)
37 | }
38 |
39 | /**
40 | * 加载 content item
41 | */
42 | private fun setVideoItem(holder: ViewHolder, item: HomeBean.Issue.Item) {
43 | val itemData = item.data
44 | val cover = itemData?.cover?.feed?:""
45 | // 加载封页图
46 | GlideApp.with(mContext)
47 | .load(cover)
48 | .apply(RequestOptions().placeholder(R.drawable.placeholder_banner))
49 | .transition(DrawableTransitionOptions().crossFade())
50 | .into(holder.getView(R.id.iv_image))
51 | holder.setText(R.id.tv_title, itemData?.title?:"")
52 |
53 | // 格式化时间
54 | val timeFormat = durationFormat(itemData?.duration)
55 |
56 | holder.setText(R.id.tv_tag, "#${itemData?.category}/$timeFormat")
57 |
58 | holder.setOnItemClickListener(listener = View.OnClickListener {
59 | goToVideoPlayer(mContext as Activity, holder.getView(R.id.iv_image), item)
60 | })
61 |
62 |
63 | }
64 |
65 | /**
66 | * 跳转到视频详情页面播放
67 | *
68 | * @param activity
69 | * @param view
70 | */
71 | private fun goToVideoPlayer(activity: Activity, view: View, itemData: HomeBean.Issue.Item) {
72 | val intent = Intent(activity, VideoDetailActivity::class.java)
73 | intent.putExtra(Constants.BUNDLE_VIDEO_DATA, itemData)
74 | intent.putExtra(VideoDetailActivity.Companion.TRANSITION, true)
75 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
76 | val pair = Pair(view, VideoDetailActivity.IMG_TRANSITION)
77 | val activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(
78 | activity, pair)
79 | ActivityCompat.startActivity(activity, intent, activityOptions.toBundle())
80 | } else {
81 | activity.startActivity(intent)
82 | activity.overridePendingTransition(R.anim.anim_in, R.anim.anim_out)
83 | }
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/adapter/FollowAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.adapter
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.support.v7.widget.LinearLayoutManager
6 | import android.support.v7.widget.RecyclerView
7 | import android.widget.ImageView
8 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
9 | import com.hazz.kotlinmvp.R
10 | import com.hazz.kotlinmvp.glide.GlideApp
11 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
12 | import com.hazz.kotlinmvp.view.recyclerview.MultipleType
13 | import com.hazz.kotlinmvp.view.recyclerview.ViewHolder
14 | import com.hazz.kotlinmvp.view.recyclerview.adapter.CommonAdapter
15 |
16 | /**
17 | * Created by xuhao on 2017/12/7.
18 | * desc: 关注 adapter
19 | */
20 | class FollowAdapter(context: Context, dataList: ArrayList)
21 | : CommonAdapter(context, dataList, object : MultipleType {
22 | override fun getLayoutId(item: HomeBean.Issue.Item, position: Int): Int {
23 | return when {
24 | item.type == "videoCollectionWithBrief" ->
25 | R.layout.item_follow
26 | else ->
27 | throw IllegalAccessException("Api 解析出错了,出现其他类型")
28 | }
29 | }
30 | }) {
31 |
32 |
33 | fun addData(dataList: ArrayList) {
34 | this.mData.addAll(dataList)
35 | notifyDataSetChanged()
36 | }
37 |
38 |
39 | /**
40 | * 绑定数据
41 | */
42 | override fun bindData(holder: ViewHolder, data: HomeBean.Issue.Item, position: Int) {
43 |
44 | when {
45 | data.type == "videoCollectionWithBrief" -> setAuthorInfo(data, holder)
46 | }
47 |
48 | }
49 |
50 |
51 | /**
52 | * 加载作者信息
53 | */
54 | private fun setAuthorInfo(item: HomeBean.Issue.Item, holder: ViewHolder) {
55 | val headerData = item.data?.header
56 | /**
57 | * 加载作者头像
58 | */
59 | holder.setImagePath(R.id.iv_avatar, object : ViewHolder.HolderImageLoader(headerData?.icon!!) {
60 | override fun loadImage(iv: ImageView, path: String) {
61 | GlideApp.with(mContext)
62 | .load(path)
63 | .placeholder(R.mipmap.default_avatar).circleCrop()
64 | .transition(DrawableTransitionOptions().crossFade())
65 | .into(holder.getView(R.id.iv_avatar))
66 | }
67 |
68 | })
69 | holder.setText(R.id.tv_title, headerData.title)
70 | holder.setText(R.id.tv_desc, headerData.description)
71 |
72 | val recyclerView = holder.getView(R.id.fl_recyclerView)
73 | /**
74 | * 设置嵌套水平的 RecyclerView
75 | */
76 | recyclerView.layoutManager = LinearLayoutManager(mContext as Activity,LinearLayoutManager.HORIZONTAL,false)
77 | recyclerView.adapter = FollowHorizontalAdapter(mContext,item.data.itemList,R.layout.item_follow_horizontal)
78 |
79 | }
80 |
81 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/adapter/HotKeywordsAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.adapter
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.widget.TextView
6 | import com.google.android.flexbox.FlexboxLayoutManager
7 | import com.hazz.kotlinmvp.R
8 | import com.hazz.kotlinmvp.view.recyclerview.ViewHolder
9 | import com.hazz.kotlinmvp.view.recyclerview.adapter.CommonAdapter
10 |
11 | /**
12 | * Created by xuhao on 2017/12/4.
13 | * desc: Tag 标签布局的 Adapter
14 | */
15 | class HotKeywordsAdapter(mContext: Context,mList: ArrayList, layoutId: Int) :
16 | CommonAdapter(mContext, mList, layoutId){
17 |
18 |
19 |
20 |
21 | /**
22 | * Kotlin的函数可以作为参数,写callback的时候,可以不用interface了
23 | */
24 |
25 | private var mOnTagItemClick: ((tag:String) -> Unit)? = null
26 |
27 | fun setOnTagItemClickListener(onTagItemClickListener:(tag:String) -> Unit) {
28 | this.mOnTagItemClick = onTagItemClickListener
29 | }
30 |
31 | override fun bindData(holder: ViewHolder, data: String, position: Int) {
32 |
33 | holder.setText(R.id.tv_title,data)
34 |
35 | val params = holder.getView(R.id.tv_title).layoutParams
36 | if(params is FlexboxLayoutManager.LayoutParams){
37 | params.flexGrow = 1.0f
38 | }
39 |
40 | holder.setOnItemClickListener(object :View.OnClickListener{
41 | override fun onClick(v: View?) {
42 | mOnTagItemClick?.invoke(data)
43 | }
44 |
45 | }
46 |
47 | )
48 |
49 | }
50 |
51 |
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/adapter/WatchHistoryAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.adapter
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.support.v4.app.ActivityCompat
7 | import android.support.v4.app.ActivityOptionsCompat
8 | import android.support.v4.content.ContextCompat
9 | import android.support.v4.util.Pair
10 | import android.view.View
11 | import android.widget.ImageView
12 | import android.widget.TextView
13 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
14 | import com.hazz.kotlinmvp.Constants
15 | import com.hazz.kotlinmvp.R
16 | import com.hazz.kotlinmvp.durationFormat
17 | import com.hazz.kotlinmvp.glide.GlideApp
18 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
19 | import com.hazz.kotlinmvp.ui.activity.VideoDetailActivity
20 | import com.hazz.kotlinmvp.view.recyclerview.ViewHolder
21 | import com.hazz.kotlinmvp.view.recyclerview.adapter.CommonAdapter
22 |
23 | /**
24 | * Created by xuhao on 2017/12/11.
25 | * desc:
26 | */
27 | class WatchHistoryAdapter(context: Context, dataList: ArrayList, layoutId: Int)
28 | : CommonAdapter(context, dataList, layoutId) {
29 |
30 |
31 | //绑定数据
32 | override fun bindData(holder: ViewHolder, data: HomeBean.Issue.Item, position: Int) {
33 | with(holder) {
34 | setText(R.id.tv_title, data.data?.title!!)
35 | setText(R.id.tv_tag, "#${data.data.category} / ${durationFormat(data.data.duration)}")
36 | setImagePath(R.id.iv_video_small_card, object : ViewHolder.HolderImageLoader(data.data.cover.detail) {
37 | override fun loadImage(iv: ImageView, path: String) {
38 | GlideApp.with(mContext)
39 | .load(path)
40 | .placeholder(R.drawable.placeholder_banner)
41 | .transition(DrawableTransitionOptions().crossFade())
42 | .into(iv)
43 | }
44 | })
45 | }
46 | holder.getView(R.id.tv_title).setTextColor(ContextCompat.getColor(mContext,R.color.color_black))
47 | holder.setOnItemClickListener(listener = View.OnClickListener {
48 | goToVideoPlayer(mContext as Activity, holder.getView(R.id.iv_video_small_card), data)
49 | })
50 | }
51 |
52 |
53 | /**
54 | * 跳转到视频详情页面播放
55 | *
56 | * @param activity
57 | * @param view
58 | */
59 | private fun goToVideoPlayer(activity: Activity, view: View, itemData: HomeBean.Issue.Item) {
60 | val intent = Intent(activity, VideoDetailActivity::class.java)
61 | intent.putExtra(Constants.BUNDLE_VIDEO_DATA, itemData)
62 | intent.putExtra(VideoDetailActivity.TRANSITION, true)
63 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
64 | val pair = Pair(view, VideoDetailActivity.IMG_TRANSITION)
65 | val activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(
66 | activity, pair)
67 | ActivityCompat.startActivity(activity, intent, activityOptions.toBundle())
68 | } else {
69 | activity.startActivity(intent)
70 | activity.overridePendingTransition(R.anim.anim_in, R.anim.anim_out)
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/fragment/DiscoveryFragment.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.fragment
2 |
3 | import android.os.Bundle
4 | import android.support.v4.app.Fragment
5 | import com.hazz.kotlinmvp.R
6 | import com.hazz.kotlinmvp.base.BaseFragment
7 | import com.hazz.kotlinmvp.base.BaseFragmentAdapter
8 | import com.hazz.kotlinmvp.utils.StatusBarUtil
9 | import com.hazz.kotlinmvp.view.TabLayoutHelper
10 | import kotlinx.android.synthetic.main.fragment_hot.*
11 |
12 | /**
13 | * Created by xuhao on 2017/12/7.
14 | * desc: 发现(和热门首页同样的布局)
15 | */
16 | class DiscoveryFragment : BaseFragment() {
17 |
18 | private val tabList = ArrayList()
19 |
20 | private val fragments = ArrayList()
21 |
22 | private var mTitle: String? = null
23 |
24 | companion object {
25 | fun getInstance(title: String): DiscoveryFragment {
26 | val fragment = DiscoveryFragment()
27 | val bundle = Bundle()
28 | fragment.arguments = bundle
29 | fragment.mTitle = title
30 | return fragment
31 | }
32 | }
33 |
34 | override fun getLayoutId(): Int = R.layout.fragment_hot
35 |
36 | override fun initView() {
37 |
38 | //状态栏透明和间距处理
39 | activity?.let { StatusBarUtil.darkMode(it) }
40 | activity?.let { StatusBarUtil.setPaddingSmart(it, toolbar) }
41 |
42 | tv_header_title.text = mTitle
43 |
44 | tabList.add("关注")
45 | tabList.add("分类")
46 | fragments.add(FollowFragment.getInstance("关注"))
47 | fragments.add(CategoryFragment.getInstance("分类"))
48 |
49 | /**
50 | * getSupportFragmentManager() 替换为getChildFragmentManager()
51 | */
52 | mViewPager.adapter = BaseFragmentAdapter(childFragmentManager, fragments, tabList)
53 | mTabLayout.setupWithViewPager(mViewPager)
54 | TabLayoutHelper.setUpIndicatorWidth(mTabLayout)
55 |
56 |
57 | }
58 |
59 | override fun lazyLoad() {
60 | }
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/fragment/HotFragment.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.fragment
2 |
3 | import android.os.Bundle
4 | import android.support.v4.app.Fragment
5 | import com.hazz.kotlinmvp.R
6 | import com.hazz.kotlinmvp.base.BaseFragment
7 | import com.hazz.kotlinmvp.base.BaseFragmentAdapter
8 | import com.hazz.kotlinmvp.mvp.contract.HotTabContract
9 | import com.hazz.kotlinmvp.mvp.model.bean.TabInfoBean
10 | import com.hazz.kotlinmvp.mvp.presenter.HotTabPresenter
11 | import com.hazz.kotlinmvp.net.exception.ErrorStatus
12 | import com.hazz.kotlinmvp.showToast
13 | import com.hazz.kotlinmvp.utils.StatusBarUtil
14 | import kotlinx.android.synthetic.main.fragment_hot.*
15 |
16 | /**
17 | * Created by xuhao on 2017/11/9.
18 | * 热门
19 | */
20 | class HotFragment : BaseFragment(), HotTabContract.View {
21 |
22 | private val mPresenter by lazy { HotTabPresenter() }
23 |
24 | private var mTitle: String? = null
25 |
26 | /**
27 | * 存放 tab 标题
28 | */
29 | private val mTabTitleList = ArrayList()
30 |
31 | private val mFragmentList = ArrayList()
32 |
33 | companion object {
34 | fun getInstance(title: String): HotFragment {
35 | val fragment = HotFragment()
36 | val bundle = Bundle()
37 | fragment.arguments = bundle
38 | fragment.mTitle = title
39 | return fragment
40 | }
41 | }
42 |
43 | init {
44 | mPresenter.attachView(this)
45 | }
46 |
47 |
48 | override fun getLayoutId(): Int = R.layout.fragment_hot
49 |
50 |
51 | override fun lazyLoad() {
52 | mPresenter.getTabInfo()
53 | }
54 |
55 | override fun initView() {
56 |
57 | mLayoutStatusView = multipleStatusView
58 | //状态栏透明和间距处理
59 | activity?.let { StatusBarUtil.darkMode(it) }
60 | activity?.let { StatusBarUtil.setPaddingSmart(it, toolbar) }
61 | }
62 |
63 |
64 | override fun showLoading() {
65 | multipleStatusView.showLoading()
66 | }
67 |
68 | override fun dismissLoading() {
69 |
70 | }
71 |
72 | /**
73 | * 设置 TabInfo
74 | */
75 | override fun setTabInfo(tabInfoBean: TabInfoBean) {
76 | multipleStatusView.showContent()
77 |
78 | tabInfoBean.tabInfo.tabList.mapTo(mTabTitleList) { it.name }
79 | tabInfoBean.tabInfo.tabList.mapTo(mFragmentList) { RankFragment.getInstance(it.apiUrl) }
80 |
81 | mViewPager.adapter = BaseFragmentAdapter(childFragmentManager,mFragmentList,mTabTitleList)
82 | mTabLayout.setupWithViewPager(mViewPager)
83 |
84 | }
85 |
86 | override fun showError(errorMsg: String,errorCode:Int) {
87 | showToast(errorMsg)
88 | if (errorCode == ErrorStatus.NETWORK_ERROR) {
89 | multipleStatusView.showNoNetwork()
90 | } else {
91 | multipleStatusView.showError()
92 | }
93 | }
94 |
95 | override fun onDestroy() {
96 | super.onDestroy()
97 | mPresenter.detachView()
98 | }
99 |
100 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/fragment/MineFragment.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.fragment
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.view.View
6 | import com.hazz.kotlinmvp.R
7 | import com.hazz.kotlinmvp.base.BaseFragment
8 | import com.hazz.kotlinmvp.showToast
9 | import com.hazz.kotlinmvp.ui.activity.AboutActivity
10 | import com.hazz.kotlinmvp.ui.activity.ProfileHomePageActivity
11 | import com.hazz.kotlinmvp.ui.activity.WatchHistoryActivity
12 | import com.hazz.kotlinmvp.utils.StatusBarUtil
13 | import kotlinx.android.synthetic.main.fragment_mine.*
14 |
15 | /**
16 | * Created by xuhao on 2017/11/9.
17 | * 我的
18 | */
19 | class MineFragment : BaseFragment(),View.OnClickListener {
20 |
21 |
22 | private var mTitle:String? =null
23 |
24 |
25 | companion object {
26 | fun getInstance(title:String): MineFragment {
27 | val fragment = MineFragment()
28 | val bundle = Bundle()
29 | fragment.arguments = bundle
30 | fragment.mTitle = title
31 | return fragment
32 | }
33 | }
34 |
35 |
36 | override fun getLayoutId(): Int= R.layout.fragment_mine
37 |
38 | override fun initView() {
39 | //状态栏透明和间距处理
40 | activity?.let { StatusBarUtil.darkMode(it) }
41 | activity?.let { StatusBarUtil.setPaddingSmart(it, toolbar) }
42 |
43 | tv_view_homepage.setOnClickListener(this)
44 | iv_avatar.setOnClickListener(this)
45 | iv_about.setOnClickListener(this)
46 |
47 | tv_collection.setOnClickListener(this)
48 | tv_comment.setOnClickListener(this)
49 |
50 | tv_mine_message.setOnClickListener(this)
51 | tv_mine_attention.setOnClickListener(this)
52 | tv_mine_cache.setOnClickListener(this)
53 | tv_watch_history.setOnClickListener(this)
54 | tv_feedback.setOnClickListener(this)
55 |
56 |
57 | }
58 |
59 | override fun lazyLoad() {
60 |
61 | }
62 |
63 |
64 |
65 | override fun onClick(v: View?) {
66 | when{
67 | v?.id==R.id.iv_avatar|| v?.id==R.id.tv_view_homepage -> {
68 | val intent = Intent(activity, ProfileHomePageActivity::class.java)
69 | startActivity(intent)
70 | }
71 | v?.id==R.id.iv_about ->{
72 | val intent = Intent(activity, AboutActivity::class.java)
73 | startActivity(intent)
74 | }
75 | v?.id==R.id.tv_collection -> showToast("收藏")
76 | v?.id==R.id.tv_comment -> showToast("评论")
77 | v?.id==R.id.tv_mine_message -> showToast("我的消息")
78 | v?.id==R.id.tv_mine_attention -> showToast("我的关注")
79 | v?.id==R.id.tv_mine_attention -> showToast("我的缓存")
80 | v?.id==R.id.tv_watch_history -> startActivity(Intent(activity,WatchHistoryActivity::class.java))
81 | v?.id==R.id.tv_feedback -> showToast("意见反馈")
82 |
83 | }
84 | }
85 |
86 |
87 |
88 |
89 |
90 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/ui/fragment/RankFragment.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.ui.fragment
2 |
3 | import android.os.Bundle
4 | import android.support.v7.widget.LinearLayoutManager
5 | import com.hazz.kotlinmvp.R
6 | import com.hazz.kotlinmvp.base.BaseFragment
7 | import com.hazz.kotlinmvp.mvp.contract.RankContract
8 | import com.hazz.kotlinmvp.mvp.model.bean.HomeBean
9 | import com.hazz.kotlinmvp.mvp.presenter.RankPresenter
10 | import com.hazz.kotlinmvp.net.exception.ErrorStatus
11 | import com.hazz.kotlinmvp.showToast
12 | import com.hazz.kotlinmvp.ui.adapter.CategoryDetailAdapter
13 | import kotlinx.android.synthetic.main.fragment_rank.*
14 |
15 | /**
16 | * Created by xuhao on 2017/11/30.
17 | * desc:
18 | */
19 | class RankFragment : BaseFragment(), RankContract.View {
20 |
21 |
22 | private val mPresenter by lazy { RankPresenter() }
23 |
24 | private val mAdapter by lazy { activity?.let { CategoryDetailAdapter(it, itemList, R.layout.item_category_detail) } }
25 |
26 | private var itemList = ArrayList()
27 |
28 | private var apiUrl: String? = null
29 |
30 | companion object {
31 | fun getInstance(apiUrl: String): RankFragment {
32 | val fragment = RankFragment()
33 | val bundle = Bundle()
34 | fragment.arguments = bundle
35 | fragment.apiUrl = apiUrl
36 | return fragment
37 | }
38 | }
39 |
40 | init {
41 | mPresenter.attachView(this)
42 | }
43 |
44 |
45 | override fun getLayoutId(): Int = R.layout.fragment_rank
46 |
47 | override fun initView() {
48 | mRecyclerView.layoutManager = LinearLayoutManager(activity)
49 | mRecyclerView.adapter = mAdapter
50 |
51 | mLayoutStatusView =multipleStatusView
52 |
53 | }
54 |
55 | override fun lazyLoad() {
56 | if (!apiUrl.isNullOrEmpty()) {
57 | mPresenter.requestRankList(apiUrl!!)
58 | }
59 | }
60 |
61 | override fun showLoading() {
62 | multipleStatusView.showLoading()
63 | }
64 |
65 | override fun dismissLoading() {
66 |
67 | }
68 |
69 | override fun setRankList(itemList: ArrayList) {
70 | multipleStatusView.showContent()
71 |
72 | mAdapter?.addData(itemList)
73 | }
74 |
75 | override fun showError(errorMsg: String,errorCode:Int) {
76 | showToast(errorMsg)
77 | if (errorCode == ErrorStatus.NETWORK_ERROR) {
78 | multipleStatusView.showNoNetwork()
79 | } else {
80 | multipleStatusView.showError()
81 | }
82 | }
83 |
84 | override fun onDestroy() {
85 | super.onDestroy()
86 | mPresenter.detachView()
87 | }
88 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/utils/CleanLeakUtils.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.utils
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.view.inputmethod.InputMethodManager
6 | import com.orhanobut.logger.Logger
7 |
8 | import java.lang.reflect.Field
9 |
10 | /**
11 | * Created by xuhao on 2017/12/13.
12 | * desc:
13 | */
14 |
15 | object CleanLeakUtils {
16 |
17 | fun fixInputMethodManagerLeak(destContext: Context?) {
18 | if (destContext == null) {
19 | return
20 | }
21 | val inputMethodManager = destContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
22 |
23 | val viewArray = arrayOf("mCurRootView", "mServedView", "mNextServedView")
24 | var filed: Field
25 | var filedObject: Any?
26 |
27 | for (view in viewArray) {
28 | try {
29 | filed = inputMethodManager.javaClass.getDeclaredField(view)
30 | if (!filed.isAccessible) {
31 | filed.isAccessible = true
32 | }
33 | filedObject = filed.get(inputMethodManager)
34 | if (filedObject != null && filedObject is View) {
35 | val fileView = filedObject as View?
36 | if (fileView!!.context === destContext) { // 被InputMethodManager持有引用的context是想要目标销毁的
37 | filed.set(inputMethodManager, null) // 置空,破坏掉path to gc节点
38 | } else {
39 | break// 不是想要目标销毁的,即为又进了另一层界面了,不要处理,避免影响原逻辑,也就不用继续for循环了
40 | }
41 | }
42 | } catch (t: Throwable) {
43 | t.printStackTrace()
44 | }
45 |
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/utils/DisplayManager.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.utils
2 |
3 | import android.content.Context
4 | import android.util.DisplayMetrics
5 |
6 | /**
7 | * Created by xuhao on 2017/11/27.
8 | * desc:
9 | */
10 |
11 | object DisplayManager {
12 | init {
13 |
14 | }
15 |
16 | private var displayMetrics: DisplayMetrics? = null
17 |
18 | private var screenWidth: Int? = null
19 |
20 | private var screenHeight: Int? = null
21 |
22 | private var screenDpi: Int? = null
23 |
24 | fun init(context: Context) {
25 | displayMetrics = context.resources.displayMetrics
26 | screenWidth = displayMetrics?.widthPixels
27 | screenHeight = displayMetrics?.heightPixels
28 | screenDpi = displayMetrics?.densityDpi
29 | }
30 |
31 |
32 | //UI图的大小
33 | private const val STANDARD_WIDTH = 1080
34 | private const val STANDARD_HEIGHT = 1920
35 |
36 |
37 | fun getScreenWidth(): Int? {
38 | return screenWidth
39 | }
40 |
41 | fun getScreenHeight(): Int? {
42 | return screenHeight
43 | }
44 |
45 |
46 | /**
47 | * 传入UI图中问题的高度,单位像素
48 | * @param size
49 | * @return
50 | */
51 | fun getPaintSize(size: Int): Int? {
52 | return getRealHeight(size)
53 | }
54 |
55 | /**
56 | * 输入UI图的尺寸,输出实际的px
57 | *
58 | * @param px ui图中的大小
59 | * @return
60 | */
61 | fun getRealWidth(px: Int): Int? {
62 | //ui图的宽度
63 | return getRealWidth(px, STANDARD_WIDTH.toFloat())
64 | }
65 |
66 | /**
67 | * 输入UI图的尺寸,输出实际的px,第二个参数是父布局
68 | *
69 | * @param px ui图中的大小
70 | * @param parentWidth 父view在ui图中的高度
71 | * @return
72 | */
73 | fun getRealWidth(px: Int, parentWidth: Float): Int? {
74 | return (px / parentWidth * getScreenWidth()!!).toInt()
75 | }
76 |
77 | /**
78 | * 输入UI图的尺寸,输出实际的px
79 | *
80 | * @param px ui图中的大小
81 | * @return
82 | */
83 | fun getRealHeight(px: Int): Int? {
84 | //ui图的宽度
85 | return getRealHeight(px, STANDARD_HEIGHT.toFloat())
86 | }
87 |
88 | /**
89 | * 输入UI图的尺寸,输出实际的px,第二个参数是父布局
90 | *
91 | * @param px ui图中的大小
92 | * @param parentHeight 父view在ui图中的高度
93 | * @return
94 | */
95 | fun getRealHeight(px: Int, parentHeight: Float): Int? {
96 | return (px / parentHeight * getScreenHeight()!!).toInt()
97 | }
98 |
99 | /**
100 | * dip转px
101 | * @param dipValue
102 | * @return int
103 | */
104 | fun dip2px(dipValue: Float): Int? {
105 | val scale = displayMetrics?.density
106 | return (dipValue * scale!! + 0.5f).toInt()
107 | }
108 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/view/TabLayoutHelper.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.view
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Build
5 | import android.support.design.widget.TabLayout
6 | import android.widget.LinearLayout
7 | import com.hazz.kotlinmvp.utils.DisplayManager
8 | import java.lang.reflect.Field
9 |
10 | /**
11 | * Created by xuhao on 2017/12/7.
12 | * desc:
13 | */
14 | object TabLayoutHelper{
15 |
16 | @SuppressLint("ObsoleteSdkInt")
17 | fun setUpIndicatorWidth(tabLayout: TabLayout) {
18 | val tabLayoutClass = tabLayout.javaClass
19 | var tabStrip: Field? = null
20 | try {
21 | tabStrip = tabLayoutClass.getDeclaredField("mTabStrip")
22 | tabStrip!!.isAccessible = true
23 | } catch (e: NoSuchFieldException) {
24 | e.printStackTrace()
25 | }
26 |
27 | var layout: LinearLayout? = null
28 | try {
29 | if (tabStrip != null) {
30 | layout = tabStrip.get(tabLayout) as LinearLayout
31 | }
32 | for (i in 0 until layout!!.childCount) {
33 | val child = layout.getChildAt(i)
34 | child.setPadding(0, 0, 0, 0)
35 | val params = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f)
36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
37 | params.marginStart = DisplayManager.dip2px(50f)!!
38 | params.marginEnd = DisplayManager.dip2px(50f)!!
39 | }
40 | child.layoutParams = params
41 | child.invalidate()
42 | }
43 | } catch (e: IllegalAccessException) {
44 | e.printStackTrace()
45 | }
46 |
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/view/ViewAnimUtils.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.view
2 |
3 | import android.animation.Animator
4 | import android.animation.AnimatorListenerAdapter
5 | import android.annotation.TargetApi
6 | import android.content.Context
7 | import android.os.Build
8 | import android.support.annotation.ColorRes
9 | import android.support.annotation.RequiresApi
10 | import android.support.v4.content.ContextCompat
11 | import android.view.View
12 | import android.view.ViewAnimationUtils
13 | import android.view.animation.AccelerateDecelerateInterpolator
14 |
15 | /**
16 | * Created by xuhao on 2017/12/1.
17 | * desc: View 动画工具类
18 | */
19 |
20 | object ViewAnimUtils {
21 |
22 | interface OnRevealAnimationListener {
23 | fun onRevealHide()
24 |
25 | fun onRevealShow()
26 | }
27 |
28 |
29 |
30 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
31 | fun animateRevealShow(
32 | context: Context, view: View,
33 | startRadius: Int, @ColorRes color: Int,
34 | listener: OnRevealAnimationListener) {
35 | val cx = (view.left + view.right) / 2
36 | val cy = (view.top + view.bottom) / 2
37 |
38 | val finalRadius = Math.hypot(view.width.toDouble(), view.height.toDouble()).toFloat()
39 |
40 | // 设置圆形显示动画
41 | val anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, startRadius.toFloat(), finalRadius)
42 | anim.duration = 300
43 | anim.interpolator = AccelerateDecelerateInterpolator()
44 | anim.addListener(object : AnimatorListenerAdapter() {
45 | override fun onAnimationEnd(animation: Animator) {
46 | super.onAnimationEnd(animation)
47 | view.visibility = View.VISIBLE
48 | listener.onRevealShow()
49 | }
50 |
51 | override fun onAnimationStart(animation: Animator) {
52 | super.onAnimationStart(animation)
53 | view.setBackgroundColor(ContextCompat.getColor(context, color))
54 | }
55 | })
56 |
57 | anim.start()
58 | }
59 |
60 | // 圆圈凝聚效果
61 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
62 | fun animateRevealHide(
63 | context: Context, view: View,
64 | finalRadius: Int, @ColorRes color: Int,
65 | listener: OnRevealAnimationListener
66 | ) {
67 | val cx = (view.left + view.right) / 2
68 | val cy = (view.top + view.bottom) / 2
69 | val initialRadius = view.width
70 | // 与入场动画的区别就是圆圈起始和终止的半径相反
71 | val anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius.toFloat(), finalRadius.toFloat())
72 | anim.duration = 300
73 | anim.interpolator = AccelerateDecelerateInterpolator()
74 | anim.addListener(object : AnimatorListenerAdapter() {
75 | override fun onAnimationStart(animation: Animator) {
76 | super.onAnimationStart(animation)
77 | view.setBackgroundColor(ContextCompat.getColor(context, color))
78 | }
79 |
80 | override fun onAnimationEnd(animation: Animator) {
81 | super.onAnimationEnd(animation)
82 | listener.onRevealHide()
83 | view.visibility = View.INVISIBLE
84 | }
85 | })
86 | anim.start()
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/view/recyclerview/MultipleType.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.view.recyclerview
2 |
3 | /**
4 | * Created by xuhao on 2017/11/22.
5 | * desc: 多布局条目类型
6 | */
7 |
8 | interface MultipleType {
9 | fun getLayoutId(item: T, position: Int): Int
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/view/recyclerview/ViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.view.recyclerview
2 |
3 | import android.annotation.SuppressLint
4 | import android.support.v7.widget.RecyclerView
5 | import android.util.SparseArray
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.ImageView
9 | import android.widget.TextView
10 |
11 | @Suppress("UNCHECKED_CAST")
12 | /**
13 | * Created by xuhao on 2017/11/22.
14 | * desc:
15 | */
16 |
17 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
18 |
19 | //用于缓存已找的界面
20 | private var mView: SparseArray?=null
21 |
22 | init {
23 | mView = SparseArray()
24 | }
25 |
26 | fun getView(viewId: Int): T {
27 | //对已有的view做缓存
28 | var view: View? = mView?.get(viewId)
29 | //使用缓存的方式减少findViewById的次数
30 | if (view == null) {
31 | view = itemView.findViewById(viewId)
32 | mView?.put(viewId, view)
33 | }
34 | return view as T
35 | }
36 |
37 |
38 | fun getViewGroup(viewId: Int): T {
39 | //对已有的view做缓存
40 | var view: View? = mView?.get(viewId)
41 | //使用缓存的方式减少findViewById的次数
42 | if (view == null) {
43 | view = itemView.findViewById(viewId)
44 | mView?.put(viewId, view)
45 | }
46 | return view as T
47 | }
48 |
49 | @SuppressLint("SetTextI18n")
50 | //通用的功能进行封装 设置文本 设置条目点击事件 设置图片
51 | fun setText(viewId: Int, text: CharSequence): ViewHolder {
52 | val view = getView(viewId)
53 | view.text = "" + text
54 | //希望可以链式调用
55 | return this
56 | }
57 |
58 | fun setHintText(viewId: Int, text: CharSequence): ViewHolder {
59 | val view = getView(viewId)
60 | view.hint = "" + text
61 | return this
62 | }
63 |
64 | /**
65 | * 设置本地图片
66 | *
67 | * @param viewId
68 | * @param resId
69 | * @return
70 | */
71 | fun setImageResource(viewId: Int, resId: Int): ViewHolder {
72 | val iv = getView(viewId)
73 | iv.setImageResource(resId)
74 | return this
75 | }
76 |
77 | /**
78 | * 加载图片资源路径
79 | *
80 | * @param viewId
81 | * @param imageLoader
82 | * @return
83 | */
84 | fun setImagePath(viewId: Int, imageLoader: HolderImageLoader): ViewHolder {
85 | val iv = getView(viewId)
86 | imageLoader.loadImage(iv, imageLoader.path)
87 | return this
88 | }
89 |
90 | abstract class HolderImageLoader(val path: String) {
91 |
92 | /**
93 | * 需要去复写这个方法加载图片
94 | *
95 | * @param iv
96 | * @param path
97 | */
98 | abstract fun loadImage(iv: ImageView, path: String)
99 | }
100 |
101 | /**
102 | * 设置View的Visibility
103 | */
104 | fun setViewVisibility(viewId: Int, visibility: Int): ViewHolder {
105 | getView(viewId).visibility = visibility
106 | return this
107 | }
108 |
109 | /**
110 | * 设置条目点击事件
111 | */
112 | fun setOnItemClickListener(listener: View.OnClickListener) {
113 | itemView.setOnClickListener(listener)
114 | }
115 |
116 | /**
117 | * 设置条目长按事件
118 | */
119 | fun setOnItemLongClickListener(listener: View.OnLongClickListener) {
120 | itemView.setOnLongClickListener(listener)
121 | }
122 |
123 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/view/recyclerview/adapter/CommonAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.view.recyclerview.adapter
2 |
3 | import android.content.Context
4 | import android.support.v7.widget.RecyclerView
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 |
9 | import com.hazz.kotlinmvp.view.recyclerview.MultipleType
10 | import com.hazz.kotlinmvp.view.recyclerview.ViewHolder
11 |
12 | /**
13 | * Created by xuhao on 2017/11/22.
14 | * desc: 通用的 Adapter
15 | */
16 |
17 | abstract class CommonAdapter(var mContext: Context, var mData: ArrayList, //条目布局
18 | private var mLayoutId: Int) : RecyclerView.Adapter() {
19 | protected var mInflater: LayoutInflater? = null
20 | private var mTypeSupport: MultipleType? = null
21 |
22 | //使用接口回调点击事件
23 | private var mItemClickListener: OnItemClickListener? = null
24 |
25 | //使用接口回调点击事件
26 | private var mItemLongClickListener: OnItemLongClickListener? = null
27 |
28 | init {
29 | mInflater = LayoutInflater.from(mContext)
30 | }
31 |
32 | //需要多布局
33 | constructor(context: Context, data: ArrayList, typeSupport: MultipleType) : this(context, data, -1) {
34 | this.mTypeSupport = typeSupport
35 | }
36 |
37 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
38 | if (mTypeSupport != null) {
39 | //需要多布局
40 | mLayoutId = viewType
41 | }
42 | //创建view
43 | val view = mInflater?.inflate(mLayoutId, parent, false)
44 | return ViewHolder(view!!)
45 | }
46 |
47 | override fun getItemViewType(position: Int): Int {
48 | //多布局问题
49 | return mTypeSupport?.getLayoutId(mData[position], position) ?: super.getItemViewType(position)
50 | }
51 |
52 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
53 | //绑定数据
54 | bindData(holder, mData[position], position)
55 |
56 | // if (mItemClickListener != null) {
57 | // holder.itemView.setOnClickListener { mItemClickListener!!.onItemClick(mData[position], position) }
58 | // }
59 | // //长按点击事件
60 | // if (mItemLongClickListener != null) {
61 | // holder.itemView.setOnLongClickListener { mItemLongClickListener!!.onItemLongClick(mData[position], position) }
62 | // }
63 | //条目点击事件
64 | mItemClickListener?.let {
65 | holder.itemView.setOnClickListener { mItemClickListener!!.onItemClick(mData[position], position) }
66 | }
67 |
68 | //长按点击事件
69 | mItemLongClickListener?.let {
70 | holder.itemView.setOnLongClickListener { mItemLongClickListener!!.onItemLongClick(mData[position], position) }
71 | }
72 | }
73 |
74 | /**
75 | * 将必要参数传递出去
76 | *
77 | * @param holder
78 | * @param data
79 | * @param position
80 | */
81 | protected abstract fun bindData(holder: ViewHolder, data: T, position: Int)
82 |
83 | override fun getItemCount(): Int {
84 | return mData.size
85 | }
86 |
87 | fun setOnItemClickListener(itemClickListener: OnItemClickListener) {
88 | this.mItemClickListener = itemClickListener
89 | }
90 |
91 | fun setOnItemLongClickListener(itemLongClickListener: OnItemLongClickListener) {
92 | this.mItemLongClickListener = itemLongClickListener
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/view/recyclerview/adapter/OnItemClickListener.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.view.recyclerview.adapter
2 |
3 | /**
4 | * Created by Xiho on 2017/2/23.
5 | * Description: Adapter条目的点击事件
6 | */
7 | interface OnItemClickListener {
8 |
9 | fun onItemClick(obj: Any?, position: Int)
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/hazz/kotlinmvp/view/recyclerview/adapter/OnItemLongClickListener.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp.view.recyclerview.adapter
2 |
3 | /**
4 | *
5 | * Description: Adapter条目的长按事件
6 | */
7 | interface OnItemLongClickListener {
8 |
9 | fun onItemLongClick(obj: Any?, position: Int): Boolean
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/anim_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/anim_out.xml:
--------------------------------------------------------------------------------
1 |
4 |
8 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/push_bottom_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/push_bottom_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/placeholder_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/drawable-xxhdpi/placeholder_banner.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bc_background_panel.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_radius_black_border_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_radius_normal_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_radius_theme_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_radius_theme_border_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/et_cursor.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/et_round_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progressbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_bg_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_btn_blue.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_corner_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_corner_bg_small.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_number_indicator_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
12 |
13 |
18 |
19 |
20 |
26 |
27 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
16 |
17 |
23 |
24 |
33 |
34 |
35 |
36 |
46 |
47 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_video_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
16 |
17 |
20 |
21 |
26 |
27 |
32 |
33 |
38 |
39 |
40 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_hot.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
18 |
19 |
29 |
30 |
31 |
32 |
42 |
46 |
47 |
57 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_rank.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_cardview.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
19 |
20 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_category_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
14 |
15 |
19 |
20 |
25 |
26 |
36 |
37 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_flow_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_follow.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
21 |
22 |
31 |
32 |
40 |
41 |
48 |
49 |
50 |
65 |
66 |
67 |
68 |
73 |
74 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_follow_horizontal.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
18 |
19 |
28 |
29 |
38 |
39 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_home_banner.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_home_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
16 |
19 |
20 |
28 |
29 |
38 |
39 |
47 |
48 |
54 |
55 |
56 |
64 |
65 |
66 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_home_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_video_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_video_small_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
16 |
26 |
27 |
28 |
34 |
35 |
44 |
45 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_video_text_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
18 |
19 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_about_me.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_empty_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_error_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_load_footer_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_loading_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_network_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_recyclerview.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_refresh_header_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_video_tag_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
14 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_watch_history.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
35 |
36 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/default_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/default_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_about.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_clear.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_collection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_collection.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_comment.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_down_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_down_white.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_favorites.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_favorites.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_more_arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_more_arrow.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_more_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_more_black.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_offline.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_reply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_reply.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_search_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_search_black.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_search_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_search_small.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_search_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_search_white.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_share.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_action_up_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_action_up_white.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_discovery_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_discovery_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_discovery_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_discovery_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_error.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_home_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_home_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_home_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_home_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_hot_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_hot_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_hot_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_hot_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_mine_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_mine_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_mine_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_mine_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_no_data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_no_data.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_no_network.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/ic_no_network.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/img_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/img_avatar.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/img_profile_head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/img_profile_head.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/img_splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/img_splash.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/list_load_more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/list_load_more.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/web_hi_res_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xhdpi/web_hi_res_512.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/transition-v21/arc_motion.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v19/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #549cf8
5 | #EF5362
6 |
7 | #9a9a9a
8 |
9 | #5000
10 |
11 |
12 | #EF5362
13 | #FE6D4B
14 | #FFCF47
15 | #9FD661
16 | #3FD0AD
17 | #2BBDF3
18 | #00b0ff
19 | #AC8FEF
20 | #EE85C1
21 |
22 | #ff4081
23 | #dd2c00
24 | #ee447AA4
25 |
26 |
27 |
28 |
29 |
30 | #CCFFFFFF
31 |
32 | #EEEEEE
33 |
34 |
35 | #FFFFFF
36 | #000000
37 |
38 | #87CEEB
39 |
40 |
41 | #000000
42 |
43 | #ddd
44 | #aaa
45 |
46 | @color/color_lighter_gray
47 |
48 | #00000000
49 |
50 | #7FFFD4
51 |
52 | #5000
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 | 51dp
4 |
5 |
6 | 10dp
7 | 15dp
8 | 10dp
9 | 5dp
10 |
11 | 10sp
12 | 12sp
13 | 14sp
14 | 16sp
15 | 18sp
16 |
17 | 0.5dp
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Kotlin Mvp
3 |
4 | 缓存
5 | + 关注
6 | - The End-
7 |
8 | 全部分类
9 | 人气榜
10 | 关于
11 |
12 | transition_reveal
13 | 帮你找到感兴趣的视频
14 | 输入标题或描述中的关键词找到更多视频
15 | - 热门搜索词 -
16 | -「%1$s」搜索结果共%2$d个-
17 |
18 |
19 | 取消
20 |
21 | Xiho
22 | 查看个人主页 >
23 |
24 | 收藏
25 | 评论
26 | 我的消息
27 | 我的关注
28 | 我的缓存
29 | 观看记录
30 | 意见反馈
31 |
32 |
33 |
34 | 加载中…
35 | 请检查网络后点击重新加载
36 | 数据获取失败(ㄒoㄒ)~~
37 | 暂时木有内容呀~~
38 | 每日精选视频,让你大开眼界
39 |
40 |
41 | 内容部分数据归原公司《开眼Eyepetizer》版权所有
42 | 本APP只供学习交流和研究之用,\n请勿用作商业用途!
43 | copyright ©2017 Xiho.
44 | GitHub
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
34 |
35 |
36 |
40 |
41 |
48 |
49 |
55 |
56 |
57 |
64 |
65 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/test/java/com/hazz/kotlinmvp/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.hazz.kotlinmvp
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | apply from: "config.gradle"
3 | buildscript {
4 | ext.kotlin_version = '1.3.20'
5 | repositories {
6 | google()
7 | mavenCentral()
8 | jcenter()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.3.1'
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 | mavenCentral()
24 | maven {
25 | url "https://jitpack.io"
26 | }
27 | }
28 |
29 | }
30 |
31 | task clean(type: Delete) {
32 | delete rootProject.buildDir
33 | }
34 |
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | ext{
2 |
3 | android = [
4 | compileSdkVersion: 27,
5 | buildToolsVersion: "27.0.3",
6 | minSdkVersion : 19,
7 | targetSdkVersion : 27,
8 | versionCode : 6,
9 | versionName : "1.3.0"
10 | ]
11 |
12 | dependVersion = [
13 | androidSupportSdkVersion: "27.1.1",
14 | retrofitSdkVersion : "2.3.0",
15 | glideSdkVersion : "4.7.1",
16 | rxJava : "2.1.5",
17 | rxAndroid : "2.0.1"
18 | ]
19 |
20 | supportDeps = [
21 | //-------- support -------
22 | supportv4 : "com.android.support:support-v4:$dependVersion.androidSupportSdkVersion",
23 | appcompatv7 : "com.android.support:appcompat-v7:$dependVersion.androidSupportSdkVersion",
24 | cardview : "com.android.support:cardview-v7:$dependVersion.androidSupportSdkVersion",
25 | design : "com.android.support:design:$dependVersion.androidSupportSdkVersion",
26 | annotations : "com.android.support:support-annotations:$dependVersion.androidSupportSdkVersion"
27 | ]
28 |
29 |
30 | retrofit = [
31 | //------ retrofit和RxJava ---------
32 | retrofit : "com.squareup.retrofit2:retrofit:$dependVersion.retrofitSdkVersion",
33 | retrofitConverterGson : "com.squareup.retrofit2:converter-gson:$dependVersion.retrofitSdkVersion",
34 | retrofitAdapterRxjava2 : "com.squareup.retrofit2:adapter-rxjava2:$dependVersion.retrofitSdkVersion",
35 | okhttp3LoggerInterceptor: 'com.squareup.okhttp3:logging-interceptor:3.4.1'
36 | ]
37 |
38 | rxJava = [
39 | rxJava : "io.reactivex.rxjava2:rxjava:$dependVersion.rxJava",
40 | rxAndroid : "io.reactivex.rxjava2:rxandroid:$dependVersion.rxAndroid"
41 | ]
42 |
43 |
44 |
45 |
46 | glide = "com.github.bumptech.glide:glide:$dependVersion.glideSdkVersion"
47 | glideCompiler = "com.github.bumptech.glide:compiler:$dependVersion.glideSdkVersion"
48 | glideOkhttp = "com.github.bumptech.glide:okhttp3-integration:$dependVersion.glideSdkVersion"
49 |
50 |
51 | supportLibs = supportDeps.values()
52 | networkLibs = retrofit.values()
53 | rxJavaLibs = rxJava.values()
54 | otherLibs = [glide]
55 |
56 | // APT
57 | annotationProcessorLibs =[glideCompiler]
58 |
59 |
60 |
61 |
62 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Mar 07 17:29:24 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/ktmp.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/ktmp.jks
--------------------------------------------------------------------------------
/multiple-status-view/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | *.iml
--------------------------------------------------------------------------------
/multiple-status-view/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 |
5 | compileSdkVersion rootProject.ext.android.compileSdkVersion
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.android.minSdkVersion
9 | targetSdkVersion rootProject.ext.android.targetSdkVersion
10 | versionCode rootProject.ext.android.versionCode
11 | versionName rootProject.ext.android.versionName
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies { }
23 |
--------------------------------------------------------------------------------
/multiple-status-view/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\AndroidStudio\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/layout/empty_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/layout/error_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/layout/loading_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/layout/no_network_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | multiple-status-view
3 |
4 | 暂无数据
5 | 加载失败
6 | 网络异常
7 |
8 |
--------------------------------------------------------------------------------
/multiple-status-view/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
--------------------------------------------------------------------------------
/screenshot/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/01.png
--------------------------------------------------------------------------------
/screenshot/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/02.png
--------------------------------------------------------------------------------
/screenshot/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/03.png
--------------------------------------------------------------------------------
/screenshot/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/04.png
--------------------------------------------------------------------------------
/screenshot/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/05.png
--------------------------------------------------------------------------------
/screenshot/06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/06.png
--------------------------------------------------------------------------------
/screenshot/07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/07.png
--------------------------------------------------------------------------------
/screenshot/08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/08.png
--------------------------------------------------------------------------------
/screenshot/09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/09.png
--------------------------------------------------------------------------------
/screenshot/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/10.png
--------------------------------------------------------------------------------
/screenshot/kotlin-mvp-1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/git-xuhao/KotlinMvp/7b55819ca1ca026002463c0003b2638903727efc/screenshot/kotlin-mvp-1.gif
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':multiple-status-view'
2 |
--------------------------------------------------------------------------------