├── .gitignore ├── .gradle ├── 3.4.1 │ ├── file-changes │ │ └── last-build.bin │ ├── fileContent │ │ ├── annotation-processors.bin │ │ └── fileContent.lock │ └── taskHistory │ │ ├── fileHashes.bin │ │ ├── fileSnapshots.bin │ │ ├── jvmClassSignatures.bin │ │ ├── taskHistory.bin │ │ └── taskHistory.lock └── buildOutputCleanup │ ├── built.bin │ ├── cache.properties │ └── cache.properties.lock ├── README.md ├── apk └── app-debug.apk ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yangxiaobin │ │ └── gank │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── yangxiaobin │ │ │ ├── Constant.java │ │ │ └── gank │ │ │ ├── App.java │ │ │ ├── common │ │ │ ├── base │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── BasePresenter.java │ │ │ │ ├── IBaseModel.java │ │ │ │ └── IBaseView.java │ │ │ ├── bean │ │ │ │ ├── CategoryEntity.java │ │ │ │ ├── CollectionEntity.java │ │ │ │ ├── ContentItemEntity.java │ │ │ │ ├── GankDailyDataEntity.java │ │ │ │ ├── GankDailyTitleEntity.java │ │ │ │ ├── GankTotalHistoryEntity.java │ │ │ │ ├── GitHubUserEntity.java │ │ │ │ ├── RealmString.java │ │ │ │ └── SearchHistoryEntity.java │ │ │ ├── db │ │ │ │ └── RealmHelper.java │ │ │ ├── glide │ │ │ │ └── GankGlideModule.java │ │ │ ├── net │ │ │ │ ├── ApiExceptionHandler.java │ │ │ │ ├── ApiService.java │ │ │ │ └── ErrorConsumer.java │ │ │ └── utils │ │ │ │ ├── BlurBitmapUtils.java │ │ │ │ ├── CacheHelper.java │ │ │ │ ├── CircularRevealUtils.java │ │ │ │ ├── CleanCatcheUtils.java │ │ │ │ ├── ImageUtils.java │ │ │ │ ├── ImmersiveStatusBarUtils.java │ │ │ │ ├── RoundImageTransformation.java │ │ │ │ ├── Rx2Bus.java │ │ │ │ ├── RxUtils.java │ │ │ │ ├── SPUtils.java │ │ │ │ ├── Unicode2ChineseUtils.java │ │ │ │ ├── UserUtils.java │ │ │ │ └── ViewSwitchUtils.java │ │ │ ├── di │ │ │ ├── component │ │ │ │ ├── AboutComponent.java │ │ │ │ ├── AppComponent.java │ │ │ │ └── LoginDialogComponent.java │ │ │ ├── module │ │ │ │ ├── AboutModule.java │ │ │ │ ├── ApiModule.java │ │ │ │ ├── AppModule.java │ │ │ │ ├── LoginDialogModule.java │ │ │ │ └── RepositoryModule.java │ │ │ └── scope │ │ │ │ ├── Cached.java │ │ │ │ ├── LoginUsed.java │ │ │ │ └── UnCatched.java │ │ │ └── mvp │ │ │ ├── contract │ │ │ ├── CategoryContract.java │ │ │ ├── CollectionContract.java │ │ │ ├── ContentContract.java │ │ │ ├── MainContract.java │ │ │ └── SearchContract.java │ │ │ ├── model │ │ │ ├── local │ │ │ │ └── GankItemModel.java │ │ │ └── remote │ │ │ │ ├── CategoryModel.java │ │ │ │ ├── CollectionMoel.java │ │ │ │ ├── ContentModel.java │ │ │ │ ├── MainModel.java │ │ │ │ └── SearchModel.java │ │ │ ├── presenter │ │ │ ├── CategoryPresenter.java │ │ │ ├── CollectionPresenter.java │ │ │ ├── ContentPresenter.java │ │ │ ├── MainPresenter.java │ │ │ └── SearchPresenter.java │ │ │ └── view │ │ │ ├── Itemtype │ │ │ ├── ItemTypeCategory.java │ │ │ ├── ItemTypeContentCategoryContent.java │ │ │ ├── ItemTypeContentCategoryTitle.java │ │ │ └── ItemTypeMainCard.java │ │ │ ├── activity │ │ │ ├── LandscapeVideoActivity.java │ │ │ └── MainActivity.java │ │ │ ├── adapter │ │ │ ├── CategoryAdapter.java │ │ │ ├── ContentAdapter.java │ │ │ ├── FlagForContentAdapter.java │ │ │ ├── MainAdapter.java │ │ │ └── SearchHistoryAdapter.java │ │ │ ├── fragment │ │ │ ├── AboutFragment.java │ │ │ ├── CategoryFragment.java │ │ │ ├── CollectionFragment.java │ │ │ ├── ContentFragment.java │ │ │ ├── LoginDialogFragment.java │ │ │ ├── MeiziFragment.java │ │ │ ├── PicDialogFragment.java │ │ │ ├── SearchFragment.java │ │ │ ├── SplashFragment.java │ │ │ └── WebFragment.java │ │ │ ├── listener │ │ │ └── RecyclerViewOnScrollListener.java │ │ │ └── widget │ │ │ └── cardgallery │ │ │ ├── CardAdapterHelper.java │ │ │ ├── CardLinearSnapHelper.java │ │ │ ├── CardScaleHelper.java │ │ │ └── SpeedRecyclerView.java │ └── res │ │ ├── drawable-xxhdpi │ │ ├── ic_android_128.png │ │ ├── ic_app_128.png │ │ ├── ic_clear_cache_128.png │ │ ├── ic_close_white_128.png │ │ ├── ic_collcetion_128.png │ │ ├── ic_collected_128.png │ │ ├── ic_empty_box_128.png │ │ ├── ic_error_128.png │ │ ├── ic_extend_128.png │ │ ├── ic_garbage_black_64.png │ │ ├── ic_github_200.png │ │ ├── ic_ios_128.png │ │ ├── ic_not_collected_128.png │ │ ├── ic_placeholer_128.png │ │ ├── ic_recommend_128.png │ │ ├── ic_search_white_64.png │ │ ├── ic_the_heart_stealer_128.png │ │ ├── ic_video_128.png │ │ ├── ic_web_128.png │ │ └── load_error.png │ │ ├── drawable-xxxhdpi │ │ ├── header_dialog_fragment.jpg │ │ └── ic_left_arraw_128.png │ │ ├── drawable │ │ ├── bg_dialog_fragment_login_github.xml │ │ └── lift_on_touch.xml │ │ ├── layout │ │ ├── activity_landscape_video.xml │ │ ├── activity_main_content.xml │ │ ├── activity_main_drawer.xml │ │ ├── dialog_login_github_fragment.xml │ │ ├── dialog_pic_fragment.xml │ │ ├── footer_search_history.xml │ │ ├── fragment_about.xml │ │ ├── fragment_category.xml │ │ ├── fragment_collection.xml │ │ ├── fragment_content.xml │ │ ├── fragment_meizi.xml │ │ ├── fragment_search.xml │ │ ├── fragment_splash.xml │ │ ├── fragment_web.xml │ │ ├── header_search_history.xml │ │ ├── item_content_fragment_content.xml │ │ ├── item_content_fragment_title.xml │ │ ├── item_main_recyclerivew_load_more.xml │ │ ├── item_main_recyclerview_main_card.xml │ │ ├── item_search_history_search_fragment.xml │ │ ├── layout_empty_list.xml │ │ ├── layout_header_navitaionview_main.xml │ │ ├── layout_load_error.xml │ │ └── slide_menu_collection.xml │ │ ├── menu │ │ ├── menu_navigation_main_activity.xml │ │ ├── menu_toolbar_main_activity.xml │ │ ├── menu_toolbar_search_fragment.xml │ │ └── menu_web_fragment.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── change_round_200.webp │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── yangxiaobin │ └── gank │ └── ExampleUnitTest.java ├── art ├── 1.jpeg ├── 2.jpeg ├── 3.jpeg ├── 4.jpeg ├── 5.jpeg ├── 6.jpeg └── pic_down_load.png ├── build.gradle ├── config.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .gitignore 3 | NewGank.iml 4 | app/app.iml 5 | app/presentation.iml 6 | build/ 7 | local.properties 8 | /.idea/ 9 | /.gradle/ 10 | 11 | -------------------------------------------------------------------------------- /.gradle/3.4.1/file-changes/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/3.4.1/fileContent/annotation-processors.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/3.4.1/fileContent/annotation-processors.bin -------------------------------------------------------------------------------- /.gradle/3.4.1/fileContent/fileContent.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/3.4.1/fileContent/fileContent.lock -------------------------------------------------------------------------------- /.gradle/3.4.1/taskHistory/fileHashes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/3.4.1/taskHistory/fileHashes.bin -------------------------------------------------------------------------------- /.gradle/3.4.1/taskHistory/fileSnapshots.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/3.4.1/taskHistory/fileSnapshots.bin -------------------------------------------------------------------------------- /.gradle/3.4.1/taskHistory/jvmClassSignatures.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/3.4.1/taskHistory/jvmClassSignatures.bin -------------------------------------------------------------------------------- /.gradle/3.4.1/taskHistory/taskHistory.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/3.4.1/taskHistory/taskHistory.bin -------------------------------------------------------------------------------- /.gradle/3.4.1/taskHistory/taskHistory.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/3.4.1/taskHistory/taskHistory.lock -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/built.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/.gradle/buildOutputCleanup/built.bin -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/cache.properties: -------------------------------------------------------------------------------- 1 | #Sun Sep 24 23:31:32 CST 2017 2 | gradle.version=4.1 3 | -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/cache.properties.lock: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### [GankIO](http://gank.io/) Android 客户端 感谢 代码家 提供Api支持! 2 | 3 | ### App 4 | MVP+Dagger2.android+Retrofit+RxJava2+Glide+Realm。 5 | 单Activity+多Fragment 架构,fragment back 处理。 6 | 7 | 8 | ### ScreenShot 9 | 10 | 11 | 12 | 13 | 14 | ### [APK下载](apk/app-debug.apk) 15 | 16 | [pgy下载页](https://www.pgyer.com/bgWq) 17 | 18 | 19 | 20 | 21 | ### 功能 22 | 1. GitHub 账户即可登录,无需密码,用户创建本地账户收藏干货用。 23 | 2. 侧滑收藏/取消收藏。 24 | 3. 每日干货浏览,分类浏览。 25 | 4. 搜索功能,搜索历史支持。 26 | 5. 高清妹子长按下载。 27 | 6. 干货分享(原生)。 28 | 7. 无网络缓存(okHttpClient)。 29 | 8. 缓存清理。 30 | 9. Item 图片预览图,点击查看大图。 31 | 32 | 33 | 34 | ### 开源库 35 | 1. [RxJava2](https://github.com/ReactiveX/RxJava) 36 | 2. [Dagger2.android](https://github.com/google/dagger) 37 | 3. [ButterKnife](https://github.com/JakeWharton/butterknife) 38 | 4. [Glide](https://github.com/bumptech/glide) 39 | 5. [PhotoView](https://github.com/chrisbanes/PhotoView) 40 | 6. [rxPermission](https://github.com/tbruyelle/RxPermissions) 41 | 7. [Retrofit](https://github.com/square/retrofit) 42 | 8. [Realm](https://github.com/realm/realm-java) 43 | 9. [Easy RecyclerView](https://github.com/yangxiaobinhaoshuai/EasyRecyclerView) 44 | 10. [BaseKits](https://github.com/yangxiaobinhaoshuai/Android-BaseKits) 45 | 46 | ### 欢迎Issue! 47 | -------------------------------------------------------------------------------- /apk/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/apk/app-debug.apk -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /build/ 3 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'realm-android' 3 | 4 | android { 5 | compileSdkVersion rootProject.ext.android.compileSdkVersion 6 | buildToolsVersion rootProject.ext.android.buildToolsVersion 7 | 8 | defaultConfig { 9 | applicationId "com.yangxiaobin.gank" 10 | minSdkVersion rootProject.ext.android.minSdkVersion 11 | targetSdkVersion rootProject.ext.android.targetSdkVersion 12 | versionCode rootProject.ext.android.versionCode 13 | versionName rootProject.ext.android.versionName 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | 16 | //启用renderscript 17 | renderscriptTargetApi = 18 18 | renderscriptSupportModeEnabled = true 19 | 20 | //添加如下配置就OK了 解决butterKnife问题 21 | javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } } 22 | } 23 | buildTypes { 24 | release { 25 | minifyEnabled true 26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | // for :https://stackoverflow.com/questions/37347326/errorconflict-with-dependency-com-google-code-findbugsjsr305 30 | configurations.all { 31 | resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' 32 | } 33 | // 禁止gradle严格检查图片的合法性! 34 | aaptOptions.cruncherEnabled = false 35 | aaptOptions.useNewCruncher = false 36 | } 37 | 38 | 39 | dependencies { 40 | implementation fileTree(include: ['*.jar'], dir: 'libs') 41 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { 42 | exclude group: 'com.android.support', module: 'support-annotations' 43 | }) 44 | testImplementation 'junit:junit:4.12' 45 | implementation rootProject.ext.dependencies["appcompat-v7"] 46 | implementation rootProject.ext.dependencies["cardview"] 47 | implementation rootProject.ext.dependencies["support-v4"] 48 | implementation rootProject.ext.dependencies["support_design"] 49 | // retrofit+rxJava2 50 | implementation rootProject.ext.dependencies["retrofit"] 51 | implementation rootProject.ext.dependencies["converter-gson"] 52 | implementation rootProject.ext.dependencies["retrofit2-rxjava2-adapter"] 53 | implementation rootProject.ext.dependencies["rxjava2"] 54 | implementation rootProject.ext.dependencies["rxandroid"] 55 | // okHttp log拦截器 56 | implementation rootProject.ext.dependencies["logging-interceptor"] 57 | implementation rootProject.ext.dependencies["logger"] 58 | // Glide 59 | implementation rootProject.ext.dependencies["glide"] 60 | implementation rootProject.ext.dependencies["glide-okhttp3"] 61 | annotationProcessor rootProject.ext.dependencies["glide-complier"] 62 | // ButterKnife 63 | implementation rootProject.ext.dependencies["butterknife"] 64 | implementation rootProject.ext.dependencies["butterknife-compiler"] 65 | // Dagger2 66 | implementation rootProject.ext.dependencies["dagger2"] 67 | implementation rootProject.ext.dependencies["dagger2-android"] 68 | implementation rootProject.ext.dependencies["dagger2-android-support"] 69 | annotationProcessor rootProject.ext.dependencies["dagger2-android-processor"] 70 | annotationProcessor rootProject.ext.dependencies["dagger2-processor"] 71 | // https://github.com/chrisbanes/PhotoView 72 | implementation rootProject.ext.dependencies["photoview"] 73 | // https://www.pgyer.com/doc/view/sdk_android_guide 74 | implementation 'com.pgyersdk:sdk:2.6.9@aar' 75 | // https://github.com/tbruyelle/RxPermissions 76 | implementation 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar' 77 | 78 | // yangxiaobin 79 | implementation rootProject.ext.dependencies["easy-recyclerview"] 80 | implementation rootProject.ext.dependencies["base-tools"] 81 | implementation rootProject.ext.dependencies["handsomeToast"] 82 | } 83 | -------------------------------------------------------------------------------- /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 /Users/handsomeyang/Library/Android/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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/yangxiaobin/gank/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import android.util.Log; 8 | import com.orhanobut.logger.Logger; 9 | import io.reactivex.Observable; 10 | import io.reactivex.functions.Consumer; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import org.json.JSONObject; 14 | import org.junit.Test; 15 | import org.junit.runner.RunWith; 16 | 17 | import static org.junit.Assert.*; 18 | 19 | /** 20 | * Instrumentation test, which will execute on an Android device. 21 | * 22 | * @see Testing documentation 23 | */ 24 | @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { 25 | @Test public void useAppContext() throws Exception { 26 | // Context of the app under test. 27 | Context appContext = InstrumentationRegistry.getTargetContext(); 28 | 29 | //assertEquals("com.yangxiaobin.gank", appContext.getPackageName()); 30 | JSONObject jsonObject=new JSONObject(); 31 | jsonObject.put("111","222"); 32 | jsonObject.put("3333","4444"); 33 | Log.e("1111",jsonObject.toString()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 29 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/Constant.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin; 2 | 3 | import android.support.annotation.StringDef; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | /** 8 | * Created by handsomeyang on 2017/6/27. 9 | * 全局常量 10 | */ 11 | 12 | public final class Constant { 13 | /** 14 | * gank io api 15 | */ 16 | public static final String BASE_URL = "http://gank.io/api/"; 17 | public static final long CONNECT_TIMEOUT = 15000; 18 | public static final long READ_TIMEOUT = 15000; 19 | public static final long WRITE_TIMEOUT = 15000; 20 | public static final int SAFT_QUIT_INTERVAL = 2000; 21 | public static final String CACHE_FILE_NAME = "gank.cache"; 22 | public static final int MEIZI_COUNT = 5; //默认取5天数据 23 | public static final int RECYCLERVIEW_CARD_HELPER_NULL = -1; 24 | public static final String FINISH_SPLASH = "finish_splash"; 25 | /** 26 | * SP key 27 | */ 28 | public static final String KEY_HAS_GOT_MY_HEAD_IMAGE = "key_has_got_my_head_image"; 29 | 30 | /** 31 | * gank item category 32 | */ 33 | @StringDef @Retention(RetentionPolicy.SOURCE) public @interface Category { 34 | String ANDROID = "Android"; 35 | String IOS = "iOS"; 36 | String WEB = "前端"; 37 | String SUGGEST = "瞎推荐"; 38 | String MEIZI = "福利"; 39 | String VIDEO = "休息视频"; 40 | String EXTEND = "拓展资源"; 41 | String APP = "App"; 42 | String ALL = "all"; 43 | } 44 | 45 | /** 46 | * github config 47 | */ 48 | public static final String GITHUB_SERVER = "https://api.github.com/"; 49 | /** 50 | * my github account for my head image 51 | */ 52 | public static final String MY_GITHUB_ACCOUNT = "yangxiaobinhaoshuai"; 53 | 54 | // SharePreference key 55 | public static final String KEY_USER_NAME = "key_user_name"; 56 | public static final String KEY_USER_ID_LOGIN = "key_user_id_login"; 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/App.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank; 2 | 3 | import android.support.v4.app.Fragment; 4 | import com.handsome.library.T; 5 | import com.orhanobut.logger.AndroidLogAdapter; 6 | import com.orhanobut.logger.Logger; 7 | import com.pgyersdk.crash.PgyCrashManager; 8 | import com.yangxiaobin.gank.common.bean.GankDailyDataEntity; 9 | import com.yangxiaobin.gank.common.utils.RxUtils; 10 | import com.yangxiaobin.gank.di.component.DaggerAppComponent; 11 | import com.yxb.base.utils.CommonUtils; 12 | import dagger.android.AndroidInjector; 13 | import dagger.android.DaggerApplication; 14 | import dagger.android.DispatchingAndroidInjector; 15 | import dagger.android.support.HasSupportFragmentInjector; 16 | import io.reactivex.Observable; 17 | import io.realm.Realm; 18 | import io.realm.RealmConfiguration; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import javax.inject.Inject; 22 | 23 | /** 24 | * Created by handsomeyang on 2017/6/23. 25 | */ 26 | 27 | public class App extends DaggerApplication implements HasSupportFragmentInjector { 28 | 29 | @Inject DispatchingAndroidInjector mFragmentSupportInjector; 30 | 31 | // 保存item点击过的url 32 | private List mItemUrls = new ArrayList<>(); 33 | private static App sINSTANCE; 34 | 35 | @Override public void onCreate() { 36 | super.onCreate(); 37 | initialize(); 38 | } 39 | 40 | public static App getINSTANCE() { 41 | return sINSTANCE; 42 | } 43 | 44 | public List getItemUrls() { 45 | return mItemUrls; 46 | } 47 | 48 | private void initialize() { 49 | sINSTANCE = this; 50 | CommonUtils.init(this); 51 | // doc: https://github.com/orhanobut/logger 52 | Logger.addLogAdapter(new AndroidLogAdapter()); 53 | T.init(this); 54 | // the realm file will be located in Context.getFilesDir() with the name "realm.default" 55 | Realm.init(this); 56 | RealmConfiguration configuration = 57 | new RealmConfiguration.Builder().name("gank.realm").deleteRealmIfMigrationNeeded().build(); 58 | Realm.setDefaultConfiguration(configuration); 59 | PgyCrashManager.register(this); 60 | } 61 | 62 | @Override protected AndroidInjector applicationInjector() { 63 | return DaggerAppComponent.builder().create(this); 64 | } 65 | 66 | @Override public AndroidInjector supportFragmentInjector() { 67 | return mFragmentSupportInjector; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.base; 2 | 3 | import android.os.Bundle; 4 | import butterknife.ButterKnife; 5 | import com.yxb.base.AbsBaseActivity; 6 | import dagger.android.AndroidInjection; 7 | 8 | /** 9 | * Created by handsomeyang on 2017/6/23. 10 | */ 11 | 12 | public abstract class BaseActivity> extends AbsBaseActivity { 13 | 14 | protected T mPresenter;//Presenter对象 15 | 16 | 17 | @SuppressWarnings("unchecked") @Override protected void onCreate(Bundle savedInstanceState) { 18 | AndroidInjection.inject(this); 19 | super.onCreate(savedInstanceState); 20 | mPresenter = createPresenter();//创建Presenter 21 | mPresenter.attachView((V) this); 22 | } 23 | 24 | @Override protected void onDestroy() { 25 | super.onDestroy(); 26 | mPresenter.detachView(); 27 | } 28 | 29 | protected abstract T createPresenter(); 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.base; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.View; 7 | import butterknife.ButterKnife; 8 | import butterknife.Unbinder; 9 | import com.yxb.base.AbsBaseFragment; 10 | import dagger.android.support.AndroidSupportInjection; 11 | 12 | /** 13 | * Created by handsomeyang on 2017/6/23. 14 | */ 15 | 16 | public abstract class BaseFragment extends AbsBaseFragment implements IBaseView { 17 | 18 | private Unbinder mBind; 19 | 20 | @Override protected void initialize(Bundle savedInstanceState) { 21 | mBind = ButterKnife.bind(this, mRootView); 22 | } 23 | 24 | 25 | @Override public void onAttach(Context context) { 26 | AndroidSupportInjection.inject(this); 27 | super.onAttach(context); 28 | } 29 | 30 | @Override public void onDestroy() { 31 | super.onDestroy(); 32 | mBind.unbind(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/base/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.base; 2 | 3 | import io.reactivex.disposables.CompositeDisposable; 4 | import io.reactivex.disposables.Disposable; 5 | import java.lang.ref.Reference; 6 | import java.lang.ref.WeakReference; 7 | 8 | /** 9 | * Created by handsomeyang on 2017/6/30. 10 | */ 11 | 12 | public abstract class BasePresenter { 13 | 14 | protected Reference mViewRef;//View接口类型弱引用 15 | protected CompositeDisposable mCompositeDisposable = new CompositeDisposable(); 16 | 17 | public void attachView(T view) { 18 | mViewRef = new WeakReference(view); //建立关联 19 | } 20 | 21 | protected T getView() { 22 | return mViewRef.get();//获取View 23 | } 24 | 25 | public boolean isViewAttached() {//判断是否与View建立了关联 26 | return mViewRef != null && mViewRef.get() != null; 27 | } 28 | 29 | public void detachView() {//解除关联 30 | if (mViewRef != null) { 31 | mViewRef.clear(); 32 | mViewRef = null; 33 | } 34 | } 35 | 36 | public abstract void start(); 37 | 38 | protected void unSubscribe() { 39 | mCompositeDisposable.clear(); 40 | } 41 | 42 | protected void register(Disposable disposable) { 43 | mCompositeDisposable.add(disposable); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/base/IBaseModel.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.base; 2 | 3 | /** 4 | * Created by handsomeyang on 2017/6/30. 5 | */ 6 | 7 | public interface IBaseModel { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/base/IBaseView.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.base; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by handsomeyang on 2017/6/30. 7 | */ 8 | 9 | public interface IBaseView { 10 | 11 | Context getViewContext(); 12 | 13 | void showToast(String msg); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/bean/CategoryEntity.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.bean; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by handsomeyang on 2017/7/25. 8 | */ 9 | 10 | public class CategoryEntity { 11 | 12 | /** 13 | * error : false 14 | * results : [{"_id":"5973f95d421aa90c9203d3eb","createdAt":"2017-07-23T09:18:21.828Z","desc":"Android 15 | * 层叠卡片控件,仿\"探探app\"","images":["http://img.gank.io/36e2eb02-be78-4c97-950b-28020d1e0356"],"publishedAt":"2017-07-24T12:13:11.280Z","source":"chrome","type":"Android","url":"https://github.com/fashare2015/StackLayout","used":true,"who":"Jason"},{"_id":"59746449421aa90ca209c4c0","createdAt":"2017-07-23T16:54:33.986Z","desc":"Java 16 | * 时间与日期处理","publishedAt":"2017-07-24T12:13:11.280Z","source":"chrome","type":"Android","url":"https://zhuanlan.zhihu.com/p/28055974","used":true,"who":"王下邀月熊"},{"_id":"5975480b421aa97de5c7c999","createdAt":"2017-07-24T09:06:19.690Z","desc":"RxJava2.X 17 | * 源码解析(一): 探索RxJava2分发订阅流程","publishedAt":"2017-07-24T12:13:11.280Z","source":"web","type":"Android","url":"http://url.cn/4CM8ka6","used":true,"who":"陈宇明"},{"_id":"59754c7f421aa97de5c7c99b","createdAt":"2017-07-24T09:25:19.617Z","desc":"强大和智能的RefreshLayout,支持越界回弹,集成了几十种炫酷的Header和 18 | * Footer","publishedAt":"2017-07-24T12:13:11.280Z","source":"web","type":"Android","url":"https://segmentfault.com/a/1190000010066071","used":true,"who":"树朾"},{"_id":"5975717d421aa90ca3bb6b60","createdAt":"2017-07-24T12:03:09.539Z","desc":"Android 19 | * 简洁优雅的文件选择器。","images":["http://img.gank.io/b3771674-25a1-478a-b665-f0f0960f80a4"],"publishedAt":"2017-07-24T12:13:11.280Z","source":"chrome","type":"Android","url":"https://github.com/FirzenYogesh/FileListerDialog","used":true,"who":"代码家"},{"_id":"5964c8ff421aa90ca3bb6ae1","createdAt":"2017-07-11T20:47:59.353Z","desc":"理解与设计自适应图标 20 | * \u2014\u2014 自适应图标入门指南","publishedAt":"2017-07-21T12:39:43.370Z","source":"chrome","type":"Android","url":"https://zhuanlan.zhihu.com/p/27814686","used":true,"who":"galois"},{"_id":"5969a267421aa90ca209c46a","createdAt":"2017-07-15T13:04:39.224Z","desc":"Android源码完全解析\u2014\u2014View的Measure过程","publishedAt":"2017-07-21T12:39:43.370Z","source":"web","type":"Android","url":"http://www.jianshu.com/p/4a68f9dc8f7c","used":true,"who":null},{"_id":"5971719e421aa97de5c7c97d","createdAt":"2017-07-21T11:14:38.609Z","desc":"一款非常漂亮的 21 | * Material Design 风格的音乐播放器!超棒!","images":["http://img.gank.io/9f05efe7-3196-4de4-af65-24e0a919a584"],"publishedAt":"2017-07-21T12:39:43.370Z","source":"chrome","type":"Android","url":"https://github.com/aliumujib/Orin","used":true,"who":"代码家"},{"_id":"59701bf6421aa90c9203d3c9","createdAt":"2017-07-20T10:56:54.503Z","desc":"自定义View之渐变圆环进度条","publishedAt":"2017-07-20T15:11:16.10Z","source":"web","type":"Android","url":"https://mp.weixin.qq.com/s?__biz=MzIwMzYwMTk1NA==&mid=2247485843&idx=1&sn=d5de05fc0240be0527de8d69b1616c6f&chksm=96cda8dea1ba21c8ba3c620acc07c2ef1e2afc619928587ac8201958af1eb4d3568f6516e4ac#rd","used":true,"who":"陈宇明"},{"_id":"5970415f421aa90ca3bb6b40","createdAt":"2017-07-20T13:36:31.736Z","desc":"又一个漂亮的 22 | * Android 日历组件。","images":["http://img.gank.io/20ad8aae-6740-4695-ad14-12080649690b"],"publishedAt":"2017-07-20T15:11:16.10Z","source":"chrome","type":"Android","url":"https://github.com/MagicMashRoom/SuperCalendar","used":true,"who":"代码家"}] 23 | */ 24 | @SerializedName("count") private int itemCount; 25 | private boolean error; 26 | private List results; 27 | 28 | public int getItemCount() { 29 | return itemCount; 30 | } 31 | 32 | public void setItemCount(int itemCount) { 33 | this.itemCount = itemCount; 34 | } 35 | 36 | public boolean isError() { 37 | return error; 38 | } 39 | 40 | public void setError(boolean error) { 41 | this.error = error; 42 | } 43 | 44 | public List getResults() { 45 | return results; 46 | } 47 | 48 | public void setResults(List results) { 49 | this.results = results; 50 | } 51 | 52 | @Override public String toString() { 53 | return "CategoryEntity{" + "error=" + error + ", results=" + results + '}'; 54 | } 55 | 56 | public static class ResultsBean extends ContentItemEntity { 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/bean/CollectionEntity.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.bean; 2 | 3 | import io.realm.RealmList; 4 | import io.realm.RealmObject; 5 | 6 | /** 7 | * Created by handsomeyang on 2017/8/16. 8 | */ 9 | 10 | public class CollectionEntity extends RealmObject { 11 | /** 12 | * _id : 56cc6d23421aa95caa707a69 13 | * createdAt : 2015-08-06T07:15:52.65Z 14 | * desc : 类似Link Bubble的悬浮式操作设计 15 | * publishedAt : 2015-08-07T03:57:48.45Z 16 | * type : Android 17 | * url : https://github.com/recruit-lifestyle/FloatingView 18 | * used : true 19 | * who : mthli 20 | */ 21 | 22 | private String desc; 23 | private String publishedAt; 24 | private String type; 25 | private String url; 26 | private boolean used; 27 | private RealmList images; 28 | private String who; 29 | private String title; // 类别标题 30 | private String userId; // 标识哪个用户 31 | 32 | public String getUserId() { 33 | return userId; 34 | } 35 | 36 | public void setUserId(String userId) { 37 | this.userId = userId; 38 | } 39 | 40 | public String getTitle() { 41 | return title; 42 | } 43 | 44 | public void setTitle(String title) { 45 | this.title = title; 46 | } 47 | 48 | public RealmList getImages() { 49 | return images; 50 | } 51 | 52 | public void setImages(RealmList images) { 53 | this.images = images; 54 | } 55 | 56 | public String getDesc() { 57 | return desc; 58 | } 59 | 60 | public void setDesc(String desc) { 61 | this.desc = desc; 62 | } 63 | 64 | public String getPublishedAt() { 65 | return publishedAt; 66 | } 67 | 68 | public void setPublishedAt(String publishedAt) { 69 | this.publishedAt = publishedAt; 70 | } 71 | 72 | public String getType() { 73 | return type; 74 | } 75 | 76 | public void setType(String type) { 77 | this.type = type; 78 | } 79 | 80 | public String getUrl() { 81 | return url; 82 | } 83 | 84 | public void setUrl(String url) { 85 | this.url = url; 86 | } 87 | 88 | public boolean isUsed() { 89 | return used; 90 | } 91 | 92 | public void setUsed(boolean used) { 93 | this.used = used; 94 | } 95 | 96 | public String getWho() { 97 | return who; 98 | } 99 | 100 | public void setWho(String who) { 101 | this.who = who; 102 | } 103 | 104 | @Override public String toString() { 105 | return "AndroidBean{" 106 | + '\'' 107 | + ", desc='" 108 | + desc 109 | + '\'' 110 | + ", publishedAt='" 111 | + publishedAt 112 | + '\'' 113 | + ", type='" 114 | + type 115 | + '\'' 116 | + ", url='" 117 | + url 118 | + '\'' 119 | + ", used=" 120 | + used 121 | + ", who='" 122 | + who 123 | + '\'' 124 | + '}'; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/bean/ContentItemEntity.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.bean; 2 | 3 | import io.realm.annotations.Ignore; 4 | import java.io.Serializable; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by handsomeyang on 2017/7/11. 9 | */ 10 | public class ContentItemEntity implements Serializable { 11 | /** 12 | * _id : 56cc6d23421aa95caa707a69 13 | * createdAt : 2015-08-06T07:15:52.65Z 14 | * desc : 类似Link Bubble的悬浮式操作设计 15 | * publishedAt : 2015-08-07T03:57:48.45Z 16 | * type : Android 17 | * url : https://github.com/recruit-lifestyle/FloatingView 18 | * used : true 19 | * who : mthli 20 | */ 21 | 22 | @Ignore private String _id; 23 | @Ignore private String createdAt; 24 | private String desc; 25 | private String publishedAt; 26 | private String type; 27 | private String url; 28 | private boolean used; 29 | private List images; 30 | private String who; 31 | private String title; // 类别标题 32 | @Ignore private String ganhuo_id; 33 | @Ignore private String readablity; 34 | 35 | public String getTitle() { 36 | return title; 37 | } 38 | 39 | public void setTitle(String title) { 40 | this.title = title; 41 | } 42 | 43 | public List getImages() { 44 | return images; 45 | } 46 | 47 | public void setImages(List images) { 48 | this.images = images; 49 | } 50 | 51 | public String get_id() { 52 | return _id; 53 | } 54 | 55 | public void set_id(String _id) { 56 | this._id = _id; 57 | } 58 | 59 | public String getCreatedAt() { 60 | return createdAt; 61 | } 62 | 63 | public void setCreatedAt(String createdAt) { 64 | this.createdAt = createdAt; 65 | } 66 | 67 | public String getDesc() { 68 | return desc; 69 | } 70 | 71 | public void setDesc(String desc) { 72 | this.desc = desc; 73 | } 74 | 75 | public String getPublishedAt() { 76 | return publishedAt; 77 | } 78 | 79 | public void setPublishedAt(String publishedAt) { 80 | this.publishedAt = publishedAt; 81 | } 82 | 83 | public String getType() { 84 | return type; 85 | } 86 | 87 | public void setType(String type) { 88 | this.type = type; 89 | } 90 | 91 | public String getUrl() { 92 | return url; 93 | } 94 | 95 | public void setUrl(String url) { 96 | this.url = url; 97 | } 98 | 99 | public boolean isUsed() { 100 | return used; 101 | } 102 | 103 | public void setUsed(boolean used) { 104 | this.used = used; 105 | } 106 | 107 | public String getWho() { 108 | return who; 109 | } 110 | 111 | public void setWho(String who) { 112 | this.who = who; 113 | } 114 | 115 | public String getGanhuo_id() { 116 | return ganhuo_id; 117 | } 118 | 119 | public void setGanhuo_id(String ganhuo_id) { 120 | this.ganhuo_id = ganhuo_id; 121 | } 122 | 123 | public String getReadablity() { 124 | return readablity; 125 | } 126 | 127 | public void setReadablity(String readablity) { 128 | this.readablity = readablity; 129 | } 130 | 131 | @Override public String toString() { 132 | return "ContentItemEntity{" 133 | + " desc='" 134 | + desc 135 | + '\'' 136 | + ", publishedAt='" 137 | + publishedAt 138 | + '\'' 139 | + ", type='" 140 | + type 141 | + '\'' 142 | + ", url='" 143 | + url 144 | + '\'' 145 | + ", used=" 146 | + used 147 | + ", images=" 148 | + images 149 | + ", who='" 150 | + who 151 | + '\'' 152 | + ", title='" 153 | + title 154 | + '}'; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/bean/GankDailyTitleEntity.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.bean; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by handsomeyang on 2017/7/12. 7 | */ 8 | 9 | public class GankDailyTitleEntity { 10 | 11 | private boolean error; 12 | private List results; 13 | 14 | public boolean isError() { 15 | return error; 16 | } 17 | 18 | public void setError(boolean error) { 19 | this.error = error; 20 | } 21 | 22 | public List getResults() { 23 | return results; 24 | } 25 | 26 | public void setResults(List results) { 27 | this.results = results; 28 | } 29 | 30 | @Override public String toString() { 31 | return "GankDailyTitleEntity{" + "error=" + error + ", results=" + results + '}'; 32 | } 33 | 34 | public static class ResultsBean { 35 | 36 | private String _id; 37 | private String content; 38 | private String created_at; 39 | private String publishedAt; 40 | private String rand_id; 41 | private String title; 42 | private String updated_at; 43 | 44 | public String get_id() { 45 | return _id; 46 | } 47 | 48 | public void set_id(String _id) { 49 | this._id = _id; 50 | } 51 | 52 | public String getContent() { 53 | return content; 54 | } 55 | 56 | public void setContent(String content) { 57 | this.content = content; 58 | } 59 | 60 | public String getCreated_at() { 61 | return created_at; 62 | } 63 | 64 | public void setCreated_at(String created_at) { 65 | this.created_at = created_at; 66 | } 67 | 68 | public String getPublishedAt() { 69 | return publishedAt; 70 | } 71 | 72 | public void setPublishedAt(String publishedAt) { 73 | this.publishedAt = publishedAt; 74 | } 75 | 76 | public String getRand_id() { 77 | return rand_id; 78 | } 79 | 80 | public void setRand_id(String rand_id) { 81 | this.rand_id = rand_id; 82 | } 83 | 84 | public String getTitle() { 85 | return title; 86 | } 87 | 88 | public void setTitle(String title) { 89 | this.title = title; 90 | } 91 | 92 | public String getUpdated_at() { 93 | return updated_at; 94 | } 95 | 96 | public void setUpdated_at(String updated_at) { 97 | this.updated_at = updated_at; 98 | } 99 | 100 | @Override public String toString() { 101 | return "ResultsBean{" 102 | + "_id='" 103 | + _id 104 | + '\'' 105 | + ", content='" 106 | + content 107 | + '\'' 108 | + ", created_at='" 109 | + created_at 110 | + '\'' 111 | + ", publishedAt='" 112 | + publishedAt 113 | + '\'' 114 | + ", rand_id='" 115 | + rand_id 116 | + '\'' 117 | + ", title='" 118 | + title 119 | + '\'' 120 | + ", updated_at='" 121 | + updated_at 122 | + '\'' 123 | + '}'; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/bean/RealmString.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.bean; 2 | 3 | import io.realm.RealmObject; 4 | 5 | /** 6 | * Created by handsomeyang on 2017/8/16. 7 | * 当RealmList 代替String 因为要求泛型必须直接继承RealmObject 8 | */ 9 | 10 | public class RealmString extends RealmObject { 11 | private String string; 12 | 13 | public String getString() { 14 | return string; 15 | } 16 | 17 | public void setString(String string) { 18 | this.string = string; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/bean/SearchHistoryEntity.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.bean; 2 | 3 | import io.realm.RealmObject; 4 | import io.realm.annotations.PrimaryKey; 5 | 6 | /** 7 | * Created by handsomeyang on 2017/8/30. 8 | */ 9 | 10 | public class SearchHistoryEntity extends RealmObject { 11 | @PrimaryKey private long id; 12 | private String content; 13 | private long searchTime; 14 | 15 | public long getId() { 16 | return id; 17 | } 18 | 19 | public void setId(long id) { 20 | this.id = id; 21 | } 22 | 23 | public String getContent() { 24 | return content; 25 | } 26 | 27 | public void setContent(String content) { 28 | this.content = content; 29 | } 30 | 31 | public long getSearchTime() { 32 | return searchTime; 33 | } 34 | 35 | public void setSearchTime(long searchTime) { 36 | this.searchTime = searchTime; 37 | } 38 | 39 | @Override public String toString() { 40 | return "SearchHistoryEntity{" 41 | + "content='" 42 | + content 43 | + '\'' 44 | + ", searchTime=" 45 | + searchTime 46 | + '}'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/glide/GankGlideModule.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.glide; 2 | 3 | import android.content.Context; 4 | import com.bumptech.glide.Glide; 5 | import com.bumptech.glide.GlideBuilder; 6 | import com.bumptech.glide.Registry; 7 | import com.bumptech.glide.annotation.GlideModule; 8 | import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader; 9 | import com.bumptech.glide.load.engine.cache.LruResourceCache; 10 | import com.bumptech.glide.load.engine.cache.MemorySizeCalculator; 11 | import com.bumptech.glide.load.model.GlideUrl; 12 | import com.bumptech.glide.module.AppGlideModule; 13 | import java.io.InputStream; 14 | 15 | /** 16 | * Created by handsomeyang on 2017/9/25. 17 | */ 18 | 19 | @GlideModule public class GankGlideModule extends AppGlideModule { 20 | 21 | //手动分配缓存 缓存4屏图片,默认是2 22 | @Override public void applyOptions(Context context, GlideBuilder builder) { 23 | MemorySizeCalculator calculator = 24 | new MemorySizeCalculator.Builder(context).setMemoryCacheScreens(4).build(); 25 | builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize())); 26 | } 27 | 28 | // 更换网络请求为okHttp 29 | @Override public void registerComponents(Context context, Glide glide, Registry registry) { 30 | super.registerComponents(context, glide, registry); 31 | registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/net/ApiExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.net; 2 | 3 | import com.handsome.library.T; 4 | import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; 5 | import com.orhanobut.logger.Logger; 6 | import java.net.ConnectException; 7 | import java.net.SocketTimeoutException; 8 | import java.net.UnknownHostException; 9 | import java.text.ParseException; 10 | 11 | /** 12 | * Created by handsomeyang on 2017/8/20. 13 | */ 14 | 15 | public class ApiExceptionHandler { 16 | /** 17 | * 对应HTTP的状态码 18 | */ 19 | private static final int NOT_FOUND = 404; 20 | private static final int INTERNAL_SERVER_ERROR = 500; 21 | private static final int UNSATISFIABLE_REQUEST = 504; 22 | private static final int SERVICE_TEMPORARILY_UNAVAILABLE = 503; 23 | /** 24 | * message 25 | */ 26 | private static final String SOCKET_TIMEOUT_EXCEPTION = "网络连接超时,请检查您的网络状态,稍后重试"; 27 | private static final String CONNECT_EXCEPTION = "网络连接异常,请检查您的网络状态"; 28 | private static final String UNKNOWN_HOST_EXCEPTION_MSG = "网络异常,请检查您的网络状态"; 29 | private static final String NOT_FOUND_EXCEPTION_MSG = "用户未找到"; 30 | private static final String INTERNAL_SERVER_EXCEPTION_MSG = "服务器内部错误"; 31 | private static final String UNSATISFIABLE_REQUEST_MSG = "网关超时,服务器未响应"; 32 | private static final String SERVICE_TEMPORARILY_UNAVAILABLE_MSG = "服务器错误"; 33 | 34 | private ApiExceptionHandler() { 35 | } 36 | 37 | public static void handleError(Throwable e) { 38 | if (e instanceof HttpException) { 39 | int code = ((HttpException) e).code(); 40 | switch (code) { 41 | case NOT_FOUND: 42 | // 404 43 | T.error(NOT_FOUND_EXCEPTION_MSG); 44 | break; 45 | case INTERNAL_SERVER_ERROR: 46 | // 500 47 | T.error(INTERNAL_SERVER_EXCEPTION_MSG); 48 | break; 49 | case UNSATISFIABLE_REQUEST: 50 | // 504 51 | T.error(UNSATISFIABLE_REQUEST_MSG); 52 | break; 53 | case SERVICE_TEMPORARILY_UNAVAILABLE: 54 | // 503 55 | T.error(SERVICE_TEMPORARILY_UNAVAILABLE_MSG); 56 | default: 57 | break; 58 | } 59 | } else if (e instanceof UnknownHostException) { 60 | //没有网络 61 | T.error(UNKNOWN_HOST_EXCEPTION_MSG); 62 | } else if (e instanceof SocketTimeoutException) { 63 | // 连接超时 64 | T.error(SOCKET_TIMEOUT_EXCEPTION); 65 | } else if (e instanceof ConnectException) { 66 | T.error(CONNECT_EXCEPTION); 67 | } else if (e instanceof ParseException) { 68 | T.info("解析失败"); 69 | } else { 70 | T.error("未知错误"); 71 | } 72 | if (e != null) { 73 | e.printStackTrace(); 74 | Logger.e(e.getCause() + " " + e.getMessage() + " " + e.toString()); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/net/ApiService.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.net; 2 | 3 | import com.yangxiaobin.gank.common.bean.CategoryEntity; 4 | import com.yangxiaobin.gank.common.bean.GankDailyDataEntity; 5 | import com.yangxiaobin.gank.common.bean.GankDailyTitleEntity; 6 | import com.yangxiaobin.gank.common.bean.GankTotalHistoryEntity; 7 | import com.yangxiaobin.gank.common.bean.GitHubUserEntity; 8 | import io.reactivex.Flowable; 9 | import io.reactivex.Observable; 10 | import io.reactivex.Single; 11 | import retrofit2.http.GET; 12 | import retrofit2.http.Path; 13 | 14 | /** 15 | * Created by handsomeyang on 2017/7/6. 16 | */ 17 | 18 | public interface ApiService { 19 | 20 | /** 21 | * 请求某天gank数据 22 | * 23 | * @param year 年 24 | * @param month 月 25 | * @param day 日 26 | * @return 数据 27 | */ 28 | @GET("day/{year}/{month}/{day}") Flowable getDailyData( 29 | @Path("year") int year, @Path("month") int month, @Path("day") int day); 30 | 31 | /** 32 | * 获取所有gank历史 33 | * 34 | * @return 历史日期 35 | */ 36 | @GET("day/history") Flowable getTotalHistory(); 37 | 38 | /** 39 | * 获取某几天的干货 40 | * 41 | * @param dataCount 干货数量 42 | * @param pageCount 第几页 43 | * @return 为了获取标题 44 | */ 45 | @GET("history/content/{dataCount}/{pageCount}") Single getDailyTitle( 46 | @Path("dataCount") int dataCount, @Path("pageCount") int pageCount); 47 | 48 | /** 49 | * 获取制定种类的内容 50 | * 51 | * @param category 类别 52 | * @param dataCount 数据条数 53 | * @param pageCount 第几页 54 | * @return 指定类别内容 55 | */ 56 | @GET("data/{category}/{dataCount}/{pageCount}") Flowable getSomeCategory( 57 | @Path("category") String category, @Path("dataCount") int dataCount, 58 | @Path("pageCount") int pageCount); 59 | 60 | /** 61 | * 搜索API 62 | * 63 | * @param query 查询的内容 64 | * @param category 查询的类别 category 后面可接受参数 all | Android | iOS | 休息视频 | 福利 | 拓展资源 | 前端 | 瞎推荐 | 65 | * App 66 | * @param count count 最大 50 67 | * @param page 第几页 68 | * @return 查询结果 69 | */ 70 | @GET("search/query/{query}/category/{category}/count/{count}/page/{page}") 71 | Flowable getSearchResult(@Path("query") String query, 72 | @Path("category") String category, @Path("count") int count, @Path("page") int page); 73 | 74 | /** 75 | * 获取个人gihtub 主页数据 主要是头像等 76 | * 77 | * @param user user 78 | * @return 用户信息 79 | */ 80 | @GET("users/{user}") Observable getUserInfo(@Path("user") String user); 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/net/ErrorConsumer.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.net; 2 | 3 | import io.reactivex.functions.Consumer; 4 | 5 | /** 6 | * Created by handsomeyang on 2017/8/21. 7 | */ 8 | 9 | public class ErrorConsumer implements Consumer { 10 | @Override public void accept(Throwable throwable) throws Exception { 11 | ApiExceptionHandler.handleError(throwable); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/BlurBitmapUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.support.v8.renderscript.Allocation; 6 | import android.support.v8.renderscript.Element; 7 | import android.support.v8.renderscript.RenderScript; 8 | import android.support.v8.renderscript.ScriptIntrinsicBlur; 9 | import android.text.format.Formatter; 10 | import android.widget.ImageView; 11 | import com.orhanobut.logger.Logger; 12 | 13 | /** 14 | * RenderScript图片高斯模糊 15 | * Created by jameson on 9/2/16. 16 | */ 17 | public class BlurBitmapUtils { 18 | /** 19 | * 建议模糊度(在0.0到25.0之间) 20 | */ 21 | private static final int BLUR_RADIUS = 15; 22 | private static final float SCALED_WIDTH = 1 / 10.0f; 23 | private static final float SCALED_HEIGHT = 1 / 10.0f; // 取原图的十分之一尺寸 24 | 25 | public static void blur(ImageView imageView, Bitmap bitmap) { 26 | blur(imageView, bitmap, BLUR_RADIUS); 27 | } 28 | 29 | public static void blur(ImageView imageView, Bitmap bitmap, int radius) { 30 | imageView.setImageBitmap(getBlurBitmap(imageView.getContext(), bitmap, radius)); 31 | } 32 | 33 | public static Bitmap getBlurBitmap(Context context, Bitmap bitmap) { 34 | return getBlurBitmap(context, bitmap, BLUR_RADIUS); 35 | } 36 | 37 | /** 38 | * 得到模糊后的bitmap 39 | * thanks http://wl9739.github.io/2016/07/14/教你一分钟实现模糊效果/ 40 | */ 41 | public static Bitmap getBlurBitmap(Context context, Bitmap bitmap, int radius) { 42 | // 将缩小后的图片做为预渲染的图片。 43 | Bitmap inputBitmap = 44 | Bitmap.createScaledBitmap(bitmap, ((int) (bitmap.getWidth() * SCALED_WIDTH)), 45 | ((int) (bitmap.getHeight() * SCALED_HEIGHT)), false); 46 | 47 | // 创建一张渲染后的输出图片。 48 | Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap); 49 | 50 | // 创建RenderScript内核对象 51 | RenderScript rs = RenderScript.create(context); 52 | // 创建一个模糊效果的RenderScript的工具对象 53 | ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); 54 | 55 | // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。 56 | // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。 57 | Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap); 58 | Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); 59 | 60 | // 设置渲染的模糊程度, 25f是最大模糊度 61 | blurScript.setRadius(radius); 62 | // 设置blurScript对象的输入内存 63 | blurScript.setInput(tmpIn); 64 | // 将输出数据保存到输出内存中 65 | blurScript.forEach(tmpOut); 66 | 67 | // 将数据填充到Allocation中 68 | tmpOut.copyTo(outputBitmap); 69 | // 56.53 KB 70 | //Logger.e("模糊后的bimtap:" + Formatter.formatFileSize(context, tmpOut.getBytesSize())); 71 | return outputBitmap; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/CacheHelper.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.support.v4.util.LruCache; 6 | import android.text.format.Formatter; 7 | import com.orhanobut.logger.Logger; 8 | 9 | /** 10 | * Created by handsomeyang on 2017/8/28. 11 | */ 12 | 13 | public class CacheHelper { 14 | 15 | private final LruCache mLruCache; 16 | 17 | public CacheHelper() { 18 | int maxMemory = (int) (Runtime.getRuntime().maxMemory()); 19 | int cacheSize = maxMemory / 8; 20 | // 12M 作为缓存 21 | //Logger.e("作为图片缓存大小:" + cacheSize+" format:"+Formatter.formatFileSize(context,cacheSize)); 22 | mLruCache = new LruCache(cacheSize) { 23 | @Override protected int sizeOf(String key, Bitmap value) { 24 | return value.getRowBytes() * value.getHeight(); 25 | } 26 | }; 27 | } 28 | 29 | public LruCache getLruCache() { 30 | return mLruCache; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/CircularRevealUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.view.View; 6 | import android.view.ViewAnimationUtils; 7 | import android.view.animation.AccelerateInterpolator; 8 | 9 | /** 10 | * Created by handsomeyang on 2017/7/14. 11 | */ 12 | 13 | public class CircularRevealUtils { 14 | 15 | private CircularRevealUtils() { 16 | } 17 | 18 | /** 19 | * show view with circular reveal animation 20 | * 21 | * @param v target view 22 | * @param centerX x 23 | * @param centerY y 24 | * @param finalRadius radius 25 | */ 26 | public static Animator animateRevealHide(View v, int centerX, int centerY, int finalRadius) { 27 | Animator anim = ViewAnimationUtils.createCircularReveal(v, centerX, centerY, 0, finalRadius); 28 | //viewRoot.setVisibility(View.VISIBLE); 29 | anim.setDuration(300); 30 | anim.setInterpolator(new AccelerateInterpolator()); 31 | anim.start(); 32 | return anim; 33 | } 34 | 35 | /** 36 | * show view with circular reveal animation 37 | * 38 | * @param viewRoot target view 39 | */ 40 | public static Animator animateRevealShow(View viewRoot) { 41 | int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; 42 | int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; 43 | int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight()); 44 | 45 | Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius); 46 | //viewRoot.setVisibility(View.VISIBLE); 47 | anim.setDuration(300); 48 | anim.setInterpolator(new AccelerateInterpolator()); 49 | anim.start(); 50 | return anim; 51 | } 52 | 53 | /** 54 | * hide view with circular reveal animation 55 | * 56 | * @param viewRoot target vsiew 57 | */ 58 | public static Animator animateRevealHide(final View viewRoot) { 59 | int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2; 60 | int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2; 61 | int initialRadius = viewRoot.getWidth(); 62 | 63 | Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, initialRadius, 0); 64 | //anim.addListener(new AnimatorListenerAdapter() { 65 | // @Override public void onAnimationEnd(Animator animation) { 66 | // super.onAnimationEnd(animation); 67 | // viewRoot.setVisibility(View.INVISIBLE); 68 | // } 69 | //}); 70 | anim.setDuration(300); 71 | anim.start(); 72 | return anim; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/CleanCatcheUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | /* 4 | * 缓存清理工具类 5 | * /storage/emulated/0 sd卡目录 6 | * 7 | * App缓存主要保存在两个地方: 8 | * 1> /data/data/应用包名/com.cytmxk.test/cache 9 | * 2> /storage/emulated/0/Android/data/应用包名/cache 10 | * 11 | 12 | */ 13 | 14 | import android.content.Context; 15 | import android.os.Environment; 16 | import android.text.format.Formatter; 17 | import com.orhanobut.logger.Logger; 18 | import java.io.File; 19 | 20 | public class CleanCatcheUtils { 21 | 22 | private CleanCatcheUtils() { 23 | 24 | } 25 | 26 | // 清理缓存 27 | public static boolean clear(Context context) { 28 | return delFile(context.getCacheDir()) && delFile(context.getExternalCacheDir()); 29 | } 30 | 31 | //递归删除文件 32 | private static boolean delFile(File file) { 33 | if (file.isDirectory() && file.exists()) { 34 | File[] files = file.listFiles(); 35 | for (File f : files) { 36 | if (f.isDirectory()) { 37 | delFile(f); 38 | } 39 | f.delete(); 40 | } 41 | } 42 | return file.delete(); // 删除最外层 43 | } 44 | 45 | /** 46 | * 获取App的缓存大小(单位 byte) 47 | */ 48 | public static String getCacheSize(Context context) { 49 | long result = 0; 50 | File dataDataCache = context.getCacheDir(); 51 | if (dataDataCache.exists()) { 52 | result += getFolderSize(dataDataCache); 53 | } 54 | 55 | // sd 卡挂载 56 | if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) { 57 | File SDCache = context.getExternalCacheDir(); 58 | if (null != SDCache && SDCache.exists()) { 59 | result += getFolderSize(new File(SDCache.getAbsolutePath())); 60 | } 61 | } 62 | 63 | return formatSize(context, result); 64 | } 65 | 66 | // 获取某个文件夹下面所有文件大小 67 | private static long getFolderSize(File file) { 68 | long size = 0; 69 | try { 70 | File[] fileList = file.listFiles(); 71 | for (File f : fileList) { 72 | if (f.isDirectory()) { 73 | size += getFolderSize(f); 74 | } else { 75 | size += f.length(); 76 | } 77 | } 78 | } catch (Exception e) { 79 | Logger.e("获取目录大小错误:" + e); 80 | e.printStackTrace(); 81 | } 82 | return size; 83 | } 84 | 85 | //格式化 86 | private static String formatSize(Context context, long size) { 87 | return Formatter.formatFileSize(context, size); 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/ImageUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Environment; 7 | import android.provider.MediaStore; 8 | import android.util.Log; 9 | import android.widget.ImageView; 10 | import com.bumptech.glide.Priority; 11 | import com.pgyersdk.crash.PgyCrashManager; 12 | import com.yangxiaobin.gank.R; 13 | import com.yangxiaobin.gank.common.glide.GlideApp; 14 | import java.io.BufferedInputStream; 15 | import java.io.BufferedOutputStream; 16 | import java.io.File; 17 | import java.io.FileInputStream; 18 | import java.io.FileOutputStream; 19 | import java.io.IOException; 20 | 21 | /** 22 | * Created by handsomeyang on 2017/7/26. 23 | */ 24 | 25 | public class ImageUtils { 26 | 27 | private ImageUtils() { 28 | 29 | } 30 | 31 | public static void load(Context context, String url, ImageView imageView) { 32 | try { 33 | // 自动开启内存缓存 默认混存在磁盘上是转换过大小的图片 34 | GlideApp.with(context) 35 | .load(url) 36 | .placeholder(R.drawable.ic_placeholer_128) 37 | .error(R.drawable.ic_error_128) 38 | .dontAnimate() 39 | .priority(Priority.HIGH) 40 | .into(imageView); 41 | } catch (IllegalArgumentException ex) { 42 | Log.wtf("Glide-tag", String.valueOf(imageView.getTag())); 43 | // pgy 上报 catch 异常 44 | PgyCrashManager.reportCaughtException(context, ex); 45 | } 46 | } 47 | 48 | public static void load(Context context, String url, ImageView imageView, int width, int height) { 49 | try { 50 | // 自动开启内存缓存 默认混存在磁盘上是转换过大小的图片 51 | GlideApp.with(context) 52 | .load(url) 53 | .placeholder(R.drawable.ic_placeholer_128) 54 | .error(R.drawable.ic_error_128) 55 | .dontAnimate() 56 | .override(width, height) 57 | .into(imageView); 58 | } catch (IllegalArgumentException ex) { 59 | Log.wtf("Glide-tag", String.valueOf(imageView.getTag())); 60 | // pgy 上报 catch 异常 61 | PgyCrashManager.reportCaughtException(context, ex); 62 | } 63 | } 64 | 65 | public static void loadRound(Context context, String url, ImageView imageView) { 66 | try { 67 | // 自动开启内存缓存 默认混存在磁盘上是转换过大小的图片 68 | GlideApp.with(context) 69 | .load(url) 70 | .placeholder(R.drawable.ic_placeholer_128) 71 | .error(R.drawable.ic_error_128) 72 | .centerCrop() 73 | .dontAnimate() 74 | .transform(new RoundImageTransformation()) 75 | .into(imageView); 76 | } catch (IllegalArgumentException ex) { 77 | Log.wtf("Glide-tag", String.valueOf(imageView.getTag())); 78 | // pgy 上报 catch 异常 79 | PgyCrashManager.reportCaughtException(context, ex); 80 | } 81 | } 82 | 83 | /** 84 | * 保存图片到相册 85 | * http://blog.csdn.net/xu_fu/article/details/39158747 86 | * 注意写文件权限 87 | * 88 | * @param context context 89 | * @param targetFile target file 90 | */ 91 | public static boolean saveImageToGallery(Context context, File targetFile) { 92 | // 读取target 的file 93 | try { 94 | // 输出流 保存图片 95 | File fileDir = new File(Environment.getExternalStorageDirectory(), "GankIO"); 96 | if (!fileDir.exists()) { 97 | fileDir.mkdir(); 98 | } 99 | String fileName = System.currentTimeMillis() + ".jpg"; 100 | File file = new File(fileDir, fileName); 101 | FileOutputStream fos = new FileOutputStream(file); 102 | BufferedOutputStream bos = new BufferedOutputStream(fos); 103 | 104 | //输入流 读取文件 105 | FileInputStream fis = new FileInputStream(targetFile.getAbsoluteFile()); 106 | BufferedInputStream bis = new BufferedInputStream(fis); 107 | byte[] bs = new byte[512]; 108 | int total; 109 | while ((total = bis.read(bs)) != -1) { 110 | fos.write(bs, 0, total); 111 | } 112 | bis.close(); 113 | bos.close(); 114 | // 其次把文件插入到系统图库 115 | MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), 116 | fileName, null); 117 | // 最后通知图库更新 118 | context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, 119 | Uri.parse("file://" + Environment.getExternalStorageDirectory()))); 120 | return true; 121 | } catch (IOException e) { 122 | // pgy 上报 catch 异常 123 | PgyCrashManager.reportCaughtException(context, e); 124 | e.printStackTrace(); 125 | Log.wtf("saveImageToGallery-tag", e); 126 | return false; 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/ImmersiveStatusBarUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.view.View; 7 | import android.view.Window; 8 | import android.view.WindowManager; 9 | 10 | /** 11 | * Created by handsomeyang on 2017/7/3. 12 | */ 13 | 14 | public class ImmersiveStatusBarUtils { 15 | 16 | private ImmersiveStatusBarUtils() { 17 | } 18 | 19 | public static void makeImmersivable(Activity activity) { 20 | // 沉浸式状态栏 21 | Window window = activity.getWindow(); 22 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 23 | window.setStatusBarColor(Color.TRANSPARENT); 24 | window.getDecorView() 25 | .setSystemUiVisibility( 26 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 27 | } else { 28 | window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, 29 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/RoundImageTransformation.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapShader; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 8 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 9 | import java.security.MessageDigest; 10 | 11 | /** 12 | * Created by handsomeyang on 2017/8/15. 13 | * create imageview by glide 14 | */ 15 | 16 | public class RoundImageTransformation extends BitmapTransformation { 17 | 18 | @Override 19 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { 20 | return circleCrop(pool, toTransform); 21 | } 22 | 23 | private static Bitmap circleCrop(BitmapPool pool, Bitmap source) { 24 | if (source == null) return null; 25 | int size = Math.min(source.getWidth(), source.getHeight()); 26 | int x = (source.getWidth() - size) / 2; 27 | int y = (source.getHeight() - size) / 2; 28 | Bitmap squared = Bitmap.createBitmap(source, x, y, size, size); 29 | Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888); 30 | Canvas canvas = new Canvas(result); 31 | Paint paint = new Paint(); 32 | paint.setShader( 33 | new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); 34 | paint.setAntiAlias(true); 35 | float r = size / 2f; 36 | canvas.drawCircle(r, r, r, paint); 37 | return result; 38 | } 39 | 40 | @Override public void updateDiskCacheKey(MessageDigest messageDigest) { 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/Rx2Bus.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import io.reactivex.Flowable; 4 | import io.reactivex.processors.FlowableProcessor; 5 | import io.reactivex.processors.PublishProcessor; 6 | import io.reactivex.subscribers.SerializedSubscriber; 7 | 8 | /** 9 | * Created by handsomeyang on 2017/8/9. 10 | */ 11 | 12 | public class Rx2Bus { 13 | 14 | private static Rx2Bus sRx2Bus; 15 | //相当于Rxjava1.x中的Subject 16 | private final FlowableProcessor mBus; 17 | 18 | private Rx2Bus() { 19 | //调用toSerialized()方法,保证线程安全 20 | mBus = PublishProcessor.create().toSerialized(); 21 | } 22 | 23 | public static Rx2Bus getDefault() { 24 | if (sRx2Bus == null) { 25 | synchronized (String.class) { 26 | if (sRx2Bus == null) { 27 | sRx2Bus = new Rx2Bus(); 28 | } 29 | } 30 | } 31 | return sRx2Bus; 32 | } 33 | 34 | // 发送事件 35 | public void post(Object object) { 36 | new SerializedSubscriber<>(mBus).onNext(object); 37 | } 38 | 39 | // 接受事件 40 | public Flowable toFlowable(Class aClass) { 41 | return mBus.ofType(aClass); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/RxUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import io.reactivex.Flowable; 4 | import io.reactivex.FlowableTransformer; 5 | import io.reactivex.Observable; 6 | import io.reactivex.ObservableSource; 7 | import io.reactivex.ObservableTransformer; 8 | import io.reactivex.Single; 9 | import io.reactivex.SingleSource; 10 | import io.reactivex.SingleTransformer; 11 | import io.reactivex.android.schedulers.AndroidSchedulers; 12 | import io.reactivex.schedulers.Schedulers; 13 | import org.reactivestreams.Publisher; 14 | 15 | /** 16 | * Created by handsomeyang on 2017/8/19. 17 | */ 18 | 19 | public class RxUtils { 20 | 21 | private RxUtils() { 22 | 23 | } 24 | 25 | /** 26 | * 封装rxjava线程切换 27 | * 28 | * @param 实体类型 29 | * @return ObservableTransformer 30 | */ 31 | public static ObservableTransformer switchObservableSchedulers() { 32 | return new ObservableTransformer() { 33 | @Override public ObservableSource apply(Observable observable) { 34 | return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); 35 | } 36 | }; 37 | } 38 | 39 | public static FlowableTransformer switchFlowableSchedulers() { 40 | return new FlowableTransformer() { 41 | @Override public Publisher apply(Flowable upstream) { 42 | return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); 43 | } 44 | }; 45 | } 46 | 47 | public static SingleTransformer switchSingleSchedulers() { 48 | return new SingleTransformer() { 49 | @Override public SingleSource apply(Single upstream) { 50 | 51 | return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); 52 | } 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/SPUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | import java.util.Map; 8 | 9 | /** 10 | * Created by HandsomeYang on 2016/9/20. 11 | * SharedPreferenceHelper by zhy 不直接用apply而用内部类完全是为了兼容 12 | */ 13 | 14 | public class SPUtils { 15 | private SPUtils() { 16 | 17 | } 18 | 19 | /** 20 | * 保存在手机里面的文件名 21 | */ 22 | static final String FILE_NAME = "share_data"; 23 | 24 | /** 25 | * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 26 | */ 27 | public static void put(Context context, String key, Object object) { 28 | 29 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); 30 | SharedPreferences.Editor editor = sp.edit(); 31 | 32 | if (object instanceof String) { 33 | editor.putString(key, (String) object); 34 | } else if (object instanceof Integer) { 35 | editor.putInt(key, (Integer) object); 36 | } else if (object instanceof Boolean) { 37 | editor.putBoolean(key, (Boolean) object); 38 | } else if (object instanceof Float) { 39 | editor.putFloat(key, (Float) object); 40 | } else if (object instanceof Long) { 41 | editor.putLong(key, (Long) object); 42 | } else { 43 | editor.putString(key, object.toString()); 44 | } 45 | 46 | SharedPreferencesCompat.apply(editor); 47 | } 48 | 49 | /** 50 | * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 51 | */ 52 | public static Object get(Context context, String key, Object defaultObject) { 53 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); 54 | 55 | if (defaultObject instanceof String) { 56 | return sp.getString(key, (String) defaultObject); 57 | } else if (defaultObject instanceof Integer) { 58 | return sp.getInt(key, (Integer) defaultObject); 59 | } else if (defaultObject instanceof Boolean) { 60 | return sp.getBoolean(key, (Boolean) defaultObject); 61 | } else if (defaultObject instanceof Float) { 62 | return sp.getFloat(key, (Float) defaultObject); 63 | } else if (defaultObject instanceof Long) { 64 | return sp.getLong(key, (Long) defaultObject); 65 | } 66 | 67 | return null; 68 | } 69 | 70 | /** 71 | * 移除某个key值已经对应的值 72 | */ 73 | public static void remove(Context context, String key) { 74 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); 75 | SharedPreferences.Editor editor = sp.edit(); 76 | editor.remove(key); 77 | SharedPreferencesCompat.apply(editor); 78 | } 79 | 80 | /** 81 | * 清除所有数据 82 | */ 83 | public static void clear(Context context) { 84 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); 85 | SharedPreferences.Editor editor = sp.edit(); 86 | editor.clear(); 87 | SharedPreferencesCompat.apply(editor); 88 | } 89 | 90 | /** 91 | * 查询某个key是否已经存在 92 | */ 93 | public static boolean contains(Context context, String key) { 94 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); 95 | return sp.contains(key); 96 | } 97 | 98 | /** 99 | * 返回所有的键值对 100 | */ 101 | public static Map getAll(Context context) { 102 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); 103 | return sp.getAll(); 104 | } 105 | 106 | /** 107 | * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类 108 | * 109 | * @author zhy 110 | */ 111 | private static class SharedPreferencesCompat { 112 | private static final Method sApplyMethod = findApplyMethod(); 113 | 114 | /** 115 | * 反射查找apply的方法 116 | */ 117 | @SuppressWarnings({ "unchecked", "rawtypes" }) private static Method findApplyMethod() { 118 | try { 119 | Class clz = SharedPreferences.Editor.class; 120 | return clz.getMethod("apply"); 121 | } catch (NoSuchMethodException e) { 122 | } 123 | 124 | return null; 125 | } 126 | 127 | /** 128 | * 如果找到则使用apply执行,否则使用commit 129 | */ 130 | public static void apply(SharedPreferences.Editor editor) { 131 | try { 132 | if (sApplyMethod != null) { 133 | sApplyMethod.invoke(editor); 134 | return; 135 | } 136 | } catch (IllegalArgumentException e) { 137 | } catch (IllegalAccessException e) { 138 | } catch (InvocationTargetException e) { 139 | } 140 | editor.commit(); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/Unicode2ChineseUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | /** 4 | * Created by handsomeyang on 2017/6/26. 5 | */ 6 | 7 | public class Unicode2ChineseUtils { 8 | /** 9 | * 传入汉字的Unicode编码字符串,返回相应的汉字字符串 10 | */ 11 | public static String decode(String unicodeStr) { 12 | if (unicodeStr == null) { 13 | return null; 14 | } 15 | StringBuffer retBuf = new StringBuffer(); 16 | int maxLoop = unicodeStr.length(); 17 | for (int i = 0; i < maxLoop; i++) { 18 | if (unicodeStr.charAt(i) == '\\') { 19 | if ((i < maxLoop - 5) && ((unicodeStr.charAt(i + 1) == 'u') || (unicodeStr.charAt(i + 1) 20 | == 'U'))) { 21 | try { 22 | retBuf.append((char) Integer.parseInt(unicodeStr.substring(i + 2, i + 6), 16)); 23 | i += 5; 24 | } catch (NumberFormatException localNumberFormatException) { 25 | retBuf.append(unicodeStr.charAt(i)); 26 | } 27 | } else { 28 | retBuf.append(unicodeStr.charAt(i)); 29 | } 30 | } else { 31 | retBuf.append(unicodeStr.charAt(i)); 32 | } 33 | } 34 | return retBuf.toString(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/UserUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import com.yangxiaobin.Constant; 6 | 7 | /** 8 | * Created by handsomeyang on 2017/8/19. 9 | */ 10 | 11 | public class UserUtils { 12 | private UserUtils() { 13 | 14 | } 15 | 16 | /** 17 | * @return true logined ,false not logined 18 | */ 19 | public static boolean hasLogined(Context context) { 20 | return !TextUtils.isEmpty(((String) SPUtils.get(context, Constant.KEY_USER_ID_LOGIN, ""))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/common/utils/ViewSwitchUtils.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.common.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.BitmapDrawable; 6 | import android.graphics.drawable.ColorDrawable; 7 | import android.graphics.drawable.Drawable; 8 | import android.graphics.drawable.TransitionDrawable; 9 | import android.widget.ImageView; 10 | import android.widget.RelativeLayout; 11 | 12 | /** 13 | * 图片背景切换动画帮助类 14 | * 15 | * Created by jameson on 9/3/16. 16 | */ 17 | public class ViewSwitchUtils { 18 | 19 | public static void startSwitchBackgroundAnim(ImageView view, Bitmap bitmap) { 20 | Drawable oldDrawable = view.getDrawable(); 21 | Drawable oldBitmapDrawable; 22 | TransitionDrawable oldTransitionDrawable = null; 23 | if (oldDrawable instanceof TransitionDrawable) { 24 | oldTransitionDrawable = (TransitionDrawable) oldDrawable; 25 | oldBitmapDrawable = 26 | oldTransitionDrawable.findDrawableByLayerId(oldTransitionDrawable.getId(1)); 27 | } else if (oldDrawable instanceof BitmapDrawable) { 28 | oldBitmapDrawable = oldDrawable; 29 | } else { 30 | oldBitmapDrawable = new ColorDrawable(0xffc2c2c2); 31 | } 32 | 33 | if (oldTransitionDrawable == null) { 34 | oldTransitionDrawable = 35 | new TransitionDrawable(new Drawable[] { oldBitmapDrawable, new BitmapDrawable(bitmap) }); 36 | oldTransitionDrawable.setId(0, 0); 37 | oldTransitionDrawable.setId(1, 1); 38 | oldTransitionDrawable.setCrossFadeEnabled(true); 39 | view.setImageDrawable(oldTransitionDrawable); 40 | } else { 41 | oldTransitionDrawable.setDrawableByLayerId(oldTransitionDrawable.getId(0), oldBitmapDrawable); 42 | oldTransitionDrawable.setDrawableByLayerId(oldTransitionDrawable.getId(1), 43 | new BitmapDrawable(bitmap)); 44 | } 45 | oldTransitionDrawable.startTransition(1000); 46 | } 47 | 48 | public static void startSwitchBackgroundAnim(Context context, RelativeLayout background, 49 | Bitmap bitmap) { 50 | 51 | Drawable bgDrawable = background.getBackground(); 52 | Drawable bgBitmapDrawable; 53 | // layerDrawable 54 | TransitionDrawable bgTransitionDrawable = null; 55 | if (bgDrawable instanceof TransitionDrawable) { 56 | bgTransitionDrawable = (TransitionDrawable) bgDrawable; 57 | bgBitmapDrawable = 58 | bgTransitionDrawable.findDrawableByLayerId(bgTransitionDrawable.getId(1)); 59 | } else if (bgDrawable instanceof BitmapDrawable) { 60 | bgBitmapDrawable = bgDrawable; 61 | } else { 62 | bgBitmapDrawable = new ColorDrawable(0xffc2c2c2); 63 | } 64 | 65 | if (bgTransitionDrawable == null) { 66 | bgTransitionDrawable = new TransitionDrawable( 67 | new Drawable[] { bgBitmapDrawable, new BitmapDrawable(context.getResources(), bitmap) }); 68 | bgTransitionDrawable.setId(0, 0); 69 | bgTransitionDrawable.setId(1, 1); 70 | bgTransitionDrawable.setCrossFadeEnabled(true); 71 | background.setBackground(bgTransitionDrawable); 72 | } else { 73 | //@param id The layer ID to search for. 74 | //@param drawable The replacement {@link Drawable}. 75 | bgTransitionDrawable.setDrawableByLayerId(bgTransitionDrawable.getId(0), bgBitmapDrawable); 76 | bgTransitionDrawable.setDrawableByLayerId(bgTransitionDrawable.getId(1), 77 | new BitmapDrawable(context.getResources(), bitmap)); 78 | } 79 | bgTransitionDrawable.startTransition(500); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/component/AboutComponent.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.component; 2 | 3 | import com.yangxiaobin.gank.mvp.view.fragment.AboutFragment; 4 | import dagger.Subcomponent; 5 | import dagger.android.AndroidInjector; 6 | 7 | /** 8 | * Created by handsomeyang on 2017/8/26. 9 | */ 10 | 11 | @Subcomponent public interface AboutComponent extends AndroidInjector { 12 | @Subcomponent.Builder abstract class Builder extends AndroidInjector.Builder { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/component/AppComponent.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.component; 2 | 3 | import com.yangxiaobin.gank.App; 4 | import com.yangxiaobin.gank.di.module.AboutModule; 5 | import com.yangxiaobin.gank.di.module.ApiModule; 6 | import com.yangxiaobin.gank.di.module.AppModule; 7 | import com.yangxiaobin.gank.di.module.LoginDialogModule; 8 | import com.yangxiaobin.gank.di.module.RepositoryModule; 9 | import dagger.Component; 10 | import dagger.android.AndroidInjectionModule; 11 | import dagger.android.AndroidInjector; 12 | import dagger.android.support.AndroidSupportInjectionModule; 13 | import javax.inject.Singleton; 14 | 15 | /** 16 | * Created by handsomeyang on 2017/6/26. 17 | */ 18 | @Singleton @Component(modules = { 19 | AndroidInjectionModule.class, 20 | AndroidSupportInjectionModule.class, 21 | AppModule.class, 22 | ApiModule.class, 23 | RepositoryModule.class, 24 | LoginDialogModule.class, 25 | AboutModule.class, 26 | }) public interface AppComponent extends AndroidInjector { 27 | 28 | @Component.Builder abstract class Builder extends AndroidInjector.Builder { 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/component/LoginDialogComponent.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.component; 2 | 3 | import com.yangxiaobin.gank.mvp.view.fragment.LoginDialogFragment; 4 | import dagger.Subcomponent; 5 | import dagger.android.AndroidInjector; 6 | 7 | /** 8 | * Created by handsomeyang on 2017/8/14. 9 | */ 10 | @Subcomponent public interface LoginDialogComponent extends AndroidInjector { 11 | 12 | @Subcomponent.Builder abstract class Builder 13 | extends AndroidInjector.Builder { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/module/AboutModule.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.module; 2 | 3 | import android.support.v4.app.Fragment; 4 | import com.yangxiaobin.gank.di.component.AboutComponent; 5 | import com.yangxiaobin.gank.mvp.view.fragment.AboutFragment; 6 | import dagger.Binds; 7 | import dagger.Module; 8 | import dagger.android.AndroidInjector; 9 | import dagger.android.support.FragmentKey; 10 | import dagger.multibindings.IntoMap; 11 | 12 | /** 13 | * Created by handsomeyang on 2017/8/26. 14 | */ 15 | 16 | @Module(subcomponents = AboutComponent.class) public abstract class AboutModule { 17 | 18 | @Binds @IntoMap @FragmentKey(AboutFragment.class) 19 | abstract AndroidInjector.Factory bind(AboutComponent.Builder builder); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/module/AppModule.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.module; 2 | 3 | import com.yangxiaobin.gank.mvp.view.activity.MainActivity; 4 | import com.yangxiaobin.gank.mvp.view.fragment.CategoryFragment; 5 | import com.yangxiaobin.gank.mvp.view.fragment.CollectionFragment; 6 | import com.yangxiaobin.gank.mvp.view.fragment.ContentFragment; 7 | import com.yangxiaobin.gank.mvp.view.fragment.SearchFragment; 8 | import com.yangxiaobin.gank.mvp.view.fragment.SplashFragment; 9 | import dagger.Module; 10 | import dagger.android.ContributesAndroidInjector; 11 | 12 | /** 13 | * Created by handsomeyang on 2017/7/6. 14 | * abstract @Binds 和 @Multibinds 要用static 15 | */ 16 | 17 | @Module public abstract class AppModule { 18 | 19 | // 自动生成module 和 component 20 | @ContributesAndroidInjector abstract MainActivity contributesMainActivity(); 21 | 22 | // Splash Fragment 23 | @ContributesAndroidInjector abstract SplashFragment contributesSplashFragment(); 24 | 25 | // Content Fragment 26 | @ContributesAndroidInjector abstract ContentFragment contributesGankContentFragment(); 27 | 28 | // category Activity 29 | @ContributesAndroidInjector abstract CategoryFragment contributesCategoryFragment(); 30 | 31 | // collection Fragment 32 | @ContributesAndroidInjector abstract CollectionFragment contributesCollectionFragment(); 33 | 34 | // searchFragment 35 | 36 | @ContributesAndroidInjector abstract SearchFragment contributesSearchFragment(); 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/module/LoginDialogModule.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.module; 2 | 3 | import android.support.v4.app.Fragment; 4 | import com.yangxiaobin.gank.di.component.LoginDialogComponent; 5 | import com.yangxiaobin.gank.mvp.view.fragment.LoginDialogFragment; 6 | import dagger.Binds; 7 | import dagger.Module; 8 | import dagger.android.AndroidInjector; 9 | import dagger.android.support.FragmentKey; 10 | import dagger.multibindings.IntoMap; 11 | 12 | /** 13 | * Created by handsomeyang on 2017/8/14. 14 | */ 15 | 16 | @Module(subcomponents = LoginDialogComponent.class) public abstract class LoginDialogModule { 17 | 18 | @Binds @IntoMap @FragmentKey(LoginDialogFragment.class) 19 | abstract AndroidInjector.Factory bind(LoginDialogComponent.Builder builder); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/module/RepositoryModule.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.module; 2 | 3 | import com.yangxiaobin.gank.mvp.contract.CategoryContract; 4 | import com.yangxiaobin.gank.mvp.contract.CollectionContract; 5 | import com.yangxiaobin.gank.mvp.contract.ContentContract; 6 | import com.yangxiaobin.gank.mvp.contract.MainContract; 7 | import com.yangxiaobin.gank.mvp.contract.SearchContract; 8 | import com.yangxiaobin.gank.mvp.model.remote.CategoryModel; 9 | import com.yangxiaobin.gank.mvp.model.remote.CollectionMoel; 10 | import com.yangxiaobin.gank.mvp.model.remote.ContentModel; 11 | import com.yangxiaobin.gank.mvp.model.remote.MainModel; 12 | import com.yangxiaobin.gank.mvp.model.remote.SearchModel; 13 | import com.yangxiaobin.gank.mvp.view.activity.MainActivity; 14 | import com.yangxiaobin.gank.mvp.view.fragment.CategoryFragment; 15 | import com.yangxiaobin.gank.mvp.view.fragment.CollectionFragment; 16 | import com.yangxiaobin.gank.mvp.view.fragment.ContentFragment; 17 | import com.yangxiaobin.gank.mvp.view.fragment.SearchFragment; 18 | import dagger.Binds; 19 | import dagger.Module; 20 | 21 | /** 22 | * Created by handsomeyang on 2017/7/6. 23 | */ 24 | @Module public abstract class RepositoryModule { 25 | 26 | // 表示MainContractView 由 MainActivity 提供 27 | @Binds abstract MainContract.View provideMainContractView(MainActivity mainActivity); 28 | 29 | @Binds abstract MainContract.Model provideMainContractModel(MainModel mainModel); 30 | 31 | // contentFragment 32 | @Binds abstract ContentContract.View provideContentContractView(ContentFragment contentFragment); 33 | 34 | @Binds abstract ContentContract.Model provideContentContractModel(ContentModel model); 35 | 36 | // Category fragment 37 | @Binds abstract CategoryContract.View provideCategoryContractView( 38 | CategoryFragment categoryFragment); 39 | 40 | @Binds abstract CategoryContract.Model provideCategoryContractModel(CategoryModel model); 41 | 42 | // CollectionFragment 43 | @Binds abstract CollectionContract.View provideCollectionContractView( 44 | CollectionFragment collectionFragment); 45 | 46 | @Binds abstract CollectionContract.Model provideCollctionContractModel(CollectionMoel model); 47 | 48 | // SearchFragment 49 | @Binds abstract SearchContract.View provideSearchContractView(SearchFragment view); 50 | 51 | @Binds abstract SearchContract.Model provideSearchContractModel(SearchModel model); 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/scope/Cached.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.scope; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import javax.inject.Qualifier; 6 | 7 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 8 | 9 | /** 10 | * Created by handsomeyang on 2017/6/28. 11 | */ 12 | 13 | @Qualifier @Documented @Retention(RUNTIME) public @interface Cached { 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/scope/LoginUsed.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.scope; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import javax.inject.Qualifier; 6 | 7 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 8 | 9 | /** 10 | * Created by handsomeyang on 2017/8/14. 11 | */ 12 | 13 | @Qualifier @Documented @Retention(RUNTIME) public @interface LoginUsed { 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/di/scope/UnCatched.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.di.scope; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import javax.inject.Qualifier; 7 | 8 | /** 9 | * Created by handsomeyang on 2017/6/28. 10 | */ 11 | 12 | @Qualifier @Documented @Retention(RetentionPolicy.RUNTIME) public @interface UnCatched { 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/contract/CategoryContract.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.contract; 2 | 3 | import android.os.Bundle; 4 | import com.yangxiaobin.gank.common.base.IBaseModel; 5 | import com.yangxiaobin.gank.common.base.IBaseView; 6 | import com.yangxiaobin.gank.common.bean.CategoryEntity; 7 | import com.yangxiaobin.gank.common.db.RealmHelper; 8 | import com.yangxiaobin.gank.mvp.view.adapter.CategoryAdapter; 9 | import io.reactivex.Flowable; 10 | 11 | /** 12 | * Created by handsomeyang on 2017/7/25. 13 | */ 14 | 15 | public interface CategoryContract { 16 | 17 | interface Model extends IBaseModel { 18 | 19 | Flowable getSomeCategory(String category, int dataCount, int pageCount); 20 | } 21 | 22 | interface View extends IBaseView { 23 | 24 | RealmHelper getRealmHelper(); 25 | 26 | void setRecyclerViewAdapter(CategoryAdapter adapter); 27 | 28 | void setToolbarTitle(String title); 29 | 30 | Bundle getFragmentBundle(); 31 | 32 | void stopRefresh(); 33 | 34 | void scrollRecyclerViewToPos(int pos); 35 | 36 | void removeSelf(); 37 | } 38 | 39 | interface Presenter { 40 | 41 | void onDestroy(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/contract/CollectionContract.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.contract; 2 | 3 | import com.yangxiaobin.gank.common.base.IBaseModel; 4 | import com.yangxiaobin.gank.common.base.IBaseView; 5 | import com.yangxiaobin.gank.common.db.RealmHelper; 6 | import com.yxb.easy.EasyRecyclerView; 7 | import com.yxb.easy.adapter.AdapterWrapper; 8 | 9 | /** 10 | * Created by handsomeyang on 2017/8/15. 11 | */ 12 | 13 | public interface CollectionContract { 14 | 15 | interface Model extends IBaseModel { 16 | 17 | } 18 | 19 | interface View extends IBaseView { 20 | void removeSelf(); 21 | 22 | void setRecyclerViewAdapter(AdapterWrapper adapter); 23 | 24 | RealmHelper getRealmHelper(); 25 | 26 | EasyRecyclerView getEmptyParent(); 27 | } 28 | 29 | interface Presenter { 30 | 31 | void onDestroy(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/contract/ContentContract.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.contract; 2 | 3 | import android.os.Bundle; 4 | import com.yangxiaobin.gank.common.base.IBaseModel; 5 | import com.yangxiaobin.gank.common.base.IBaseView; 6 | import com.yangxiaobin.gank.common.db.RealmHelper; 7 | import com.yangxiaobin.gank.mvp.view.adapter.ContentAdapter; 8 | 9 | /** 10 | * Created by handsomeyang on 2017/7/11. 11 | */ 12 | 13 | public interface ContentContract { 14 | 15 | interface Model extends IBaseModel { 16 | 17 | } 18 | 19 | interface View extends IBaseView { 20 | 21 | void setUpToolbar(); 22 | 23 | void setUpToolbarTitle(String title); 24 | 25 | Bundle getFragmentArgument(); 26 | 27 | void setUpRecyclerView(); 28 | 29 | void setRecyclerViewAdapter(ContentAdapter adapter); 30 | 31 | void setImageViewUrl(String url); 32 | 33 | RealmHelper getRealmHelper(); 34 | 35 | void removeSelf(); 36 | } 37 | 38 | interface Presenter { 39 | 40 | void onDestroy(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/contract/MainContract.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.contract; 2 | 3 | import android.graphics.Bitmap; 4 | import com.yangxiaobin.gank.common.base.IBaseModel; 5 | import com.yangxiaobin.gank.common.base.IBaseView; 6 | import com.yangxiaobin.gank.common.bean.GankDailyDataEntity; 7 | import com.yangxiaobin.gank.common.bean.GankDailyTitleEntity; 8 | import com.yangxiaobin.gank.common.bean.GankTotalHistoryEntity; 9 | import com.yangxiaobin.gank.common.bean.GitHubUserEntity; 10 | import com.yxb.easy.adapter.AdapterWrapper; 11 | import io.reactivex.Flowable; 12 | import io.reactivex.Observable; 13 | import io.reactivex.Single; 14 | import org.reactivestreams.Publisher; 15 | 16 | /** 17 | * Created by handsomeyang on 2017/7/6. 18 | */ 19 | 20 | public interface MainContract { 21 | 22 | interface Model extends IBaseModel { 23 | 24 | Flowable getTotalHistory(); 25 | 26 | Publisher getGankDailyData(int year, int month, int date); 27 | 28 | Single getTitle(int count, int page); 29 | 30 | Observable doGithubLogin(String account); 31 | } 32 | 33 | interface View extends IBaseView { 34 | 35 | void setToolbarTitle(String title); 36 | 37 | void setUpRecyclerView(AdapterWrapper adapter); 38 | 39 | void initCardHelper(); 40 | 41 | void startSwitchBgAnim(Bitmap bitmap); 42 | 43 | void stopLoadingMore(); 44 | 45 | void setUserHeadImage(String url); 46 | 47 | void setUserName(String name); 48 | 49 | void resetUser(); 50 | 51 | android.view.View showLoadError(); 52 | } 53 | 54 | interface Presenter { 55 | 56 | void restart(); 57 | 58 | void onDestroy(); 59 | 60 | boolean onBackPress(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/contract/SearchContract.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.contract; 2 | 3 | import android.support.v7.widget.SearchView; 4 | import android.support.v7.widget.Toolbar; 5 | import com.yangxiaobin.gank.common.base.IBaseModel; 6 | import com.yangxiaobin.gank.common.base.IBaseView; 7 | import com.yangxiaobin.gank.common.bean.CategoryEntity; 8 | import com.yangxiaobin.gank.common.db.RealmHelper; 9 | import com.yangxiaobin.gank.mvp.view.adapter.CategoryAdapter; 10 | import com.yxb.easy.EasyRecyclerView; 11 | import io.reactivex.Flowable; 12 | 13 | /** 14 | * Created by handsomeyang on 2017/8/28. 15 | */ 16 | 17 | public interface SearchContract { 18 | 19 | interface Model extends IBaseModel { 20 | 21 | Flowable getSearchRes(String query, String category, int count, int page); 22 | } 23 | 24 | interface View extends IBaseView { 25 | 26 | void removeSelf(); 27 | 28 | void setRecyclerViewAdapter(CategoryAdapter adapter); 29 | 30 | RealmHelper getRealmHelper(); 31 | 32 | void stopRefreshAndLoadMore(); 33 | 34 | void recyclerViewMoveToPos(int pos); 35 | 36 | SearchView.SearchAutoComplete getViewForInputManager(); 37 | 38 | Toolbar getSuggestWindowAnchor(); 39 | 40 | void setHistoryQueryAndSubmit(String content); 41 | 42 | EasyRecyclerView getHeaderAndFooterParent(); 43 | } 44 | 45 | interface Presenter { 46 | 47 | void onDestroy(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/model/local/GankItemModel.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.model.local; 2 | 3 | import io.realm.RealmObject; 4 | import io.realm.annotations.PrimaryKey; 5 | 6 | /** 7 | * Created by handsomeyang on 2017/7/27. 8 | */ 9 | 10 | public class GankItemModel extends RealmObject { 11 | 12 | @PrimaryKey private long id; // 主键 13 | private String url; // 网页地址 14 | private String title; // 标题 15 | private String date; // 日期 16 | private String imageUrl1; // 图片1 17 | private String imageUrl2; // 图片2 18 | private String who; // 谁审核 19 | private boolean isColleced; // 是否收藏 20 | 21 | public boolean isColleced() { 22 | return isColleced; 23 | } 24 | 25 | public void setColleced(boolean colleced) { 26 | isColleced = colleced; 27 | } 28 | 29 | public long getId() { 30 | return id; 31 | } 32 | 33 | public void setId(long id) { 34 | this.id = id; 35 | } 36 | 37 | public String getUrl() { 38 | return url; 39 | } 40 | 41 | public void setUrl(String url) { 42 | this.url = url; 43 | } 44 | 45 | public String getTitle() { 46 | return title; 47 | } 48 | 49 | public void setTitle(String title) { 50 | this.title = title; 51 | } 52 | 53 | public String getDate() { 54 | return date; 55 | } 56 | 57 | public void setDate(String date) { 58 | this.date = date; 59 | } 60 | 61 | public String getImageUrl1() { 62 | return imageUrl1; 63 | } 64 | 65 | public void setImageUrl1(String imageUrl1) { 66 | this.imageUrl1 = imageUrl1; 67 | } 68 | 69 | public String getImageUrl2() { 70 | return imageUrl2; 71 | } 72 | 73 | public void setImageUrl2(String imageUrl2) { 74 | this.imageUrl2 = imageUrl2; 75 | } 76 | 77 | public String getWho() { 78 | return who; 79 | } 80 | 81 | public void setWho(String who) { 82 | this.who = who; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/model/remote/CategoryModel.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.model.remote; 2 | 3 | import com.yangxiaobin.gank.common.bean.CategoryEntity; 4 | import com.yangxiaobin.gank.common.net.ApiService; 5 | import com.yangxiaobin.gank.common.utils.RxUtils; 6 | import com.yangxiaobin.gank.mvp.contract.CategoryContract; 7 | import io.reactivex.Flowable; 8 | import javax.inject.Inject; 9 | 10 | /** 11 | * Created by handsomeyang on 2017/7/25. 12 | */ 13 | 14 | public class CategoryModel implements CategoryContract.Model { 15 | 16 | private ApiService mApiService; 17 | 18 | @Inject public CategoryModel(ApiService apiService) { 19 | mApiService = apiService; 20 | } 21 | 22 | @Override 23 | public Flowable getSomeCategory(String category, int dataCount, int pageCount) { 24 | return mApiService.getSomeCategory(category, dataCount, pageCount) 25 | .compose(RxUtils.switchFlowableSchedulers()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/model/remote/CollectionMoel.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.model.remote; 2 | 3 | import com.yangxiaobin.gank.mvp.contract.CollectionContract; 4 | import javax.inject.Inject; 5 | 6 | /** 7 | * Created by handsomeyang on 2017/8/15. 8 | */ 9 | 10 | public class CollectionMoel implements CollectionContract.Model { 11 | @Inject public CollectionMoel() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/model/remote/ContentModel.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.model.remote; 2 | 3 | import com.yangxiaobin.gank.mvp.contract.ContentContract; 4 | import javax.inject.Inject; 5 | 6 | /** 7 | * Created by handsomeyang on 2017/7/11. 8 | */ 9 | 10 | public class ContentModel implements ContentContract.Model { 11 | @Inject public ContentModel() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/model/remote/MainModel.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.model.remote; 2 | 3 | import com.yangxiaobin.gank.common.bean.GankDailyDataEntity; 4 | import com.yangxiaobin.gank.common.bean.GankDailyTitleEntity; 5 | import com.yangxiaobin.gank.common.bean.GankTotalHistoryEntity; 6 | import com.yangxiaobin.gank.common.bean.GitHubUserEntity; 7 | import com.yangxiaobin.gank.common.net.ApiService; 8 | import com.yangxiaobin.gank.common.utils.RxUtils; 9 | import com.yangxiaobin.gank.di.scope.LoginUsed; 10 | import com.yangxiaobin.gank.mvp.contract.MainContract; 11 | import io.reactivex.Flowable; 12 | import io.reactivex.Observable; 13 | import io.reactivex.Single; 14 | import javax.inject.Inject; 15 | import retrofit2.Retrofit; 16 | 17 | /** 18 | * Created by handsomeyang on 2017/7/6. 19 | */ 20 | 21 | public class MainModel implements MainContract.Model { 22 | 23 | private ApiService mApiService; 24 | private @LoginUsed Retrofit mRetrofit; 25 | 26 | @Inject public MainModel(ApiService apiService, @LoginUsed Retrofit retrofit) { 27 | mApiService = apiService; 28 | mRetrofit = retrofit; 29 | } 30 | 31 | /** 32 | * 获取 某天gank内容 33 | * 34 | * @return 每日数据 35 | */ 36 | @Override public Flowable getGankDailyData(int year, int month, int date) { 37 | return mApiService.getDailyData(year, month, date) 38 | .compose(RxUtils.switchFlowableSchedulers()); 39 | } 40 | 41 | /** 42 | * 获取gank 历史 43 | * 44 | * @return 历史日期 45 | */ 46 | @Override public Flowable getTotalHistory() { 47 | return mApiService.getTotalHistory() 48 | .compose(RxUtils.switchFlowableSchedulers()); 49 | } 50 | 51 | /** 52 | * 获取title 53 | * 54 | * @param count 标题数量 55 | * @param page 第几页 56 | * @return 标题 57 | */ 58 | @Override public Single getTitle(int count, int page) { 59 | return mApiService.getDailyTitle(count, page) 60 | .compose(RxUtils.switchSingleSchedulers()); 61 | } 62 | 63 | @Override public Observable doGithubLogin(String account) { 64 | return mRetrofit.create(ApiService.class) 65 | .getUserInfo(account) 66 | .compose(RxUtils.switchObservableSchedulers()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/model/remote/SearchModel.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.model.remote; 2 | 3 | import com.yangxiaobin.gank.common.bean.CategoryEntity; 4 | import com.yangxiaobin.gank.common.net.ApiService; 5 | import com.yangxiaobin.gank.common.utils.RxUtils; 6 | import com.yangxiaobin.gank.mvp.contract.SearchContract; 7 | import io.reactivex.Flowable; 8 | import javax.inject.Inject; 9 | 10 | /** 11 | * Created by handsomeyang on 2017/8/28. 12 | */ 13 | 14 | public class SearchModel implements SearchContract.Model { 15 | @Inject ApiService mApiService; 16 | 17 | @Inject public SearchModel(ApiService apiService) { 18 | mApiService = apiService; 19 | } 20 | 21 | @Override 22 | public Flowable getSearchRes(String query, String category, int count, 23 | int page) { 24 | return mApiService.getSearchResult(query, category, count, page) 25 | .compose(RxUtils.switchFlowableSchedulers()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/Itemtype/ItemTypeCategory.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.Itemtype; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | import com.bumptech.glide.Glide; 9 | import com.handsome.library.T; 10 | import com.yangxiaobin.gank.App; 11 | import com.yangxiaobin.gank.R; 12 | import com.yangxiaobin.gank.common.bean.CategoryEntity; 13 | import com.yangxiaobin.gank.common.bean.ContentItemEntity; 14 | import com.yangxiaobin.gank.common.db.RealmHelper; 15 | import com.yangxiaobin.gank.common.utils.ImageUtils; 16 | import com.yangxiaobin.gank.common.utils.UserUtils; 17 | import com.yangxiaobin.gank.mvp.view.adapter.CategoryAdapter; 18 | import com.yxb.easy.adapter.SlideItemTypeDelegate; 19 | import com.yxb.easy.holder.EasyViewHolder; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by handsomeyang on 2017/9/13. 24 | */ 25 | 26 | public class ItemTypeCategory implements SlideItemTypeDelegate { 27 | 28 | private RealmHelper mRealmHelper; 29 | private CategoryAdapter mAdapter; 30 | 31 | public ItemTypeCategory(CategoryAdapter adapter) { 32 | mAdapter = adapter; 33 | } 34 | 35 | @Override public int getItemViewLayoutId() { 36 | return R.layout.item_content_fragment_content; 37 | } 38 | 39 | @Override public boolean isMatchType(CategoryEntity.ResultsBean resultsBean, int pos) { 40 | return true; 41 | } 42 | 43 | @Override 44 | public void bindData(Context context, EasyViewHolder holder, CategoryEntity.ResultsBean entity, 45 | int pos) { 46 | if (mRealmHelper == null) { 47 | mRealmHelper = new RealmHelper(context); 48 | } 49 | //content 50 | //是否收藏过 先判断是否登录 51 | if (UserUtils.hasLogined(context)) { 52 | if (mRealmHelper.findOne(entity) != null) { 53 | ((ImageView) holder.getView(R.id.imgv_is_collected_content_framgent)).setImageResource( 54 | R.drawable.ic_collected_128); 55 | } 56 | } 57 | if (App.getINSTANCE().getItemUrls().contains(entity.getUrl())) { 58 | //holder.setBackgroundRes(R.id.layout_item_content_fragment,R.color.gray); 59 | TextView tvContent = holder.getView(R.id.tv_item_content_content_fragment); 60 | tvContent.setTextColor(context.getResources().getColor(R.color.gray)); 61 | } 62 | holder.setText(R.id.tv_item_content_content_fragment, entity.getDesc()); 63 | holder.setText(R.id.tv_who_content_content_fragment, entity.getWho()); 64 | holder.setVisible(R.id.tv_when_content_content_fragment, View.VISIBLE); 65 | holder.setText(R.id.tv_when_content_content_fragment, entity.getPublishedAt().split("T")[0]); 66 | ImageView imageView1 = holder.getView(R.id.imgv1_item_content_content_fragment); 67 | ImageView imageView2 = holder.getView(R.id.imgv2_item_content_content_fragment); 68 | List images = entity.getImages(); 69 | if (entity.getImages() != null && images.size() > 0) { 70 | // 第一张gif 71 | String imageUrl2 = images.get(0); 72 | if (!TextUtils.isEmpty(imageUrl2)) { 73 | imageView2.setVisibility(View.VISIBLE); 74 | ImageUtils.load(context, imageUrl2, imageView2); 75 | } 76 | if (entity.getImages().size() > 1) { 77 | // 第二张gif 78 | String imageUrl1 = entity.getImages().get(1); 79 | if (!TextUtils.isEmpty(imageUrl1)) { 80 | imageView1.setVisibility(View.VISIBLE); 81 | Glide.with(context).load(imageUrl1).into(imageView1); 82 | ImageUtils.load(context, imageUrl1, imageView1); 83 | } 84 | } else { 85 | imageView1.setVisibility(View.GONE); 86 | } 87 | } else { 88 | imageView1.setVisibility(View.GONE); 89 | imageView2.setVisibility(View.GONE); 90 | } 91 | // 初始化侧滑菜单 92 | View tvAdd = holder.getItemView().findViewById(R.id.tv_add_collection_menu_slide); 93 | View tvRemove = holder.getItemView().findViewById(R.id.tv_remove_collection_menu_slide); 94 | if (hasInsertedBefore(entity)) { 95 | tvAdd.setVisibility(View.GONE); 96 | tvRemove.setVisibility(View.VISIBLE); 97 | } else { 98 | tvAdd.setVisibility(View.VISIBLE); 99 | tvRemove.setVisibility(View.GONE); 100 | } 101 | } 102 | 103 | // 查询是否添加过 104 | private boolean hasInsertedBefore(ContentItemEntity entity) { 105 | return mRealmHelper.findOne(entity) != null; 106 | } 107 | 108 | @Override public int getSlideMenuId() { 109 | return R.layout.slide_menu_collection; 110 | } 111 | 112 | @Override public void onSlide(View view, EasyViewHolder holder, CategoryEntity.ResultsBean entity, 113 | int pos) { 114 | Context context = view.getContext(); 115 | if (!UserUtils.hasLogined(context)) { 116 | T.info(context.getString(R.string.please_login_frist)); 117 | } else { 118 | // 登录过 119 | switch (view.getId()) { 120 | case R.id.tv_add_collection_menu_slide: 121 | mRealmHelper.insert(entity); 122 | break; 123 | case R.id.tv_remove_collection_menu_slide: 124 | mRealmHelper.delete(entity); 125 | break; 126 | default: 127 | break; 128 | } 129 | mAdapter.notifyItemChanged(pos); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/Itemtype/ItemTypeContentCategoryTitle.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.Itemtype; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.support.annotation.RequiresApi; 6 | import android.text.TextUtils; 7 | import android.widget.TextView; 8 | import com.yangxiaobin.Constant; 9 | import com.yangxiaobin.gank.R; 10 | import com.yangxiaobin.gank.common.bean.ContentItemEntity; 11 | import com.yxb.base.utils.CommonUtils; 12 | import com.yxb.easy.adapter.ItemTypeDelegate; 13 | import com.yxb.easy.holder.EasyViewHolder; 14 | 15 | /** 16 | * Created by handsomeyang on 2017/9/13. 17 | */ 18 | 19 | public class ItemTypeContentCategoryTitle implements ItemTypeDelegate { 20 | 21 | @Override public int getItemViewLayoutId() { 22 | return R.layout.item_content_fragment_title; 23 | } 24 | 25 | @Override public boolean isMatchType(ContentItemEntity contentItemEntity, int pos) { 26 | return !TextUtils.isEmpty(contentItemEntity.getTitle()); 27 | } 28 | 29 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override 30 | public void bindData(Context context, EasyViewHolder holder, ContentItemEntity entity, int pos) { 31 | //title 32 | String title = entity.getTitle(); 33 | TextView titleView = holder.getView(R.id.tv_item_title_content_fragment); 34 | titleView.setText(title); 35 | CommonUtils.setTextViewDrawableLeft(titleView, getTitleIcon(title)); 36 | } 37 | 38 | private int getTitleIcon(String title) { 39 | switch (title) { 40 | case Constant.Category.ANDROID: 41 | return R.drawable.ic_android_128; 42 | case Constant.Category.IOS: 43 | return R.drawable.ic_ios_128; 44 | case Constant.Category.WEB: 45 | return R.drawable.ic_web_128; 46 | case Constant.Category.EXTEND: 47 | return R.drawable.ic_extend_128; 48 | case Constant.Category.VIDEO: 49 | return R.drawable.ic_video_128; 50 | case Constant.Category.MEIZI: 51 | return R.drawable.ic_the_heart_stealer_128; 52 | case Constant.Category.SUGGEST: 53 | return R.drawable.ic_recommend_128; 54 | case Constant.Category.APP: 55 | return R.drawable.ic_app_128; 56 | default: 57 | return R.drawable.ic_the_heart_stealer_128; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/Itemtype/ItemTypeMainCard.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.Itemtype; 2 | 3 | import android.content.Context; 4 | import android.widget.ImageView; 5 | import com.yangxiaobin.gank.R; 6 | import com.yangxiaobin.gank.common.bean.GankDailyDataEntity; 7 | import com.yangxiaobin.gank.common.utils.ImageUtils; 8 | import com.yxb.easy.adapter.ItemTypeDelegate; 9 | import com.yxb.easy.holder.EasyViewHolder; 10 | 11 | /** 12 | * Created by handsomeyang on 2017/9/13. 13 | */ 14 | 15 | public class ItemTypeMainCard implements ItemTypeDelegate { 16 | 17 | @Override public int getItemViewLayoutId() { 18 | return R.layout.item_main_recyclerview_main_card; 19 | } 20 | 21 | @Override public boolean isMatchType(GankDailyDataEntity gankDailyDataEntity, int pos) { 22 | return true; 23 | } 24 | 25 | @Override public void bindData(Context context, EasyViewHolder holder, GankDailyDataEntity entity, 26 | int pos) { 27 | ImageView meizi = holder.getView(R.id.imgv_item_main_recyclerview); 28 | //Logger.e("妹子url:" + entity.getResults().get福利().get(0).getUrl()); 29 | String url = entity.getResults().get福利().get(0).getUrl(); 30 | ImageUtils.load(context, url, meizi); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/activity/LandscapeVideoActivity.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.Toolbar; 7 | import android.text.TextUtils; 8 | import android.view.ViewGroup; 9 | import android.widget.RelativeLayout; 10 | import com.handsome.library.T; 11 | import com.yangxiaobin.gank.R; 12 | import com.yangxiaobin.gank.mvp.view.fragment.WebFragment; 13 | import com.yxb.base.CommonKey; 14 | import com.yxb.base.utils.FragmentSkipper; 15 | 16 | public class LandscapeVideoActivity extends AppCompatActivity { 17 | 18 | @Override protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_landscape_video); 21 | initialize(); 22 | } 23 | 24 | private void initialize() { 25 | Intent intent = getIntent(); 26 | String url = intent.getStringExtra(CommonKey.STR1); 27 | String title = intent.getStringExtra(CommonKey.STR2); 28 | if (!TextUtils.isEmpty(url)) { 29 | WebFragment webFragment = new WebFragment(); 30 | FragmentSkipper.getInstance() 31 | .init(this) 32 | .target(webFragment.setUrl(url).setTitle(title)) 33 | .add(R.id.framelayout_landscape_video_activity); 34 | } else { 35 | T.info("视频地址解析错误"); 36 | } 37 | } 38 | 39 | @Override public void onWindowFocusChanged(boolean hasFocus) { 40 | super.onWindowFocusChanged(hasFocus); 41 | // 还原web toolbar 42 | RelativeLayout.LayoutParams params = 43 | new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 44 | ViewGroup.LayoutParams.WRAP_CONTENT); 45 | Toolbar toolbar = WebFragment.getToolbar(); 46 | toolbar.setPadding(0, 0, 0, 0); 47 | toolbar.setLayoutParams(params); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/adapter/CategoryAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.adapter; 2 | 3 | import com.yangxiaobin.gank.common.bean.CategoryEntity; 4 | import com.yangxiaobin.gank.mvp.view.Itemtype.ItemTypeCategory; 5 | import com.yxb.easy.adapter.MultiTypeAdapter; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by handsomeyang on 2017/7/25. 10 | */ 11 | 12 | public class CategoryAdapter extends MultiTypeAdapter { 13 | 14 | public CategoryAdapter(List dataList) { 15 | super(dataList); 16 | addItemViewDelegate(new ItemTypeCategory(this)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/adapter/ContentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.adapter; 2 | 3 | import com.yangxiaobin.gank.common.bean.ContentItemEntity; 4 | import com.yangxiaobin.gank.mvp.view.Itemtype.ItemTypeContentCategoryContent; 5 | import com.yangxiaobin.gank.mvp.view.Itemtype.ItemTypeContentCategoryTitle; 6 | import com.yxb.easy.adapter.MultiTypeAdapter; 7 | import java.util.List; 8 | 9 | /** 10 | * Created by handsomeyang on 2017/7/11. 11 | */ 12 | 13 | public class ContentAdapter extends MultiTypeAdapter { 14 | // 共用adapter 标识 15 | private String mFLag; 16 | 17 | public ContentAdapter(List dataList) { 18 | super(dataList); 19 | addItemViewDelegate(new ItemTypeContentCategoryTitle()); 20 | addItemViewDelegate(new ItemTypeContentCategoryContent(this)); 21 | } 22 | 23 | public ContentAdapter(List dataList, String FLag) { 24 | super(dataList); 25 | mFLag = FLag; 26 | } 27 | 28 | public String getFLag() { 29 | return mFLag; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/adapter/FlagForContentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.adapter; 2 | 3 | import android.support.annotation.StringDef; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | /** 8 | * Created by handsomeyang on 2017/9/19. 9 | */ 10 | 11 | @StringDef @Retention(RetentionPolicy.SOURCE) public @interface FlagForContentAdapter { 12 | String COLLECTION = "collectionFragment"; 13 | String CONTENT = "content"; 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/adapter/MainAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.adapter; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import com.yangxiaobin.gank.R; 7 | import com.yangxiaobin.gank.common.bean.GankDailyDataEntity; 8 | import com.yangxiaobin.gank.mvp.view.Itemtype.ItemTypeMainCard; 9 | import com.yangxiaobin.gank.mvp.view.widget.cardgallery.CardAdapterHelper; 10 | import com.yxb.easy.adapter.MultiTypeAdapter; 11 | import com.yxb.easy.holder.EasyViewHolder; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by handsomeyang on 2017/7/6. 16 | */ 17 | // 呈现每日数据adapter 18 | public class MainAdapter extends MultiTypeAdapter { 19 | private CardAdapterHelper mCardAdapterHelper; 20 | 21 | public MainAdapter(List dataList) { 22 | super(dataList); 23 | mCardAdapterHelper = new CardAdapterHelper(); 24 | addItemViewDelegate(new ItemTypeMainCard()); 25 | } 26 | 27 | @Override public EasyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 28 | View itemView = LayoutInflater.from(parent.getContext()) 29 | .inflate(R.layout.item_main_recyclerview_main_card, parent, false); 30 | mCardAdapterHelper.onCreateViewHolder(parent, itemView); 31 | return super.onCreateViewHolder(parent, viewType); 32 | } 33 | 34 | @Override public void onBindViewHolder(EasyViewHolder holder, int position) { 35 | super.onBindViewHolder(holder, position); 36 | mCardAdapterHelper.onBindViewHolder(holder.itemView, position, getItemCount()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/adapter/SearchHistoryAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.adapter; 2 | 3 | import com.yangxiaobin.gank.R; 4 | import com.yangxiaobin.gank.common.bean.SearchHistoryEntity; 5 | import com.yxb.base.utils.CommonUtils; 6 | import com.yxb.easy.adapter.EasyAdapter; 7 | import com.yxb.easy.holder.EasyViewHolder; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by handsomeyang on 2017/8/30. 12 | */ 13 | 14 | public class SearchHistoryAdapter extends EasyAdapter { 15 | 16 | public SearchHistoryAdapter(List dataList, int layoutId) { 17 | super(dataList, layoutId); 18 | } 19 | 20 | @Override 21 | protected void bindViewHolder(EasyViewHolder holder, SearchHistoryEntity entity, int pos) { 22 | holder.setText(R.id.tv_search_key_word_item_search_history, entity.getContent()); 23 | holder.setText(R.id.tv_search_time_item_search_history, 24 | CommonUtils.formatTime(entity.getSearchTime(), "yyyy-MM-dd HH:mm:ss")); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/AboutFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.Toolbar; 7 | import android.text.SpannableString; 8 | import android.text.Spanned; 9 | import android.text.TextUtils; 10 | import android.text.method.LinkMovementMethod; 11 | import android.text.style.ForegroundColorSpan; 12 | import android.text.style.StyleSpan; 13 | import android.text.style.URLSpan; 14 | import android.view.View; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | import butterknife.BindView; 18 | import butterknife.ButterKnife; 19 | import butterknife.Unbinder; 20 | import com.yangxiaobin.Constant; 21 | import com.yangxiaobin.gank.R; 22 | import com.yangxiaobin.gank.common.bean.GitHubUserEntity; 23 | import com.yangxiaobin.gank.common.net.ApiService; 24 | import com.yangxiaobin.gank.common.net.ErrorConsumer; 25 | import com.yangxiaobin.gank.common.utils.ImageUtils; 26 | import com.yangxiaobin.gank.common.utils.RxUtils; 27 | import com.yangxiaobin.gank.common.utils.SPUtils; 28 | import com.yangxiaobin.gank.di.scope.LoginUsed; 29 | import com.yxb.base.AbsBaseFragment; 30 | import dagger.android.support.AndroidSupportInjection; 31 | import io.reactivex.functions.Consumer; 32 | import javax.inject.Inject; 33 | import retrofit2.Retrofit; 34 | 35 | /** 36 | * A simple {@link Fragment} subclass. 37 | */ 38 | public class AboutFragment extends AbsBaseFragment implements View.OnClickListener { 39 | 40 | @BindView(R.id.toolbar_about_frament) Toolbar mToolbar; 41 | @BindView(R.id.tv_card_about_fragment) TextView mTvAboutContent; 42 | @BindView(R.id.imgv_author_head_about_fragment) ImageView mImageViewAuthor; 43 | @BindView(R.id.tv_github_page_about_framgent) TextView mTvGithubPage; 44 | @Inject @LoginUsed Retrofit mRetrofit; 45 | private Unbinder mBind; 46 | 47 | @Override protected int getLayoutResId() { 48 | return R.layout.fragment_about; 49 | } 50 | 51 | @Override public void onAttach(Context context) { 52 | AndroidSupportInjection.inject(this); 53 | super.onAttach(context); 54 | } 55 | 56 | @Override protected void initialize(Bundle bundle) { 57 | mBind = ButterKnife.bind(this, mRootView); 58 | mToolbar.setNavigationOnClickListener(this); 59 | initAboutApp(); 60 | initAboutAuthor(); 61 | initGithubPage(); 62 | } 63 | 64 | private void initGithubPage() { 65 | //超级链接(需要添加setMovementMethod方法附加响应) 66 | String githubText = "githup: https://github.com/yangxiaobinhaoshuai"; 67 | SpannableString spannableString = new SpannableString(githubText); 68 | // 粗体 69 | spannableString.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, 7, 70 | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //粗体 71 | // 设置超链接 72 | spannableString.setSpan(new URLSpan("https://github.com/yangxiaobinhaoshuai"), 7, 73 | githubText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 74 | //设置超链接字体前景色 为蓝色 75 | spannableString.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorPrimary)), 76 | 7, githubText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置前景色为洋红色 77 | mTvGithubPage.setText(spannableString); 78 | // 响应超链接 79 | mTvGithubPage.setMovementMethod(LinkMovementMethod.getInstance()); 80 | } 81 | 82 | private void initAboutAuthor() { 83 | String headImageUrl = (String) SPUtils.get(mContext, Constant.KEY_HAS_GOT_MY_HEAD_IMAGE, ""); 84 | if (!TextUtils.isEmpty(headImageUrl)) { 85 | ImageUtils.load(mContext, headImageUrl, mImageViewAuthor); 86 | return; 87 | } 88 | // 获取github 头像 89 | mRetrofit.create(ApiService.class) 90 | .getUserInfo(Constant.MY_GITHUB_ACCOUNT) 91 | .compose(RxUtils.switchObservableSchedulers()) 92 | .subscribe(new Consumer() { 93 | @Override public void accept(GitHubUserEntity entity) throws Exception { 94 | String myAvatarUrl = entity.getAvatar_url(); 95 | if (!TextUtils.isEmpty(myAvatarUrl)) { 96 | SPUtils.put(mContext, Constant.KEY_HAS_GOT_MY_HEAD_IMAGE, myAvatarUrl); 97 | ImageUtils.load(mContext, myAvatarUrl, mImageViewAuthor); 98 | } 99 | } 100 | }, new ErrorConsumer()); 101 | } 102 | 103 | private void initAboutApp() { 104 | String aboutText = "分享干货和萌妹子。" 105 | + "\n" 106 | + "\r\n功能:" 107 | + "\r\n · 每日干货推荐" 108 | + "\r\n · 干货分类查询" 109 | + "\r\n · 侧滑收藏/移除收藏干货" 110 | + "\r\n · 用户管理" 111 | + "\r\n · 下载喜欢的妹子做壁纸 :)" 112 | + "\r\n · 缓存清理"; 113 | 114 | mTvAboutContent.setText(aboutText); 115 | mRootView.setBackgroundResource(R.drawable.bg_dialog_fragment_login_github); 116 | } 117 | 118 | @Override public void onClick(View v) { 119 | getFragmentManager().popBackStack(); 120 | } 121 | 122 | @Override public void onDestroy() { 123 | super.onDestroy(); 124 | mBind.unbind(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/CategoryFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.DividerItemDecoration; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.Toolbar; 9 | import butterknife.BindView; 10 | import com.yangxiaobin.gank.R; 11 | import com.yangxiaobin.gank.common.base.BaseFragment; 12 | import com.yangxiaobin.gank.common.db.RealmHelper; 13 | import com.yangxiaobin.gank.mvp.contract.CategoryContract; 14 | import com.yangxiaobin.gank.mvp.presenter.CategoryPresenter; 15 | import com.yangxiaobin.gank.mvp.view.adapter.CategoryAdapter; 16 | import com.yxb.easy.EasyRecyclerView; 17 | import com.yxb.easy.refresh.SwipeTopBottomLayout; 18 | import javax.inject.Inject; 19 | 20 | /** 21 | * A simple {@link Fragment} subclass. 22 | */ 23 | public class CategoryFragment extends BaseFragment implements CategoryContract.View { 24 | 25 | @Inject RealmHelper mRealmHelper; 26 | @Inject CategoryPresenter mPresenter; 27 | @BindView(R.id.toolbar_single_cateogory_fragment) Toolbar mToolbar; 28 | @BindView(R.id.recyclerview_single_category_fragment) EasyRecyclerView mRecyclerView; 29 | private SwipeTopBottomLayout mSwipeTopBottomLayout; 30 | 31 | @Override protected int getLayoutResId() { 32 | return R.layout.fragment_category; 33 | } 34 | 35 | @Override protected void initialize(Bundle bundle) { 36 | super.initialize(bundle); 37 | mPresenter.start(); 38 | // toolbar 39 | mToolbar.setNavigationIcon(R.drawable.ic_left_arraw_128); 40 | mToolbar.setNavigationOnClickListener(mPresenter); 41 | // recyclerview 42 | mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); 43 | mRecyclerView.addItemDecoration( 44 | new DividerItemDecoration(mContext, DividerItemDecoration.VERTICAL)); 45 | mRecyclerView.setNeedRefresh(true); 46 | 47 | mSwipeTopBottomLayout = mRecyclerView.getSwipeTopBottomLayout(); 48 | mSwipeTopBottomLayout.setRefreshing(true); 49 | mSwipeTopBottomLayout.setOnLoadMoreListener(mPresenter); 50 | mSwipeTopBottomLayout.setOnRefreshListener(mPresenter); 51 | mRecyclerView.setOnItemClickListener(mPresenter, R.id.layout_item_content_fragment, 52 | R.id.imgv1_item_content_content_fragment, R.id.imgv2_item_content_content_fragment); 53 | } 54 | 55 | @Override public Context getViewContext() { 56 | return mContext; 57 | } 58 | 59 | @Override public void showToast(String msg) { 60 | 61 | } 62 | 63 | @Override public RealmHelper getRealmHelper() { 64 | return mRealmHelper; 65 | } 66 | 67 | @Override public void setRecyclerViewAdapter(CategoryAdapter adapter) { 68 | mRecyclerView.setAdapter(adapter); 69 | } 70 | 71 | @Override public void setToolbarTitle(String title) { 72 | mToolbar.setTitle(title); 73 | } 74 | 75 | @Override public Bundle getFragmentBundle() { 76 | return getArguments(); 77 | } 78 | 79 | @Override public void stopRefresh() { 80 | mSwipeTopBottomLayout.setLoadingMore(false); 81 | mSwipeTopBottomLayout.setRefreshing(false); 82 | } 83 | 84 | @Override public void scrollRecyclerViewToPos(int pos) { 85 | mRecyclerView.smoothScrollToPosition(pos); 86 | } 87 | 88 | @Override public void removeSelf() { 89 | getFragmentManager().beginTransaction().remove(this).commitAllowingStateLoss(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/CollectionFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.DividerItemDecoration; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.Toolbar; 9 | import butterknife.BindView; 10 | import com.handsome.library.T; 11 | import com.yangxiaobin.gank.R; 12 | import com.yangxiaobin.gank.common.base.BaseFragment; 13 | import com.yangxiaobin.gank.common.db.RealmHelper; 14 | import com.yangxiaobin.gank.common.utils.UserUtils; 15 | import com.yangxiaobin.gank.mvp.contract.CollectionContract; 16 | import com.yangxiaobin.gank.mvp.presenter.CollectionPresenter; 17 | import com.yxb.easy.EasyRecyclerView; 18 | import com.yxb.easy.adapter.AdapterWrapper; 19 | import javax.inject.Inject; 20 | 21 | /** 22 | * A simple {@link Fragment} subclass. 23 | */ 24 | public class CollectionFragment extends BaseFragment implements CollectionContract.View { 25 | 26 | @BindView(R.id.recyclerview_collection_fragment) EasyRecyclerView mRecyclerView; 27 | @BindView(R.id.toolbar_collection_frament) Toolbar mToolbar; 28 | @Inject CollectionPresenter mPresenter; 29 | @Inject RealmHelper mRealmHelper; 30 | 31 | @Override protected int getLayoutResId() { 32 | return R.layout.fragment_collection; 33 | } 34 | 35 | @Override protected void initialize(Bundle bundle) { 36 | super.initialize(bundle); 37 | mToolbar.setTitle("收藏"); 38 | mToolbar.setNavigationIcon(R.drawable.ic_left_arraw_128); 39 | mToolbar.setNavigationOnClickListener(mPresenter); 40 | if (!UserUtils.hasLogined(mContext)) { 41 | T.info(getString(R.string.please_login_frist)); 42 | return; 43 | } 44 | mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); 45 | mRecyclerView.setAntiShake(1000); 46 | mRecyclerView.setOnItemClickListener(mPresenter, R.id.layout_item_content_fragment, 47 | R.id.imgv1_item_content_content_fragment, R.id.imgv2_item_content_content_fragment, 48 | R.id.layout_title_content_fragment); 49 | mRecyclerView.addItemDecoration( 50 | new DividerItemDecoration(mContext, DividerItemDecoration.VERTICAL)); 51 | mPresenter.start(); 52 | } 53 | 54 | @Override public Context getViewContext() { 55 | return mContext; 56 | } 57 | 58 | @Override public void showToast(String msg) { 59 | 60 | } 61 | 62 | @Override public void removeSelf() { 63 | getFragmentManager().beginTransaction().remove(this).commitAllowingStateLoss(); 64 | } 65 | 66 | @Override public void setRecyclerViewAdapter(AdapterWrapper adapter) { 67 | mRecyclerView.setAdapter(adapter); 68 | } 69 | 70 | @Override public RealmHelper getRealmHelper() { 71 | return mRealmHelper; 72 | } 73 | 74 | @Override public EasyRecyclerView getEmptyParent() { 75 | return mRecyclerView; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/ContentFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.DividerItemDecoration; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.Toolbar; 10 | import android.widget.ImageView; 11 | import butterknife.BindView; 12 | import com.handsome.library.T; 13 | import com.yangxiaobin.gank.R; 14 | import com.yangxiaobin.gank.common.base.BaseFragment; 15 | import com.yangxiaobin.gank.common.db.RealmHelper; 16 | import com.yangxiaobin.gank.common.utils.ImageUtils; 17 | import com.yangxiaobin.gank.mvp.contract.ContentContract; 18 | import com.yangxiaobin.gank.mvp.presenter.ContentPresenter; 19 | import com.yangxiaobin.gank.mvp.view.adapter.ContentAdapter; 20 | import com.yxb.base.utils.ConvertUtils; 21 | import com.yxb.base.utils.ScreenUtils; 22 | import com.yxb.easy.EasyRecyclerView; 23 | import javax.inject.Inject; 24 | 25 | /** 26 | * A simple {@link Fragment} subclass. 27 | */ 28 | public class ContentFragment extends BaseFragment implements ContentContract.View { 29 | 30 | @Inject ContentPresenter mPresenter; 31 | @Inject RealmHelper mRealmHelper; 32 | @BindView(R.id.auto_recyclerview_content_fragment) EasyRecyclerView mRecyclerView; 33 | @BindView(R.id.imgv_collapse_conentent_fragment) ImageView mImageView; 34 | @BindView(R.id.toolbar_content_fragment) Toolbar mToolbar; 35 | @BindView(R.id.fab_content_fragment) FloatingActionButton mFabVideo; 36 | 37 | @Override protected int getLayoutResId() { 38 | return R.layout.fragment_content; 39 | } 40 | 41 | @Override protected void initialize(Bundle bundle) { 42 | super.initialize(bundle); 43 | mPresenter.start(); 44 | } 45 | 46 | @Override public Context getViewContext() { 47 | return mContext; 48 | } 49 | 50 | @Override public void showToast(String msg) { 51 | T.info(msg); 52 | } 53 | 54 | @Override public void setUpToolbar() { 55 | mToolbar.setNavigationIcon(R.drawable.ic_left_arraw_128); 56 | mToolbar.setNavigationOnClickListener(mPresenter); 57 | mImageView.setOnClickListener(mPresenter); 58 | mFabVideo.setOnClickListener(mPresenter); 59 | } 60 | 61 | @Override public void setUpToolbarTitle(String title) { 62 | mToolbar.setTitle(title); 63 | } 64 | 65 | @Override public Bundle getFragmentArgument() { 66 | return getArguments(); 67 | } 68 | 69 | @Override public void setUpRecyclerView() { 70 | mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); 71 | mRecyclerView.addItemDecoration( 72 | new DividerItemDecoration(mContext, DividerItemDecoration.VERTICAL)); 73 | mRecyclerView.setAntiShake(1000); 74 | mRecyclerView.setOnItemClickListener(mPresenter, R.id.layout_item_content_fragment, 75 | R.id.imgv1_item_content_content_fragment, R.id.imgv2_item_content_content_fragment, 76 | R.id.layout_title_content_fragment); 77 | } 78 | 79 | @Override public void setRecyclerViewAdapter(ContentAdapter adapter) { 80 | mRecyclerView.setAdapter(adapter); 81 | } 82 | 83 | @Override public void setImageViewUrl(String url) { 84 | float screenWidth = ScreenUtils.getScreenWidth(); 85 | int height = ConvertUtils.dp2px(156); 86 | ImageUtils.load(mContext, url, mImageView, ((int) screenWidth), height); 87 | } 88 | 89 | @Override public RealmHelper getRealmHelper() { 90 | return mRealmHelper; 91 | } 92 | 93 | @Override public void removeSelf() { 94 | getFragmentManager().beginTransaction().remove(this).commit(); 95 | } 96 | 97 | @Override public void onDestroy() { 98 | super.onDestroy(); 99 | mPresenter.onDestroy(); 100 | mRealmHelper.closeRealm(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/LoginDialogFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.design.widget.TextInputLayout; 7 | import android.support.v4.app.DialogFragment; 8 | import android.text.TextUtils; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.EditText; 13 | import android.widget.ProgressBar; 14 | import android.widget.TextView; 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | import butterknife.OnClick; 18 | import butterknife.Unbinder; 19 | import com.yangxiaobin.Constant; 20 | import com.yangxiaobin.gank.R; 21 | import com.yangxiaobin.gank.common.bean.GitHubUserEntity; 22 | import com.yangxiaobin.gank.common.db.RealmHelper; 23 | import com.yangxiaobin.gank.common.net.ErrorConsumer; 24 | import com.yangxiaobin.gank.common.utils.Rx2Bus; 25 | import com.yangxiaobin.gank.common.utils.SPUtils; 26 | import com.yangxiaobin.gank.di.scope.LoginUsed; 27 | import com.yangxiaobin.gank.mvp.model.remote.MainModel; 28 | import dagger.android.support.AndroidSupportInjection; 29 | import io.reactivex.disposables.Disposable; 30 | import io.reactivex.functions.Consumer; 31 | import javax.inject.Inject; 32 | import retrofit2.Retrofit; 33 | 34 | /** 35 | * Created by handsomeyang on 2017/8/14. 36 | */ 37 | 38 | public class LoginDialogFragment extends DialogFragment { 39 | 40 | @BindView(R.id.edt_account_login_github_dialog) EditText mEdtAccount; 41 | @BindView(R.id.til_account_login_github_dialog) TextInputLayout mTilAccount; 42 | @BindView(R.id.tv_login_login_github_dialog) TextView mTvLogin; 43 | @BindView(R.id.tv_cancel_login_github_dialog) TextView mTvCancel; 44 | @BindView(R.id.progressbar_login_github_dialog) ProgressBar mProgressBar; 45 | private Unbinder unbinder; 46 | @Inject @LoginUsed Retrofit mRetrofit; 47 | @Inject RealmHelper mRealmHelper; 48 | @Inject MainModel mModel; 49 | private Disposable mSubscribe; 50 | 51 | @Override public void onAttach(Context context) { 52 | AndroidSupportInjection.inject(this); 53 | super.onAttach(context); 54 | } 55 | 56 | @Nullable @Override 57 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 58 | @Nullable Bundle savedInstanceState) { 59 | View rootView = inflater.inflate(R.layout.dialog_login_github_fragment, container, false); 60 | unbinder = ButterKnife.bind(this, rootView); 61 | String userName = (String) SPUtils.get(getContext(), Constant.KEY_USER_NAME, ""); 62 | if (!TextUtils.isEmpty(userName)) { 63 | mEdtAccount.setText(userName); 64 | } 65 | return rootView; 66 | } 67 | 68 | @OnClick({ R.id.tv_login_login_github_dialog, R.id.tv_cancel_login_github_dialog }) 69 | public void onViewClicked(View view) { 70 | switch (view.getId()) { 71 | case R.id.tv_login_login_github_dialog: 72 | String account = mEdtAccount.getText().toString().trim(); 73 | if (checkEdts(account)) { 74 | mTvLogin.setVisibility(View.INVISIBLE); 75 | mProgressBar.setVisibility(View.VISIBLE); 76 | doLoginGithub(account); 77 | } 78 | break; 79 | case R.id.tv_cancel_login_github_dialog: 80 | dismiss(); 81 | break; 82 | } 83 | } 84 | 85 | // login github 86 | private void doLoginGithub(final String account) { 87 | 88 | // 操作db保存数据 89 | mSubscribe = mModel.doGithubLogin(account).subscribe(new Consumer() { 90 | @Override public void accept(final GitHubUserEntity entity) throws Exception { 91 | // 操作db保存数据 92 | Rx2Bus.getDefault().post(entity); 93 | SPUtils.put(getContext(), Constant.KEY_USER_NAME, account); 94 | SPUtils.put(getContext(), Constant.KEY_USER_ID_LOGIN, account); 95 | mRealmHelper.insertUser(entity); 96 | mProgressBar.setVisibility(View.INVISIBLE); 97 | mTvLogin.setVisibility(View.VISIBLE); 98 | dismiss(); 99 | } 100 | }, new ErrorConsumer()); 101 | } 102 | 103 | private boolean checkEdts(String account) { 104 | if (TextUtils.isEmpty(account)) { 105 | mTilAccount.setError("账号不能为空"); 106 | return false; 107 | } 108 | return true; 109 | } 110 | 111 | @Override public void onDestroyView() { 112 | super.onDestroyView(); 113 | unbinder.unbind(); 114 | } 115 | 116 | @Override public void onDestroy() { 117 | super.onDestroy(); 118 | if (mSubscribe != null && !mSubscribe.isDisposed()) { 119 | mSubscribe.dispose(); 120 | } 121 | mRealmHelper.closeRealm(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/MeiziFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.Snackbar; 5 | import android.support.v4.app.Fragment; 6 | import android.text.TextUtils; 7 | import android.view.View; 8 | import butterknife.BindView; 9 | import butterknife.ButterKnife; 10 | import butterknife.Unbinder; 11 | import com.bumptech.glide.Glide; 12 | import com.bumptech.glide.request.target.Target; 13 | import com.github.chrisbanes.photoview.PhotoView; 14 | import com.handsome.library.T; 15 | import com.yangxiaobin.gank.R; 16 | import com.yangxiaobin.gank.common.utils.ImageUtils; 17 | import com.yxb.base.AbsBaseFragment; 18 | import com.yxb.base.CommonKey; 19 | import io.reactivex.Flowable; 20 | import io.reactivex.android.schedulers.AndroidSchedulers; 21 | import io.reactivex.functions.Consumer; 22 | import io.reactivex.functions.Function; 23 | import io.reactivex.schedulers.Schedulers; 24 | import java.io.File; 25 | import org.reactivestreams.Publisher; 26 | 27 | /** 28 | * A simple {@link Fragment} subclass. 29 | */ 30 | public class MeiziFragment extends AbsBaseFragment implements View.OnLongClickListener { 31 | 32 | @BindView(R.id.photoview_meizi_fragment) PhotoView mPhotoView; 33 | private String mMeiziUrl; 34 | private Unbinder mBind; 35 | 36 | @Override protected int getLayoutResId() { 37 | return R.layout.fragment_meizi; 38 | } 39 | 40 | @Override protected void initialize(Bundle bundle) { 41 | mBind = ButterKnife.bind(this, mRootView); 42 | Bundle arguments = getArguments(); 43 | if (arguments != null) { 44 | mMeiziUrl = arguments.getString(CommonKey.STR1); 45 | ImageUtils.load(mContext, mMeiziUrl, mPhotoView); 46 | } else { 47 | T.error("获取妹子失败"); 48 | } 49 | mPhotoView.setOnLongClickListener(this); 50 | } 51 | 52 | private void showSnackBar(View v) { 53 | Snackbar snackbar = Snackbar.make(v, "下载妹子?", Snackbar.LENGTH_SHORT); 54 | if (!TextUtils.isEmpty("下载")) { 55 | snackbar.setAction("下载", new View.OnClickListener() { 56 | @Override public void onClick(View v) { 57 | saveMeizi(); 58 | } 59 | }); 60 | } 61 | snackbar.show(); 62 | } 63 | 64 | @Override public boolean onLongClick(View v) { 65 | showSnackBar(v); 66 | return false; 67 | } 68 | 69 | private void saveMeizi() { 70 | Flowable.just(mMeiziUrl) 71 | .subscribeOn(Schedulers.newThread()) 72 | .flatMap(new Function>() { 73 | @Override public Publisher apply(String s) throws Exception { 74 | return Flowable.just(Glide.with(mContext) 75 | .load(mMeiziUrl) 76 | .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) 77 | .get()); 78 | } 79 | }) 80 | .observeOn(AndroidSchedulers.mainThread()) 81 | .subscribe(new Consumer() { 82 | @Override public void accept(File file) throws Exception { 83 | boolean isSuccess = ImageUtils.saveImageToGallery(mContext, file); 84 | if (isSuccess) { 85 | T.info("保存到相册成功"); 86 | } else { 87 | T.error("妹子保存失败"); 88 | } 89 | } 90 | }); 91 | } 92 | 93 | @Override public void onDestroy() { 94 | super.onDestroy(); 95 | mBind.unbind(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/PicDialogFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.app.Dialog; 4 | import android.graphics.drawable.ColorDrawable; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.DialogFragment; 8 | import android.text.TextUtils; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.ImageView; 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | import butterknife.OnClick; 16 | import butterknife.Unbinder; 17 | import com.github.chrisbanes.photoview.PhotoView; 18 | import com.yangxiaobin.gank.R; 19 | import com.yangxiaobin.gank.common.utils.ImageUtils; 20 | import com.yxb.base.utils.ScreenUtils; 21 | 22 | /** 23 | * Created by handsomeyang on 2017/8/16. 24 | */ 25 | 26 | public class PicDialogFragment extends DialogFragment { 27 | 28 | @BindView(R.id.imgv_content_pic_dialog_framgent) PhotoView mImageView; 29 | Unbinder unbinder; 30 | @BindView(R.id.imgv_close_pic_dialog_fragment) ImageView mCloseImage; 31 | private String mUrl; 32 | private Dialog mDialog; 33 | 34 | @Nullable @Override 35 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 36 | @Nullable Bundle savedInstanceState) { 37 | View rootView = inflater.inflate(R.layout.dialog_pic_fragment, container, false); 38 | unbinder = ButterKnife.bind(this, rootView); 39 | if (!TextUtils.isEmpty(mUrl)) { 40 | //Logger.e("图片URL:"+mUrl); 41 | float screenHeight = ScreenUtils.getScreenHeight(); 42 | ImageUtils.load(getContext(), mUrl, mImageView, ((int) screenHeight), 43 | ((int) (screenHeight * 3 / 4))); 44 | } 45 | mDialog = getDialog(); 46 | mDialog.setCanceledOnTouchOutside(true); 47 | mDialog.getWindow().setBackgroundDrawable(new ColorDrawable()); 48 | return rootView; 49 | } 50 | 51 | public void setUrl(String url) { 52 | mUrl = url; 53 | } 54 | 55 | @Override public void onDestroyView() { 56 | super.onDestroyView(); 57 | unbinder.unbind(); 58 | } 59 | 60 | @OnClick(R.id.imgv_close_pic_dialog_fragment) public void onViewClicked() { 61 | if (mDialog != null && mDialog.isShowing()) { 62 | mDialog.dismiss(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/SearchFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.annotation.RequiresApi; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v7.widget.DividerItemDecoration; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.SearchView; 11 | import android.support.v7.widget.Toolbar; 12 | import butterknife.BindView; 13 | import com.handsome.library.T; 14 | import com.yangxiaobin.gank.R; 15 | import com.yangxiaobin.gank.common.base.BaseFragment; 16 | import com.yangxiaobin.gank.common.db.RealmHelper; 17 | import com.yangxiaobin.gank.mvp.contract.SearchContract; 18 | import com.yangxiaobin.gank.mvp.presenter.SearchPresenter; 19 | import com.yangxiaobin.gank.mvp.view.adapter.CategoryAdapter; 20 | import com.yxb.easy.EasyRecyclerView; 21 | import com.yxb.easy.refresh.SwipeTopBottomLayout; 22 | import javax.inject.Inject; 23 | 24 | /** 25 | * A simple {@link Fragment} subclass. 26 | */ 27 | public class SearchFragment extends BaseFragment implements SearchContract.View { 28 | 29 | @BindView(R.id.toolbar_search_framgent) Toolbar mToolbar; 30 | @BindView(R.id.recyclerview_search_fragment) EasyRecyclerView mRecyclerView; 31 | @Inject SearchPresenter mPresenter; 32 | @Inject RealmHelper mRealmHelper; 33 | private SwipeTopBottomLayout mSwipeTopBottomLayout; 34 | private SearchView.SearchAutoComplete mSearchTextView; 35 | private SearchView mSearchView; 36 | 37 | @Override protected int getLayoutResId() { 38 | return R.layout.fragment_search; 39 | } 40 | 41 | @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void initialize(Bundle bundle) { 42 | super.initialize(bundle); 43 | initToolbar(); 44 | initRecyclerView(); 45 | mPresenter.start(); 46 | } 47 | 48 | private void initRecyclerView() { 49 | mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); 50 | mRecyclerView.addItemDecoration( 51 | new DividerItemDecoration(mContext, DividerItemDecoration.VERTICAL)); 52 | mRecyclerView.setNeedRefresh(true); 53 | mRecyclerView.setAntiShake(1000); 54 | mRecyclerView.setOnItemClickListener(mPresenter); 55 | mSwipeTopBottomLayout = mRecyclerView.getSwipeTopBottomLayout(); 56 | mSwipeTopBottomLayout.setOnRefreshListener(mPresenter); 57 | mSwipeTopBottomLayout.setOnLoadMoreListener(mPresenter); 58 | } 59 | 60 | private void initToolbar() { 61 | mToolbar.setNavigationIcon(R.drawable.ic_left_arraw_128); 62 | mToolbar.setNavigationOnClickListener(mPresenter); 63 | mToolbar.inflateMenu(R.menu.menu_toolbar_search_fragment); 64 | mToolbar.setTitle("搜索"); 65 | mSearchView = (SearchView) mToolbar.findViewById(R.id.search_view_menu_item_search_fragment); 66 | // if false searchView always visible, bug looks ugly 67 | mSearchView.setIconifiedByDefault(false); 68 | // 修改search view textColor 为白色 69 | mSearchTextView = (SearchView.SearchAutoComplete) mSearchView.findViewById( 70 | android.support.v7.appcompat.R.id.search_src_text); 71 | mSearchView.setSubmitButtonEnabled(true); 72 | mSearchTextView.setTextColor(getResources().getColor(R.color.white)); 73 | mSearchTextView.setHintTextColor(getResources().getColor(R.color.gray)); 74 | mSearchView.setQueryHint("搜索福利试试"); 75 | mSearchView.setOnQueryTextListener(mPresenter); 76 | mSearchTextView.setOnClickListener(mPresenter); 77 | } 78 | 79 | @Override public Context getViewContext() { 80 | return mContext; 81 | } 82 | 83 | @Override public void showToast(String msg) { 84 | T.info(msg); 85 | } 86 | 87 | @Override public void removeSelf() { 88 | getFragmentManager().beginTransaction().remove(this).commitAllowingStateLoss(); 89 | } 90 | 91 | @Override public void setRecyclerViewAdapter(CategoryAdapter adapter) { 92 | mRecyclerView.setAdapter(adapter); 93 | } 94 | 95 | @Override public RealmHelper getRealmHelper() { 96 | return mRealmHelper; 97 | } 98 | 99 | @Override public void stopRefreshAndLoadMore() { 100 | mSwipeTopBottomLayout.setRefreshing(false); 101 | mSwipeTopBottomLayout.setLoadingMore(false); 102 | } 103 | 104 | @Override public void recyclerViewMoveToPos(int pos) { 105 | mRecyclerView.smoothScrollToPosition(pos); 106 | } 107 | 108 | @Override public SearchView.SearchAutoComplete getViewForInputManager() { 109 | return mSearchTextView; 110 | } 111 | 112 | @Override public Toolbar getSuggestWindowAnchor() { 113 | return mToolbar; 114 | } 115 | 116 | @Override public void setHistoryQueryAndSubmit(String content) { 117 | mSearchView.setQuery(content, true); 118 | } 119 | 120 | @Override public EasyRecyclerView getHeaderAndFooterParent() { 121 | return mRecyclerView; 122 | } 123 | 124 | @Override public void onDestroy() { 125 | super.onDestroy(); 126 | mPresenter.onDestroy(); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/fragment/SplashFragment.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.widget.ImageView; 7 | import butterknife.BindView; 8 | import com.yangxiaobin.gank.R; 9 | import com.yangxiaobin.gank.common.base.BaseFragment; 10 | import com.yangxiaobin.gank.common.utils.Rx2Bus; 11 | import io.reactivex.Observable; 12 | import io.reactivex.disposables.Disposable; 13 | import io.reactivex.functions.Consumer; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /** 17 | * A simple {@link Fragment} subclass. 18 | */ 19 | public class SplashFragment extends BaseFragment { 20 | 21 | @BindView(R.id.imgv_splash_fragment) ImageView mImageView; 22 | private Disposable mSubscribe; 23 | 24 | @Override protected int getLayoutResId() { 25 | return R.layout.fragment_splash; 26 | } 27 | 28 | @Override protected void initialize(Bundle bundle) { 29 | super.initialize(bundle); 30 | // mainActivity 联网成功post事件 31 | mSubscribe = Rx2Bus.getDefault().toFlowable(String.class).subscribe(new Consumer() { 32 | @Override public void accept(String s) throws Exception { 33 | destroySelf(); 34 | } 35 | }); 36 | } 37 | 38 | private void destroySelf() { 39 | getFragmentManager().beginTransaction().remove(SplashFragment.this).commitAllowingStateLoss(); 40 | } 41 | 42 | @Override public Context getViewContext() { 43 | return mContext; 44 | } 45 | 46 | @Override public void showToast(String msg) { 47 | // to do nothing 48 | } 49 | 50 | @Override public void onDestroy() { 51 | super.onDestroy(); 52 | if (mSubscribe != null && !mSubscribe.isDisposed()) { 53 | mSubscribe.dispose(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/widget/cardgallery/CardAdapterHelper.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.widget.cardgallery; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import com.yxb.base.utils.ConvertUtils; 7 | 8 | /** 9 | * adapter中调用onCreateViewHolder, onBindViewHolder 10 | * Created by jameson on 9/1/16. 11 | */ 12 | public class CardAdapterHelper { 13 | private int mPagePadding = 15; 14 | private int mShowLeftCardWidth = 15; 15 | 16 | public void onCreateViewHolder(ViewGroup parent, View itemView) { 17 | RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) itemView.getLayoutParams(); 18 | lp.width = parent.getWidth() - ConvertUtils.dp2px(2 * (mPagePadding + mShowLeftCardWidth)); 19 | itemView.setLayoutParams(lp); 20 | } 21 | 22 | public void onBindViewHolder(View itemView, final int position, int itemCount) { 23 | int padding = ConvertUtils.dp2px(mPagePadding); 24 | itemView.setPadding(padding, 0, padding, 0); 25 | int leftMarin = position == 0 ? padding + ConvertUtils.dp2px(mShowLeftCardWidth) : 0; 26 | int rightMarin = 27 | position == itemCount - 1 ? padding + ConvertUtils.dp2px(mShowLeftCardWidth) : 0; 28 | setViewMargin(itemView, leftMarin, 0, rightMarin, 0); 29 | } 30 | 31 | private void setViewMargin(View view, int left, int top, int right, int bottom) { 32 | ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); 33 | if (lp.leftMargin != left 34 | || lp.topMargin != top 35 | || lp.rightMargin != right 36 | || lp.bottomMargin != bottom) { 37 | lp.setMargins(left, top, right, bottom); 38 | view.setLayoutParams(lp); 39 | } 40 | } 41 | 42 | public void setPagePadding(int pagePadding) { 43 | mPagePadding = pagePadding; 44 | } 45 | 46 | public void setShowLeftCardWidth(int showLeftCardWidth) { 47 | mShowLeftCardWidth = showLeftCardWidth; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/widget/cardgallery/CardLinearSnapHelper.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.widget.cardgallery; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.LinearSnapHelper; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | /** 9 | * 防止卡片在第一页和最后一页因无法"居中"而一直循环调用onScrollStateChanged-->SnapHelper.snapToTargetExistingView-->onScrollStateChanged 10 | * Created by jameson on 9/3/16. 11 | */ 12 | public class CardLinearSnapHelper extends LinearSnapHelper { 13 | public boolean mNoNeedToScroll = false; 14 | 15 | @Override 16 | public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, 17 | @NonNull View targetView) { 18 | if (mNoNeedToScroll) { 19 | return new int[] { 0, 0 }; 20 | } else { 21 | return super.calculateDistanceToFinalSnap(layoutManager, targetView); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/yangxiaobin/gank/mvp/view/widget/cardgallery/SpeedRecyclerView.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank.mvp.view.widget.cardgallery; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.Nullable; 5 | import android.util.AttributeSet; 6 | import com.yxb.easy.EasyRecyclerView; 7 | 8 | /** 9 | * 控制fling速度的RecyclerView 10 | * 11 | * Created by jameson on 9/1/16. 12 | */ 13 | public class SpeedRecyclerView extends EasyRecyclerView { 14 | private static final float FLING_SCALE_DOWN_FACTOR = 0.5f; // 减速因子 15 | private static final int FLING_MAX_VELOCITY = 8000; // 最大顺时滑动速度 16 | 17 | public SpeedRecyclerView(Context context) { 18 | super(context); 19 | } 20 | 21 | public SpeedRecyclerView(Context context, @Nullable AttributeSet attrs) { 22 | super(context, attrs); 23 | } 24 | 25 | /* public SpeedRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { 26 | super(context, attrs, defStyle); 27 | }*/ 28 | 29 | @Override public boolean fling(int velocityX, int velocityY) { 30 | velocityX = solveVelocity(velocityX); 31 | velocityY = solveVelocity(velocityY); 32 | return super.fling(velocityX, velocityY); 33 | } 34 | 35 | private int solveVelocity(int velocity) { 36 | if (velocity > 0) { 37 | return Math.min(velocity, FLING_MAX_VELOCITY); 38 | } else { 39 | return Math.max(velocity, -FLING_MAX_VELOCITY); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_android_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_android_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_app_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_app_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_clear_cache_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_clear_cache_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_close_white_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_close_white_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_collcetion_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_collcetion_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_collected_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_collected_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_empty_box_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_empty_box_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_error_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_error_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_extend_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_extend_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_garbage_black_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_garbage_black_64.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_github_200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_github_200.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_ios_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_ios_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_not_collected_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_not_collected_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_placeholer_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_placeholer_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_recommend_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_recommend_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_search_white_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_search_white_64.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_the_heart_stealer_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_the_heart_stealer_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_video_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_video_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_web_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/ic_web_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/load_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxhdpi/load_error.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/header_dialog_fragment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxxhdpi/header_dialog_fragment.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_left_arraw_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/drawable-xxxhdpi/ic_left_arraw_128.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_dialog_fragment_login_github.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/lift_on_touch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_landscape_video.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_login_github_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 22 | 23 | 32 | 33 | 47 | 48 | 60 | 61 | 62 | 71 | 72 | 81 | 82 | 92 | 102 | 103 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_pic_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/footer_search_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 15 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_category.xml: -------------------------------------------------------------------------------- 1 | 11 | 19 | 20 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_collection.xml: -------------------------------------------------------------------------------- 1 | 9 | 17 | 18 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_content.xml: -------------------------------------------------------------------------------- 1 | 10 | 17 | 25 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 56 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_meizi.xml: -------------------------------------------------------------------------------- 1 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_search.xml: -------------------------------------------------------------------------------- 1 | 12 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_splash.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_web.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 22 | 23 | 24 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/header_search_history.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 15 | 16 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_content_fragment_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 30 | 31 | 47 | 48 | 58 | 59 | 70 | 71 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_content_fragment_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_main_recyclerivew_load_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_main_recyclerview_main_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_search_history_search_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 24 | 25 | 36 | 37 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_empty_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_header_navitaionview_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_load_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 17 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/slide_menu_collection.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 20 | 21 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_navigation_main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 37 | 38 | 42 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_toolbar_main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_toolbar_search_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_web_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 12 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/change_round_200.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-xxhdpi/change_round_200.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #FFFFFF 8 | #000 9 | #6000 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 256dp 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 每日干货 3 | 4 | 5 | Hello blank fragment 6 | 7 | 再按一次退出 8 | 解析服务器错误 9 | 10 | 11 | share_element_main_item_to_content 12 | 首页 13 | 14 | Android 15 | iOS 16 | Web 17 | 福利 18 | 瞎推荐 19 | Video 20 | 拓展资源 21 | 收藏 22 | 清理缓存 23 | App 24 | 打开侧拉菜单 25 | 关闭侧拉菜单 26 | 账号或者密码不合法 27 | 今天没有视频哟 28 | 用于获取github主页头像、姓名和创建本地账户 29 | 退出登录? 30 | 请先登录 31 | 清理缓存 32 | 缓存清理中… 33 | 网络不可用 34 | V1.0.0 35 | 没有数据了 36 | 加载网络资源失败,点击重试 37 | 关于作者 38 | 杨晓彬 39 | github主页 40 | 0.00 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 23 | 31 | 32 | 33 | 37 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/test/java/com/yangxiaobin/gank/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.yangxiaobin.gank; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test public void addition_isCorrect() throws Exception { 14 | //assertEquals(4, 2 + 2); 15 | System.out.println("1111" + 1f / 0.96000004d); 16 | } 17 | } -------------------------------------------------------------------------------- /art/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/art/1.jpeg -------------------------------------------------------------------------------- /art/2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/art/2.jpeg -------------------------------------------------------------------------------- /art/3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/art/3.jpeg -------------------------------------------------------------------------------- /art/4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/art/4.jpeg -------------------------------------------------------------------------------- /art/5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/art/5.jpeg -------------------------------------------------------------------------------- /art/6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/art/6.jpeg -------------------------------------------------------------------------------- /art/pic_down_load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/art/pic_down_load.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | apply from:"config.gradle" 3 | 4 | buildscript { 5 | repositories { 6 | jcenter() 7 | mavenCentral() 8 | maven { 9 | url 'https://maven.google.com/' 10 | name 'Google' 11 | } 12 | } 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:3.0.0-beta6' 15 | 16 | // NOTE: Do not place your application dependencies here; they belong 17 | // in the individual module build.gradle files 18 | 19 | classpath "io.realm:realm-gradle-plugin:3.1.1" 20 | } 21 | } 22 | 23 | allprojects { 24 | repositories { 25 | jcenter() 26 | mavenCentral() 27 | maven { url "https://jitpack.io" } 28 | maven { url "https://raw.githubusercontent.com/Pgyer/mvn_repo_pgyer/master" } 29 | maven { 30 | url 'https://maven.google.com/' 31 | name 'Google' 32 | } 33 | } 34 | } 35 | 36 | task clean(type: Delete) { 37 | delete rootProject.buildDir 38 | } 39 | -------------------------------------------------------------------------------- /config.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | 3 | android = [compileSdkVersion: 26, 4 | buildToolsVersion: "26.0.1", 5 | applicationId : "com.yangxiobin.demolib", 6 | minSdkVersion : 16, 7 | targetSdkVersion : 26, 8 | versionCode : 2, 9 | versionName : "1.1"] 10 | 11 | 12 | 13 | def supportVersion = "26.1.0" 14 | def daggerVersion = "2.11" 15 | def rxJavaVersion = "2.1.4" 16 | def rxAndroidVersion = "2.0.1" 17 | def retrofit2Version = "2.3.0" 18 | def butterKnifeVersion = "8.8.1" 19 | def easyRecyclerViewVersion = "0.1.0" 20 | def baseToolsVersion = "0.1.4" 21 | def glideVersion = "4.1.1" 22 | def loggerVersion="2.1.1" 23 | 24 | dependencies = ["test" : "junit:junit:4.12", 25 | 26 | "appcompat-v7" : "com.android.support:appcompat-v7:$supportVersion", 27 | "support-v4" : "com.android.support:support-v4:$supportVersion", 28 | "support_design" : "com.android.support:design:$supportVersion", 29 | "recyclerview" : "com.android.support:recyclerview-v7:$supportVersion", 30 | "cardview" : "com.android.support:cardview-v7:$supportVersion", 31 | 32 | "retrofit" : "com.squareup.retrofit2:retrofit:$retrofit2Version", 33 | "converter-gson" : "com.squareup.retrofit2:converter-gson:$retrofit2Version", 34 | 35 | "adapter-rxjava" : "com.squareup.retrofit2:daadapter-rxjava:$retrofit2Version", 36 | "retrofit2-rxjava2-adapter": "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0", 37 | 38 | "rxjava2" : "io.reactivex.rxjava2:rxjava:$rxJavaVersion", 39 | "rxandroid" : "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion", 40 | 41 | "rxlifecycle" : "com.trello:rxlifecycle:0.8.0", 42 | "rxlifecycle-components" : "com.trello:rxlifecycle-components:0.8.0", 43 | 44 | "butterknife" : "com.jakewharton:butterknife:$butterKnifeVersion", 45 | "butterknife-compiler" : "com.jakewharton:butterknife-compiler:$butterKnifeVersion", 46 | 47 | "dagger2" : "com.google.dagger:dagger:$daggerVersion", 48 | "dagger2-android" : "com.google.dagger:dagger-android:$daggerVersion", 49 | "dagger2-android-support" : "com.google.dagger:dagger-android-support:$daggerVersion", 50 | "dagger2-android-processor": "com.google.dagger:dagger-android-processor:$daggerVersion", 51 | "dagger2-processor" : "com.google.dagger:dagger-compiler:$daggerVersion", 52 | 53 | "logging-interceptor" : "com.squareup.okhttp3:logging-interceptor:3.9.0", 54 | "logger" : "com.orhanobut:logger:$loggerVersion", 55 | 56 | "pullToRefresh" : "com.carme.module:pullToRefresh:1.0.13", 57 | 58 | "glide" : "com.github.bumptech.glide:glide:$glideVersion", 59 | "glide-complier" : "com.github.bumptech.glide:compiler:$glideVersion", 60 | "glide-okhttp3" : "com.github.bumptech.glide:okhttp3-integration:$glideVersion", 61 | 62 | "bugly" : "com.tencent.bugly:nativecrashreport:3.0", 63 | "bugly-upgrade" : "com.tencent.bugly:crashreport_upgrade:1.1.7", 64 | "jpush" : "cn.jiguang:jpush:2.2.0", 65 | "hotfix" : "com.taobao.android:alisdk-hotfix:1.4.0", 66 | 67 | "otto" : "com.squareup:otto:1.3.8", 68 | "mpandroidchart" : "com.github.PhilJay:MPAndroidChart:v3.0.1", 69 | "multidex" : "com.android.support:multidex:1.0.1", 70 | 71 | "photoview" : "com.github.chrisbanes:PhotoView:2.0.0", 72 | 73 | "easy-recyclerview" : "com.yangxiaobin:recyclerview:$easyRecyclerViewVersion", 74 | "base-tools" : "com.yangxiaobin:basetools:$baseToolsVersion", 75 | "handsomeToast" : "com.yangxiaobin:handsomeToast:1.1.4" 76 | 77 | ] 78 | } 79 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangxiaobinhaoshuai/NewGank/8fb72edfea851ed9aac2398e3c5dfe17ba72cdfd/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Sep 24 23:31:30 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------