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