├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ ├── avoscloud-feedback-v3.14.9.jar │ ├── avoscloud-sdk-v3.14.2.jar │ ├── fastjson.jar │ ├── httpmime-4.2.4.jar │ ├── okhttp-2.6.0-leancloud.jar │ └── okio-1.6.0-leancloud.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── pub │ │ └── kanzhibo │ │ └── app │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── pub │ │ │ └── kanzhibo │ │ │ └── app │ │ │ ├── App.java │ │ │ ├── api │ │ │ ├── ApiClient.java │ │ │ ├── ILiveApi.java │ │ │ └── RxSchedulers.java │ │ │ ├── base │ │ │ ├── BaseActivity.java │ │ │ ├── BaseFragment.java │ │ │ ├── BaseLceActivity.java │ │ │ ├── BaseLceFragment.java │ │ │ ├── BaseResponse.java │ │ │ ├── BaseRxLcePresenter.java │ │ │ └── BaseSearchPresent.java │ │ │ ├── common │ │ │ ├── CommonActivity.java │ │ │ ├── EmptyException.java │ │ │ ├── WebViewActivity.java │ │ │ └── widget │ │ │ │ ├── RoundImageView.java │ │ │ │ ├── SwipeRefreshLoadMoreLayout.java │ │ │ │ └── ToggleButton.java │ │ │ ├── douyu │ │ │ ├── FollowFragment.java │ │ │ ├── FollowPresenter.java │ │ │ ├── FollowUserAdapter.java │ │ │ └── FollowView.java │ │ │ ├── global │ │ │ └── Constants.java │ │ │ ├── login │ │ │ ├── LoginFragment.java │ │ │ ├── LoginPresenter.java │ │ │ └── LoginView.java │ │ │ ├── main │ │ │ ├── LivePresent.java │ │ │ ├── LiveUserAdapter.java │ │ │ ├── LiveUserFragment.java │ │ │ ├── LiveView.java │ │ │ └── MainActivity.java │ │ │ ├── model │ │ │ ├── BaseResponse.java │ │ │ ├── DouyuBigData.java │ │ │ ├── DouyuFollowLiveData.java │ │ │ ├── FollowLive.java │ │ │ ├── PlatForm.java │ │ │ ├── QuanminJsonRequest.java │ │ │ ├── UserInfo.java │ │ │ ├── event │ │ │ │ ├── DouyuLoginEvent.java │ │ │ │ ├── FollowEvent.java │ │ │ │ ├── LoginEvent.java │ │ │ │ ├── RegisterEvent.java │ │ │ │ └── SearchEvent.java │ │ │ ├── roominfo │ │ │ │ ├── DouYuUserInfo.java │ │ │ │ ├── HuyaOffUserInfo.java │ │ │ │ ├── HuyaUserInfo.java │ │ │ │ ├── PandaUserInfo.java │ │ │ │ └── ZhanqiUserInfo.java │ │ │ └── searchliveuser │ │ │ │ ├── LiveUser.java │ │ │ │ ├── LiveUserDouYu.java │ │ │ │ ├── LiveUserPanda.java │ │ │ │ ├── LiveUserPanda_Old.java │ │ │ │ ├── LiveUserQuanmin.java │ │ │ │ ├── LiveUserZhanqi.java │ │ │ │ ├── UserHuyaLive.java │ │ │ │ └── UserHuyaPlay.java │ │ │ ├── register │ │ │ ├── RegisterFragment.java │ │ │ ├── RegisterPresenter.java │ │ │ └── RegisterView.java │ │ │ ├── search │ │ │ ├── SearchActivity.java │ │ │ ├── SearchUserFragment.java │ │ │ ├── SearchView.java │ │ │ └── present │ │ │ │ ├── DouyuSearchPresent.java │ │ │ │ ├── HuyaSearchPresent.java │ │ │ │ ├── PandaSearchPresent.java │ │ │ │ ├── QuanminSearchPresent.java │ │ │ │ └── ZhanqiSearchPresent.java │ │ │ └── util │ │ │ ├── CommonUtil.java │ │ │ ├── DialogHelp.java │ │ │ ├── ResUtil.java │ │ │ ├── SharedPreferencesUtils.java │ │ │ ├── StringUtils.java │ │ │ └── VersionUtils.java │ └── res │ │ ├── anim │ │ └── anim_bottom_in.xml │ │ ├── drawable-v21 │ │ ├── ic_menu_camera.xml │ │ ├── ic_menu_gallery.xml │ │ ├── ic_menu_manage.xml │ │ ├── ic_menu_send.xml │ │ ├── ic_menu_share.xml │ │ └── ic_menu_slideshow.xml │ │ ├── drawable │ │ ├── avoscloud_feedback_actionbar_background.xml │ │ ├── avoscloud_feedback_thread_actionbar_back.png │ │ ├── empty_bike.xml │ │ ├── live_status_backgroud.xml │ │ └── side_nav_bar.xml │ │ ├── layout │ │ ├── activity_common.xml │ │ ├── activity_main.xml │ │ ├── activity_search.xml │ │ ├── activity_webview.xml │ │ ├── app_bar_main.xml │ │ ├── avoscloud_feedback_activity_conversation.xml │ │ ├── avoscloud_feedback_dev_reply.xml │ │ ├── avoscloud_feedback_thread_actionbar.xml │ │ ├── avoscloud_feedback_user_reply.xml │ │ ├── common_toolbar.xml │ │ ├── content_main.xml │ │ ├── fragment_follow.xml │ │ ├── fragment_liveuser_list.xml │ │ ├── fragment_login.xml │ │ ├── fragment_register.xml │ │ ├── item_follow_user.xml │ │ ├── item_fragment_live_user.xml │ │ ├── nav_header_main.xml │ │ ├── view_error.xml │ │ └── view_loading.xml │ │ ├── menu │ │ ├── activity_main_drawer.xml │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── avoscloud_feedback_dev_reply_background.9.png │ │ ├── avoscloud_feedback_notification.9.png │ │ ├── avoscloud_feedback_thread_actionbar_back.png │ │ ├── avoscloud_feedback_user_reply_background.9.png │ │ ├── ic_action_return.png │ │ ├── ic_action_return_white.png │ │ ├── ic_action_sahre_white.png │ │ ├── ic_actionbar_menu.png │ │ ├── ic_actionbar_menu_more.png │ │ ├── ic_actionbar_menu_more_white.png │ │ ├── ic_actionbar_menu_white.png │ │ ├── ic_actionbar_search.png │ │ ├── ic_actionbar_search_white.png │ │ ├── ic_close_actioncard.png │ │ ├── ic_launcher.png │ │ ├── out_1.png │ │ ├── out_10.png │ │ ├── out_11.png │ │ ├── out_12.png │ │ ├── out_13.png │ │ ├── out_14.png │ │ ├── out_15.png │ │ ├── out_16.png │ │ ├── out_17.png │ │ ├── out_18.png │ │ ├── out_19.png │ │ ├── out_2.png │ │ ├── out_20.png │ │ ├── out_21.png │ │ ├── out_22.png │ │ ├── out_23.png │ │ ├── out_24.png │ │ ├── out_25.png │ │ ├── out_26.png │ │ ├── out_3.png │ │ ├── out_4.png │ │ ├── out_5.png │ │ ├── out_6.png │ │ ├── out_7.png │ │ ├── out_8.png │ │ ├── out_9.png │ │ └── room_backgroud_default.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── drawables.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── pub │ └── kanzhibo │ └── app │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.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 | .idea 11 | */build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | >虎牙的数据也搞完了,但是请求那有点乱,应该是可以写的更赞一点的。待更。 2 | 3 | >里面集成了bugly 4 | bugly地址:https://bugly.qq.com 5 | 在bugly注册了然后在Application里面修改下bugly id就可以直接使用,当然,你如果嫌麻烦可以直接发我下邮件,把你添加到管理员里,反正我已经注册了。 6 | 7 | # 看直播 8 | 9 | 聚集了斗鱼,熊猫,全民,虎牙和战旗5个平台的搜索接口,用leancloud保存关注的直播房间列表。 10 | 其实就是最近学了不少东西,想练习下,嗯,基本上能用到的都用到了,话说mosby真的是个非常好的mvp框架,rxjava+retrofit也是屌的不行,当然,也在逐渐摸索中,一个操作符就能炸的我半天晕晕乎乎的。 11 | 12 | ### TODO 13 | - [ ] 使用realm保存数据到本地 14 | - [ ] 关注的直播开播推送提醒 15 | - [ ] 6.0以上的权限管理 16 | - [ ] 搜索的优化 17 | - [ ] 使用tinker进行热修复 18 | - [ ] 美化意见反馈页面 19 | 20 | 21 | ---- 22 | ![](http://ww1.sinaimg.cn/mw690/735ac53bjw1f9jv2vj8g6j21po25s7wh.jpg) 23 | ---- 24 | 25 | ### 感谢 26 | - [@张鸿洋][7] 27 | - [@扔物线][8] 28 | - [@drakeet][9] 29 | - [@代码家][10] 30 | - [@小鄧子][12] 31 | - [@Jude95][13] 32 | - [@泡在网上编代码][14] 33 | - [@Freelander][6] 34 | - [@xcc3641][5] 35 | 36 | [5]:https://github.com/xcc3641/SeeWeather 37 | [6]:https://github.com/Freelander/Elephant 38 | [7]: https://github.com/hongyangAndroid 39 | [8]: https://github.com/rengwuxian 40 | [9]: https://github.com/drakeet 41 | [10]: https://github.com/daimajia 42 | [12]: https://github.com/SmartDengg 43 | [13]: https://github.com/Jude95 44 | [14]: http://weibo.com/u/2711441293?topnav=1&wvr=6&topsug=1&is_all=1 45 | 46 | 47 | ## Third-party Libraries 48 | 49 | Project | Introduction 50 | -------- | ------ 51 | [bugly](https://bugly.qq.com) | 崩溃收集,超级好用 52 | [AndroidAutoLayout](https://github.com/hongyangAndroid/AndroidAutoLayout) | 屏幕适配 53 | [RxJava](https://github.com/ReactiveX/RxJava) | RxJava is a Java VM implementation of Reactive Extensions 54 | [RxAndroid](https://github.com/ReactiveX/RxAndroid) | Android specific bindings for RxJava 55 | [Retrofit](https://github.com/square/retrofit) | Type-safe HTTP client for Android and Java by Square 56 | [leakcanary](https://github.com/square/leakcanary) | A memory leak detection library for Android and Java. 57 | [BaseRecyclerViewAdapterHelper](https://github.com/CymChad/BaseRecyclerViewAdapterHelper) | Powerful and flexible RecyclerAdapter 58 | [Gson](https://github.com/google/gson) | Gson is a Java library that can be used to convert Java Objects into their JSON representation 59 | [glide](https://github.com/bumptech/glide) | An image loading and caching library for Android focused on smooth scrolling. 60 | [butterknife](https://github.com/JakeWharton/butterknife) | Bind Android views and callbacks to fields and methods 61 | [android-Ultra-Pull-To-Refresh-With-Load-More](https://github.com/captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More) | This is a modification of the [Ultra-Pull-to-Refresh](https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh) library which supports load-more for any view 62 | [mosby](https://github.com/sockeqwe/mosby) | this library help you build modern android apps with a clean Model-View-Presenter architecture 63 | 64 | ## License 65 | 66 | Copyright 2016 Freelander 67 | 68 | Licensed under the [Apache License2.0](https://github.com/Freelander/Elephant/blob/master/LICENSE) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'android-apt' 3 | apply plugin: 'realm-android' 4 | 5 | android { 6 | compileSdkVersion 25 7 | buildToolsVersion "24.0.3" 8 | defaultConfig { 9 | applicationId "pub.kanzhibo.app" 10 | minSdkVersion 18 11 | targetSdkVersion 24 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | ndk { 16 | //设置支持的cpu 17 | abiFilters 'armeabi', 'armeabi-v7a'//, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a' 18 | } 19 | } 20 | 21 | aaptOptions { 22 | cruncherEnabled = false 23 | } 24 | dexOptions { 25 | jumboMode true 26 | } 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | } 32 | } 33 | packagingOptions { 34 | exclude 'META-INF/DEPENDENCIES' 35 | exclude 'META-INF/LICENSE' 36 | exclude 'META-INF/LICENSE.txt' 37 | exclude 'META-INF/license.txt' 38 | exclude 'META-INF/NOTICE' 39 | exclude 'META-INF/NOTICE.txt' 40 | exclude 'META-INF/notice.txt' 41 | exclude 'META-INF/ASL2.0' 42 | } 43 | lintOptions { 44 | abortOnError false 45 | } 46 | splits { 47 | abi { 48 | enable true 49 | reset() 50 | include 'armeabi', 'armeabi-v7a' 51 | universalApk false 52 | } 53 | } 54 | signingConfigs { 55 | release { 56 | storeFile file("demo.jks") 57 | storePassword "test123" 58 | keyAlias "test123" 59 | keyPassword "test123" 60 | } 61 | } 62 | } 63 | 64 | dependencies { 65 | compile fileTree(dir: 'libs', include: ['*.jar']) 66 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 67 | exclude group: 'com.android.support', module: 'support-annotations' 68 | }) 69 | //图片加载 70 | // compile 'com.facebook.fresco:fresco:0.12.0' 71 | //bug收集反馈,听说bugly正在内测热修复 72 | //可以用eventbus,也可以用这个 73 | //View注入 74 | //网络请求 75 | //啥都不说了 76 | //屏幕适配 77 | //沉浸式标题栏 78 | //mvp library 79 | //oom检测,必备 80 | //简化Adapter书写并且提供了各种事件处理 81 | //saving and restoring activity or fragment instance state 82 | // compile "frankiesardo:icepick:3.2.0" 83 | // compile "frankiesardo:icepick-processor:3.2.0" 84 | compile 'com.android.support:appcompat-v7:24.2.1' 85 | compile 'com.android.support:design:24.2.1' 86 | compile 'com.android.support:support-v4:24.2.1' 87 | compile 'com.android.support:recyclerview-v7:24.2.1' 88 | compile 'com.android.support:cardview-v7:24.2.1' 89 | compile 'com.github.bumptech.glide:glide:3.7.0' 90 | compile 'com.tencent.bugly:crashreport:latest.release' 91 | compile 'com.tencent.bugly:nativecrashreport:latest.release' 92 | compile 'com.hwangjr.rxbus:rxbus:1.0.4' 93 | compile 'com.jakewharton:butterknife:8.4.0' 94 | compile 'com.squareup.retrofit2:retrofit:2.1.0' 95 | compile 'com.squareup.retrofit2:converter-gson:2.1.0' 96 | compile 'io.reactivex:rxandroid:1.1.0' 97 | compile 'io.reactivex:rxjava:1.1.0' 98 | compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' 99 | compile 'com.jakewharton.rxbinding:rxbinding:0.4.0' 100 | compile 'com.zhy:autolayout:1.4.3' 101 | compile 'com.jaeger.statusbaruitl:library:1.2.4' 102 | compile 'com.hannesdorfmann.mosby:mvp:2.0.1' 103 | compile 'com.hannesdorfmann.mosby:viewstate:2.0.1' 104 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:v2.4.4' 105 | compile 'com.sdsmdg.tastytoast:tastytoast:0.1.0' 106 | testCompile 'junit:junit:4.12' 107 | testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' 108 | apt 'com.jakewharton:butterknife-compiler:8.4.0' 109 | apt 'com.hannesdorfmann.annotatedadapter:processor:1.1.1' 110 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' 111 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' 112 | compile 'in.srain.cube:ptr-load-more:1.0.6' 113 | } 114 | -------------------------------------------------------------------------------- /app/libs/avoscloud-feedback-v3.14.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanturbo/Kanzhibo/26b4780369143684c459c68e5ba3e5f253fb812e/app/libs/avoscloud-feedback-v3.14.9.jar -------------------------------------------------------------------------------- /app/libs/avoscloud-sdk-v3.14.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanturbo/Kanzhibo/26b4780369143684c459c68e5ba3e5f253fb812e/app/libs/avoscloud-sdk-v3.14.2.jar -------------------------------------------------------------------------------- /app/libs/fastjson.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanturbo/Kanzhibo/26b4780369143684c459c68e5ba3e5f253fb812e/app/libs/fastjson.jar -------------------------------------------------------------------------------- /app/libs/httpmime-4.2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanturbo/Kanzhibo/26b4780369143684c459c68e5ba3e5f253fb812e/app/libs/httpmime-4.2.4.jar -------------------------------------------------------------------------------- /app/libs/okhttp-2.6.0-leancloud.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanturbo/Kanzhibo/26b4780369143684c459c68e5ba3e5f253fb812e/app/libs/okhttp-2.6.0-leancloud.jar -------------------------------------------------------------------------------- /app/libs/okio-1.6.0-leancloud.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanturbo/Kanzhibo/26b4780369143684c459c68e5ba3e5f253fb812e/app/libs/okio-1.6.0-leancloud.jar -------------------------------------------------------------------------------- /app/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:\WorkSdk\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 | -------------------------------------------------------------------------------- /app/src/androidTest/java/pub/kanzhibo/app/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("pub.kanzhibo.app", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 35 | 36 | 37 | 40 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/App.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.avos.avoscloud.AVOSCloud; 7 | 8 | import com.tencent.bugly.crashreport.CrashReport; 9 | 10 | import io.realm.Realm; 11 | import io.realm.RealmConfiguration; 12 | import pub.kanzhibo.app.util.SharedPreferencesUtils; 13 | 14 | import static pub.kanzhibo.app.global.Constants.Key.ISLOGIN; 15 | 16 | public class App extends Application { 17 | 18 | public static Context context; 19 | 20 | @Override 21 | public void onCreate() { 22 | super.onCreate(); 23 | context = this; 24 | CrashReport.initCrashReport(getApplicationContext(), "900057711", false); 25 | AVOSCloud.initialize(this, "CIVyV1zRVPbkMQC88fyO9cuW-gzGzoHsz", "Tqbvbhznm5vc1BYdzMTXHeVd"); 26 | Realm.init(this); 27 | RealmConfiguration config = new RealmConfiguration.Builder().schemaVersion(1).build(); 28 | Realm.setDefaultConfiguration(config); 29 | } 30 | 31 | public static Context getContext() { 32 | return context; 33 | } 34 | 35 | public static boolean isLogIn() { 36 | return SharedPreferencesUtils.getBoolean(context, ISLOGIN, false); 37 | } 38 | 39 | public static void logIn() { 40 | SharedPreferencesUtils.saveBoolean(context, ISLOGIN, true); 41 | } 42 | 43 | public static void logOut() { 44 | SharedPreferencesUtils.saveBoolean(context, ISLOGIN, false); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/api/ApiClient.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.api; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import okhttp3.OkHttpClient; 6 | import retrofit2.Retrofit; 7 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 8 | import retrofit2.converter.gson.GsonConverterFactory; 9 | 10 | /** 11 | * Created by snail on 16/10/30. 12 | */ 13 | public class ApiClient { 14 | private static final int DEFAULT_TIMEOUT = 10000; 15 | 16 | private static Retrofit retrofit; 17 | 18 | private static ILiveApi mLiveApi; 19 | 20 | private static ApiClient apiClient; 21 | 22 | public static ApiClient getInstance() { 23 | if (apiClient == null) { 24 | apiClient = new ApiClient(); 25 | } 26 | return apiClient; 27 | } 28 | 29 | public ILiveApi getLiveApi(String baseUrl) { 30 | // return mLiveApi == null ? configRetrofit(ILiveApi.class) : mLiveApi; 31 | return configRetrofit(ILiveApi.class,baseUrl); 32 | } 33 | 34 | 35 | private T configRetrofit(Class service,String baseUrl) { 36 | OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder(); 37 | okHttpClient.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); 38 | retrofit = new Retrofit.Builder() 39 | .baseUrl(baseUrl) 40 | .client(okHttpClient.build()) 41 | .addConverterFactory(GsonConverterFactory.create()) 42 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 43 | .build(); 44 | 45 | return retrofit.create(service); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/api/ILiveApi.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.api; 2 | 3 | import okhttp3.RequestBody; 4 | import okhttp3.ResponseBody; 5 | import pub.kanzhibo.app.model.DouyuBigData; 6 | import pub.kanzhibo.app.model.FollowLive; 7 | import pub.kanzhibo.app.model.UserInfo; 8 | import pub.kanzhibo.app.model.roominfo.DouYuUserInfo; 9 | import pub.kanzhibo.app.model.roominfo.HuyaOffUserInfo; 10 | import pub.kanzhibo.app.model.roominfo.HuyaUserInfo; 11 | import pub.kanzhibo.app.model.roominfo.PandaUserInfo; 12 | import pub.kanzhibo.app.model.roominfo.ZhanqiUserInfo; 13 | import pub.kanzhibo.app.model.searchliveuser.LiveUserDouYu; 14 | import pub.kanzhibo.app.model.searchliveuser.LiveUserPanda; 15 | import pub.kanzhibo.app.model.searchliveuser.LiveUserQuanmin; 16 | import pub.kanzhibo.app.model.searchliveuser.LiveUserZhanqi; 17 | import retrofit2.http.Body; 18 | import retrofit2.http.GET; 19 | import retrofit2.http.POST; 20 | import retrofit2.http.Path; 21 | import retrofit2.http.Query; 22 | import rx.Observable; 23 | 24 | /** 25 | * Created by snail on 16/10/30. 26 | */ 27 | public interface ILiveApi { 28 | //注:所有的搜索都限制为20条,这是写死的,所以如果使用接口的话请注意这一点 29 | 30 | /** 31 | * 虎牙 32 | * 33 | * @param searchKey 34 | * @param rows 35 | * @return 36 | */ 37 | @GET("?m=Search&do=getSearchContent&uid=0&app=11&v=4&typ=-5") 38 | Observable searchHuya(@Query("q") String searchKey, @Query("rows") int rows); 39 | 40 | /** 41 | * 战旗 42 | * 43 | * @param searchKey 44 | * @param rows 45 | * @return 46 | */ 47 | @GET("/api/touch/search?t=anchor&nums=236&ver=2.6.6&os=3") 48 | Observable searchZhanqi(@Query("q") String searchKey, @Query("page") int rows); 49 | 50 | /** 51 | * 斗鱼 52 | * 53 | * @param searchKey 54 | * @param offset 0,10,20 55 | * @return 56 | */ 57 | @GET("/api/v1/searchNew/{search_string}/1?limit=20") 58 | Observable searchDouyu(@Path("search_string") String searchKey, @Query("offset") int offset); 59 | 60 | /** 61 | * 全民 62 | * 63 | * @param requestBody 64 | * @return 65 | */ 66 | @POST("/site/search") 67 | Observable searchQuanmin(@Body RequestBody requestBody); 68 | 69 | /** 70 | * 熊猫 71 | * 72 | * @param searchKey 73 | * @param pageno // * @param status 在线状态 2在线 3不在线 74 | * @return 75 | */ 76 | // 手机端的接口,因为熊猫tv的app是根据是否在线用两个tab分别来展示的,所以需要传个status字段 77 | // @GET("/ajax_search?__version=2.0.2.1493&__plat=android&__channel=xiaomi&pagenum=20") 78 | // Observable searchPanda(@Query("keyword") String searchKey, @Query("pageno") int pageno, @Query("status") int status); 79 | //这儿是pc端的接口 80 | @GET("/ajax_search?order_cond=fans&pagenum=20") 81 | Observable searchPanda(@Query("name") String searchKey, @Query("pageno") int pageno); 82 | 83 | /** 84 | * 获取熊猫tv直播房间信息 85 | * 86 | * @param roomid 87 | * @return 88 | */ 89 | @GET("/ajax_get_liveroom_baseinfo") 90 | Observable getPandaRoomInfo(@Query("roomid") String roomid); 91 | 92 | /** 93 | * 获取斗鱼tv直播房间信息 94 | * 95 | * @param roomid 96 | * @return 97 | */ 98 | @GET("/api/RoomApi/room/{roomid}") 99 | Observable getDouyuRoomInfo(@Path("roomid") String roomid); 100 | 101 | /** 102 | * 获取全民tv直播房间信息 103 | * 104 | * @param roomid 105 | * @return 106 | */ 107 | @GET("/json/rooms/{roomid}/info.json") 108 | Observable getQuanminRoomInfo(@Path("roomid") String roomid); 109 | 110 | /** 111 | * 获取战旗tv直播房间信息 112 | * 113 | * @param roomid 114 | * @return 115 | */ 116 | @GET("/api/static/live.roomid/{roomid}") 117 | Observable getZhanqiRoomInfo(@Path("roomid") String roomid); 118 | 119 | /** 120 | * 获取战旗tv热门列表数据 121 | * 122 | * @return 123 | */ 124 | @GET("/api/v1/getbigDataRoom") 125 | Observable getBigData(); 126 | 127 | /** 128 | * 获取虎牙直播房间信息 129 | * 130 | * @return 131 | */ 132 | @GET("/api/liveinfo?gameId=") 133 | Observable getHuyaRoomInfo_1(@Query("uid") String uid); 134 | 135 | /** 136 | * 获取虎牙直播房间信息 137 | * 138 | * @return 139 | */ 140 | @GET("hosts/{uid}?token=null") 141 | Observable getHuyaRoomInfo_2(@Path("uid") String uid); 142 | 143 | /** 144 | * 斗鱼登录 145 | * 146 | * @param username 147 | * @param password 148 | * @return 149 | */ 150 | @GET("/api/v1/login") 151 | Observable login(@Query("username") String username, @Query("password") String password); 152 | 153 | /** 154 | * 获取斗鱼关注的主播 155 | * 156 | * @param token 157 | * @return 158 | */ 159 | @GET("/api/v1/remind_list") 160 | Observable getFollow(@Query("token") String token, @Query("limit") String limit, @Query("offset") String offset); 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/api/RxSchedulers.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.api; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import rx.Observable; 6 | import rx.android.schedulers.AndroidSchedulers; 7 | import rx.schedulers.Schedulers; 8 | 9 | /** 10 | * 通用的Rx线程转换类 11 | * 参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0819/3327.html 12 | */ 13 | public class RxSchedulers { 14 | 15 | static final Observable.Transformer schedulersTransformer = new Observable.Transformer() { 16 | @Override public Object call(Object observable) { 17 | return ((Observable) observable).subscribeOn(Schedulers.io()) 18 | .observeOn(AndroidSchedulers.mainThread()); 19 | } 20 | }; 21 | 22 | public static Observable.Transformer applySchedulers() { 23 | return (Observable.Transformer) schedulersTransformer; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Hannes Dorfmann. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package pub.kanzhibo.app.base; 19 | 20 | import android.os.Bundle; 21 | import android.support.v7.app.AppCompatActivity; 22 | 23 | import butterknife.ButterKnife; 24 | //import icepick.Icepick; 25 | 26 | /** 27 | * Base class for Activities which already setup butterknife and icepick 28 | * 29 | * @author Hannes Dorfmann 30 | */ 31 | public class BaseActivity extends AppCompatActivity { 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | injectDependencies(); 36 | super.onCreate(savedInstanceState); 37 | // Icepick.restoreInstanceState(this, savedInstanceState); 38 | } 39 | 40 | @Override 41 | public void onContentChanged() { 42 | super.onContentChanged(); 43 | ButterKnife.bind(this); 44 | } 45 | 46 | @Override 47 | protected void onSaveInstanceState(Bundle outState) { 48 | super.onSaveInstanceState(outState); 49 | // Icepick.saveInstanceState(this, outState); 50 | } 51 | 52 | protected void injectDependencies() { 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Hannes Dorfmann. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package pub.kanzhibo.app.base; 19 | 20 | import android.os.Bundle; 21 | import android.support.annotation.LayoutRes; 22 | import android.support.annotation.Nullable; 23 | import android.support.v4.app.Fragment; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | import android.view.ViewGroup; 27 | 28 | 29 | import com.hannesdorfmann.mosby.mvp.MvpFragment; 30 | import com.hannesdorfmann.mosby.mvp.MvpPresenter; 31 | import com.hannesdorfmann.mosby.mvp.MvpView; 32 | 33 | import butterknife.ButterKnife; 34 | //import icepick.Icepick; 35 | 36 | /** 37 | * Base Fragment for this app that uses Butterknife, Icepick and dependency injection 38 | * 39 | * @author Hannes Dorfmann 40 | */ 41 | public abstract class BaseFragment> extends MvpFragment { 42 | 43 | @Override 44 | public void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | } 47 | 48 | @LayoutRes 49 | protected abstract int getLayoutRes(); 50 | 51 | @Nullable 52 | @Override 53 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 54 | @Nullable Bundle savedInstanceState) { 55 | // Icepick.restoreInstanceState(this, savedInstanceState); 56 | return inflater.inflate(getLayoutRes(), container, false); 57 | } 58 | 59 | @Override 60 | public void onSaveInstanceState(Bundle outState) { 61 | super.onSaveInstanceState(outState); 62 | // Icepick.saveInstanceState(this, outState); 63 | } 64 | 65 | @Override 66 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 67 | super.onViewCreated(view, savedInstanceState); 68 | ButterKnife.bind(this, view); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/base/BaseLceActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Hannes Dorfmann. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package pub.kanzhibo.app.base; 19 | 20 | import android.os.Bundle; 21 | import android.view.View; 22 | 23 | import com.hannesdorfmann.mosby.mvp.MvpPresenter; 24 | import com.hannesdorfmann.mosby.mvp.lce.MvpLceView; 25 | import com.hannesdorfmann.mosby.mvp.viewstate.lce.MvpLceViewStateActivity; 26 | 27 | import butterknife.ButterKnife; 28 | //import icepick.Icepick; 29 | 30 | /** 31 | * @author Hannes Dorfmann 32 | */ 33 | public abstract class BaseLceActivity, P extends MvpPresenter> 34 | extends MvpLceViewStateActivity { 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | injectDependencies(); 39 | super.onCreate(savedInstanceState); 40 | // Icepick.restoreInstanceState(this, savedInstanceState); 41 | } 42 | 43 | @Override 44 | public void onContentChanged() { 45 | super.onContentChanged(); 46 | ButterKnife.bind(this); 47 | } 48 | 49 | @Override 50 | protected void onSaveInstanceState(Bundle outState) { 51 | super.onSaveInstanceState(outState); 52 | // Icepick.saveInstanceState(this, outState); 53 | } 54 | 55 | protected void injectDependencies() { 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/base/BaseLceFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Hannes Dorfmann. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package pub.kanzhibo.app.base; 19 | 20 | import android.os.Bundle; 21 | import android.support.annotation.LayoutRes; 22 | import android.support.annotation.Nullable; 23 | import android.view.LayoutInflater; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | 27 | import com.hannesdorfmann.mosby.mvp.MvpPresenter; 28 | import com.hannesdorfmann.mosby.mvp.lce.MvpLceFragment; 29 | import com.hannesdorfmann.mosby.mvp.lce.MvpLceView; 30 | import com.hannesdorfmann.mosby.mvp.viewstate.lce.MvpLceViewStateFragment; 31 | 32 | import butterknife.ButterKnife; 33 | //import icepick.Icepick; 34 | 35 | /** 36 | * Base LCE ViewState Fragment for this app that uses Butterknife, Icepick and dependency injection 37 | * 38 | * @author Hannes Dorfmann 39 | */ 40 | public abstract class BaseLceFragment, P extends MvpPresenter> 41 | extends MvpLceFragment { 42 | 43 | @Override 44 | public void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | } 47 | 48 | @LayoutRes 49 | protected abstract int getLayoutRes(); 50 | 51 | @Nullable 52 | @Override 53 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 54 | @Nullable Bundle savedInstanceState) { 55 | // Icepick.restoreInstanceState(this, savedInstanceState); 56 | return inflater.inflate(getLayoutRes(), container, false); 57 | } 58 | 59 | @Override 60 | public void onSaveInstanceState(Bundle outState) { 61 | super.onSaveInstanceState(outState); 62 | // Icepick.saveInstanceState(this, outState); 63 | } 64 | 65 | @Override 66 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 67 | super.onViewCreated(view, savedInstanceState); 68 | ButterKnife.bind(this, view); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/base/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.base; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by turbo on 2016/10/28. 7 | * Base model 8 | */ 9 | 10 | public class BaseResponse implements Serializable { 11 | int code; 12 | int status; 13 | String message; 14 | T data; 15 | 16 | public int getCode() { 17 | return code; 18 | } 19 | 20 | public void setCode(int code) { 21 | this.code = code; 22 | } 23 | 24 | public int getStatus() { 25 | return status; 26 | } 27 | 28 | public void setStatus(int status) { 29 | this.status = status; 30 | } 31 | 32 | public String getMessage() { 33 | return message; 34 | } 35 | 36 | public void setMessage(String message) { 37 | this.message = message; 38 | } 39 | 40 | public T getData() { 41 | return data; 42 | } 43 | 44 | public void setData(T data) { 45 | this.data = data; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/base/BaseRxLcePresenter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Hannes Dorfmann. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package pub.kanzhibo.app.base; 19 | 20 | import com.hannesdorfmann.mosby.mvp.lce.MvpLceView; 21 | 22 | import rx.Observable; 23 | import rx.Subscriber; 24 | import rx.android.schedulers.AndroidSchedulers; 25 | import rx.schedulers.Schedulers; 26 | 27 | /** 28 | * A presenter for RxJava, that assumes that only one Observable is subscribed by this presenter. 29 | * The idea is, that you make your (chain of) Observable and pass it to {@link 30 | * #subscribe(Observable, boolean)}. The presenter internally subscribes himself as Subscriber to 31 | * the 32 | * observable 33 | * (which executes the observable). 34 | * 35 | * @author Hannes Dorfmann 36 | * @since 1.0.0 37 | */ 38 | public abstract class BaseRxLcePresenter, M> 39 | extends com.hannesdorfmann.mosby.mvp.MvpBasePresenter 40 | implements com.hannesdorfmann.mosby.mvp.MvpPresenter { 41 | 42 | protected Subscriber subscriber; 43 | 44 | /** 45 | * Unsubscribes the subscriber and set it to null 46 | */ 47 | protected void unsubscribe() { 48 | if (subscriber != null && !subscriber.isUnsubscribed()) { 49 | subscriber.unsubscribe(); 50 | } 51 | 52 | subscriber = null; 53 | } 54 | 55 | /** 56 | * Subscribes the presenter himself as subscriber on the observable 57 | * 58 | * @param observable The observable to subscribe 59 | * @param pullToRefresh Pull to refresh? 60 | */ 61 | public void subscribe(Observable observable, final boolean pullToRefresh) { 62 | 63 | if (isViewAttached()) { 64 | getView().showLoading(pullToRefresh); 65 | } 66 | 67 | unsubscribe(); 68 | 69 | subscriber = new Subscriber() { 70 | private boolean ptr = pullToRefresh; 71 | 72 | @Override 73 | public void onCompleted() { 74 | BaseRxLcePresenter.this.onCompleted(); 75 | } 76 | 77 | @Override 78 | public void onError(Throwable e) { 79 | BaseRxLcePresenter.this.onError(e, ptr); 80 | } 81 | 82 | @Override 83 | public void onNext(M m) { 84 | BaseRxLcePresenter.this.onNext(m); 85 | } 86 | }; 87 | 88 | observable.subscribeOn(Schedulers.io()) 89 | .observeOn(AndroidSchedulers.mainThread()) 90 | .subscribe(subscriber); 91 | } 92 | 93 | protected void onCompleted() { 94 | if (isViewAttached()) { 95 | getView().showContent(); 96 | } 97 | unsubscribe(); 98 | } 99 | 100 | protected void onError(Throwable e, boolean pullToRefresh) { 101 | if (isViewAttached()) { 102 | getView().showError(e, pullToRefresh); 103 | } 104 | unsubscribe(); 105 | } 106 | 107 | protected void onNext(M data) { 108 | if (isViewAttached()) { 109 | getView().setData(data); 110 | } 111 | } 112 | 113 | @Override 114 | public void detachView(boolean retainInstance) { 115 | super.detachView(retainInstance); 116 | if (!retainInstance) { 117 | unsubscribe(); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/base/BaseSearchPresent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.base; 2 | 3 | import com.avos.avoscloud.AVCloudQueryResult; 4 | import com.avos.avoscloud.AVException; 5 | import com.avos.avoscloud.AVObject; 6 | import com.avos.avoscloud.AVQuery; 7 | import com.avos.avoscloud.AVRelation; 8 | import com.avos.avoscloud.AVUser; 9 | import com.avos.avoscloud.CloudQueryCallback; 10 | import com.avos.avoscloud.FindCallback; 11 | import com.avos.avoscloud.SaveCallback; 12 | 13 | import java.util.List; 14 | 15 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 16 | import pub.kanzhibo.app.search.SearchView; 17 | import rx.Subscriber; 18 | import rx.Subscription; 19 | 20 | /** 21 | * Created by snail on 16/10/30. 22 | */ 23 | public abstract class BaseSearchPresent extends BaseRxLcePresenter> { 24 | 25 | //todo 关于设计模式----presenter 26 | //todo BaseRxLcePresenter使用这个的理由? 27 | 28 | protected Subscription subscription; 29 | 30 | public abstract void searchUser(final boolean pullToRefresh, String searchKey, int page); 31 | 32 | public void followLive(final boolean follow, LiveUser liveUser) { 33 | //根据follow添加或者删除关注的主播 34 | final AVObject followUser = new AVObject("LiveUser"); 35 | followUser.put("uid", liveUser.getUid()); 36 | followUser.put("platform", liveUser.getPlatform().getPlatform()); 37 | if (follow) { 38 | followUser.saveInBackground(new SaveCallback() { 39 | @Override 40 | public void done(AVException e) { 41 | if (e == null) { 42 | AVRelation relation = AVUser.getCurrentUser().getRelation("followLiveUser");// 新建一个 AVRelation 43 | relation.add(followUser); 44 | AVUser.getCurrentUser().saveInBackground(); 45 | } 46 | } 47 | }); 48 | } else { 49 | AVQuery query = new AVQuery<>("LiveUser"); 50 | query.whereEqualTo("uid", liveUser.getUid()); 51 | query.findInBackground(new FindCallback() { 52 | @Override 53 | public void done(List list, AVException e) { 54 | AVQuery.doCloudQueryInBackground("delete from LiveUser where objectId='" + list.get(0).getObjectId() + "'", new CloudQueryCallback() { 55 | @Override 56 | public void done(AVCloudQueryResult avCloudQueryResult, AVException e) { 57 | 58 | } 59 | }); 60 | } 61 | }); 62 | 63 | } 64 | } 65 | 66 | 67 | protected void preRequest(boolean pullToRefresh) { 68 | getView().showLoading(pullToRefresh); 69 | if (subscription != null && subscription.isUnsubscribed()) 70 | subscription.unsubscribe(); 71 | } 72 | 73 | public Subscriber> getSubscriber() { 74 | return subscriber = new Subscriber>() { 75 | @Override 76 | public void onCompleted() { 77 | 78 | } 79 | 80 | @Override 81 | public void onError(Throwable e) { 82 | getView().showError(e, false); 83 | } 84 | 85 | @Override 86 | public void onNext(List liveUsers) { 87 | if (isViewAttached()) { 88 | if (liveUsers.size() == 0) { 89 | getView().showError(null, false); 90 | } else { 91 | getView().setData(liveUsers); 92 | getView().showContent(); 93 | getView().stopRefresh(); 94 | } 95 | } 96 | } 97 | }; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/common/CommonActivity.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.common; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.SparseArray; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.TextView; 10 | 11 | import com.avos.avoscloud.AVException; 12 | import com.avos.avoscloud.AVObject; 13 | import com.avos.avoscloud.SaveCallback; 14 | import com.hwangjr.rxbus.RxBus; 15 | import com.hwangjr.rxbus.annotation.Subscribe; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | import butterknife.BindView; 21 | import butterknife.ButterKnife; 22 | import butterknife.OnClick; 23 | import io.realm.Realm; 24 | import io.realm.RealmResults; 25 | import pub.kanzhibo.app.R; 26 | import pub.kanzhibo.app.base.BaseActivity; 27 | import pub.kanzhibo.app.douyu.FollowFragment; 28 | import pub.kanzhibo.app.login.LoginFragment; 29 | import pub.kanzhibo.app.model.PlatForm; 30 | import pub.kanzhibo.app.model.DouyuFollowLiveData; 31 | import pub.kanzhibo.app.model.event.RegisterEvent; 32 | import pub.kanzhibo.app.register.RegisterFragment; 33 | 34 | public class CommonActivity extends BaseActivity { 35 | @BindView(R.id.btn_option) 36 | Button btnOption; 37 | private SparseArray fragmentList; 38 | @BindView(R.id.tv_title) 39 | TextView mTitleTV; 40 | int mIndex; 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.activity_common); 46 | ButterKnife.bind(this); 47 | Intent intent = getIntent(); 48 | RxBus.get().register(this); 49 | fragmentList = new SparseArray(); 50 | LoginFragment loginFragment = new LoginFragment(); 51 | Bundle bundle = new Bundle(); 52 | bundle.putString("from", "douyu"); 53 | loginFragment.setArguments(bundle); 54 | fragmentList.put(0, new LoginFragment()); 55 | fragmentList.put(1, new RegisterFragment()); 56 | fragmentList.put(2, loginFragment); 57 | fragmentList.put(3, new FollowFragment()); 58 | switch (intent.getStringExtra("Fragment")) { 59 | case "login": 60 | mIndex = 0; 61 | mTitleTV.setText("登录"); 62 | break; 63 | case "register": 64 | mIndex = 1; 65 | mTitleTV.setText("注册"); 66 | break; 67 | case "douyuLogin": 68 | mIndex = 2; 69 | mTitleTV.setText("登录斗鱼"); 70 | break; 71 | case "FollowFragment": 72 | mIndex = 3; 73 | mTitleTV.setText("我的斗鱼关注"); 74 | btnOption.setVisibility(View.VISIBLE); 75 | break; 76 | } 77 | getSupportFragmentManager().beginTransaction() 78 | .replace(R.id.fragmentContainer, fragmentList.get(mIndex)) 79 | .commit(); 80 | } 81 | 82 | @OnClick(R.id.ib_back) 83 | void back() { 84 | this.finish(); 85 | } 86 | 87 | @OnClick(R.id.btn_option) 88 | void option() { 89 | if (getIntent() != null && "FollowFragment".equals(getIntent().getStringExtra("Fragment"))) { 90 | //todo 导入斗鱼关注的直播 91 | Realm realm = Realm.getDefaultInstance(); 92 | RealmResults douyuFollowLiveDatas = realm.where(DouyuFollowLiveData.class).findAll(); 93 | List avObjectList = new ArrayList<>(); 94 | for(DouyuFollowLiveData douyuFollowLiveData :douyuFollowLiveDatas) { 95 | AVObject followUser = new AVObject("LiveUser"); 96 | followUser.put("uid", douyuFollowLiveData.getRoom_id()); 97 | followUser.put("platform", PlatForm.DOUYU.getPlatform()); 98 | avObjectList.add(followUser); 99 | } 100 | AVObject.saveAllInBackground(avObjectList, new SaveCallback() { 101 | @Override 102 | public void done(AVException e) { 103 | e.printStackTrace(); 104 | } 105 | }); 106 | } 107 | } 108 | 109 | @Subscribe 110 | public void registerCallBack(RegisterEvent registerEvent) { 111 | if (registerEvent.getRegsiterStatus()) { 112 | getSupportFragmentManager().beginTransaction() 113 | .replace(R.id.fragmentContainer, fragmentList.get(0)) 114 | .commit(); 115 | } else { 116 | getSupportFragmentManager().beginTransaction() 117 | .replace(R.id.fragmentContainer, fragmentList.get(1)) 118 | .commit(); 119 | } 120 | } 121 | 122 | @Override 123 | protected void onDestroy() { 124 | super.onDestroy(); 125 | RxBus.get().unregister(this); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/common/EmptyException.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.common; 2 | 3 | /** 4 | * Created by turbo on 2016/11/3. 5 | */ 6 | 7 | public class EmptyException extends Throwable { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/common/WebViewActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Freelander 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package pub.kanzhibo.app.common; 17 | 18 | import android.app.ProgressDialog; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.os.Bundle; 22 | import android.text.TextUtils; 23 | import android.webkit.WebChromeClient; 24 | import android.webkit.WebSettings; 25 | import android.webkit.WebView; 26 | import android.webkit.WebViewClient; 27 | import android.widget.TextView; 28 | 29 | import butterknife.BindView; 30 | import butterknife.ButterKnife; 31 | import butterknife.OnClick; 32 | import pub.kanzhibo.app.R; 33 | import pub.kanzhibo.app.base.BaseActivity; 34 | import pub.kanzhibo.app.global.Constants; 35 | 36 | /** 37 | * 通用的WebViewActivity 38 | */ 39 | public class WebViewActivity extends BaseActivity { 40 | 41 | @BindView(R.id.webView) 42 | WebView mWebView; 43 | @BindView(R.id.tv_title) 44 | TextView mTitleTV; 45 | private String mWebUrl, mTitle; 46 | 47 | public static Intent newIntent(Context context, String title, String url) { 48 | Intent intent = new Intent(context, WebViewActivity.class); 49 | intent.putExtra(Constants.Key.WEB_TITLE, title); 50 | intent.putExtra(Constants.Key.WEB_URL, url); 51 | return intent; 52 | } 53 | 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.activity_webview); 58 | ButterKnife.bind(this); 59 | initWebview(); 60 | } 61 | 62 | private void initWebview() { 63 | final ProgressDialog progressDialog = new ProgressDialog(this); 64 | progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 65 | progressDialog.setCanceledOnTouchOutside(false); 66 | progressDialog.setMessage("拼命加载中..."); 67 | if (!progressDialog.isShowing()) { 68 | progressDialog.show(); 69 | } 70 | mWebView.setWebChromeClient(new WebChromeClient() { 71 | @Override 72 | public void onReceivedTitle(WebView view, String title) { 73 | super.onReceivedTitle(view, title); 74 | if (TextUtils.isEmpty(mTitle)) { 75 | mTitleTV.setText(title); 76 | } 77 | } 78 | }); 79 | mWebView.getSettings().setUseWideViewPort(true); 80 | mWebView.getSettings().setLoadWithOverviewMode(true); 81 | mWebView.getSettings().setAllowFileAccess(true); 82 | //如果访问的页面中有Javascript,则webview必须设置支持Javascript 83 | mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); 84 | mWebView.getSettings().setAppCacheEnabled(true); 85 | mWebView.getSettings().setDomStorageEnabled(true); 86 | mWebView.getSettings().setDatabaseEnabled(true); 87 | mWebView.getSettings().setJavaScriptEnabled(true); 88 | 89 | mWebView.setWebViewClient(new WebViewClient() { 90 | @Override 91 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 92 | view.loadUrl(url); 93 | return true; 94 | } 95 | 96 | @Override 97 | public void onPageFinished(WebView view, String url) { 98 | progressDialog.dismiss(); 99 | } 100 | 101 | @Override 102 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { 103 | super.onReceivedError(view, errorCode, description, failingUrl); 104 | } 105 | }); 106 | mWebUrl = getIntent().getStringExtra(Constants.Key.WEB_URL); 107 | mTitle = getIntent().getStringExtra(Constants.Key.WEB_TITLE); 108 | mWebView.loadUrl(mWebUrl); 109 | mTitleTV.setText(mTitle + ""); 110 | } 111 | 112 | @OnClick(R.id.ib_back) 113 | void back() { 114 | this.finish(); 115 | } 116 | 117 | @Override 118 | public void finish() { 119 | if (mWebView.canGoBack()) { 120 | mWebView.goBack(); 121 | } else { 122 | super.finish(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/common/widget/SwipeRefreshLoadMoreLayout.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.common.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.util.AttributeSet; 6 | import android.view.ViewGroup; 7 | 8 | import in.srain.cube.views.ptr.PtrFrameLayout; 9 | import in.srain.cube.views.ptr.header.MaterialHeader; 10 | import pub.kanzhibo.app.util.ResUtil; 11 | 12 | /** 13 | * 模仿知乎的刷新控件 14 | *

15 | * Created by snail on 16/11/6. 16 | *

17 | * 需要引入https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh 18 | */ 19 | public class SwipeRefreshLoadMoreLayout extends PtrFrameLayout { 20 | 21 | private int[] colors = new int[]{Color.parseColor("#6E9AC1"), Color.parseColor("#6E9AC1"), 22 | Color.parseColor("#6E9AC1"), Color.parseColor("#6E9AC1")}; 23 | 24 | public SwipeRefreshLoadMoreLayout(Context context) { 25 | super(context); 26 | 27 | this.initConfig(); 28 | this.initHeader(); 29 | this.initFooter(); 30 | } 31 | 32 | public SwipeRefreshLoadMoreLayout(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | 35 | this.initConfig(); 36 | this.initHeader(); 37 | this.initFooter(); 38 | } 39 | 40 | private void initFooter() { 41 | 42 | MaterialHeader footer = new MaterialHeader(getContext()); 43 | footer.setColorSchemeColors(colors); 44 | footer.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 45 | ViewGroup.LayoutParams.WRAP_CONTENT)); 46 | footer.setPadding(0, 20, 0, 25); 47 | footer.setPtrFrameLayout(this); 48 | 49 | this.addPtrUIHandler(footer); 50 | this.setFooterView(footer); 51 | } 52 | 53 | private void initHeader() { 54 | MaterialHeader header = new MaterialHeader(getContext()); 55 | header.setColorSchemeColors(colors); 56 | header.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 57 | ViewGroup.LayoutParams.WRAP_CONTENT)); 58 | header.setPadding(0, 25, 0, 20); 59 | header.setPtrFrameLayout(this); 60 | 61 | this.addPtrUIHandler(header); 62 | this.setHeaderView(header); 63 | } 64 | 65 | private void initConfig() { 66 | setOffsetToRefresh(ResUtil.dp2px(getContext(), 100)); 67 | /** 68 | * 阻尼系数 69 | * 默认: 1.7f,越大,感觉下拉时越吃力 70 | */ 71 | setResistance(1.7f); 72 | 73 | /** 74 | * 触发刷新时移动的位置比例 75 | * 默认,1.2f,移动达到头部高度1.2倍时可触发刷新操作 76 | */ 77 | setRatioOfHeaderHeightToRefresh(1.2f); 78 | 79 | /** 80 | * 回弹延时 81 | * 默认 200ms,回弹到刷新高度所用时间 82 | */ 83 | setDurationToClose(200); 84 | 85 | /** 86 | * 头部回弹时间 87 | * 默认1000ms 88 | */ 89 | setDurationToCloseHeader(1000); 90 | 91 | /** 92 | * 刷新是保持头部 93 | * 默认值 true 94 | */ 95 | setKeepHeaderWhenRefresh(true); 96 | 97 | /** 98 | * 下拉刷新 / 释放刷新 99 | * 默认为释放刷新 false 100 | */ 101 | setPullToRefresh(true); 102 | 103 | /** 104 | * 刷新时,保持内容不动,仅头部下移, 使用 Material Design 风格才好看一点 105 | * 默认 false 106 | */ 107 | setPinContent(true); 108 | 109 | /** 110 | * 刷新模式 111 | * 默认 TOP:只支持下拉 112 | * Bottom:只支持上拉 113 | * BOTH:两种同时支持 114 | */ 115 | setMode(Mode.BOTH); 116 | 117 | 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/douyu/FollowFragment.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.douyu; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.support.v7.widget.StaggeredGridLayoutManager; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import com.hwangjr.rxbus.RxBus; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import butterknife.BindView; 18 | import in.srain.cube.views.ptr.PtrDefaultHandler; 19 | import in.srain.cube.views.ptr.PtrFrameLayout; 20 | import io.realm.Realm; 21 | import pub.kanzhibo.app.R; 22 | import pub.kanzhibo.app.base.BaseLceFragment; 23 | import pub.kanzhibo.app.common.widget.SwipeRefreshLoadMoreLayout; 24 | import pub.kanzhibo.app.model.DouyuFollowLiveData; 25 | import pub.kanzhibo.app.util.SharedPreferencesUtils; 26 | 27 | /** 28 | * 斗鱼关注的直播页面 29 | */ 30 | public class FollowFragment extends BaseLceFragment, FollowView, FollowPresenter> implements FollowView { 31 | 32 | 33 | @BindView(R.id.recyclerview_follow) 34 | RecyclerView recyclerviewFollow; 35 | private FollowUserAdapter mFollowUserAdapter; 36 | private List mFollowUserList; 37 | private Realm mRealm; 38 | 39 | @Override 40 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 41 | super.onViewCreated(view, savedInstanceState); 42 | recyclerviewFollow.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); 43 | contentView.setPtrHandler(new PtrDefaultHandler() { 44 | @Override 45 | public void onRefreshBegin(PtrFrameLayout ptrFrameLayout) { 46 | loadData(true); 47 | } 48 | }); 49 | mRealm = Realm.getDefaultInstance(); 50 | RxBus.get().register(this); 51 | loadData(true); 52 | } 53 | 54 | @Override 55 | public FollowPresenter createPresenter() { 56 | return new FollowPresenter(); 57 | } 58 | 59 | 60 | @Override 61 | protected int getLayoutRes() { 62 | return R.layout.fragment_follow; 63 | } 64 | 65 | @Override 66 | public void stopRefresh() { 67 | contentView.refreshComplete(); 68 | } 69 | 70 | @Override 71 | public void showContent() { 72 | super.showContent(); 73 | stopRefresh(); 74 | } 75 | 76 | @Override 77 | public void showLoading(boolean pullToRefresh) { 78 | if (!pullToRefresh) { 79 | super.showLoading(pullToRefresh); 80 | } 81 | } 82 | 83 | 84 | @Override 85 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 86 | View rootView = super.onCreateView(inflater, container, savedInstanceState); 87 | return rootView; 88 | } 89 | 90 | @Override 91 | protected String getErrorMessage(Throwable e, boolean pullToRefresh) { 92 | return e.getMessage(); 93 | } 94 | 95 | @Override 96 | public void setData(List data) { 97 | if (mFollowUserAdapter == null) { 98 | mFollowUserList = new ArrayList<>(); 99 | mFollowUserList.addAll(data); 100 | mFollowUserAdapter = new FollowUserAdapter(R.layout.item_follow_user,mFollowUserList); 101 | recyclerviewFollow.setAdapter(mFollowUserAdapter); 102 | } else { 103 | mFollowUserList.addAll(data); 104 | } 105 | mFollowUserAdapter.notifyDataSetChanged(); 106 | showContent(); 107 | mRealm.beginTransaction(); 108 | List dataBeanList = mRealm.copyToRealmOrUpdate(data); 109 | mRealm.commitTransaction(); 110 | } 111 | 112 | @Override 113 | public void loadData(boolean pullToRefresh) { 114 | presenter.getFollow(pullToRefresh, SharedPreferencesUtils.getToken(getActivity()), "20", ""); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/douyu/FollowPresenter.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.douyu; 2 | 3 | import android.support.design.widget.Snackbar; 4 | import android.util.Log; 5 | 6 | import com.avos.avoscloud.AVException; 7 | import com.avos.avoscloud.AVUser; 8 | import com.avos.avoscloud.LogInCallback; 9 | import com.hannesdorfmann.mosby.mvp.MvpBasePresenter; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import pub.kanzhibo.app.App; 14 | import pub.kanzhibo.app.api.ApiClient; 15 | import pub.kanzhibo.app.api.RxSchedulers; 16 | import pub.kanzhibo.app.global.Constants; 17 | import pub.kanzhibo.app.model.FollowLive; 18 | import pub.kanzhibo.app.model.UserInfo; 19 | import pub.kanzhibo.app.util.SharedPreferencesUtils; 20 | import rx.Observable; 21 | import rx.functions.Action1; 22 | import rx.functions.Func0; 23 | import rx.functions.Func1; 24 | 25 | /** 26 | * Created by turbo on 2016/12/26. 27 | */ 28 | 29 | public class FollowPresenter extends MvpBasePresenter { 30 | 31 | public void getFollow(final boolean refresh, final String token,final String limit,final String offset) { 32 | getView().showLoading(refresh); 33 | Observable 34 | .defer(new Func0>() { 35 | @Override 36 | public Observable call() { 37 | return ApiClient.getInstance().getLiveApi(Constants.DOUYU_BASE_URL).getFollow(token,limit,offset); 38 | } 39 | }) 40 | .retryWhen(new RetryWithDelay(3, 1000)) 41 | .compose(RxSchedulers.applySchedulers()) 42 | .subscribe(new Action1() { 43 | @Override 44 | public void call(FollowLive followLive) { 45 | getView().setData(followLive.getData()); 46 | } 47 | } 48 | , new Action1() { 49 | @Override 50 | public void call(Throwable throwable) { 51 | getView().showError(throwable,refresh); 52 | } 53 | } 54 | ); 55 | } 56 | 57 | class RetryWithDelay implements 58 | Func1, Observable> { 59 | 60 | private final int maxRetries; 61 | private final int retryDelayMillis; 62 | private int retryCount; 63 | 64 | public RetryWithDelay(int maxRetries, int retryDelayMillis) { 65 | this.maxRetries = maxRetries; 66 | this.retryDelayMillis = retryDelayMillis; 67 | this.retryCount = 0; 68 | } 69 | 70 | @Override 71 | public Observable call(Observable attempts) { 72 | return attempts.flatMap(new Func1>() { 73 | @Override 74 | public Observable call(final Throwable throwable) { 75 | if (++retryCount <= maxRetries) { 76 | if (throwable instanceof Exception) { 77 | //// TODO: 2016/12/20 有待改进 78 | Log.i("======", "重新登录"); 79 | //重新登录 80 | ApiClient.getInstance().getLiveApi(Constants.DOUYU_BASE_URL).login(SharedPreferencesUtils.getDouyuUserName(App.getContext()), SharedPreferencesUtils.getDouyuPassword(App.getContext())) 81 | .compose(RxSchedulers.applySchedulers()) 82 | .subscribe(new Action1() { 83 | @Override 84 | public void call(UserInfo userInfo) { 85 | SharedPreferencesUtils.saveToken(App.getContext(), userInfo.getData().getToken()); 86 | } 87 | }); 88 | return Observable.timer(retryDelayMillis, 89 | TimeUnit.MILLISECONDS); 90 | } 91 | } 92 | return Observable.error(throwable); 93 | } 94 | }); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/douyu/FollowUserAdapter.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.douyu; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.widget.FrameLayout; 5 | 6 | import com.bumptech.glide.Glide; 7 | import com.bumptech.glide.request.animation.GlideAnimation; 8 | import com.bumptech.glide.request.target.SimpleTarget; 9 | import com.chad.library.adapter.base.BaseQuickAdapter; 10 | import com.chad.library.adapter.base.BaseViewHolder; 11 | 12 | import java.util.List; 13 | 14 | import pub.kanzhibo.app.R; 15 | import pub.kanzhibo.app.model.DouyuFollowLiveData; 16 | 17 | 18 | /** 19 | * Created by turbo on 2016/12/26. 20 | */ 21 | 22 | public class FollowUserAdapter extends BaseQuickAdapter { 23 | public FollowUserAdapter(int layoutResId, List data) { 24 | super(layoutResId, data); 25 | } 26 | 27 | @Override 28 | protected void convert(BaseViewHolder baseViewHolder, DouyuFollowLiveData dataBean) { 29 | baseViewHolder.setText(R.id.tv_nickname, dataBean.getNickname()) 30 | .setText(R.id.tv_roomname, dataBean.getName()); 31 | final FrameLayout frameRoomSrc = (FrameLayout) baseViewHolder.getConvertView().findViewById(R.id.frame_room_src); 32 | SimpleTarget target = new SimpleTarget() { 33 | @Override 34 | public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) { 35 | frameRoomSrc.setBackground(resource); 36 | } 37 | }; 38 | Glide.with(mContext).load(dataBean.getRoom_src()).into(target); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/douyu/FollowView.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.douyu; 2 | 3 | import com.hannesdorfmann.mosby.mvp.lce.MvpLceView; 4 | 5 | import java.util.List; 6 | 7 | import pub.kanzhibo.app.model.DouyuFollowLiveData; 8 | 9 | /** 10 | * Created by turbo on 2016/12/26. 11 | */ 12 | 13 | public interface FollowView extends MvpLceView> { 14 | void stopRefresh(); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/global/Constants.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.global; 2 | 3 | /** 4 | * Created by snail on 16/10/30. 5 | */ 6 | public interface Constants { 7 | String DOUYU_BASE_URL = "http://capi.douyucdn.cn"; 8 | String DOUYU_OPEN_BASE_URL = "http://open.douyucdn.cn"; 9 | String HUYA_BASE_URL = "http://search.huya.com/"; 10 | String QUANMIN_BASE_URL = "http://www.quanmin.tv/"; 11 | String ZHANQI_BASE_URL = "http://www.zhanqi.tv/"; 12 | String PANDA_BASE_URL = "http://api.m.panda.tv/"; 13 | String HUYA_ROOM_BASE_URL_1 = "http://phone.huya.com/"; 14 | String HUYA_ROOM_BASE_URL_2 = "http://m.fans.huya.com/"; 15 | String IMG_URl = "http://aigestudio.com/wp-content/uploads/2016/08/logo.png"; 16 | 17 | public interface Key { 18 | String WEB_URL = "web_url"; 19 | String WEB_TITLE = "web_title"; 20 | String SELECT_SAVE_WHERE = "selectLocalOrServer"; 21 | String SAVE_WHERE = "savewhere"; 22 | String ISLOGIN = "islogin"; 23 | int LOGIN_REQUEST_CODE = 110; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/login/LoginFragment.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.login; 2 | 3 | 4 | import android.app.ProgressDialog; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.v4.app.Fragment; 8 | import android.view.View; 9 | import android.widget.AutoCompleteTextView; 10 | import android.widget.Button; 11 | import android.widget.EditText; 12 | import android.widget.ProgressBar; 13 | import android.widget.ScrollView; 14 | import android.widget.TextView; 15 | 16 | import com.avos.avoscloud.AVUser; 17 | import com.hwangjr.rxbus.RxBus; 18 | 19 | import butterknife.BindView; 20 | import butterknife.OnClick; 21 | import pub.kanzhibo.app.App; 22 | import pub.kanzhibo.app.R; 23 | import pub.kanzhibo.app.base.BaseFragment; 24 | import pub.kanzhibo.app.common.CommonActivity; 25 | import pub.kanzhibo.app.model.UserInfo; 26 | import pub.kanzhibo.app.model.event.DouyuLoginEvent; 27 | import pub.kanzhibo.app.model.event.LoginEvent; 28 | import pub.kanzhibo.app.model.event.RegisterEvent; 29 | import pub.kanzhibo.app.util.SharedPreferencesUtils; 30 | import pub.kanzhibo.app.util.StringUtils; 31 | 32 | /** 33 | * 登录界面 34 | */ 35 | public class LoginFragment extends BaseFragment implements LoginView { 36 | 37 | @BindView(R.id.auto_ctv_username) 38 | AutoCompleteTextView mUserName; 39 | @BindView(R.id.auto_ctv_password) 40 | EditText mPasswordView; 41 | @BindView(R.id.login_progress) 42 | ProgressBar mProgressView; 43 | @BindView(R.id.login_form) 44 | ScrollView mLoginFormView; 45 | @BindView(R.id.btn_login) 46 | Button mLoginButton; 47 | @BindView(R.id.btn_register) 48 | Button mRegisterButton; 49 | @BindView(R.id.tv_error) 50 | TextView tvError; 51 | private ProgressDialog mProgressDialog; 52 | 53 | @Override 54 | public LoginPresenter createPresenter() { 55 | return new LoginPresenter(); 56 | } 57 | 58 | 59 | @Override 60 | protected int getLayoutRes() { 61 | return R.layout.fragment_login; 62 | } 63 | 64 | @OnClick(R.id.btn_login) 65 | void login() { 66 | showLoading(); 67 | Bundle bundle = getArguments(); 68 | String userName = mUserName.getText().toString().trim(); 69 | String password = mPasswordView.getText().toString().trim(); 70 | if (bundle != null) { 71 | String from = bundle.getString("from"); 72 | if ("douyu".equals(from)) { 73 | if(StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)){ 74 | tvError.setText("亲,输入帐号和密码啊!"); 75 | mProgressDialog.dismiss(); 76 | return; 77 | } 78 | ((LoginPresenter) presenter).loginDouYu(userName, password); 79 | mRegisterButton.setVisibility(View.GONE); 80 | } else { 81 | ((LoginPresenter) presenter).login(userName, password); 82 | } 83 | } else { 84 | ((LoginPresenter) presenter).login(userName, password); 85 | } 86 | 87 | } 88 | 89 | @OnClick(R.id.btn_register) 90 | void register() { 91 | RxBus.get().post(new RegisterEvent(false)); 92 | } 93 | 94 | @Override 95 | public void showError(String errMessage) { 96 | mProgressDialog.dismiss(); 97 | tvError.setText(errMessage + ""); 98 | } 99 | 100 | @Override 101 | public void showLoading() { 102 | mProgressDialog = new ProgressDialog(getActivity()); 103 | mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 104 | mProgressDialog.setCanceledOnTouchOutside(true); 105 | mProgressDialog.setMessage("拼命加载中..."); 106 | if (!mProgressDialog.isShowing()) { 107 | mProgressDialog.show(); 108 | } 109 | } 110 | 111 | @Override 112 | public void loginSuccessful(AVUser user) { 113 | mProgressDialog.dismiss(); 114 | App.logIn(); 115 | RxBus.get().post(new LoginEvent(user)); 116 | getActivity().finish(); 117 | } 118 | 119 | @Override 120 | public void loginSuccessful(UserInfo userInfo) { 121 | mProgressDialog.dismiss(); 122 | RxBus.get().post(new DouyuLoginEvent(userInfo)); 123 | SharedPreferencesUtils.saveToken(getActivity(), userInfo.getData().getToken()); 124 | Intent intent = new Intent(getActivity(), CommonActivity.class); 125 | intent.putExtra("Fragment", "FollowFragment"); 126 | startActivity(intent); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/login/LoginPresenter.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.login; 2 | 3 | import com.avos.avoscloud.AVException; 4 | import com.avos.avoscloud.AVUser; 5 | import com.avos.avoscloud.LogInCallback; 6 | import com.hannesdorfmann.mosby.mvp.MvpBasePresenter; 7 | 8 | import pub.kanzhibo.app.App; 9 | import pub.kanzhibo.app.api.ApiClient; 10 | import pub.kanzhibo.app.api.RxSchedulers; 11 | import pub.kanzhibo.app.global.Constants; 12 | import pub.kanzhibo.app.model.UserInfo; 13 | import pub.kanzhibo.app.util.SharedPreferencesUtils; 14 | import rx.functions.Action1; 15 | 16 | /** 17 | * Created by turbo on 2016/11/2. 18 | */ 19 | 20 | public class LoginPresenter extends MvpBasePresenter { 21 | public void login(String email, String password) { 22 | //todo 对email和password进行校验 23 | AVUser.logInInBackground(email, password, new LogInCallback() { 24 | @Override 25 | public void done(AVUser avUser, AVException e) { 26 | if (avUser != null) { 27 | getView().loginSuccessful(avUser); 28 | } else { 29 | getView().showError("登陆失败,请检查用户名或者密码"); 30 | } 31 | } 32 | }); 33 | } 34 | 35 | public void loginDouYu(final String email, final String password) { 36 | ApiClient.getInstance().getLiveApi(Constants.DOUYU_BASE_URL).login(email, password) 37 | .compose(RxSchedulers.applySchedulers()) 38 | .subscribe(new Action1() { 39 | @Override 40 | public void call(UserInfo userInfo) { 41 | SharedPreferencesUtils.saveDouyuUserName(App.getContext(), email); 42 | SharedPreferencesUtils.saveDouyuPassword(App.getContext(), password); 43 | getView().loginSuccessful(userInfo); 44 | } 45 | }, new Action1() { 46 | @Override 47 | public void call(Throwable throwable) { 48 | getView().showError(throwable.getMessage()); 49 | } 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/login/LoginView.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.login; 2 | 3 | import com.avos.avoscloud.AVUser; 4 | import com.hannesdorfmann.mosby.mvp.MvpView; 5 | 6 | import pub.kanzhibo.app.model.UserInfo; 7 | 8 | /** 9 | * Created by turbo on 2016/11/2. 10 | */ 11 | 12 | public interface LoginView extends MvpView { 13 | 14 | public void showError(String errMessage); 15 | 16 | public void showLoading(); 17 | 18 | void loginSuccessful(AVUser user); 19 | 20 | void loginSuccessful(UserInfo userInfo); 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/main/LiveUserAdapter.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.main; 2 | 3 | import android.support.annotation.AnimRes; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.animation.Animation; 6 | import android.view.animation.AnimationUtils; 7 | import android.widget.ImageView; 8 | 9 | import com.bumptech.glide.Glide; 10 | import com.chad.library.adapter.base.BaseQuickAdapter; 11 | import com.chad.library.adapter.base.BaseViewHolder; 12 | 13 | import java.util.List; 14 | 15 | import pub.kanzhibo.app.R; 16 | import pub.kanzhibo.app.common.widget.ToggleButton; 17 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 18 | 19 | /** 20 | * Created by turbo on 2016/10/28. 21 | * 搜索页面也是用这个adapter 22 | */ 23 | 24 | public class LiveUserAdapter extends BaseQuickAdapter { 25 | 26 | 27 | //自定义一个关注的监听事件 28 | private LiveUserFollowListner liveUserFollowListner; 29 | protected int mLastPosition = -1; 30 | 31 | public LiveUserFollowListner getLiveUserFollowListner() { 32 | return liveUserFollowListner; 33 | } 34 | 35 | public void setLiveUserFollowListner(LiveUserFollowListner liveUserFollowListner) { 36 | this.liveUserFollowListner = liveUserFollowListner; 37 | } 38 | 39 | public LiveUserAdapter(List data) { 40 | super(R.layout.item_fragment_live_user, data); 41 | } 42 | 43 | @Override 44 | protected void convert(final BaseViewHolder viewHolder, final LiveUser liveUser) { 45 | //如果需要获取position viewHolder.getLayoutPosition() 46 | viewHolder.setText(R.id.tv_username, liveUser.getUserName()) 47 | .setText(R.id.tv_roomtitle, liveUser.getRoomTitle()) 48 | .setText(R.id.tv_viewercount, liveUser.getViewersCount()) 49 | .setText(R.id.tv_live_status, liveUser.getStatus()); 50 | if (liveUser.isHasFocus()) { 51 | ((ToggleButton) viewHolder.getView(R.id.togglebutton_focus)).setToggleOn(); 52 | } 53 | ((ToggleButton) viewHolder.getView(R.id.togglebutton_focus)).setOnToggleChanged(new ToggleButton.OnToggleChanged() { 54 | @Override 55 | public void onToggle(boolean on) { 56 | liveUserFollowListner.onFollow(on, liveUser); 57 | } 58 | }); 59 | Glide.with(mContext).load(liveUser.getUserIconUrl()).crossFade().into((ImageView) viewHolder.getView(R.id.roundimage_roombackgroud)); 60 | setItemAppearAnimation(viewHolder,viewHolder.getAdapterPosition(), R.anim.anim_bottom_in); 61 | } 62 | protected void setItemAppearAnimation(RecyclerView.ViewHolder holder, int position, @AnimRes int type) { 63 | if (position > mLastPosition/* && !isFooterPosition(position)*/) { 64 | Animation animation = AnimationUtils.loadAnimation(holder.itemView.getContext(), type); 65 | holder.itemView.startAnimation(animation); 66 | mLastPosition = position; 67 | } 68 | } 69 | public interface LiveUserFollowListner { 70 | public void onFollow(boolean followStatus, LiveUser liveUser); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/main/LiveView.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.main; 2 | 3 | import com.hannesdorfmann.mosby.mvp.lce.MvpLceView; 4 | 5 | import java.util.List; 6 | 7 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 8 | 9 | /** 10 | * Created by snail on 16/10/30. 11 | */ 12 | public interface LiveView extends MvpLceView> { 13 | void stopRefresh(); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by turbo on 2016/11/1. 7 | * 一般情况下会用到这个基类,因为服务器会返回统一的格式,但是这儿因为多个平台返回格式并不统一,所以没有用到 8 | */ 9 | 10 | public class BaseResponse implements Serializable { 11 | int code; 12 | int msg; 13 | T data; 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/FollowLive.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by snail on 16/12/19. 7 | */ 8 | public class FollowLive { 9 | 10 | 11 | /*{ 12 | "error": 903, 13 | "data": "登录信息已过期,请重新登录" 14 | }*/ 15 | /** 16 | * error : 0 17 | * data : [{"id":"122024","room_id":"122024","room_src":"https://rpic.douyucdn.cn/a1612/19/22/122024_161219223618.jpg","vertical_src":"https://rpic.douyucdn.cn/a1612/19/22/122024_161219223618.jpg","isVertical":0,"cate_id":"55","nickname":"大帝LioN","show_status":"1","owner_uid":"3781256","name":"LioN大帝~非主流猥琐上岛~NEW!","game_tag_id":"55","game_tag_name":"魔兽争霸","owner":"大帝LioN","owner_avatar_small":"https://apic.douyucdn.cn/upload/avatar/face/201605/10/360701b4c49070888234591356fa1b49_small.jpg?rltime","owner_avatar_middle":"https://apic.douyucdn.cn/upload/avatar/face/201605/10/360701b4c49070888234591356fa1b49_middle.jpg?rltime","owner_avatar_big":"https://apic.douyucdn.cn/upload/avatar/face/201605/10/360701b4c49070888234591356fa1b49_big.jpg?rltime","remind_status":"1","live_status":"99","online":10602,"show_time":"1482077407","fans":"124695","ranktype":0}] 18 | */ 19 | 20 | private int error; 21 | /** 22 | * id : 122024 23 | * room_id : 122024 24 | * room_src : https://rpic.douyucdn.cn/a1612/19/22/122024_161219223618.jpg 25 | * vertical_src : https://rpic.douyucdn.cn/a1612/19/22/122024_161219223618.jpg 26 | * isVertical : 0 27 | * cate_id : 55 28 | * nickname : 大帝LioN 29 | * show_status : 1 30 | * owner_uid : 3781256 31 | * name : LioN大帝~非主流猥琐上岛~NEW! 32 | * game_tag_id : 55 33 | * game_tag_name : 魔兽争霸 34 | * owner : 大帝LioN 35 | * owner_avatar_small : https://apic.douyucdn.cn/upload/avatar/face/201605/10/360701b4c49070888234591356fa1b49_small.jpg?rltime 36 | * owner_avatar_middle : https://apic.douyucdn.cn/upload/avatar/face/201605/10/360701b4c49070888234591356fa1b49_middle.jpg?rltime 37 | * owner_avatar_big : https://apic.douyucdn.cn/upload/avatar/face/201605/10/360701b4c49070888234591356fa1b49_big.jpg?rltime 38 | * remind_status : 1 39 | * live_status : 99 40 | * online : 10602 41 | * show_time : 1482077407 42 | * fans : 124695 43 | * ranktype : 0 44 | */ 45 | 46 | private List data; 47 | 48 | public int getError() { 49 | return error; 50 | } 51 | 52 | public void setError(int error) { 53 | this.error = error; 54 | } 55 | 56 | public List getData() { 57 | return data; 58 | } 59 | 60 | public void setData(List data) { 61 | this.data = data; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/PlatForm.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model; 2 | 3 | /** 4 | * Created by turbo on 2016/11/1. 5 | */ 6 | 7 | public enum PlatForm { 8 | DOUYU(1), HUYA(2), ZHANQI(3), PANDA(4), QUANMIN(5); 9 | // 成员变量 10 | private int platform; 11 | 12 | // 构造方法 13 | private PlatForm(int platform) { 14 | this.platform = platform; 15 | } 16 | 17 | public int getPlatform() { 18 | return platform; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/QuanminJsonRequest.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model; 2 | 3 | /** 4 | * Created by turbo on 2016/11/1. 5 | */ 6 | 7 | public class QuanminJsonRequest { 8 | 9 | /** 10 | * device : 862374032398188 11 | * v : 2.1.3 12 | * screen : 2 13 | * ch : xiaomi 14 | * sh : 1280 15 | * p : {"size":10,"key":"lyn","page":0,"categoryId":0} 16 | * sw : 720 17 | * uid : a7514f777d03 18 | * net : 0 19 | * ver : 4 20 | * os : 1 21 | */ 22 | 23 | private String device; 24 | private String v; 25 | private String screen; 26 | private String ch; 27 | private int sh; 28 | /** 29 | * size : 10 30 | * key : lyn 31 | * page : 0 32 | * categoryId : 0 33 | */ 34 | 35 | private PEntity p; 36 | private int sw; 37 | private String uid; 38 | private String net; 39 | private String ver; 40 | private String os; 41 | 42 | public String getDevice() { 43 | return device; 44 | } 45 | 46 | public void setDevice(String device) { 47 | this.device = device; 48 | } 49 | 50 | public String getV() { 51 | return v; 52 | } 53 | 54 | public void setV(String v) { 55 | this.v = v; 56 | } 57 | 58 | public String getScreen() { 59 | return screen; 60 | } 61 | 62 | public void setScreen(String screen) { 63 | this.screen = screen; 64 | } 65 | 66 | public String getCh() { 67 | return ch; 68 | } 69 | 70 | public void setCh(String ch) { 71 | this.ch = ch; 72 | } 73 | 74 | public int getSh() { 75 | return sh; 76 | } 77 | 78 | public void setSh(int sh) { 79 | this.sh = sh; 80 | } 81 | 82 | public PEntity getP() { 83 | return p; 84 | } 85 | 86 | public void setP(PEntity p) { 87 | this.p = p; 88 | } 89 | 90 | public int getSw() { 91 | return sw; 92 | } 93 | 94 | public void setSw(int sw) { 95 | this.sw = sw; 96 | } 97 | 98 | public String getUid() { 99 | return uid; 100 | } 101 | 102 | public void setUid(String uid) { 103 | this.uid = uid; 104 | } 105 | 106 | public String getNet() { 107 | return net; 108 | } 109 | 110 | public void setNet(String net) { 111 | this.net = net; 112 | } 113 | 114 | public String getVer() { 115 | return ver; 116 | } 117 | 118 | public void setVer(String ver) { 119 | this.ver = ver; 120 | } 121 | 122 | public String getOs() { 123 | return os; 124 | } 125 | 126 | public void setOs(String os) { 127 | this.os = os; 128 | } 129 | 130 | public static class PEntity { 131 | private int size; 132 | private String key; 133 | private int page; 134 | private int categoryId; 135 | 136 | public int getSize() { 137 | return size; 138 | } 139 | 140 | public void setSize(int size) { 141 | this.size = size; 142 | } 143 | 144 | public String getKey() { 145 | return key; 146 | } 147 | 148 | public void setKey(String key) { 149 | this.key = key; 150 | } 151 | 152 | public int getPage() { 153 | return page; 154 | } 155 | 156 | public void setPage(int page) { 157 | this.page = page; 158 | } 159 | 160 | public int getCategoryId() { 161 | return categoryId; 162 | } 163 | 164 | public void setCategoryId(int categoryId) { 165 | this.categoryId = categoryId; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/event/DouyuLoginEvent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.event; 2 | 3 | import com.hwangjr.rxbus.annotation.Produce; 4 | 5 | import pub.kanzhibo.app.model.UserInfo; 6 | 7 | /** 8 | * Created by snail on 16/12/28. 9 | */ 10 | public class DouyuLoginEvent { 11 | private UserInfo user; 12 | 13 | public DouyuLoginEvent(UserInfo user) { 14 | this.user = user; 15 | } 16 | 17 | public void setUserInfo(UserInfo user) { 18 | this.user = user; 19 | } 20 | 21 | @Produce 22 | public UserInfo getUserInfo() { 23 | return this.user; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/event/FollowEvent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.event; 2 | 3 | import com.hwangjr.rxbus.annotation.Produce; 4 | 5 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 6 | 7 | /** 8 | * Created by turbo on 2016/10/31. 9 | */ 10 | 11 | public class FollowEvent { 12 | private boolean follow; 13 | private LiveUser liveUser; 14 | 15 | public FollowEvent(boolean follow,LiveUser liveUser) { 16 | this.follow = follow; 17 | this.liveUser = liveUser; 18 | } 19 | 20 | public void setfollow(boolean follow) { 21 | this.follow = follow; 22 | } 23 | 24 | @Produce 25 | public boolean getfollow() { 26 | return this.follow; 27 | } 28 | 29 | public LiveUser getLiveUser() { 30 | return liveUser; 31 | } 32 | 33 | public void setLiveUser(LiveUser liveUser) { 34 | this.liveUser = liveUser; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/event/LoginEvent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.event; 2 | 3 | import com.avos.avoscloud.AVUser; 4 | import com.hwangjr.rxbus.annotation.Produce; 5 | 6 | import pub.kanzhibo.app.model.UserInfo; 7 | 8 | /** 9 | * Created by turbo on 2016/10/31. 10 | */ 11 | 12 | public class LoginEvent { 13 | private AVUser user; 14 | 15 | public LoginEvent(AVUser user) { 16 | this.user = user; 17 | } 18 | 19 | public void setUser(AVUser user) { 20 | this.user = user; 21 | } 22 | 23 | @Produce 24 | public AVUser getUser() { 25 | return this.user; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/event/RegisterEvent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.event; 2 | 3 | import com.hwangjr.rxbus.annotation.Produce; 4 | 5 | /** 6 | * Created by turbo on 2016/11/2. 7 | */ 8 | 9 | public class RegisterEvent { 10 | private boolean regsiterStatus; 11 | 12 | public RegisterEvent(boolean regsiterStatus) { 13 | this.regsiterStatus = regsiterStatus; 14 | } 15 | 16 | @Produce 17 | public boolean getRegsiterStatus() { 18 | return regsiterStatus; 19 | } 20 | 21 | public void setRegsiterStatus(boolean regsiterStatus) { 22 | this.regsiterStatus = regsiterStatus; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/event/SearchEvent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.event; 2 | 3 | import com.hwangjr.rxbus.annotation.Produce; 4 | import com.hwangjr.rxbus.annotation.Subscribe; 5 | import com.hwangjr.rxbus.thread.EventThread; 6 | 7 | /** 8 | * Created by turbo on 2016/10/31. 9 | */ 10 | 11 | public class SearchEvent { 12 | private String searchKey; 13 | 14 | public SearchEvent(String searchKey) { 15 | this.searchKey = searchKey; 16 | } 17 | 18 | public void setSearchKey(String searchKey) { 19 | this.searchKey = searchKey; 20 | } 21 | 22 | @Produce 23 | public String getSearchKey() { 24 | return this.searchKey; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/roominfo/HuyaOffUserInfo.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.roominfo; 2 | 3 | /** 4 | * Created by turbo on 2016/11/9. 5 | * 虎牙不在直播的用户信息 6 | */ 7 | 8 | public class HuyaOffUserInfo { 9 | 10 | /** 11 | * uid : 500066171 12 | * badgeName : 13 | * name : 董导 董小飒 14 | * type : 2 15 | * avatar : http://img.live.yy.com/avatar/1082/64/b3bb6f0caa54e70a0391bceab9e093_180_135.jpg? 16 | * fans : 366510 17 | * praiseCount : 0 18 | * praiseRank : -1 19 | * privs : 2 20 | * isFollowed : 0 21 | * muted : 0 22 | */ 23 | 24 | private DataEntity data; 25 | 26 | public DataEntity getData() { 27 | return data; 28 | } 29 | 30 | public void setData(DataEntity data) { 31 | this.data = data; 32 | } 33 | 34 | public static class DataEntity { 35 | private int uid; 36 | private String badgeName; 37 | private String name; 38 | private int type; 39 | private String avatar; 40 | private int fans; 41 | private int praiseCount; 42 | private int praiseRank; 43 | private int privs; 44 | private int isFollowed; 45 | private int muted; 46 | 47 | public int getUid() { 48 | return uid; 49 | } 50 | 51 | public void setUid(int uid) { 52 | this.uid = uid; 53 | } 54 | 55 | public String getBadgeName() { 56 | return badgeName; 57 | } 58 | 59 | public void setBadgeName(String badgeName) { 60 | this.badgeName = badgeName; 61 | } 62 | 63 | public String getName() { 64 | return name; 65 | } 66 | 67 | public void setName(String name) { 68 | this.name = name; 69 | } 70 | 71 | public int getType() { 72 | return type; 73 | } 74 | 75 | public void setType(int type) { 76 | this.type = type; 77 | } 78 | 79 | public String getAvatar() { 80 | return avatar; 81 | } 82 | 83 | public void setAvatar(String avatar) { 84 | this.avatar = avatar; 85 | } 86 | 87 | public int getFans() { 88 | return fans; 89 | } 90 | 91 | public void setFans(int fans) { 92 | this.fans = fans; 93 | } 94 | 95 | public int getPraiseCount() { 96 | return praiseCount; 97 | } 98 | 99 | public void setPraiseCount(int praiseCount) { 100 | this.praiseCount = praiseCount; 101 | } 102 | 103 | public int getPraiseRank() { 104 | return praiseRank; 105 | } 106 | 107 | public void setPraiseRank(int praiseRank) { 108 | this.praiseRank = praiseRank; 109 | } 110 | 111 | public int getPrivs() { 112 | return privs; 113 | } 114 | 115 | public void setPrivs(int privs) { 116 | this.privs = privs; 117 | } 118 | 119 | public int getIsFollowed() { 120 | return isFollowed; 121 | } 122 | 123 | public void setIsFollowed(int isFollowed) { 124 | this.isFollowed = isFollowed; 125 | } 126 | 127 | public int getMuted() { 128 | return muted; 129 | } 130 | 131 | public void setMuted(int muted) { 132 | this.muted = muted; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/searchliveuser/LiveUser.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.searchliveuser; 2 | 3 | import pub.kanzhibo.app.model.PlatForm; 4 | 5 | /** 6 | * Created by turbo on 2016/10/28. 7 | */ 8 | public class LiveUser { 9 | //平台 10 | PlatForm platform; 11 | //uid 12 | String uid; 13 | //主播用户名 14 | String userName; 15 | //直播间名称 16 | String roomTitle; 17 | //直播状态 根据各个平台的返回转成两种状态:在直播,未开播 18 | String status; 19 | //观众人数 20 | String viewersCount; 21 | //是否关注 22 | boolean hasFocus; 23 | //用户头像 24 | String userIconUrl; 25 | //房间背景图片 26 | String roomBackgroudUrl; 27 | 28 | public String getUid() { 29 | return uid; 30 | } 31 | 32 | public void setUid(String uid) { 33 | this.uid = uid; 34 | } 35 | 36 | public String getUserName() { 37 | return userName; 38 | } 39 | 40 | public void setUserName(String userName) { 41 | this.userName = userName; 42 | } 43 | 44 | public String getRoomTitle() { 45 | return roomTitle; 46 | } 47 | 48 | public void setRoomTitle(String roomTitle) { 49 | this.roomTitle = roomTitle; 50 | } 51 | 52 | public String getStatus() { 53 | return status; 54 | } 55 | 56 | public void setStatus(String status) { 57 | this.status = status; 58 | } 59 | 60 | public String getViewersCount() { 61 | return viewersCount; 62 | } 63 | 64 | public void setViewersCount(String viewersCount) { 65 | this.viewersCount = viewersCount; 66 | } 67 | 68 | public boolean isHasFocus() { 69 | return hasFocus; 70 | } 71 | 72 | public void setHasFocus(boolean hasFocus) { 73 | this.hasFocus = hasFocus; 74 | } 75 | 76 | public String getUserIconUrl() { 77 | return userIconUrl; 78 | } 79 | 80 | public void setUserIconUrl(String userIconUrl) { 81 | this.userIconUrl = userIconUrl; 82 | } 83 | 84 | public String getRoomBackgroudUrl() { 85 | return roomBackgroudUrl; 86 | } 87 | 88 | public void setRoomBackgroudUrl(String roomBackgroudUrl) { 89 | this.roomBackgroudUrl = roomBackgroudUrl; 90 | } 91 | 92 | public PlatForm getPlatform() { 93 | return platform; 94 | } 95 | 96 | public void setPlatform(PlatForm platform) { 97 | this.platform = platform; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/searchliveuser/UserHuyaLive.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.searchliveuser; 2 | 3 | /** 4 | * Created by snail on 16/10/30. 5 | * 正在直播的 6 | */ 7 | public class UserHuyaLive { 8 | 9 | /** 10 | * aid : 7186418 11 | * gameId : 1 12 | * gameName : 英雄联盟 13 | * game_channel : 99425467 14 | * game_imgUrl : http://huyaimg.dwstatic.com/avatar/1029/21/77aed1c053f4a4938ffaf9b618aa06_180_135.jpg?1385633936 15 | * game_introduction : 西门剑姬屠杀白金段 16 | * game_nick : 正恒丶西门 17 | * game_privateHost : ximen 18 | * game_roomName : ┊西 门 ¨18-23点直播 新浪微博:西门电竞孔子” 19 | * game_screenshot : http://screenshot.dwstatic.com/yysnapshot/a781a5d8e5defda753c442706cb77905dcbb53ea 20 | * game_shortChannel : 90010 21 | * game_subChannel : 2330849298 22 | * game_total_count : 265557 23 | * liveSourceType : 0 24 | * screen_type : 0 25 | */ 26 | 27 | private int aid; 28 | private int gameId; 29 | private String gameName; 30 | private int game_channel; 31 | private String game_imgUrl; 32 | private String game_introduction; 33 | private String game_nick; 34 | private String game_privateHost; 35 | private String game_roomName; 36 | private String game_screenshot; 37 | private int game_shortChannel; 38 | private long game_subChannel; 39 | private int game_total_count; 40 | private String liveSourceType; 41 | private int screen_type; 42 | 43 | public int getAid() { 44 | return aid; 45 | } 46 | 47 | public void setAid(int aid) { 48 | this.aid = aid; 49 | } 50 | 51 | public int getGameId() { 52 | return gameId; 53 | } 54 | 55 | public void setGameId(int gameId) { 56 | this.gameId = gameId; 57 | } 58 | 59 | public String getGameName() { 60 | return gameName; 61 | } 62 | 63 | public void setGameName(String gameName) { 64 | this.gameName = gameName; 65 | } 66 | 67 | public int getGame_channel() { 68 | return game_channel; 69 | } 70 | 71 | public void setGame_channel(int game_channel) { 72 | this.game_channel = game_channel; 73 | } 74 | 75 | public String getGame_imgUrl() { 76 | return game_imgUrl; 77 | } 78 | 79 | public void setGame_imgUrl(String game_imgUrl) { 80 | this.game_imgUrl = game_imgUrl; 81 | } 82 | 83 | public String getGame_introduction() { 84 | return game_introduction; 85 | } 86 | 87 | public void setGame_introduction(String game_introduction) { 88 | this.game_introduction = game_introduction; 89 | } 90 | 91 | public String getGame_nick() { 92 | return game_nick; 93 | } 94 | 95 | public void setGame_nick(String game_nick) { 96 | this.game_nick = game_nick; 97 | } 98 | 99 | public String getGame_privateHost() { 100 | return game_privateHost; 101 | } 102 | 103 | public void setGame_privateHost(String game_privateHost) { 104 | this.game_privateHost = game_privateHost; 105 | } 106 | 107 | public String getGame_roomName() { 108 | return game_roomName; 109 | } 110 | 111 | public void setGame_roomName(String game_roomName) { 112 | this.game_roomName = game_roomName; 113 | } 114 | 115 | public String getGame_screenshot() { 116 | return game_screenshot; 117 | } 118 | 119 | public void setGame_screenshot(String game_screenshot) { 120 | this.game_screenshot = game_screenshot; 121 | } 122 | 123 | public int getGame_shortChannel() { 124 | return game_shortChannel; 125 | } 126 | 127 | public void setGame_shortChannel(int game_shortChannel) { 128 | this.game_shortChannel = game_shortChannel; 129 | } 130 | 131 | public long getGame_subChannel() { 132 | return game_subChannel; 133 | } 134 | 135 | public void setGame_subChannel(long game_subChannel) { 136 | this.game_subChannel = game_subChannel; 137 | } 138 | 139 | public int getGame_total_count() { 140 | return game_total_count; 141 | } 142 | 143 | public void setGame_total_count(int game_total_count) { 144 | this.game_total_count = game_total_count; 145 | } 146 | 147 | public String getLiveSourceType() { 148 | return liveSourceType; 149 | } 150 | 151 | public void setLiveSourceType(String liveSourceType) { 152 | this.liveSourceType = liveSourceType; 153 | } 154 | 155 | public int getScreen_type() { 156 | return screen_type; 157 | } 158 | 159 | public void setScreen_type(int screen_type) { 160 | this.screen_type = screen_type; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/model/searchliveuser/UserHuyaPlay.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.model.searchliveuser; 2 | 3 | /** 4 | * Created by turbo on 2016/10/28. 5 | * 正在播放的 6 | */ 7 | 8 | public class UserHuyaPlay { 9 | 10 | /** 11 | * aid : 23865881 12 | * gameLiveOn : false 13 | * game_activityCount : 3139231 14 | * game_avatarUrl180 : http://huyaimg.dwstatic.com/avatar/1083/32/a922f67d41235e26b57daef0b043f5_180_135.jpg 15 | * game_avatarUrl52 : http://huyaimg.dwstatic.com/avatar/1083/32/a922f67d41235e26b57daef0b043f5_180_135.jpg 16 | * game_channel : 78941969 17 | * game_liveLink : http://www.huya.com/miss 18 | * game_longChannel : 78941969 19 | * game_nick : Miss大小姐 20 | * game_profileLink : http://www.huya.com/miss/home 21 | * game_recommendStatus : 4 22 | * game_subChannel : 2502884626 23 | * screen_type : 0 24 | * uid : 1466346678 25 | */ 26 | 27 | private int aid; 28 | private boolean gameLiveOn; 29 | private int game_activityCount; 30 | private String game_avatarUrl180; 31 | private String game_avatarUrl52; 32 | private int game_channel; 33 | private String game_liveLink; 34 | private int game_longChannel; 35 | private String game_nick; 36 | private String game_profileLink; 37 | private int game_recommendStatus; 38 | private long game_subChannel; 39 | private int screen_type; 40 | private int uid; 41 | 42 | public int getAid() { 43 | return aid; 44 | } 45 | 46 | public void setAid(int aid) { 47 | this.aid = aid; 48 | } 49 | 50 | public boolean isGameLiveOn() { 51 | return gameLiveOn; 52 | } 53 | 54 | public void setGameLiveOn(boolean gameLiveOn) { 55 | this.gameLiveOn = gameLiveOn; 56 | } 57 | 58 | public int getGame_activityCount() { 59 | return game_activityCount; 60 | } 61 | 62 | public void setGame_activityCount(int game_activityCount) { 63 | this.game_activityCount = game_activityCount; 64 | } 65 | 66 | public String getGame_avatarUrl180() { 67 | return game_avatarUrl180; 68 | } 69 | 70 | public void setGame_avatarUrl180(String game_avatarUrl180) { 71 | this.game_avatarUrl180 = game_avatarUrl180; 72 | } 73 | 74 | public String getGame_avatarUrl52() { 75 | return game_avatarUrl52; 76 | } 77 | 78 | public void setGame_avatarUrl52(String game_avatarUrl52) { 79 | this.game_avatarUrl52 = game_avatarUrl52; 80 | } 81 | 82 | public int getGame_channel() { 83 | return game_channel; 84 | } 85 | 86 | public void setGame_channel(int game_channel) { 87 | this.game_channel = game_channel; 88 | } 89 | 90 | public String getGame_liveLink() { 91 | return game_liveLink; 92 | } 93 | 94 | public void setGame_liveLink(String game_liveLink) { 95 | this.game_liveLink = game_liveLink; 96 | } 97 | 98 | public int getGame_longChannel() { 99 | return game_longChannel; 100 | } 101 | 102 | public void setGame_longChannel(int game_longChannel) { 103 | this.game_longChannel = game_longChannel; 104 | } 105 | 106 | public String getGame_nick() { 107 | return game_nick; 108 | } 109 | 110 | public void setGame_nick(String game_nick) { 111 | this.game_nick = game_nick; 112 | } 113 | 114 | public String getGame_profileLink() { 115 | return game_profileLink; 116 | } 117 | 118 | public void setGame_profileLink(String game_profileLink) { 119 | this.game_profileLink = game_profileLink; 120 | } 121 | 122 | public int getGame_recommendStatus() { 123 | return game_recommendStatus; 124 | } 125 | 126 | public void setGame_recommendStatus(int game_recommendStatus) { 127 | this.game_recommendStatus = game_recommendStatus; 128 | } 129 | 130 | public long getGame_subChannel() { 131 | return game_subChannel; 132 | } 133 | 134 | public void setGame_subChannel(long game_subChannel) { 135 | this.game_subChannel = game_subChannel; 136 | } 137 | 138 | public int getScreen_type() { 139 | return screen_type; 140 | } 141 | 142 | public void setScreen_type(int screen_type) { 143 | this.screen_type = screen_type; 144 | } 145 | 146 | public int getUid() { 147 | return uid; 148 | } 149 | 150 | public void setUid(int uid) { 151 | this.uid = uid; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/register/RegisterFragment.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.register; 2 | 3 | 4 | import android.app.ProgressDialog; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.AutoCompleteTextView; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | import android.widget.ProgressBar; 14 | import android.widget.ScrollView; 15 | import android.widget.TextView; 16 | 17 | import com.hannesdorfmann.mosby.mvp.MvpPresenter; 18 | import com.hwangjr.rxbus.RxBus; 19 | 20 | import butterknife.BindView; 21 | import butterknife.OnClick; 22 | import pub.kanzhibo.app.R; 23 | import pub.kanzhibo.app.base.BaseFragment; 24 | import pub.kanzhibo.app.model.event.RegisterEvent; 25 | 26 | /** 27 | * A simple {@link Fragment} subclass. 28 | */ 29 | public class RegisterFragment extends BaseFragment implements RegisterView { 30 | 31 | @BindView(R.id.auto_ctv_username) 32 | AutoCompleteTextView mUserName; 33 | @BindView(R.id.auto_ctv_password) 34 | EditText mPasswordView; 35 | @BindView(R.id.login_progress) 36 | ProgressBar mProgressView; 37 | @BindView(R.id.login_form) 38 | ScrollView mLoginFormView; 39 | @BindView(R.id.btn_register) 40 | Button mRegisterButton; 41 | @BindView(R.id.tv_error) 42 | TextView tvError; 43 | private ProgressDialog mProgressDialog; 44 | 45 | @Override 46 | public RegisterPresenter createPresenter() { 47 | return new RegisterPresenter(); 48 | } 49 | 50 | 51 | @Override 52 | protected int getLayoutRes() { 53 | return R.layout.fragment_register; 54 | } 55 | 56 | @OnClick(R.id.btn_register) 57 | void register() { 58 | showProgress(); 59 | ((RegisterPresenter) presenter).register(mUserName.getText().toString().trim(), mPasswordView.getText().toString().trim()); 60 | } 61 | 62 | @Override 63 | public void showError(String errMessage) { 64 | if (mProgressDialog != null) 65 | mProgressDialog.dismiss(); 66 | tvError.setText(errMessage + ""); 67 | } 68 | 69 | @Override 70 | public void showProgress() { 71 | mProgressDialog = new ProgressDialog(getActivity()); 72 | mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 73 | mProgressDialog.setCanceledOnTouchOutside(true); 74 | mProgressDialog.setMessage("拼命加载中..."); 75 | if (!mProgressDialog.isShowing()) { 76 | mProgressDialog.show(); 77 | } 78 | } 79 | 80 | @Override 81 | public void registerSuccessful() { 82 | mProgressDialog.dismiss(); 83 | RxBus.get().post(new RegisterEvent(true)); 84 | } 85 | 86 | @Override 87 | public void onResume() { 88 | super.onResume(); 89 | mUserName.setText(""); 90 | mPasswordView.setText(""); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/register/RegisterPresenter.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.register; 2 | 3 | import com.avos.avoscloud.AVException; 4 | import com.avos.avoscloud.AVUser; 5 | import com.avos.avoscloud.SignUpCallback; 6 | import com.hannesdorfmann.mosby.mvp.MvpBasePresenter; 7 | 8 | /** 9 | * Created by turbo on 2016/11/2. 10 | */ 11 | 12 | public class RegisterPresenter extends MvpBasePresenter { 13 | public void register(String email, String password) { 14 | //todo 使用RxBind是否可以对email进行校验 15 | AVUser user = new AVUser();// 新建 AVUser 对象实例 16 | user.setUsername(email);// 设置用户名 17 | user.setPassword(password);// 设置密码 18 | user.setEmail(email);// 设置邮箱 19 | user.signUpInBackground(new SignUpCallback() { 20 | @Override 21 | public void done(AVException e) { 22 | if (e == null) { 23 | // 注册成功 24 | getView().registerSuccessful(); 25 | } else { 26 | // 失败的原因可能有多种,常见的是用户名已经存在。 27 | String errMessage = ""; 28 | switch (e.getCode()) { 29 | case 202: 30 | case 203: 31 | errMessage = "电子邮箱已被注册!"; 32 | break; 33 | 34 | } 35 | getView().showError(errMessage); 36 | } 37 | } 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/register/RegisterView.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.register; 2 | 3 | import com.hannesdorfmann.mosby.mvp.MvpView; 4 | 5 | /** 6 | * Created by turbo on 2016/11/2. 7 | * mvpView 就是说界面上需要的所有动作的定义 8 | * mvpPresenter 界面上所有的逻辑操作 这儿有个mvpPresenter和mvpBasePresenter 这两个其实差不多,但是继承mvpBasePresenter的话 9 | * 不但继承了attachView 和detachView两个方法,还创建了一个软引用的view(即fragment),即不需要自己再去维护presenter和view的联系了 10 | * mvpFragment 有两个用处: 11 | * 1、在合适的地方(比如进入fragment加载数据,或者button的点击事件)调用present的方法 12 | * 2.实现所有动作的定义 implements mvpView,在合适的地方展示view(比如说加载数据时候的loading,加载完成之后的数据显示) 13 | *

14 | * LCE模块的话就是对loading-content-error这个部分做了进一步封装,使用起来方便些。 15 | * 当然,比如说login这样的模块或者只是简单的一个网络请求或者逻辑,是不需要继承lce模块的类和接口的 16 | */ 17 | 18 | public interface RegisterView extends MvpView { 19 | 20 | public void showError(String errMessage); 21 | 22 | public void showProgress(); 23 | 24 | public void registerSuccessful(); 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/search/SearchActivity.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.search; 2 | 3 | import android.support.design.widget.TabLayout; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.os.Bundle; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.widget.EditText; 13 | import android.widget.ImageButton; 14 | 15 | import com.hwangjr.rxbus.RxBus; 16 | import com.jakewharton.rxbinding.view.RxView; 17 | import com.jakewharton.rxbinding.widget.RxCompoundButton; 18 | import com.jakewharton.rxbinding.widget.RxTextView; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.List; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | import butterknife.BindArray; 26 | import butterknife.BindView; 27 | import butterknife.OnClick; 28 | import pub.kanzhibo.app.R; 29 | import pub.kanzhibo.app.base.BaseActivity; 30 | import pub.kanzhibo.app.model.PlatForm; 31 | import pub.kanzhibo.app.model.event.SearchEvent; 32 | import rx.functions.Action1; 33 | 34 | public class SearchActivity extends BaseActivity { 35 | 36 | @BindView(R.id.viewPager) 37 | ViewPager viewPager; 38 | @BindView(R.id.tabLayout) 39 | TabLayout tabLayout; 40 | @BindView(R.id.et_search_key) 41 | EditText searchKeyEditText; 42 | @BindView(R.id.ib_search) 43 | ImageButton mIbSearch; 44 | String[] mPlatForms; 45 | 46 | 47 | @Override 48 | protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | setContentView(R.layout.activity_search); 51 | mPlatForms = getResources().getStringArray(R.array.platform); 52 | viewPager.setAdapter(new SearchFragmentStatePagerAdapter(getSupportFragmentManager(), Arrays.asList(mPlatForms))); 53 | viewPager.setOffscreenPageLimit(5); 54 | tabLayout.setupWithViewPager(viewPager); 55 | //给editText内部的drawable添加点击事件 56 | searchKeyEditText.setOnTouchListener(new View.OnTouchListener() { 57 | @Override 58 | public boolean onTouch(View v, MotionEvent event) { 59 | if (event.getAction() == MotionEvent.ACTION_UP) { 60 | if (event.getRawX() >= searchKeyEditText.getRight() - searchKeyEditText.getTotalPaddingRight()) { 61 | searchKeyEditText.setText(""); 62 | return true; 63 | } 64 | } 65 | return false; 66 | } 67 | }); 68 | RxView.clicks(mIbSearch).throttleFirst(1, TimeUnit.SECONDS).subscribe(new Action1() { 69 | @Override 70 | public void call(Void aVoid) { 71 | RxBus.get().post(new SearchEvent(searchKeyEditText.getText().toString().trim())); 72 | } 73 | }); 74 | } 75 | 76 | @OnClick(R.id.ib_back) 77 | void back() { 78 | this.finish(); 79 | } 80 | 81 | //todo fragment的缓存 82 | class SearchFragmentStatePagerAdapter extends FragmentStatePagerAdapter { 83 | 84 | List titles; 85 | 86 | public SearchFragmentStatePagerAdapter(FragmentManager fm, List titles) { 87 | super(fm); 88 | this.titles = titles; 89 | } 90 | 91 | @Override 92 | public Fragment getItem(int position) { 93 | SearchUserFragment searchUserFragment = new SearchUserFragment(); 94 | Bundle bundle = new Bundle(); 95 | switch (titles.get(position)) { 96 | case "熊猫": 97 | bundle.putSerializable("platform", PlatForm.PANDA); 98 | searchUserFragment.setArguments(bundle); 99 | return searchUserFragment; 100 | case "虎牙": 101 | bundle.putSerializable("platform", PlatForm.HUYA); 102 | searchUserFragment.setArguments(bundle); 103 | return searchUserFragment; 104 | case "战旗": 105 | bundle.putSerializable("platform", PlatForm.ZHANQI); 106 | searchUserFragment.setArguments(bundle); 107 | return searchUserFragment; 108 | case "全民": 109 | bundle.putSerializable("platform", PlatForm.QUANMIN); 110 | searchUserFragment.setArguments(bundle); 111 | return searchUserFragment; 112 | default: 113 | bundle.putSerializable("platform", PlatForm.DOUYU); 114 | searchUserFragment.setArguments(bundle); 115 | return searchUserFragment; 116 | } 117 | 118 | } 119 | 120 | @Override 121 | public int getCount() { 122 | return titles.size(); 123 | } 124 | 125 | @Override 126 | public CharSequence getPageTitle(int position) { 127 | return titles.get(position); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/search/SearchView.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.search; 2 | 3 | import com.hannesdorfmann.mosby.mvp.lce.MvpLceView; 4 | 5 | import java.util.List; 6 | 7 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 8 | 9 | /** 10 | * Created by snail on 16/10/30. 11 | */ 12 | public interface SearchView extends MvpLceView> { 13 | void stopRefresh(); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/search/present/DouyuSearchPresent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.search.present; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import pub.kanzhibo.app.api.ApiClient; 7 | import pub.kanzhibo.app.api.RxSchedulers; 8 | import pub.kanzhibo.app.base.BaseSearchPresent; 9 | import pub.kanzhibo.app.global.Constants; 10 | import pub.kanzhibo.app.model.PlatForm; 11 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 12 | import pub.kanzhibo.app.model.searchliveuser.LiveUserDouYu; 13 | import rx.functions.Func1; 14 | 15 | /** 16 | * Created by snail on 16/10/30. 17 | */ 18 | public class DouyuSearchPresent extends BaseSearchPresent { 19 | 20 | @Override 21 | public void searchUser(final boolean pullToRefresh, String searchKey, int page) { 22 | preRequest(pullToRefresh); 23 | //todo 关于设计模式----presenter 24 | subscription = ApiClient.getInstance().getLiveApi(Constants.DOUYU_BASE_URL) 25 | .searchDouyu(searchKey, page * 10) 26 | .map(new Func1>() { 27 | @Override 28 | public List call(LiveUserDouYu liveUserDouYu) { 29 | List result = new ArrayList(); 30 | if (liveUserDouYu.getError() == 0 && liveUserDouYu.getData().getRoom() != null && liveUserDouYu.getData().getRoom().size() > 0) { 31 | for (LiveUserDouYu.DataEntity.RoomEntity entity : liveUserDouYu.getData().getRoom()) { 32 | LiveUser liveUser = new LiveUser(); 33 | liveUser.setUserName(entity.getNickname()); 34 | liveUser.setUid(entity.getRoom_id()); 35 | //todo 应该查询本地数据库 36 | liveUser.setPlatform(PlatForm.DOUYU); 37 | liveUser.setHasFocus(false); 38 | liveUser.setRoomTitle(entity.getRoom_name()); 39 | liveUser.setUserIconUrl(entity.getAvatar()); 40 | liveUser.setViewersCount("关注人数:" + entity.getFans()); 41 | liveUser.setStatus("1".equals(entity.getShow_status()) ? "在直播" : "未开播"); 42 | result.add(liveUser); 43 | } 44 | } 45 | return result; 46 | } 47 | }) 48 | .compose(RxSchedulers.>applySchedulers()) 49 | .subscribe(getSubscriber()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/search/present/HuyaSearchPresent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.search.present; 2 | 3 | import com.google.gson.Gson; 4 | 5 | import org.json.JSONArray; 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | 9 | import java.io.IOException; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import okhttp3.ResponseBody; 14 | import pub.kanzhibo.app.api.ApiClient; 15 | import pub.kanzhibo.app.api.RxSchedulers; 16 | import pub.kanzhibo.app.base.BaseSearchPresent; 17 | import pub.kanzhibo.app.global.Constants; 18 | import pub.kanzhibo.app.model.PlatForm; 19 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 20 | import pub.kanzhibo.app.model.searchliveuser.UserHuyaLive; 21 | import pub.kanzhibo.app.model.searchliveuser.UserHuyaPlay; 22 | import rx.functions.Func1; 23 | 24 | /** 25 | * Created by snail on 16/10/30. 26 | */ 27 | public class HuyaSearchPresent extends BaseSearchPresent { 28 | 29 | @Override 30 | public void searchUser(final boolean pullToRefresh, String searchKey, int page) { 31 | preRequest(pullToRefresh); 32 | //todo 抓下虎牙的加载更多数据app内是如何请求的 33 | subscription = ApiClient.getInstance().getLiveApi(Constants.HUYA_BASE_URL).searchHuya(searchKey, (page + 1) * 10) 34 | .map(new Func1>() { 35 | @Override 36 | public List call(ResponseBody responseBody) { 37 | List result = null; 38 | String responseJsonStr = null; 39 | try { 40 | //todo 虎牙的数据有点懵逼,所以使用原生的json解析方式 我猜应该还有比较智能的解析方式 41 | responseJsonStr = new String(responseBody.bytes()); 42 | JSONObject latestNewsJSON = new JSONObject(responseJsonStr); 43 | JSONArray responsePlay = latestNewsJSON.getJSONObject("response").getJSONObject("1").getJSONArray("docs"); 44 | JSONArray responseLive = latestNewsJSON.getJSONObject("response").getJSONObject("3").getJSONArray("docs"); 45 | if (responsePlay.length() != 0) { 46 | Gson gson = new Gson(); 47 | UserHuyaPlay[] liveUserHuyas = gson.fromJson(responsePlay.toString(), UserHuyaPlay[].class); 48 | result = new ArrayList(); 49 | for (int i = 0; i < liveUserHuyas.length; i++) { 50 | LiveUser liveUser = new LiveUser(); 51 | liveUser.setUid(liveUserHuyas[i].getUid()+""); 52 | liveUser.setPlatform(PlatForm.HUYA); 53 | liveUser.setUserName(liveUserHuyas[i].getGame_nick()); 54 | //todo 应该查询本地数据库 55 | liveUser.setHasFocus(false); 56 | liveUser.setRoomTitle("查询不到相关信息"); 57 | liveUser.setUserIconUrl(liveUserHuyas[i].getGame_avatarUrl52()); 58 | liveUser.setViewersCount("关注人数:" + liveUserHuyas[i].getGame_activityCount()); 59 | liveUser.setStatus(liveUserHuyas[i].isGameLiveOn() ? "在直播" : "未开播"); 60 | result.add(liveUser); 61 | } 62 | } else if (responsePlay.length() == 0 && responseLive.length() != 0) { 63 | Gson gson = new Gson(); 64 | UserHuyaLive[] liveUserHuyas = gson.fromJson(responseLive.toString(), UserHuyaLive[].class); 65 | result = new ArrayList(); 66 | for (int i = 0; i < liveUserHuyas.length; i++) { 67 | LiveUser liveUser = new LiveUser(); 68 | liveUser.setUserName(liveUserHuyas[i].getGame_nick()); 69 | //todo 应该查询本地数据库 70 | liveUser.setHasFocus(false); 71 | liveUser.setRoomTitle(liveUserHuyas[i].getGame_introduction()); 72 | liveUser.setUserIconUrl(liveUserHuyas[i].getGame_imgUrl()); 73 | liveUser.setViewersCount("观看人数" + liveUserHuyas[i].getGame_total_count()); 74 | liveUser.setStatus("1"); 75 | result.add(liveUser); 76 | } 77 | } else { 78 | //未找到直播 79 | } 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | } catch (JSONException e) { 83 | e.printStackTrace(); 84 | } 85 | return result; 86 | } 87 | }) 88 | .compose(RxSchedulers.>applySchedulers()) 89 | .subscribe(getSubscriber()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/search/present/PandaSearchPresent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.search.present; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import pub.kanzhibo.app.api.ApiClient; 7 | import pub.kanzhibo.app.api.RxSchedulers; 8 | import pub.kanzhibo.app.base.BaseSearchPresent; 9 | import pub.kanzhibo.app.global.Constants; 10 | import pub.kanzhibo.app.model.PlatForm; 11 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 12 | import pub.kanzhibo.app.model.searchliveuser.LiveUserPanda; 13 | import rx.functions.Func1; 14 | 15 | /** 16 | * Created by snail on 16/10/30. 17 | */ 18 | public class PandaSearchPresent extends BaseSearchPresent { 19 | 20 | @Override 21 | public void searchUser(final boolean pullToRefresh, String searchKey, int page) { 22 | //熊猫tv的接口有点特殊--app接口特殊,已经转换为pc端接口 23 | //todo 现在展示的图片是直播截图,并不是用户头像,整合两个请求到一起getPandaRoomInfo 24 | preRequest(pullToRefresh); 25 | subscription = ApiClient.getInstance().getLiveApi(Constants.PANDA_BASE_URL) 26 | .searchPanda(searchKey, page) 27 | .map(new Func1>() { 28 | @Override 29 | public List call(LiveUserPanda liveUserPanda) { 30 | List result = new ArrayList(); 31 | if (liveUserPanda.getErrno() == 0 && Integer.parseInt(liveUserPanda.getData().getTotal()) > 0) { 32 | List items = liveUserPanda.getData().getItems(); 33 | for (LiveUserPanda.DataEntity.ItemsEntity entity : items) { 34 | LiveUser liveUser = new LiveUser(); 35 | liveUser.setUid(entity.getRoomid()); 36 | liveUser.setPlatform(PlatForm.PANDA); 37 | liveUser.setUserName(entity.getNickname()); 38 | //todo 应该查询本地数据库 39 | liveUser.setHasFocus(false); 40 | liveUser.setRoomTitle(entity.getName()); 41 | liveUser.setUserIconUrl(entity.getPictures().getImg()); 42 | liveUser.setViewersCount("关注人数:" + entity.getFans()); 43 | liveUser.setStatus("2".equals(entity.getStatus()) ? "在直播" : "未开播"); 44 | result.add(liveUser); 45 | } 46 | } 47 | return result; 48 | } 49 | }) 50 | .compose(RxSchedulers.>applySchedulers()) 51 | .subscribe(getSubscriber()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/search/present/QuanminSearchPresent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.search.present; 2 | 3 | import org.json.JSONException; 4 | import org.json.JSONObject; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import okhttp3.RequestBody; 10 | import pub.kanzhibo.app.api.ApiClient; 11 | import pub.kanzhibo.app.api.RxSchedulers; 12 | import pub.kanzhibo.app.base.BaseSearchPresent; 13 | import pub.kanzhibo.app.global.Constants; 14 | import pub.kanzhibo.app.model.PlatForm; 15 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 16 | import pub.kanzhibo.app.model.searchliveuser.LiveUserQuanmin; 17 | import rx.functions.Func1; 18 | 19 | /** 20 | * Created by snail on 16/10/30. 21 | */ 22 | public class QuanminSearchPresent extends BaseSearchPresent { 23 | 24 | @Override 25 | public void searchUser(final boolean pullToRefresh, String searchKey, int page) { 26 | preRequest(pullToRefresh); 27 | String jsonStr = "{\"device\":\" 9799abf2a99657ca \",\"v\":\"2.1.3\",\"screen\":\"2\",\"ch\":\"xiaomi\",\"sh\":1280,\"p\":{\"size\":20,\"key\":\"" + searchKey + "\",\"page\":" + page + ",\"categoryId\":0},\"sw\":720,\"uid\":\"a7514f777d03\",\"net\":\"0\",\"ver\":\"4\",\"os\":\"1\"}"; 28 | RequestBody body = null; 29 | try { 30 | body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), (new JSONObject(jsonStr)).toString()); 31 | } catch (JSONException e) { 32 | e.printStackTrace(); 33 | } 34 | subscription = ApiClient.getInstance().getLiveApi(Constants.QUANMIN_BASE_URL) 35 | .searchQuanmin(body) 36 | .map(new Func1>() { 37 | @Override 38 | public List call(LiveUserQuanmin liveUserQuanmin) { 39 | List result = new ArrayList(); 40 | if (liveUserQuanmin.getCode() == 200 && liveUserQuanmin.getData().getTotal() > 0) { 41 | List items = liveUserQuanmin.getData().getItems(); 42 | for (LiveUserQuanmin.DataEntity.ItemsEntity entity : items) { 43 | LiveUser liveUser = new LiveUser(); 44 | liveUser.setUid(entity.getUid()+""); 45 | liveUser.setPlatform(PlatForm.QUANMIN); 46 | liveUser.setUserName(entity.getNick()); 47 | //todo 应该查询本地数据库 48 | liveUser.setHasFocus(false); 49 | liveUser.setRoomTitle(entity.getTitle()); 50 | liveUser.setUserIconUrl(entity.getAvatar()); 51 | liveUser.setViewersCount("观看人数:" + entity.getView()); 52 | liveUser.setStatus(entity.isPlay_status() ? "在直播" : "未开播"); 53 | result.add(liveUser); 54 | } 55 | } 56 | return result; 57 | } 58 | }) 59 | .compose(RxSchedulers.>applySchedulers()) 60 | .subscribe(getSubscriber()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/search/present/ZhanqiSearchPresent.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.search.present; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import pub.kanzhibo.app.api.ApiClient; 7 | import pub.kanzhibo.app.api.RxSchedulers; 8 | import pub.kanzhibo.app.base.BaseSearchPresent; 9 | import pub.kanzhibo.app.global.Constants; 10 | import pub.kanzhibo.app.model.PlatForm; 11 | import pub.kanzhibo.app.model.searchliveuser.LiveUser; 12 | import pub.kanzhibo.app.model.searchliveuser.LiveUserZhanqi; 13 | import rx.functions.Func1; 14 | 15 | /** 16 | * Created by snail on 16/10/30. 17 | */ 18 | public class ZhanqiSearchPresent extends BaseSearchPresent { 19 | 20 | @Override 21 | public void searchUser(final boolean pullToRefresh, String searchKey, int page) { 22 | preRequest(pullToRefresh); 23 | subscription = ApiClient.getInstance().getLiveApi(Constants.ZHANQI_BASE_URL) 24 | .searchZhanqi(searchKey, page + 1) 25 | .map(new Func1>() { 26 | @Override 27 | public List call(LiveUserZhanqi liveUserZhanqi) { 28 | List result = new ArrayList(); 29 | if (liveUserZhanqi.getCode() == 0 && liveUserZhanqi.getData() != null && liveUserZhanqi.getData().size() > 0) { 30 | for (LiveUserZhanqi.DataEntity entity : liveUserZhanqi.getData()) { 31 | LiveUser liveUser = new LiveUser(); 32 | liveUser.setUid(entity.getId().replace("room-","")); 33 | liveUser.setPlatform(PlatForm.ZHANQI); 34 | liveUser.setUserName(entity.getNickname().replace("","").replace("","")); 35 | //todo 应该查询本地数据库 36 | liveUser.setHasFocus(false); 37 | liveUser.setRoomTitle(entity.getTitle()); 38 | liveUser.setUserIconUrl(entity.getAvatar()); 39 | liveUser.setViewersCount("关注人数:" + entity.getDocTag().getFollows()); 40 | liveUser.setStatus("0".equals(entity.getStatus()) ? "在直播" : "未开播"); 41 | result.add(liveUser); 42 | } 43 | } 44 | return result; 45 | } 46 | }) 47 | .compose(RxSchedulers.>applySchedulers()) 48 | .subscribe(getSubscriber()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/util/DialogHelp.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.util; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.support.v7.app.AlertDialog; 7 | import android.text.Html; 8 | import android.text.TextUtils; 9 | 10 | import static pub.kanzhibo.app.global.Constants.Key.SELECT_SAVE_WHERE; 11 | 12 | /** 13 | * 对话框辅助类 14 | */ 15 | public class DialogHelp { 16 | 17 | /*** 18 | * 获取一个dialog 19 | * 20 | * @param context 21 | * @return 22 | */ 23 | public static AlertDialog.Builder getDialog(Context context) { 24 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 25 | return builder; 26 | } 27 | 28 | /*** 29 | * 获取一个耗时等待对话框 30 | * 31 | * @param context 32 | * @param message 33 | * @return 34 | */ 35 | public static ProgressDialog getWaitDialog(Context context, String message) { 36 | ProgressDialog waitDialog = new ProgressDialog(context); 37 | if (!TextUtils.isEmpty(message)) { 38 | waitDialog.setMessage(message); 39 | } 40 | return waitDialog; 41 | } 42 | 43 | /*** 44 | * 获取一个信息对话框,注意需要自己手动调用show方法显示 45 | * 46 | * @param context 47 | * @param message 48 | * @param onClickListener 49 | * @return 50 | */ 51 | public static AlertDialog.Builder getMessageDialog(Context context, String message, DialogInterface.OnClickListener onClickListener) { 52 | AlertDialog.Builder builder = getDialog(context); 53 | builder.setMessage(message); 54 | builder.setPositiveButton("确定", onClickListener); 55 | return builder; 56 | } 57 | 58 | public static AlertDialog.Builder getMessageDialog(Context context, String message) { 59 | return getMessageDialog(context, message, null); 60 | } 61 | 62 | public static AlertDialog.Builder getConfirmDialog(Context context, String message, DialogInterface.OnClickListener onClickListener) { 63 | AlertDialog.Builder builder = getDialog(context); 64 | builder.setMessage(Html.fromHtml(message)); 65 | builder.setPositiveButton("确定", onClickListener); 66 | builder.setNegativeButton("取消", null); 67 | return builder; 68 | } 69 | public static AlertDialog.Builder getConfirmDialog(Context context, String confirmText, String message, DialogInterface.OnClickListener onClickListener) { 70 | AlertDialog.Builder builder = getDialog(context); 71 | builder.setMessage(Html.fromHtml(message)); 72 | builder.setPositiveButton(confirmText, onClickListener); 73 | builder.setNegativeButton("取消", null); 74 | return builder; 75 | } 76 | 77 | public static AlertDialog.Builder getConfirmDialog(Context context, String message, DialogInterface.OnClickListener onOkClickListener, DialogInterface.OnClickListener onCancleClickListener) { 78 | AlertDialog.Builder builder = getDialog(context); 79 | builder.setMessage(message); 80 | if ("您有未发送的帖子".equals(message)) { 81 | builder.setPositiveButton("查看", onOkClickListener); 82 | } else 83 | builder.setPositiveButton("确定", onOkClickListener); 84 | builder.setNegativeButton("取消", onCancleClickListener); 85 | return builder; 86 | } 87 | 88 | public static AlertDialog.Builder getSelectDialog(Context context, String title, String[] arrays, DialogInterface.OnClickListener onClickListener) { 89 | AlertDialog.Builder builder = getDialog(context); 90 | builder.setItems(arrays, onClickListener); 91 | if (!TextUtils.isEmpty(title)) { 92 | builder.setTitle(title); 93 | } 94 | builder.setPositiveButton("取消", null); 95 | return builder; 96 | } 97 | 98 | public static AlertDialog.Builder getSelectDialog(Context context, String[] arrays, DialogInterface.OnClickListener onClickListener) { 99 | return getSelectDialog(context, "", arrays, onClickListener); 100 | } 101 | 102 | public static AlertDialog.Builder getSingleChoiceDialog(Context context, String title, String[] arrays, int selectIndex, DialogInterface.OnClickListener onClickListener) { 103 | AlertDialog.Builder builder = getDialog(context); 104 | builder.setSingleChoiceItems(arrays, selectIndex, onClickListener); 105 | if (!TextUtils.isEmpty(title)) { 106 | builder.setTitle(title); 107 | } 108 | builder.setNegativeButton("取消", null); 109 | return builder; 110 | } 111 | 112 | public static AlertDialog.Builder getSingleChoiceDialog(Context context, String[] arrays, int selectIndex, DialogInterface.OnClickListener onClickListener) { 113 | return getSingleChoiceDialog(context, "", arrays, selectIndex, onClickListener); 114 | } 115 | public static void getSelectSaveDataDialog(final Context context, boolean alwaysShow, int index, DialogInterface.OnClickListener onClickListener) { 116 | if (!SharedPreferencesUtils.getBoolean(context, SELECT_SAVE_WHERE, false) || alwaysShow) { 117 | String[] strings = {"只保存到本地", "保存到服务器"}; 118 | getSingleChoiceDialog(context, "选择保存方式", strings, index, onClickListener) 119 | .show(); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/util/ResUtil.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by ykrc17 on 2016/10/23. 7 | */ 8 | 9 | public class ResUtil { 10 | public static int dp2px(Context context, float dp) { 11 | return (int) (context.getResources().getDisplayMetrics().density * dp + 0.5); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/util/SharedPreferencesUtils.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.util; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | public class SharedPreferencesUtils { 7 | 8 | public static String SP_NAME = "config"; 9 | private static SharedPreferences sp; 10 | 11 | /** 12 | * SharedPreferences 保存boolean 13 | * 14 | * @param context 15 | * @param key 16 | * @param value 17 | */ 18 | public static void saveBoolean(Context context, String key, boolean value) { 19 | if (sp == null) 20 | sp = context.getSharedPreferences(SP_NAME, 0); 21 | sp.edit().putBoolean(key, value).commit(); 22 | } 23 | 24 | public static boolean getBoolean(Context context, String key, boolean defValue) { 25 | if (sp == null) { 26 | sp = context.getSharedPreferences(SP_NAME, 0); 27 | 28 | } 29 | return sp.getBoolean(key, defValue); 30 | } 31 | 32 | 33 | /** 34 | * SharedPreferences 保存字符串 35 | * 36 | * @param context 37 | * @param key 38 | * @param value 39 | */ 40 | public static void saveString(Context context, String key, String value) { 41 | if (sp == null) 42 | sp = context.getSharedPreferences(SP_NAME, 0); 43 | sp.edit().putString(key, value).commit(); 44 | } 45 | 46 | public static String getString(Context context, String key, String defValue) { 47 | if (sp == null) { 48 | sp = context.getSharedPreferences(SP_NAME, 0); 49 | 50 | } 51 | return sp.getString(key, defValue); 52 | } 53 | 54 | /** 55 | * 保存token 56 | * 57 | * @param context 58 | * @param value 59 | */ 60 | public static void saveToken(Context context, String value) { 61 | saveString(context, "token", value); 62 | } 63 | 64 | public static String getToken(Context context) { 65 | return getString(context, "token", null); 66 | } 67 | 68 | /** 69 | * 保存用户名 70 | * 71 | * @param context 72 | * @param value 73 | */ 74 | public static void saveUserName(Context context, String value) { 75 | saveString(context, "douyuusername", value); 76 | } 77 | 78 | public static String getUserName(Context context) { 79 | return getString(context, "douyuusername", null); 80 | } 81 | 82 | /** 83 | * 保存斗鱼用户名 84 | * 85 | * @param context 86 | * @param value 87 | */ 88 | public static void saveDouyuUserName(Context context, String value) { 89 | saveString(context, "douyuusername", value); 90 | } 91 | 92 | public static String getDouyuUserName(Context context) { 93 | return getString(context, "douyuusername", null); 94 | } 95 | 96 | /** 97 | * 保存斗鱼登录密码 98 | * 99 | * @param context 100 | * @param value 101 | */ 102 | public static void saveDouyuPassword(Context context, String value) { 103 | saveString(context, "douyupassword", value); 104 | } 105 | 106 | public static String getDouyuPassword(Context context) { 107 | return getString(context, "douyupassword", null); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/pub/kanzhibo/app/util/VersionUtils.java: -------------------------------------------------------------------------------- 1 | package pub.kanzhibo.app.util; 2 | 3 | /** 4 | * Created by turbo on 2016/12/30. 5 | */ 6 | 7 | import android.os.Build; 8 | import android.support.annotation.RequiresApi; 9 | 10 | public final class VersionUtils { 11 | 12 | @RequiresApi(Build.VERSION_CODES.N_MR1) 13 | public static boolean isAfter25() { 14 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1; 15 | } 16 | 17 | @RequiresApi(Build.VERSION_CODES.N) 18 | public static boolean isAfter24() { 19 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; 20 | } 21 | 22 | public static boolean isAfter23() { 23 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; 24 | } 25 | 26 | public static boolean isAfter22() { 27 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1; 28 | } 29 | 30 | public static boolean isAfter21() { 31 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; 32 | } 33 | 34 | public static boolean isAfter20() { 35 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH; 36 | } 37 | 38 | public static boolean isAfter19() { 39 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 40 | } 41 | 42 | public static boolean isAfter18() { 43 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; 44 | } 45 | 46 | public static boolean isAfter17() { 47 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1; 48 | } 49 | 50 | public static boolean isAfter16() { 51 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 52 | } 53 | 54 | public static boolean isAfter14() { 55 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; 56 | } 57 | 58 | public static boolean isAfter13() { 59 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2; 60 | } 61 | 62 | public static boolean isAfter11() { 63 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; 64 | } 65 | 66 | public static boolean isAfter9() { 67 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD; 68 | } 69 | 70 | public static boolean isAfter8() { 71 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO; 72 | } 73 | 74 | public static boolean isAfter5() { 75 | return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_bottom_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_menu_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_menu_gallery.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_menu_manage.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_menu_send.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_menu_share.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_menu_slideshow.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/avoscloud_feedback_actionbar_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/avoscloud_feedback_thread_actionbar_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fanturbo/Kanzhibo/26b4780369143684c459c68e5ba3e5f253fb812e/app/src/main/res/drawable/avoscloud_feedback_thread_actionbar_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty_bike.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 57 | 60 | 63 | 66 | 69 | 72 | 75 | 78 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/live_status_backgroud.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/side_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_common.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 21 | 22 | 32 | 33 | 42 | 43 | 44 | 50 | 51 | 56 | 57 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_bar_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/avoscloud_feedback_activity_conversation.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 21 | 22 | 31 | 32 | 33 | 45 | 46 | 47 | 61 | 62 | 63 | 64 | 78 | 79 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /app/src/main/res/layout/avoscloud_feedback_dev_reply.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | 28 | 29 | 35 | 36 | 37 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/avoscloud_feedback_thread_actionbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/avoscloud_feedback_user_reply.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | 29 | 30 | 36 | 37 | 38 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 22 | 23 | 32 | 33 | 39 | 40 | 49 | 50 | 51 |