├── .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 | 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 | 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 | --------------------------------------------------------------------------------