├── .gitignore ├── LICENSE.txt ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── hotbitmapgg │ │ └── moequest │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── hotbitmapgg │ │ │ └── moequest │ │ │ ├── MoeQuestApp.java │ │ │ ├── adapter │ │ │ ├── DoubanMeiziAdapter.java │ │ │ ├── GankMeiziAdapter.java │ │ │ ├── HuaBanMeiziAdapter.java │ │ │ ├── JiandanMeiziAdapter.java │ │ │ ├── MeiziTuAdapter.java │ │ │ ├── TaoFemaleAdapter.java │ │ │ └── helper │ │ │ │ ├── AbsRecyclerViewAdapter.java │ │ │ │ ├── EndlessRecyclerOnScrollListener.java │ │ │ │ └── HeaderViewRecyclerAdapter.java │ │ │ ├── base │ │ │ ├── RxBaseActivity.java │ │ │ └── RxBaseFragment.java │ │ │ ├── entity │ │ │ ├── douban │ │ │ │ └── DoubanMeizi.java │ │ │ ├── gank │ │ │ │ ├── GankMeizi.java │ │ │ │ ├── GankMeiziInfo.java │ │ │ │ └── GankMeiziResult.java │ │ │ ├── huaban │ │ │ │ ├── HuaBanMeizi.java │ │ │ │ └── HuaBanMeiziInfo.java │ │ │ ├── jiandan │ │ │ │ └── JianDanMeizi.java │ │ │ ├── meizitu │ │ │ │ └── MeiziTu.java │ │ │ └── taomodel │ │ │ │ ├── Contentlist.java │ │ │ │ ├── Pagebean.java │ │ │ │ ├── ShowapiResBody.java │ │ │ │ └── TaoFemale.java │ │ │ ├── module │ │ │ ├── commonality │ │ │ │ ├── AppAboutActivity.java │ │ │ │ ├── AppSplashActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MeiziDetailsFragment.java │ │ │ │ └── SingleMeiziDetailsActivity.java │ │ │ ├── douban │ │ │ │ ├── DoubanMeiziFragment.java │ │ │ │ ├── DoubanMeiziPageActivity.java │ │ │ │ └── DoubanSimpleMeiziFragment.java │ │ │ ├── gank │ │ │ │ ├── GankMeiziFragment.java │ │ │ │ └── GankMeiziPageActivity.java │ │ │ ├── huaban │ │ │ │ ├── HuaBanMeiziFragment.java │ │ │ │ └── HuaBanMeiziSimpleFragment.java │ │ │ ├── jiandan │ │ │ │ └── JianDanMeiziFragment.java │ │ │ ├── meizitu │ │ │ │ ├── MeiziTuFragment.java │ │ │ │ ├── MeiziTuPageActivity.java │ │ │ │ └── MeiziTuSimpleFragment.java │ │ │ └── taogirl │ │ │ │ ├── TaoFemaleFragment.java │ │ │ │ └── TaoFemalePagerActivity.java │ │ │ ├── network │ │ │ ├── RetrofitHelper.java │ │ │ └── api │ │ │ │ ├── DoubanMeizhiApi.java │ │ │ │ ├── GankMeiziApi.java │ │ │ │ ├── HuaBanMeiziApi.java │ │ │ │ ├── JianDanMeiziApi.java │ │ │ │ ├── MeiziTuApi.java │ │ │ │ └── TaoFemaleaApi.java │ │ │ ├── notice │ │ │ ├── Distance.java │ │ │ ├── FloatView.java │ │ │ ├── HeadsUp.java │ │ │ └── HeadsUpManager.java │ │ │ ├── rx │ │ │ └── RxBus.java │ │ │ ├── service │ │ │ ├── AlarmReceiver.java │ │ │ └── KeepAlarmLiveReceiver.java │ │ │ ├── utils │ │ │ ├── AlarmManagerUtils.java │ │ │ ├── ConstantUtil.java │ │ │ ├── GlideDownloadImageUtil.java │ │ │ ├── HeadsUpUtils.java │ │ │ ├── ImmersiveUtil.java │ │ │ ├── LogUtil.java │ │ │ ├── MeiziUtil.java │ │ │ ├── PreferencesLoader.java │ │ │ ├── ShareUtil.java │ │ │ ├── SnackbarUtil.java │ │ │ ├── StatusBarCompat.java │ │ │ └── SystemUiVisibilityUtil.java │ │ │ └── widget │ │ │ ├── CircleImageView.java │ │ │ ├── CircleProgressView.java │ │ │ ├── DepthTransFormes.java │ │ │ ├── HackyViewPager.java │ │ │ ├── PhotoImageView.java │ │ │ └── RatioImageView.java │ └── res │ │ ├── drawable-hdpi │ │ ├── bow_tie.png │ │ ├── flower.png │ │ ├── high_importance.png │ │ ├── home.png │ │ ├── ic_back.png │ │ ├── ic_download.png │ │ ├── ic_favorite_icon.png │ │ ├── ic_location.png │ │ ├── ic_share.png │ │ ├── ic_slide_menu_avatar_no_login.png │ │ ├── notification_bg3.9.png │ │ ├── picture.png │ │ ├── placeholder_image.png │ │ ├── share.png │ │ ├── wedding_dress.png │ │ └── year_of_rooster.png │ │ ├── drawable-nodpi │ │ ├── ic_avatar1.jpg │ │ ├── ic_avatar10.jpg │ │ ├── ic_avatar11.jpg │ │ ├── ic_avatar2.jpg │ │ ├── ic_avatar3.jpg │ │ ├── ic_avatar4.jpg │ │ ├── ic_avatar5.jpg │ │ ├── ic_avatar6.jpg │ │ ├── ic_avatar7.jpg │ │ ├── ic_avatar8.jpg │ │ └── ic_avatar9.jpg │ │ ├── drawable-xxhdpi │ │ ├── bg.jpg │ │ └── ic_bg.jpg │ │ ├── drawable │ │ ├── bg_card.9.png │ │ ├── bg_transparency_to_grey.xml │ │ ├── notification_bg.xml │ │ └── shadow_gradient_reserve.xml │ │ ├── layout │ │ ├── activity_about.xml │ │ ├── activity_main.xml │ │ ├── activity_meizi_pager.xml │ │ ├── activity_meizi_pic.xml │ │ ├── activity_splash.xml │ │ ├── activity_tao_female.xml │ │ ├── activity_tao_pager.xml │ │ ├── card_item_meizi.xml │ │ ├── fragment_douban_meizi.xml │ │ ├── fragment_gank_meizi.xml │ │ ├── fragment_huaban_meizi.xml │ │ ├── fragment_jiandan_meizi.xml │ │ ├── fragment_meizi_details.xml │ │ ├── fragment_meizitu.xml │ │ ├── fragment_simple_meizi.xml │ │ ├── item_huaban_meizi.xml │ │ ├── item_jiandan_meizi.xml │ │ ├── item_tao_female.xml │ │ ├── layout_toolbar.xml │ │ ├── load_more_foot_layout.xml │ │ ├── nav_header_main.xml │ │ ├── notification.xml │ │ └── notification_bg.xml │ │ ├── menu │ │ ├── menu_meizi.xml │ │ └── menu_nav.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v19 │ │ └── styles.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── attr.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── hotbitmapgg │ └── moequest │ └── ExampleUnitTest.java ├── art ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png ├── 06.png ├── 07.png ├── 08.png ├── 09.png ├── 10.png ├── bg.jpg └── index.png ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | 10 | .idea/compiler.xml 11 | 12 | .idea/copyright/profiles_settings.xml 13 | 14 | .idea/encodings.xml 15 | 16 | .idea/gradle.xml 17 | 18 | .idea/misc.xml 19 | 20 | .idea/modules.xml 21 | 22 | .idea/vcs.xml 23 | 24 | .idea/misc.xml 25 | 26 | .idea/runConfigurations.xml 27 | 28 | projectFilesBackup/.idea/workspace.xml 29 | 30 | .idea/dictionaries/hcc.xml 31 | 32 | .idea/inspectionProfiles/profiles_settings.xml 33 | 34 | .idea/inspectionProfiles/Project_Default.xml 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 萌妹纸 2 | 3 | [![Wercker](https://img.shields.io/badge/Android%20Client-MoeQuest-brightgreen.svg)]() [![Wercker](https://img.shields.io/badge/Gradle-2.1.3-brightgreen.svg)]() [![Wercker](https://img.shields.io/wercker/ci/wercker/docs.svg?maxAge=2592000)]() [![Crates.io](https://img.shields.io/crates/l/rustc-serialize.svg?maxAge=2592000)]() 4 | 5 | The meizi of a material design style welfare App & 一款MaterialDesign风格的妹子福利App. 6 | 7 | ![](https://github.com/HotBitmapGG/MoeQuest/blob/master/art/bg.jpg?raw=true) 8 | 9 | # 简介 10 | 11 | * 每日更新各种妹纸福利,喜欢的请star一波,谢谢啦. 12 | 13 | ## 功能介绍 14 | 15 | * 1.数据均来自抓取各大网站妹子福利图,gank,豆瓣,花瓣,煎蛋,淘女郎,妹子图. 16 | * 2.使用Rxjava系列类库 + Realm数据库 + Glide实现. 17 | * 3.遵循Google的Material Design. 18 | 19 | ## 更新说明 20 | 21 | ### V2.1.1 22 | * 1.修复了一个issuse提出的崩溃问题,界面共享元素动画使用的问题. 23 | 24 | 25 | ### v2.1 26 | * 1.修复了部分bug. 27 | * 2.新增妹纸图模块. 28 | 29 | 30 | ### v2.0 31 | * 1.关闭了两个issuse,修改了一个RecycleView刷新的bug,解决方案来自@drakeet大神. 32 | * 2.增加了gank和豆瓣妹纸的界面共享元素动画效果. 33 | * 3.优化了部分代码,会持续优化中. 34 | 35 | ## Apk下载 36 | 37 | * 更新到v2.1.1 38 | 39 | ![](https://github.com/HotBitmapGG/MoeQuest/blob/master/art/index.png?raw=true) 40 | 41 | ## 截图 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ## 声明 55 | 56 | 本项目所使用API主要来Gank.io,易源接口,以及抓取各网站数据,若被告知需停止共享与使用,本人会及时删除此页面与整个项目,请您暸解相关情况,并遵守开源协议. 57 | 58 | 59 | ## About me 60 | 61 | [![Wercker](https://img.shields.io/badge/weibo-HotBitmapGG-blue.svg)](http://weibo.com/3223089177/profile?topnav=1&wvr=6&is_all=1) 62 | 63 | An android developer in Wuhan. 64 | 65 | If you want to make friends with me, You can focus on my weibo. 66 | 67 | 68 | ## License 69 | 70 | Copyright 2017 HotBitmapGG 71 | 72 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 73 | 74 | http://www.apache.org/licenses/LICENSE-2.0 75 | 76 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | maven { url "https://jitpack.io" } 5 | } 6 | dependencies { 7 | classpath 'me.tatarka:gradle-retrolambda:3.2.5' 8 | } 9 | } 10 | 11 | 12 | apply plugin: 'com.android.application' 13 | apply plugin: 'me.tatarka.retrolambda' 14 | 15 | android { 16 | compileSdkVersion 25 17 | buildToolsVersion "25.0.2" 18 | 19 | defaultConfig { 20 | applicationId "com.hotbitmapgg.moequest" 21 | minSdkVersion 17 22 | targetSdkVersion 25 23 | versionCode 4 24 | versionName "2.2" 25 | 26 | ndk { 27 | // 设置支持的SO库架构 28 | abiFilters 'armeabi' , 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a' 29 | } 30 | } 31 | buildTypes { 32 | release { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 35 | } 36 | } 37 | 38 | compileOptions { 39 | sourceCompatibility JavaVersion.VERSION_1_8 40 | targetCompatibility JavaVersion.VERSION_1_8 41 | } 42 | 43 | packagingOptions { 44 | exclude 'META-INF/services/javax.annotation.processing.Processor' 45 | } 46 | } 47 | 48 | dependencies { 49 | compile fileTree(dir: 'libs', include: ['*.jar']) 50 | testCompile 'junit:junit:4.12' 51 | //AndroidLib 52 | compile 'com.android.support:appcompat-v7:25.1.0' 53 | compile 'com.android.support:cardview-v7:25.1.0' 54 | compile 'com.android.support:design:25.1.0' 55 | //Retrofit2 56 | compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4' 57 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' 58 | compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' 59 | //OkHttp3 60 | compile 'com.squareup.okhttp3:okhttp:3.2.0' 61 | compile 'com.squareup.okhttp3:logging-interceptor:3.2.0' 62 | //RxJava and RxAndroid 63 | compile 'io.reactivex:rxandroid:1.1.0' 64 | compile 'io.reactivex:rxjava:1.1.0' 65 | //RxLifecycle 内存泄露 66 | compile 'com.trello:rxlifecycle-components:0.6.1' 67 | //RxBinding系列 68 | compile 'com.jakewharton.rxbinding:rxbinding:0.3.0' 69 | compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0' 70 | compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0' 71 | //RxPermissons 权限管理 72 | compile 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar' 73 | // 调试工具 74 | compile 'com.facebook.stetho:stetho:1.3.1' 75 | compile 'com.facebook.stetho:stetho-okhttp3:1.3.1' 76 | //黄油刀 77 | compile 'com.jakewharton:butterknife:7.0.1' 78 | //图片加载库 79 | compile 'com.github.bumptech.glide:glide:3.7.0' 80 | //jsoup网页解析 81 | compile 'org.jsoup:jsoup:1.8.3' 82 | //TabLayout 83 | compile 'com.flyco.tablayout:FlycoTabLayout_Lib:2.0.6@aar' 84 | compile 'com.android.support:support-v13:25.1.0' 85 | //Realm数据 86 | compile 'io.realm:realm-android:0.87.0' 87 | //腾讯bugly 88 | //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.1.5 89 | compile 'com.tencent.bugly:crashreport:2.1.5' 90 | //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.2.0 91 | compile 'com.tencent.bugly:nativecrashreport:2.2.0' 92 | //photoView 93 | compile 'com.github.chrisbanes:PhotoView:1.2.6' 94 | } 95 | -------------------------------------------------------------------------------- /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/hcc/Desktop/SDK/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 entry 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.entry.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/hotbitmapgg/moequest/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase 10 | { 11 | 12 | public ApplicationTest() 13 | { 14 | 15 | super(Application.class); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 42 | 43 | 47 | 48 | 52 | 53 | 57 | 58 | 62 | 63 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/MoeQuestApp.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest; 2 | 3 | import com.hotbitmapgg.moequest.utils.ConstantUtil; 4 | import com.tencent.bugly.crashreport.CrashReport; 5 | import io.realm.DynamicRealm; 6 | import io.realm.Realm; 7 | import io.realm.RealmConfiguration; 8 | import io.realm.RealmMigration; 9 | 10 | import android.app.Application; 11 | import android.content.Context; 12 | 13 | /** 14 | * Created by hcc on 16/6/25 12:07 15 | * 100332338@qq.com 16 | *

17 | * 萌妹子App 18 | */ 19 | public class MoeQuestApp extends Application { 20 | 21 | private static Context mAppContext; 22 | 23 | 24 | @Override 25 | public void onCreate() { 26 | 27 | super.onCreate(); 28 | mAppContext = this; 29 | // 配置Realm数据库 30 | RealmConfiguration configuration = new RealmConfiguration 31 | .Builder(this) 32 | .deleteRealmIfMigrationNeeded() 33 | .schemaVersion(6) 34 | .migration(new RealmMigration() { 35 | 36 | @Override 37 | public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { 38 | 39 | } 40 | }).build(); 41 | 42 | Realm.setDefaultConfiguration(configuration); 43 | 44 | //配置腾讯bugly 45 | CrashReport.initCrashReport(getApplicationContext(), ConstantUtil.BUGLY_ID, false); 46 | } 47 | 48 | 49 | public static Context getContext() { 50 | 51 | return mAppContext; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/DoubanMeiziAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter; 2 | 3 | import com.bumptech.glide.Glide; 4 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 5 | import com.hotbitmapgg.moequest.R; 6 | import com.hotbitmapgg.moequest.adapter.helper.AbsRecyclerViewAdapter; 7 | import com.hotbitmapgg.moequest.entity.douban.DoubanMeizi; 8 | import com.hotbitmapgg.moequest.widget.RatioImageView; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import android.support.v4.view.ViewCompat; 13 | import android.support.v7.widget.RecyclerView; 14 | import android.view.LayoutInflater; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.TextView; 18 | 19 | public class DoubanMeiziAdapter extends AbsRecyclerViewAdapter { 20 | 21 | private List meiziList = new ArrayList<>(); 22 | 23 | 24 | public DoubanMeiziAdapter(RecyclerView recyclerView, List meiziList) { 25 | 26 | super(recyclerView); 27 | this.meiziList = meiziList; 28 | } 29 | 30 | 31 | @Override 32 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 33 | 34 | bindContext(parent.getContext()); 35 | return new ItemViewHolder( 36 | LayoutInflater.from(getContext()).inflate(R.layout.card_item_meizi, parent, false)); 37 | } 38 | 39 | 40 | @Override 41 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 42 | 43 | if (holder instanceof ItemViewHolder) { 44 | final ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 45 | itemViewHolder.mTextView.setText(meiziList.get(position).getTitle()); 46 | Glide.with(getContext()) 47 | .load(meiziList.get(position).getUrl()) 48 | .centerCrop() 49 | .diskCacheStrategy(DiskCacheStrategy.ALL) 50 | .placeholder(R.drawable.placeholder_image) 51 | .into(itemViewHolder.ratioImageView) 52 | .getSize((width, height) -> { 53 | 54 | if (!itemViewHolder.item.isShown()) { 55 | itemViewHolder.item.setVisibility(View.VISIBLE); 56 | } 57 | }); 58 | 59 | itemViewHolder.ratioImageView.setTag(R.string.app_name, meiziList.get(position).getUrl()); 60 | ViewCompat.setTransitionName(itemViewHolder.ratioImageView, meiziList.get(position).getUrl()); 61 | } 62 | 63 | super.onBindViewHolder(holder, position); 64 | } 65 | 66 | 67 | @Override 68 | public int getItemCount() { 69 | 70 | return meiziList.size(); 71 | } 72 | 73 | 74 | public class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 75 | 76 | public RatioImageView ratioImageView; 77 | 78 | public TextView mTextView; 79 | 80 | public View item; 81 | 82 | 83 | public ItemViewHolder(View itemView) { 84 | 85 | super(itemView); 86 | item = itemView; 87 | ratioImageView = $(R.id.item_img); 88 | mTextView = $(R.id.item_title); 89 | ratioImageView.setOriginalSize(50, 50); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/GankMeiziAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter; 2 | 3 | import com.bumptech.glide.Glide; 4 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 5 | import com.hotbitmapgg.moequest.R; 6 | import com.hotbitmapgg.moequest.adapter.helper.AbsRecyclerViewAdapter; 7 | import com.hotbitmapgg.moequest.entity.gank.GankMeizi; 8 | import com.hotbitmapgg.moequest.widget.RatioImageView; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import android.support.v4.view.ViewCompat; 13 | import android.support.v7.widget.RecyclerView; 14 | import android.view.LayoutInflater; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.TextView; 18 | 19 | public class GankMeiziAdapter extends AbsRecyclerViewAdapter { 20 | 21 | private List meizis = new ArrayList<>(); 22 | 23 | 24 | public GankMeiziAdapter(RecyclerView recyclerView, List meizis) { 25 | 26 | super(recyclerView); 27 | this.meizis = meizis; 28 | } 29 | 30 | 31 | @Override 32 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 33 | 34 | bindContext(parent.getContext()); 35 | return new ItemViewHolder( 36 | LayoutInflater.from(getContext()).inflate(R.layout.card_item_meizi, parent, false)); 37 | } 38 | 39 | 40 | @Override 41 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 42 | 43 | if (holder instanceof ItemViewHolder) { 44 | final ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 45 | itemViewHolder.mTextView.setText(meizis.get(position).getDesc()); 46 | Glide.with(getContext()) 47 | .load(meizis.get(position).getUrl()) 48 | .centerCrop() 49 | .diskCacheStrategy(DiskCacheStrategy.ALL) 50 | .placeholder(R.drawable.placeholder_image) 51 | .into(itemViewHolder.ratioImageView) 52 | .getSize((width, height) -> { 53 | 54 | if (!itemViewHolder.item.isShown()) { 55 | itemViewHolder.item.setVisibility(View.VISIBLE); 56 | } 57 | }); 58 | 59 | itemViewHolder.ratioImageView.setTag(R.string.app_name, meizis.get(position).getUrl()); 60 | ViewCompat.setTransitionName(itemViewHolder.ratioImageView, meizis.get(position).getUrl()); 61 | } 62 | 63 | super.onBindViewHolder(holder, position); 64 | } 65 | 66 | 67 | @Override 68 | public int getItemCount() { 69 | 70 | return meizis == null ? 0 : meizis.size(); 71 | } 72 | 73 | 74 | public class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 75 | 76 | public RatioImageView ratioImageView; 77 | 78 | public TextView mTextView; 79 | 80 | public View item; 81 | 82 | 83 | public ItemViewHolder(View itemView) { 84 | 85 | super(itemView); 86 | item = itemView; 87 | ratioImageView = $(R.id.item_img); 88 | mTextView = $(R.id.item_title); 89 | ratioImageView.setOriginalSize(50, 50); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/HuaBanMeiziAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter; 2 | 3 | import com.bumptech.glide.Glide; 4 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 5 | import com.hotbitmapgg.moequest.R; 6 | import com.hotbitmapgg.moequest.adapter.helper.AbsRecyclerViewAdapter; 7 | import com.hotbitmapgg.moequest.entity.huaban.HuaBanMeiziInfo; 8 | import com.hotbitmapgg.moequest.widget.RatioImageView; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import android.support.v7.widget.RecyclerView; 13 | import android.view.LayoutInflater; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | import android.widget.TextView; 17 | 18 | public class HuaBanMeiziAdapter extends AbsRecyclerViewAdapter { 19 | 20 | private List meiziList = new ArrayList<>(); 21 | 22 | 23 | public HuaBanMeiziAdapter(RecyclerView recyclerView, List meiziList) { 24 | 25 | super(recyclerView); 26 | this.meiziList = meiziList; 27 | } 28 | 29 | 30 | @Override 31 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 32 | 33 | bindContext(parent.getContext()); 34 | return new ItemViewHolder( 35 | LayoutInflater.from(getContext()).inflate(R.layout.item_huaban_meizi, parent, false)); 36 | } 37 | 38 | 39 | @Override 40 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 41 | 42 | if (holder instanceof ItemViewHolder) { 43 | final ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 44 | itemViewHolder.mTextView.setText(meiziList.get(position).getTitle()); 45 | Glide.with(getContext()) 46 | .load(meiziList.get(position).getThumb()) 47 | .centerCrop() 48 | .diskCacheStrategy(DiskCacheStrategy.ALL) 49 | .placeholder(R.drawable.placeholder_image) 50 | .into(itemViewHolder.ratioImageView) 51 | .getSize((width, height) -> { 52 | 53 | if (!itemViewHolder.item.isShown()) { 54 | itemViewHolder.item.setVisibility(View.VISIBLE); 55 | } 56 | }); 57 | } 58 | 59 | super.onBindViewHolder(holder, position); 60 | } 61 | 62 | 63 | @Override 64 | public int getItemCount() { 65 | 66 | return meiziList.size(); 67 | } 68 | 69 | 70 | public class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 71 | 72 | public RatioImageView ratioImageView; 73 | 74 | public TextView mTextView; 75 | 76 | public View item; 77 | 78 | 79 | public ItemViewHolder(View itemView) { 80 | 81 | super(itemView); 82 | item = itemView; 83 | ratioImageView = $(R.id.item_img); 84 | mTextView = $(R.id.item_title); 85 | ratioImageView.setOriginalSize(50, 50); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/JiandanMeiziAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter; 2 | 3 | import com.bumptech.glide.Glide; 4 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 5 | import com.hotbitmapgg.moequest.R; 6 | import com.hotbitmapgg.moequest.adapter.helper.AbsRecyclerViewAdapter; 7 | import com.hotbitmapgg.moequest.entity.jiandan.JianDanMeizi; 8 | import com.hotbitmapgg.moequest.utils.LogUtil; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import android.support.v7.widget.RecyclerView; 13 | import android.view.LayoutInflater; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | import android.widget.ImageView; 17 | import android.widget.TextView; 18 | 19 | public class JiandanMeiziAdapter extends AbsRecyclerViewAdapter { 20 | 21 | private List datas = new ArrayList<>(); 22 | 23 | 24 | public JiandanMeiziAdapter(RecyclerView recyclerView, List datas) { 25 | 26 | super(recyclerView); 27 | this.datas = datas; 28 | } 29 | 30 | 31 | @Override 32 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 33 | 34 | bindContext(parent.getContext()); 35 | return new ItemViewHolder( 36 | LayoutInflater.from(getContext()).inflate(R.layout.item_jiandan_meizi, parent, false)); 37 | } 38 | 39 | 40 | @Override 41 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 42 | 43 | if (holder instanceof ItemViewHolder) { 44 | ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 45 | JianDanMeizi.JianDanMeiziData jianDanMeiziData = datas.get(position); 46 | String picUrl; 47 | if (jianDanMeiziData.pics[0].endsWith(".gif")) { 48 | picUrl = jianDanMeiziData.pics[0] 49 | .replace("mw600", "small") 50 | .replace("mw690", "small") 51 | .replace("mw1200", "small") 52 | .replace("mw1024", "small") 53 | .replace("large", "small"); 54 | LogUtil.all(picUrl); 55 | } else { 56 | picUrl = jianDanMeiziData.pics[0]; 57 | } 58 | 59 | Glide.clear(itemViewHolder.mImage); 60 | Glide.with(getContext()) 61 | .load(picUrl) 62 | .asBitmap() 63 | .centerCrop() 64 | .placeholder(R.drawable.placeholder_image) 65 | .diskCacheStrategy(DiskCacheStrategy.ALL) 66 | //.override(200, 250) 67 | .into(itemViewHolder.mImage); 68 | 69 | itemViewHolder.mDesc.setText(datas.get(position).commentAuthor); 70 | itemViewHolder.mDate.setText(datas.get(position).commentDate); 71 | } 72 | 73 | super.onBindViewHolder(holder, position); 74 | } 75 | 76 | 77 | @Override 78 | public int getItemCount() { 79 | 80 | return datas.size(); 81 | } 82 | 83 | 84 | public class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 85 | 86 | public ImageView mImage; 87 | 88 | public TextView mDesc; 89 | 90 | public TextView mDate; 91 | 92 | 93 | public ItemViewHolder(View itemView) { 94 | 95 | super(itemView); 96 | mImage = $(R.id.item_fill_image); 97 | mDesc = $(R.id.item_desc); 98 | mDate = $(R.id.item_date); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/MeiziTuAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter; 2 | 3 | import com.bumptech.glide.Glide; 4 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 5 | import com.hotbitmapgg.moequest.R; 6 | import com.hotbitmapgg.moequest.adapter.helper.AbsRecyclerViewAdapter; 7 | import com.hotbitmapgg.moequest.entity.meizitu.MeiziTu; 8 | import com.hotbitmapgg.moequest.widget.RatioImageView; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import android.support.v4.view.ViewCompat; 13 | import android.support.v7.widget.RecyclerView; 14 | import android.view.LayoutInflater; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.TextView; 18 | 19 | public class MeiziTuAdapter extends AbsRecyclerViewAdapter { 20 | 21 | private List meiziList = new ArrayList<>(); 22 | 23 | 24 | public MeiziTuAdapter(RecyclerView recyclerView, List meiziList) { 25 | 26 | super(recyclerView); 27 | this.meiziList = meiziList; 28 | } 29 | 30 | 31 | @Override 32 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 33 | 34 | bindContext(parent.getContext()); 35 | return new ItemViewHolder( 36 | LayoutInflater.from(getContext()).inflate(R.layout.card_item_meizi, parent, false)); 37 | } 38 | 39 | 40 | @Override 41 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 42 | 43 | if (holder instanceof ItemViewHolder) { 44 | final ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 45 | itemViewHolder.mTextView.setText(meiziList.get(position).getTitle()); 46 | Glide.with(getContext()) 47 | .load(meiziList.get(position).getImageurl()) 48 | .centerCrop() 49 | .diskCacheStrategy(DiskCacheStrategy.ALL) 50 | .placeholder(R.drawable.placeholder_image) 51 | .into(itemViewHolder.ratioImageView) 52 | .getSize((width, height) -> { 53 | 54 | if (!itemViewHolder.item.isShown()) { 55 | itemViewHolder.item.setVisibility(View.VISIBLE); 56 | } 57 | }); 58 | 59 | itemViewHolder.ratioImageView.setTag(R.string.app_name, 60 | meiziList.get(position).getImageurl()); 61 | ViewCompat.setTransitionName(itemViewHolder.ratioImageView, 62 | meiziList.get(position).getImageurl()); 63 | } 64 | 65 | super.onBindViewHolder(holder, position); 66 | } 67 | 68 | 69 | @Override 70 | public int getItemCount() { 71 | 72 | return meiziList.size(); 73 | } 74 | 75 | 76 | public class ItemViewHolder extends ClickableViewHolder { 77 | 78 | public RatioImageView ratioImageView; 79 | 80 | public TextView mTextView; 81 | 82 | public View item; 83 | 84 | 85 | public ItemViewHolder(View itemView) { 86 | 87 | super(itemView); 88 | item = itemView; 89 | ratioImageView = $(R.id.item_img); 90 | mTextView = $(R.id.item_title); 91 | ratioImageView.setOriginalSize(50, 50); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/TaoFemaleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter; 2 | 3 | import com.bumptech.glide.Glide; 4 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 5 | import com.hotbitmapgg.moequest.R; 6 | import com.hotbitmapgg.moequest.adapter.helper.AbsRecyclerViewAdapter; 7 | import com.hotbitmapgg.moequest.entity.taomodel.Contentlist; 8 | import com.hotbitmapgg.moequest.module.commonality.SingleMeiziDetailsActivity; 9 | import com.hotbitmapgg.moequest.module.taogirl.TaoFemalePagerActivity; 10 | import com.hotbitmapgg.moequest.widget.CircleImageView; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import android.app.Activity; 15 | import android.app.ActivityOptions; 16 | import android.content.Context; 17 | import android.content.Intent; 18 | import android.support.v7.widget.RecyclerView; 19 | import android.view.LayoutInflater; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | import android.widget.ImageView; 23 | import android.widget.TextView; 24 | 25 | public class TaoFemaleAdapter extends AbsRecyclerViewAdapter { 26 | 27 | private List datas = new ArrayList<>(); 28 | 29 | Context mContext; 30 | 31 | 32 | public TaoFemaleAdapter(RecyclerView recyclerView, List datas, Context context) { 33 | 34 | super(recyclerView); 35 | this.datas = datas; 36 | this.mContext = context; 37 | } 38 | 39 | 40 | @Override 41 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 42 | 43 | bindContext(parent.getContext()); 44 | return new ItemViewHolder( 45 | LayoutInflater.from(getContext()).inflate(R.layout.item_tao_female, parent, false)); 46 | } 47 | 48 | 49 | @Override 50 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 51 | 52 | if (holder instanceof ItemViewHolder) { 53 | ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 54 | Contentlist contentlist = datas.get(position); 55 | Glide.with(getContext()) 56 | .load(contentlist.avatarUrl) 57 | .centerCrop() 58 | .dontAnimate() 59 | .placeholder(R.drawable.ic_slide_menu_avatar_no_login) 60 | .diskCacheStrategy(DiskCacheStrategy.ALL) 61 | .into(itemViewHolder.mAvatar); 62 | 63 | itemViewHolder.mUserName.setText(contentlist.realName); 64 | itemViewHolder.mUserLocation.setText(contentlist.city); 65 | itemViewHolder.mUserWidth.setText("体重: " + contentlist.weight); 66 | itemViewHolder.mUserHeight.setText("身高: " + contentlist.height); 67 | itemViewHolder.mUserFansNum.setText(contentlist.totalFanNum); 68 | itemViewHolder.mType.setText(contentlist.type); 69 | 70 | setImageList(itemViewHolder, contentlist.imgList, contentlist.avatarUrl, 71 | contentlist.realName); 72 | } 73 | super.onBindViewHolder(holder, position); 74 | } 75 | 76 | 77 | private void setImageList(final ItemViewHolder itemViewHolder, final ArrayList imgList, final String url, final String name) { 78 | 79 | Glide.clear(itemViewHolder.mImage); 80 | Glide.with(getContext()) 81 | .load(url) 82 | .centerCrop() 83 | .placeholder(R.drawable.placeholder_image) 84 | .diskCacheStrategy(DiskCacheStrategy.ALL) 85 | .into(itemViewHolder.mImage); 86 | 87 | itemViewHolder.mImageNum.setText(imgList.size() + "张"); 88 | 89 | itemViewHolder.mImage.setOnClickListener(v -> { 90 | 91 | if (imgList.size() > 0) { 92 | TaoFemalePagerActivity.luancher((Activity) getContext(), imgList, 0); 93 | } else { 94 | Intent intent = SingleMeiziDetailsActivity.LuanchActivity((Activity) mContext, url, name); 95 | if (android.os.Build.VERSION.SDK_INT >= 21) { 96 | mContext.startActivity(intent, 97 | ActivityOptions.makeSceneTransitionAnimation((Activity) mContext, 98 | itemViewHolder.mImage, "transitionImg").toBundle()); 99 | } else { 100 | mContext.startActivity(intent); 101 | } 102 | } 103 | }); 104 | } 105 | 106 | 107 | @Override 108 | public int getItemCount() { 109 | 110 | return datas.size(); 111 | } 112 | 113 | 114 | public class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 115 | 116 | public CircleImageView mAvatar; 117 | 118 | public TextView mUserName; 119 | 120 | public TextView mUserLocation; 121 | 122 | public ImageView mImage; 123 | 124 | public TextView mUserFansNum; 125 | 126 | public TextView mUserHeight; 127 | 128 | public TextView mUserWidth; 129 | 130 | public TextView mType; 131 | 132 | public TextView mImageNum; 133 | 134 | 135 | public ItemViewHolder(View itemView) { 136 | 137 | super(itemView); 138 | mAvatar = $(R.id.tao_avatar); 139 | mUserName = $(R.id.tao_name); 140 | mUserLocation = $(R.id.tao_location); 141 | mImage = $(R.id.tao_image); 142 | mUserFansNum = $(R.id.tao_fans_num); 143 | mUserHeight = $(R.id.tao_height); 144 | mUserWidth = $(R.id.tao_width); 145 | mType = $(R.id.tao_type); 146 | mImageNum = $(R.id.tao_image_num); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/helper/AbsRecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter.helper; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.content.Context; 7 | import android.support.annotation.IdRes; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | 11 | /** 12 | * Created by hcc on 16/8/4 14:12 13 | * 100332338@qq.com 14 | *

15 | * RecycleViewAdapter基类 16 | */ 17 | public abstract class AbsRecyclerViewAdapter extends 18 | RecyclerView.Adapter { 19 | 20 | private Context context; 21 | 22 | protected RecyclerView mRecyclerView; 23 | 24 | private List mListeners = new ArrayList<>(); 25 | 26 | 27 | public AbsRecyclerViewAdapter(RecyclerView recyclerView) { 28 | 29 | this.mRecyclerView = recyclerView; 30 | this.mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 31 | 32 | @Override 33 | public void onScrollStateChanged(RecyclerView rv, int newState) { 34 | 35 | for (RecyclerView.OnScrollListener listener : mListeners) { 36 | listener.onScrollStateChanged(rv, newState); 37 | } 38 | } 39 | 40 | 41 | @Override 42 | public void onScrolled(RecyclerView rv, int dx, int dy) { 43 | 44 | for (RecyclerView.OnScrollListener listener : mListeners) { 45 | listener.onScrolled(rv, dx, dy); 46 | } 47 | } 48 | }); 49 | } 50 | 51 | 52 | public void addOnScrollListener(RecyclerView.OnScrollListener listener) { 53 | 54 | mListeners.add(listener); 55 | } 56 | 57 | 58 | public interface OnItemClickListener { 59 | 60 | void onItemClick(int position, ClickableViewHolder holder); 61 | } 62 | 63 | interface OnItemLongClickListener { 64 | 65 | boolean onItemLongClick(int position, ClickableViewHolder holder); 66 | } 67 | 68 | private OnItemClickListener itemClickListener; 69 | 70 | private OnItemLongClickListener itemLongClickListener; 71 | 72 | 73 | public void setOnItemClickListener(OnItemClickListener listener) { 74 | 75 | this.itemClickListener = listener; 76 | } 77 | 78 | 79 | public void setOnItemLongClickListener(OnItemLongClickListener listener) { 80 | 81 | this.itemLongClickListener = listener; 82 | } 83 | 84 | 85 | public void bindContext(Context context) { 86 | 87 | this.context = context; 88 | } 89 | 90 | 91 | public Context getContext() { 92 | 93 | return this.context; 94 | } 95 | 96 | 97 | @Override 98 | public void onBindViewHolder(final ClickableViewHolder holder, final int position) { 99 | 100 | holder.getParentView().setOnClickListener(v -> { 101 | 102 | if (itemClickListener != null) { 103 | itemClickListener.onItemClick(position, holder); 104 | } 105 | }); 106 | holder.getParentView().setOnLongClickListener(v -> itemLongClickListener != null 107 | && itemLongClickListener.onItemLongClick(position, holder)); 108 | } 109 | 110 | 111 | public static class ClickableViewHolder extends RecyclerView.ViewHolder { 112 | 113 | private View parentView; 114 | 115 | 116 | public ClickableViewHolder(View itemView) { 117 | 118 | super(itemView); 119 | this.parentView = itemView; 120 | } 121 | 122 | 123 | public View getParentView() { 124 | 125 | return parentView; 126 | } 127 | 128 | 129 | @SuppressWarnings("unchecked") 130 | public T $(@IdRes int id) { 131 | 132 | return (T) parentView.findViewById(id); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/helper/EndlessRecyclerOnScrollListener.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter.helper; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | 6 | /** 7 | * Created by hcc on 16/8/7 21:18 8 | * 100332338@qq.com 9 | *

10 | * 自定义RecylcerView上拉加载处理 11 | */ 12 | public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener { 13 | 14 | private int previousTotal = 0; 15 | 16 | private boolean loading = true; 17 | 18 | private int currentPage = 1; 19 | 20 | private LinearLayoutManager mLinearLayoutManager; 21 | 22 | 23 | protected EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) { 24 | 25 | this.mLinearLayoutManager = linearLayoutManager; 26 | } 27 | 28 | 29 | @Override 30 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 31 | 32 | super.onScrolled(recyclerView, dx, dy); 33 | 34 | if (dy == 0) { 35 | return; 36 | } 37 | 38 | int visibleItemCount = recyclerView.getChildCount(); 39 | int totalItemCount = mLinearLayoutManager.getItemCount(); 40 | int lastCompletelyVisiableItemPosition 41 | = mLinearLayoutManager.findLastCompletelyVisibleItemPosition(); 42 | 43 | if (loading) { 44 | if (totalItemCount > previousTotal) { 45 | loading = false; 46 | previousTotal = totalItemCount; 47 | } 48 | } 49 | 50 | if (!loading && (visibleItemCount > 0) && 51 | (lastCompletelyVisiableItemPosition >= totalItemCount - 1)) { 52 | currentPage++; 53 | onLoadMore(currentPage); 54 | loading = true; 55 | } 56 | } 57 | 58 | 59 | public void refresh() { 60 | 61 | loading = true; 62 | previousTotal = 0; 63 | currentPage = 1; 64 | } 65 | 66 | 67 | public abstract void onLoadMore(int currentPage); 68 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/adapter/helper/HeaderViewRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.adapter.helper; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | /** 13 | * RecycleView添加头部 14 | */ 15 | public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter { 16 | 17 | private static final int HEADERS_START = Integer.MIN_VALUE; 18 | 19 | private static final int FOOTERS_START = Integer.MIN_VALUE + 10; 20 | 21 | private static final int ITEMS_START = Integer.MIN_VALUE + 20; 22 | 23 | private static final int ADAPTER_MAX_TYPES = 100; 24 | 25 | private RecyclerView.Adapter mWrappedAdapter; 26 | 27 | private List mHeaderViews, mFooterViews; 28 | 29 | private Map mItemTypesOffset; 30 | 31 | 32 | public HeaderViewRecyclerAdapter(RecyclerView.Adapter adapter) { 33 | 34 | mHeaderViews = new ArrayList<>(); 35 | mFooterViews = new ArrayList<>(); 36 | mItemTypesOffset = new HashMap<>(); 37 | setWrappedAdapter(adapter); 38 | } 39 | 40 | 41 | public void setAdapter(RecyclerView.Adapter adapter) { 42 | 43 | if (mWrappedAdapter != null && mWrappedAdapter.getItemCount() > 0) { 44 | notifyItemRangeRemoved(getHeaderCount(), mWrappedAdapter.getItemCount()); 45 | } 46 | setWrappedAdapter(adapter); 47 | notifyItemRangeInserted(getHeaderCount(), mWrappedAdapter.getItemCount()); 48 | } 49 | 50 | 51 | @Override 52 | public int getItemViewType(int position) { 53 | 54 | int hCount = getHeaderCount(); 55 | if (position < hCount) { 56 | return HEADERS_START + position; 57 | } else { 58 | int itemCount = mWrappedAdapter.getItemCount(); 59 | if (position < hCount + itemCount) { 60 | return getAdapterTypeOffset() + mWrappedAdapter.getItemViewType(position - hCount); 61 | } else { 62 | return FOOTERS_START + position - hCount - itemCount; 63 | } 64 | } 65 | } 66 | 67 | 68 | @Override 69 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { 70 | 71 | if (viewType < HEADERS_START + getHeaderCount()) { 72 | return new StaticViewHolder(mHeaderViews.get(viewType - HEADERS_START)); 73 | } else if (viewType < FOOTERS_START + getFooterCount()) { 74 | return new StaticViewHolder(mFooterViews.get(viewType - FOOTERS_START)); 75 | } else { 76 | return mWrappedAdapter.onCreateViewHolder(viewGroup, viewType - getAdapterTypeOffset()); 77 | } 78 | } 79 | 80 | 81 | @Override 82 | public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { 83 | 84 | int hCount = getHeaderCount(); 85 | if (position >= hCount && position < hCount + mWrappedAdapter.getItemCount()) { 86 | mWrappedAdapter.onBindViewHolder(viewHolder, position - hCount); 87 | } 88 | } 89 | 90 | 91 | public void addHeaderView(View view) { 92 | 93 | mHeaderViews.add(view); 94 | } 95 | 96 | 97 | public void addFooterView(View view) { 98 | 99 | mFooterViews.add(view); 100 | } 101 | 102 | 103 | @Override 104 | public int getItemCount() { 105 | 106 | return getHeaderCount() + getFooterCount() + getWrappedItemCount(); 107 | } 108 | 109 | 110 | public int getWrappedItemCount() { 111 | 112 | return mWrappedAdapter.getItemCount(); 113 | } 114 | 115 | 116 | public int getHeaderCount() { 117 | 118 | return mHeaderViews.size(); 119 | } 120 | 121 | 122 | public int getFooterCount() { 123 | 124 | return mFooterViews.size(); 125 | } 126 | 127 | 128 | private void setWrappedAdapter(RecyclerView.Adapter adapter) { 129 | 130 | if (mWrappedAdapter != null) mWrappedAdapter.unregisterAdapterDataObserver(mDataObserver); 131 | mWrappedAdapter = adapter; 132 | Class adapterClass = mWrappedAdapter.getClass(); 133 | if (!mItemTypesOffset.containsKey(adapterClass)) putAdapterTypeOffset(adapterClass); 134 | mWrappedAdapter.registerAdapterDataObserver(mDataObserver); 135 | } 136 | 137 | 138 | private void putAdapterTypeOffset(Class adapterClass) { 139 | 140 | mItemTypesOffset.put(adapterClass, ITEMS_START + mItemTypesOffset.size() * ADAPTER_MAX_TYPES); 141 | } 142 | 143 | 144 | private int getAdapterTypeOffset() { 145 | 146 | return mItemTypesOffset.get(mWrappedAdapter.getClass()); 147 | } 148 | 149 | 150 | private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() { 151 | 152 | @Override 153 | public void onChanged() { 154 | 155 | super.onChanged(); 156 | notifyDataSetChanged(); 157 | } 158 | 159 | 160 | @Override 161 | public void onItemRangeChanged(int positionStart, int itemCount) { 162 | 163 | super.onItemRangeChanged(positionStart, itemCount); 164 | notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount); 165 | } 166 | 167 | 168 | @Override 169 | public void onItemRangeInserted(int positionStart, int itemCount) { 170 | 171 | super.onItemRangeInserted(positionStart, itemCount); 172 | notifyItemRangeInserted(positionStart + getHeaderCount(), itemCount); 173 | } 174 | 175 | 176 | @Override 177 | public void onItemRangeRemoved(int positionStart, int itemCount) { 178 | 179 | super.onItemRangeRemoved(positionStart, itemCount); 180 | notifyItemRangeRemoved(positionStart + getHeaderCount(), itemCount); 181 | } 182 | 183 | 184 | @Override 185 | public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { 186 | 187 | super.onItemRangeMoved(fromPosition, toPosition, itemCount); 188 | int hCount = getHeaderCount(); 189 | // TODO: No notifyItemRangeMoved method? 190 | notifyItemRangeChanged(fromPosition + hCount, toPosition + hCount + itemCount); 191 | } 192 | }; 193 | 194 | private static class StaticViewHolder extends RecyclerView.ViewHolder { 195 | 196 | public StaticViewHolder(View itemView) { 197 | 198 | super(itemView); 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/base/RxBaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.base; 2 | 3 | import butterknife.ButterKnife; 4 | import com.trello.rxlifecycle.components.support.RxAppCompatActivity; 5 | 6 | import android.os.Bundle; 7 | 8 | public abstract class RxBaseActivity extends RxAppCompatActivity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | 13 | super.onCreate(savedInstanceState); 14 | //设置布局内容 15 | setContentView(getLayoutId()); 16 | //初始化黄油刀控件绑定框架 17 | ButterKnife.bind(this); 18 | //初始化控件 19 | initViews(savedInstanceState); 20 | //初始化ToolBar 21 | initToolBar(); 22 | } 23 | 24 | 25 | @Override 26 | protected void onDestroy() { 27 | 28 | super.onDestroy(); 29 | ButterKnife.unbind(this); 30 | } 31 | 32 | 33 | public abstract int getLayoutId(); 34 | 35 | public abstract void initViews(Bundle savedInstanceState); 36 | 37 | public abstract void initToolBar(); 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/base/RxBaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.base; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.trello.rxlifecycle.components.support.RxFragment; 10 | 11 | import butterknife.ButterKnife; 12 | 13 | public abstract class RxBaseFragment extends RxFragment { 14 | 15 | private View rootView; 16 | 17 | 18 | @Nullable 19 | @Override 20 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 21 | 22 | rootView = inflater.inflate(getLayoutId(), container, false); 23 | 24 | return rootView; 25 | } 26 | 27 | 28 | @Override 29 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 30 | 31 | super.onViewCreated(view, savedInstanceState); 32 | ButterKnife.bind(this, view); 33 | initViews(); 34 | } 35 | 36 | 37 | @Override 38 | public void onDetach() { 39 | 40 | super.onDetach(); 41 | } 42 | 43 | 44 | public abstract int getLayoutId(); 45 | 46 | public abstract void initViews(); 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/douban/DoubanMeizi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.douban; 2 | 3 | import io.realm.RealmObject; 4 | 5 | public class DoubanMeizi extends RealmObject { 6 | 7 | private String url; 8 | 9 | private String title; 10 | 11 | private int type; 12 | 13 | 14 | public int getType() { 15 | 16 | return type; 17 | } 18 | 19 | 20 | public void setType(int type) { 21 | 22 | this.type = type; 23 | } 24 | 25 | 26 | public String getUrl() { 27 | 28 | return url; 29 | } 30 | 31 | 32 | public void setUrl(String url) { 33 | 34 | this.url = url; 35 | } 36 | 37 | 38 | public String getTitle() { 39 | 40 | return title; 41 | } 42 | 43 | 44 | public void setTitle(String title) { 45 | 46 | this.title = title; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/gank/GankMeizi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.gank; 2 | 3 | import io.realm.RealmObject; 4 | 5 | public class GankMeizi extends RealmObject { 6 | 7 | private String _id; 8 | 9 | private String createdAt; 10 | 11 | private String desc; 12 | 13 | private String publishedAt; 14 | 15 | private String source; 16 | 17 | private String type; 18 | 19 | private String url; 20 | 21 | private boolean used; 22 | 23 | private String who; 24 | 25 | 26 | public String get_id() { 27 | 28 | return _id; 29 | } 30 | 31 | 32 | public void set_id(String _id) { 33 | 34 | this._id = _id; 35 | } 36 | 37 | 38 | public String getCreatedAt() { 39 | 40 | return createdAt; 41 | } 42 | 43 | 44 | public void setCreatedAt(String createdAt) { 45 | 46 | this.createdAt = createdAt; 47 | } 48 | 49 | 50 | public String getDesc() { 51 | 52 | return desc; 53 | } 54 | 55 | 56 | public void setDesc(String desc) { 57 | 58 | this.desc = desc; 59 | } 60 | 61 | 62 | public String getPublishedAt() { 63 | 64 | return publishedAt; 65 | } 66 | 67 | 68 | public void setPublishedAt(String publishedAt) { 69 | 70 | this.publishedAt = publishedAt; 71 | } 72 | 73 | 74 | public String getSource() { 75 | 76 | return source; 77 | } 78 | 79 | 80 | public void setSource(String source) { 81 | 82 | this.source = source; 83 | } 84 | 85 | 86 | public String getType() { 87 | 88 | return type; 89 | } 90 | 91 | 92 | public void setType(String type) { 93 | 94 | this.type = type; 95 | } 96 | 97 | 98 | public String getUrl() { 99 | 100 | return url; 101 | } 102 | 103 | 104 | public void setUrl(String url) { 105 | 106 | this.url = url; 107 | } 108 | 109 | 110 | public boolean isUsed() { 111 | 112 | return used; 113 | } 114 | 115 | 116 | public void setUsed(boolean used) { 117 | 118 | this.used = used; 119 | } 120 | 121 | 122 | public String getWho() { 123 | 124 | return who; 125 | } 126 | 127 | 128 | public void setWho(String who) { 129 | 130 | this.who = who; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/gank/GankMeiziInfo.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.gank; 2 | 3 | public class GankMeiziInfo { 4 | 5 | public String _id; 6 | 7 | public String createdAt; 8 | 9 | public String desc; 10 | 11 | public String publishedAt; 12 | 13 | public String source; 14 | 15 | public String type; 16 | 17 | public String url; 18 | 19 | public boolean used; 20 | 21 | public String who; 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/gank/GankMeiziResult.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.gank; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | public class GankMeiziResult { 8 | 9 | public boolean error; 10 | 11 | @SerializedName("results") 12 | public List gankMeizis; 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/huaban/HuaBanMeizi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.huaban; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.annotations.SerializedName; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | public class HuaBanMeizi { 14 | 15 | @SerializedName("showapi_res_code") 16 | public int code; 17 | 18 | @SerializedName("showapi_res_error") 19 | public String error; 20 | 21 | @SerializedName("showapi_res_body") 22 | public JsonObject list; 23 | 24 | public List infos; 25 | 26 | 27 | /** 28 | * 解析json返回的数据 拼接为集合 29 | */ 30 | public static HuaBanMeizi createFromJson(String json) { 31 | 32 | HuaBanMeizi result = new Gson().fromJson(json, HuaBanMeizi.class); 33 | Iterator> iterator = result.list.entrySet().iterator(); 34 | if (result.infos == null) { 35 | result.infos = new ArrayList<>(); 36 | } 37 | while (iterator.hasNext()) { 38 | Map.Entry element = iterator.next(); 39 | try { 40 | result.infos.add(new Gson().fromJson(element.getValue(), HuaBanMeiziInfo.class)); 41 | } catch (Exception e) { 42 | 43 | } 44 | } 45 | 46 | result.list = null; 47 | 48 | return result; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/huaban/HuaBanMeiziInfo.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.huaban; 2 | 3 | public class HuaBanMeiziInfo { 4 | 5 | private String thumb; 6 | 7 | private String title; 8 | 9 | private String url; 10 | 11 | private int type; 12 | 13 | 14 | public String getThumb() { 15 | 16 | return thumb; 17 | } 18 | 19 | 20 | public void setThumb(String thumb) { 21 | 22 | this.thumb = thumb; 23 | } 24 | 25 | 26 | public String getTitle() { 27 | 28 | return title; 29 | } 30 | 31 | 32 | public void setTitle(String title) { 33 | 34 | this.title = title; 35 | } 36 | 37 | 38 | public String getUrl() { 39 | 40 | return url; 41 | } 42 | 43 | 44 | public void setUrl(String url) { 45 | 46 | this.url = url; 47 | } 48 | 49 | 50 | public int getType() { 51 | 52 | return type; 53 | } 54 | 55 | 56 | public void setType(int type) { 57 | 58 | this.type = type; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/jiandan/JianDanMeizi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.jiandan; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by hcc on 16/6/28 20:26 9 | * 100332338@qq.com 10 | *

11 | * "comment_ID":"3184860", "comment_post_ID":"21183", "comment_author": 12 | * "FD", "comment_author_email":"user@example.com", "comment_author_url": 13 | * "", "comment_author_IP":"211.162.219.188", "comment_date": 14 | * "2016-06-28 20:51:34", "comment_date_gmt":"2016-06-28 12:51:34", "comment_content": 15 | * "", 16 | * "comment_karma": 17 | * "0", "comment_approved":"1", "comment_agent": 18 | * "Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko\/20100101 Firefox\/47.0", 19 | * "comment_type": 20 | * "", "comment_parent":"0", "user_id":"0", "comment_subscribe":"N", "comment_reply_ID": 21 | * "0", "vote_positive":"1", "vote_negative":"4", "vote_ip_pool":"", "text_content": 22 | * "", "pics":["http:\/\/ww4.sinaimg.cn\/mw600\/a15b4afegw1f5b87y6cw5j20xc18g1kx.jpg"], 23 | * "videos":[] 24 | */ 25 | public class JianDanMeizi { 26 | 27 | public String status; 28 | 29 | @SerializedName("current_page") 30 | public int currentPage; 31 | 32 | @SerializedName("total_comments") 33 | public int totalComments; 34 | 35 | @SerializedName("page_count") 36 | public int pageCount; 37 | 38 | public int count; 39 | 40 | public List comments; 41 | 42 | public class JianDanMeiziData { 43 | 44 | @SerializedName("comment_ID") 45 | public String commentID; 46 | 47 | @SerializedName("comment_author") 48 | public String commentAuthor; 49 | 50 | @SerializedName("comment_date") 51 | public String commentDate; 52 | 53 | @SerializedName("text_content") 54 | public String textContent; 55 | 56 | @SerializedName("vote_positive") 57 | public String votePositive; 58 | 59 | @SerializedName("vote_negative") 60 | public String voteNegative; 61 | 62 | @SerializedName("comment_counts") 63 | public String commentCounts; 64 | 65 | public String[] pics; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/meizitu/MeiziTu.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.meizitu; 2 | 3 | import java.io.Serializable; 4 | 5 | import io.realm.RealmObject; 6 | import io.realm.annotations.PrimaryKey; 7 | 8 | /** 9 | * Created by hcc on 16/7/19 20:00 10 | * 100332338@qq.com 11 | */ 12 | public class MeiziTu extends RealmObject implements Serializable { 13 | 14 | private int count; 15 | 16 | private int width; 17 | 18 | private int height; 19 | 20 | @PrimaryKey 21 | private String imageurl; 22 | 23 | private String url; 24 | 25 | private String title; 26 | 27 | private String type; 28 | 29 | private int groupid; 30 | 31 | private int order; 32 | 33 | 34 | public int getGroupid() { 35 | 36 | return groupid; 37 | } 38 | 39 | 40 | public void setGroupid(int groupid) { 41 | 42 | this.groupid = groupid; 43 | } 44 | 45 | 46 | public int getOrder() { 47 | 48 | return order; 49 | } 50 | 51 | 52 | public void setOrder(int order) { 53 | 54 | this.order = order; 55 | } 56 | 57 | 58 | public String getType() { 59 | 60 | return type; 61 | } 62 | 63 | 64 | public void setType(String type) { 65 | 66 | this.type = type; 67 | } 68 | 69 | 70 | public int getWidth() { 71 | 72 | return width; 73 | } 74 | 75 | 76 | public void setWidth(int width) { 77 | 78 | this.width = width; 79 | } 80 | 81 | 82 | public int getCount() { 83 | 84 | return count; 85 | } 86 | 87 | 88 | public void setCount(int count) { 89 | 90 | this.count = count; 91 | } 92 | 93 | 94 | public int getHeight() { 95 | 96 | return height; 97 | } 98 | 99 | 100 | public void setHeight(int height) { 101 | 102 | this.height = height; 103 | } 104 | 105 | 106 | public String getImageurl() { 107 | 108 | return imageurl; 109 | } 110 | 111 | 112 | public void setImageurl(String imageurl) { 113 | 114 | this.imageurl = imageurl; 115 | } 116 | 117 | 118 | public String getUrl() { 119 | 120 | return url; 121 | } 122 | 123 | 124 | public void setUrl(String url) { 125 | 126 | this.url = url; 127 | } 128 | 129 | 130 | public String getTitle() { 131 | 132 | return title; 133 | } 134 | 135 | 136 | public void setTitle(String title) { 137 | 138 | this.title = title; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/taomodel/Contentlist.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.taomodel; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class Contentlist { 6 | 7 | public int totalFavorNum; 8 | 9 | public String realName; 10 | 11 | public String totalFanNum; 12 | 13 | public String link; 14 | 15 | public String weight; 16 | 17 | public String avatarUrl; 18 | 19 | public String type; 20 | 21 | public String userId; 22 | 23 | public String city; 24 | 25 | public String height; 26 | 27 | public ArrayList imgList; 28 | 29 | public String cardUrl; 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/taomodel/Pagebean.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.taomodel; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class Pagebean { 6 | 7 | public ArrayList contentlist; 8 | 9 | public String maxResult; 10 | 11 | public String currentPage; 12 | 13 | public String allNum; 14 | 15 | public String allPages; 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/taomodel/ShowapiResBody.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.taomodel; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class ShowapiResBody { 6 | 7 | @SerializedName("ret_code") 8 | public String retCode; 9 | 10 | public Pagebean pagebean; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/entity/taomodel/TaoFemale.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.entity.taomodel; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class TaoFemale { 6 | 7 | @SerializedName("showapi_res_body") 8 | public ShowapiResBody showapiResBody; 9 | 10 | @SerializedName("showapi_res_error") 11 | public String showapiResError; 12 | 13 | @SerializedName("showapi_res_code") 14 | public int showapiResCode; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/commonality/AppAboutActivity.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.commonality; 2 | 3 | import android.content.pm.PackageInfo; 4 | import android.content.pm.PackageManager; 5 | import android.os.Bundle; 6 | import android.support.design.widget.CollapsingToolbarLayout; 7 | import android.support.v7.app.ActionBar; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.MenuItem; 10 | 11 | import com.hotbitmapgg.moequest.R; 12 | import com.hotbitmapgg.moequest.base.RxBaseActivity; 13 | 14 | import butterknife.Bind; 15 | 16 | /** 17 | * Created by hcc on 16/6/30 21:57 18 | * 100332338@qq.com 19 | *

20 | * App关于界面 21 | */ 22 | public class AppAboutActivity extends RxBaseActivity { 23 | 24 | @Bind(R.id.toolbar) 25 | Toolbar mToolbar; 26 | 27 | @Bind(R.id.collapsing_toolbar) 28 | CollapsingToolbarLayout mCollapsingToolbarLayout; 29 | 30 | 31 | @Override 32 | public int getLayoutId() { 33 | 34 | return R.layout.activity_about; 35 | } 36 | 37 | 38 | @Override 39 | public void initViews(Bundle savedInstanceState) { 40 | 41 | } 42 | 43 | 44 | @Override 45 | public void initToolBar() { 46 | 47 | setSupportActionBar(mToolbar); 48 | ActionBar supportActionBar = getSupportActionBar(); 49 | if (supportActionBar != null) { 50 | supportActionBar.setDisplayHomeAsUpEnabled(true); 51 | } 52 | 53 | String version = getVersion(); 54 | mCollapsingToolbarLayout.setTitle("关于萌妹纸" + "v" + version); 55 | } 56 | 57 | 58 | @Override 59 | public boolean onOptionsItemSelected(MenuItem item) { 60 | 61 | switch (item.getItemId()) { 62 | case android.R.id.home: 63 | onBackPressed(); 64 | return true; 65 | } 66 | return super.onOptionsItemSelected(item); 67 | } 68 | 69 | 70 | private String getVersion() { 71 | 72 | try { 73 | PackageInfo pi = getPackageManager().getPackageInfo(getPackageName(), 0); 74 | return pi.versionName; 75 | } catch (PackageManager.NameNotFoundException e) { 76 | e.printStackTrace(); 77 | return getString(R.string.about_version); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/commonality/AppSplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.commonality; 2 | 3 | import butterknife.Bind; 4 | import butterknife.ButterKnife; 5 | import com.hotbitmapgg.moequest.R; 6 | import java.util.concurrent.TimeUnit; 7 | import rx.Observable; 8 | import rx.Subscription; 9 | import rx.android.schedulers.AndroidSchedulers; 10 | 11 | import android.animation.Animator; 12 | import android.animation.AnimatorListenerAdapter; 13 | import android.animation.AnimatorSet; 14 | import android.animation.ObjectAnimator; 15 | import android.app.Activity; 16 | import android.content.Intent; 17 | import android.os.Bundle; 18 | import android.widget.ImageView; 19 | 20 | /** 21 | * Created by hcc on 16/6/30 21:57 22 | * 100332338@qq.com 23 | *

24 | * App欢迎页面 25 | */ 26 | public class AppSplashActivity extends Activity { 27 | 28 | @Bind(R.id.splash_image) 29 | ImageView mSplashImage; 30 | 31 | private static final int ANIMATION_TIME = 2000; 32 | 33 | private static final float SCALE_END = 1.13F; 34 | 35 | private Subscription subscribe; 36 | 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_splash); 43 | ButterKnife.bind(this); 44 | subscribe = Observable.timer(1000, TimeUnit.MILLISECONDS) 45 | .observeOn(AndroidSchedulers.mainThread()) 46 | .subscribe(aLong -> { 47 | startAnim(); 48 | }); 49 | } 50 | 51 | 52 | private void startAnim() { 53 | 54 | ObjectAnimator animatorX = ObjectAnimator.ofFloat(mSplashImage, "scaleX", 1f, SCALE_END); 55 | ObjectAnimator animatorY = ObjectAnimator.ofFloat(mSplashImage, "scaleY", 1f, SCALE_END); 56 | 57 | AnimatorSet set = new AnimatorSet(); 58 | set.setDuration(ANIMATION_TIME).play(animatorX).with(animatorY); 59 | set.start(); 60 | 61 | set.addListener(new AnimatorListenerAdapter() { 62 | 63 | @Override 64 | public void onAnimationEnd(Animator animation) { 65 | 66 | startActivity(new Intent(AppSplashActivity.this, MainActivity.class)); 67 | AppSplashActivity.this.finish(); 68 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); 69 | } 70 | }); 71 | } 72 | 73 | 74 | @Override 75 | public void onBackPressed() { 76 | 77 | super.onBackPressed(); 78 | if (subscribe != null && !subscribe.isUnsubscribed()) { 79 | subscribe.unsubscribe(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/commonality/MeiziDetailsFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.commonality; 2 | 3 | import butterknife.Bind; 4 | import com.bumptech.glide.Glide; 5 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 6 | import com.bumptech.glide.load.resource.drawable.GlideDrawable; 7 | import com.bumptech.glide.request.RequestListener; 8 | import com.bumptech.glide.request.target.Target; 9 | import com.hotbitmapgg.moequest.R; 10 | import com.hotbitmapgg.moequest.base.RxBaseFragment; 11 | import com.hotbitmapgg.moequest.rx.RxBus; 12 | import com.hotbitmapgg.moequest.utils.ConstantUtil; 13 | import com.hotbitmapgg.moequest.utils.GlideDownloadImageUtil; 14 | import com.tbruyelle.rxpermissions.RxPermissions; 15 | import java.io.File; 16 | import rx.Observable; 17 | import rx.android.schedulers.AndroidSchedulers; 18 | import rx.functions.Func1; 19 | import rx.schedulers.Schedulers; 20 | import uk.co.senab.photoview.PhotoViewAttacher; 21 | 22 | import android.Manifest; 23 | import android.net.Uri; 24 | import android.os.Bundle; 25 | import android.os.Environment; 26 | import android.support.v7.app.AlertDialog; 27 | import android.view.View; 28 | import android.widget.ImageView; 29 | import android.widget.TextView; 30 | import android.widget.Toast; 31 | 32 | /** 33 | * Created by hcc on 16/7/5 21:14 34 | * 100332338@qq.com 35 | *

36 | * 去掉了重复的界面,整合为一个界面 37 | * 妹子详情Fragment显示界面 38 | */ 39 | public class MeiziDetailsFragment extends RxBaseFragment 40 | implements RequestListener { 41 | 42 | @Bind(R.id.meizi) 43 | ImageView mImageView; 44 | 45 | @Bind(R.id.tv_image_error) 46 | TextView mImageError; 47 | 48 | private static final String EXTRA_URL = "extra_url"; 49 | 50 | private String url; 51 | 52 | private PhotoViewAttacher mPhotoViewAttacher; 53 | 54 | 55 | public static MeiziDetailsFragment newInstance(String url) { 56 | 57 | MeiziDetailsFragment mMeiziFragment = new MeiziDetailsFragment(); 58 | Bundle mBundle = new Bundle(); 59 | mBundle.putString(EXTRA_URL, url); 60 | mMeiziFragment.setArguments(mBundle); 61 | 62 | return mMeiziFragment; 63 | } 64 | 65 | 66 | @Override 67 | public int getLayoutId() { 68 | 69 | return R.layout.fragment_meizi_details; 70 | } 71 | 72 | 73 | @Override 74 | public void initViews() { 75 | 76 | url = getArguments().getString(EXTRA_URL); 77 | Glide.with(this).load(url) 78 | .diskCacheStrategy(DiskCacheStrategy.ALL) 79 | .crossFade(0) 80 | .listener(this) 81 | .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); 82 | } 83 | 84 | 85 | private void saveImageToGallery() { 86 | 87 | Observable.just(R.string.app_name) 88 | .compose(this.bindToLifecycle()) 89 | .compose(RxPermissions.getInstance(getActivity()) 90 | .ensure(Manifest.permission.WRITE_EXTERNAL_STORAGE)) 91 | .observeOn(Schedulers.io()) 92 | .filter(aBoolean -> aBoolean) 93 | .flatMap(new Func1>() { 94 | 95 | @Override 96 | public Observable call(Boolean aBoolean) { 97 | 98 | return GlideDownloadImageUtil.saveImageToLocal(getActivity(), url); 99 | } 100 | }) 101 | .observeOn(AndroidSchedulers.mainThread()) 102 | .subscribe(uri -> { 103 | 104 | File appDir = new File(Environment.getExternalStorageDirectory(), 105 | ConstantUtil.FILE_DIR); 106 | String msg = String.format("图片已保存至 %s 文件夹", appDir.getAbsolutePath()); 107 | Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show(); 108 | }, throwable -> { 109 | 110 | Toast.makeText(getActivity(), "保存失败,请重试", Toast.LENGTH_SHORT).show(); 111 | }); 112 | } 113 | 114 | 115 | @Override 116 | public boolean onException(Exception e, String model, 117 | Target target, boolean isFirstResource) { 118 | 119 | mImageError.setVisibility(View.VISIBLE); 120 | return false; 121 | } 122 | 123 | 124 | @Override 125 | public boolean onResourceReady(GlideDrawable resource, String model, 126 | Target target, boolean 127 | isFromMemoryCache, boolean isFirstResource) { 128 | 129 | mImageView.setImageDrawable(resource); 130 | mPhotoViewAttacher = new PhotoViewAttacher(mImageView); 131 | mImageError.setVisibility(View.GONE); 132 | setPhotoViewAttacher(); 133 | return false; 134 | } 135 | 136 | 137 | private void setPhotoViewAttacher() { 138 | mPhotoViewAttacher.setOnLongClickListener(v -> { 139 | 140 | new AlertDialog.Builder(getActivity()) 141 | .setMessage("是否保存到本地?") 142 | .setNegativeButton("取消", (dialog, which) -> dialog.cancel()) 143 | .setPositiveButton("确定", (dialog, which) -> { 144 | saveImageToGallery(); 145 | dialog.dismiss(); 146 | }) 147 | .show(); 148 | 149 | return true; 150 | }); 151 | 152 | mPhotoViewAttacher.setOnViewTapListener( 153 | (view, v, v1) -> RxBus.getInstance().post("hideAppBar")); 154 | mImageError.setOnClickListener(v -> RxBus.getInstance().post("hideAppBar")); 155 | } 156 | 157 | 158 | public View getSharedElement() { 159 | 160 | return mImageView; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/douban/DoubanMeiziFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.douban; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentStatePagerAdapter; 6 | import android.support.v4.view.ViewPager; 7 | 8 | import com.flyco.tablayout.SlidingTabLayout; 9 | import com.hotbitmapgg.moequest.R; 10 | import com.hotbitmapgg.moequest.base.RxBaseFragment; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | import butterknife.Bind; 16 | 17 | /** 18 | * Created by hcc on 16/6/25 19:48 19 | * 100332338@qq.com 20 | *

21 | * 豆瓣妹子 22 | */ 23 | public class DoubanMeiziFragment extends RxBaseFragment { 24 | 25 | @Bind(R.id.sliding_tabs) 26 | SlidingTabLayout mSlidingTabLayout; 27 | 28 | @Bind(R.id.view_pager) 29 | ViewPager mViewPager; 30 | 31 | private List titles = Arrays.asList("大胸妹", "小翘臀", "黑丝袜", "美图控", "高颜值"); 32 | 33 | private List cids = Arrays.asList(2, 6, 7, 3, 4); 34 | 35 | 36 | public static DoubanMeiziFragment newInstance() { 37 | 38 | return new DoubanMeiziFragment(); 39 | } 40 | 41 | 42 | @Override 43 | public int getLayoutId() { 44 | 45 | return R.layout.fragment_douban_meizi; 46 | } 47 | 48 | 49 | @Override 50 | public void initViews() { 51 | 52 | initFragments(); 53 | } 54 | 55 | 56 | private void initFragments() { 57 | 58 | mViewPager.setAdapter(new DoubanMeiziPageAdapter(getChildFragmentManager())); 59 | mViewPager.setOffscreenPageLimit(1); 60 | mSlidingTabLayout.setViewPager(mViewPager); 61 | } 62 | 63 | 64 | private class DoubanMeiziPageAdapter extends FragmentStatePagerAdapter { 65 | 66 | public DoubanMeiziPageAdapter(FragmentManager fm) { 67 | 68 | super(fm); 69 | } 70 | 71 | 72 | @Override 73 | public Fragment getItem(int position) { 74 | 75 | return DoubanSimpleMeiziFragment.newInstance(cids.get(position), position); 76 | } 77 | 78 | 79 | @Override 80 | public CharSequence getPageTitle(int position) { 81 | 82 | return titles.get(position); 83 | } 84 | 85 | 86 | @Override 87 | public int getCount() { 88 | 89 | return titles.size(); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/huaban/HuaBanMeiziFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.huaban; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentStatePagerAdapter; 6 | import android.support.v4.view.ViewPager; 7 | 8 | import com.flyco.tablayout.SlidingTabLayout; 9 | import com.hotbitmapgg.moequest.R; 10 | import com.hotbitmapgg.moequest.base.RxBaseFragment; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | import butterknife.Bind; 16 | 17 | /** 18 | * Created by hcc on 16/8/13 12:50 19 | * 100332338@qq.com 20 | *

21 | * 花瓣妹子接口对应type: 22 | * 大胸妹=34 23 | * 小清新=35 24 | * 文艺范=36 25 | * 性感妹=37 26 | * 大长腿=38 27 | * 黑丝袜=39 28 | * 小翘臀=40 29 | */ 30 | public class HuaBanMeiziFragment extends RxBaseFragment { 31 | 32 | @Bind(R.id.sliding_tabs) 33 | SlidingTabLayout mSlidingTabLayout; 34 | 35 | @Bind(R.id.view_pager) 36 | ViewPager mViewPager; 37 | 38 | private List titles = Arrays.asList("大胸妹", "小清新", "文艺范", "性感妹", "大长腿", "黑丝袜", "小翘臀"); 39 | 40 | private List cids = Arrays.asList(34, 35, 36, 37, 38, 39, 40); 41 | 42 | 43 | public static HuaBanMeiziFragment newInstance() { 44 | 45 | return new HuaBanMeiziFragment(); 46 | } 47 | 48 | 49 | @Override 50 | public int getLayoutId() { 51 | 52 | return R.layout.fragment_huaban_meizi; 53 | } 54 | 55 | 56 | @Override 57 | public void initViews() { 58 | 59 | mViewPager.setAdapter(new HuaBanMeiziPageAdapter(getChildFragmentManager())); 60 | mSlidingTabLayout.setViewPager(mViewPager); 61 | } 62 | 63 | 64 | private class HuaBanMeiziPageAdapter extends FragmentStatePagerAdapter { 65 | 66 | public HuaBanMeiziPageAdapter(FragmentManager fm) { 67 | 68 | super(fm); 69 | } 70 | 71 | 72 | @Override 73 | public Fragment getItem(int position) { 74 | 75 | return HuaBanMeiziSimpleFragment 76 | .newInstance(cids.get(position), position); 77 | } 78 | 79 | 80 | @Override 81 | public CharSequence getPageTitle(int position) { 82 | 83 | return titles.get(position); 84 | } 85 | 86 | 87 | @Override 88 | public int getCount() { 89 | 90 | return titles.size(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/huaban/HuaBanMeiziSimpleFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.huaban; 2 | 3 | import butterknife.Bind; 4 | import com.hotbitmapgg.moequest.R; 5 | import com.hotbitmapgg.moequest.adapter.HuaBanMeiziAdapter; 6 | import com.hotbitmapgg.moequest.base.RxBaseFragment; 7 | import com.hotbitmapgg.moequest.entity.huaban.HuaBanMeizi; 8 | import com.hotbitmapgg.moequest.entity.huaban.HuaBanMeiziInfo; 9 | import com.hotbitmapgg.moequest.module.commonality.SingleMeiziDetailsActivity; 10 | import com.hotbitmapgg.moequest.network.RetrofitHelper; 11 | import com.hotbitmapgg.moequest.utils.ConstantUtil; 12 | import com.hotbitmapgg.moequest.utils.SnackbarUtil; 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import rx.android.schedulers.AndroidSchedulers; 17 | import rx.schedulers.Schedulers; 18 | 19 | import android.app.ActivityOptions; 20 | import android.content.Intent; 21 | import android.os.Bundle; 22 | import android.support.v4.widget.SwipeRefreshLayout; 23 | import android.support.v7.widget.RecyclerView; 24 | import android.support.v7.widget.StaggeredGridLayoutManager; 25 | 26 | /** 27 | * Created by hcc on 16/8/13 12:50 28 | * 100332338@qq.com 29 | *

30 | * 花瓣妹子详情界面 31 | */ 32 | public class HuaBanMeiziSimpleFragment extends RxBaseFragment { 33 | 34 | @Bind(R.id.recycle) 35 | RecyclerView mRecyclerView; 36 | 37 | @Bind(R.id.swipe_refresh) 38 | SwipeRefreshLayout mSwipeRefreshLayout; 39 | 40 | private static final int PRELOAD_SIZE = 6; 41 | 42 | public static final String EXTRA_CID = "extra_cid"; 43 | 44 | public static final String EXTRA_TYPE = "extra_type"; 45 | 46 | private boolean mIsLoadMore = true; 47 | 48 | private int cid; 49 | 50 | private int pageNum = 20; 51 | 52 | private int page = 1; 53 | 54 | private HuaBanMeiziAdapter mAdapter; 55 | 56 | private StaggeredGridLayoutManager mLayoutManager; 57 | 58 | private List meiziInfos = new ArrayList<>(); 59 | 60 | private boolean mIsRefreshing = false; 61 | 62 | private int type; 63 | 64 | 65 | public static HuaBanMeiziSimpleFragment newInstance(int cid, int type) { 66 | 67 | HuaBanMeiziSimpleFragment mHuaBanMeiziSimpleFragment = new HuaBanMeiziSimpleFragment(); 68 | Bundle bundle = new Bundle(); 69 | bundle.putInt(EXTRA_CID, cid); 70 | bundle.putInt(EXTRA_TYPE, type); 71 | mHuaBanMeiziSimpleFragment.setArguments(bundle); 72 | 73 | return mHuaBanMeiziSimpleFragment; 74 | } 75 | 76 | 77 | @Override 78 | public int getLayoutId() { 79 | 80 | return R.layout.fragment_simple_meizi; 81 | } 82 | 83 | 84 | @Override 85 | public void initViews() { 86 | 87 | cid = getArguments().getInt(EXTRA_CID); 88 | type = getArguments().getInt(EXTRA_TYPE); 89 | 90 | showProgress(); 91 | initRecycleView(); 92 | } 93 | 94 | 95 | private void initRecycleView() { 96 | 97 | mRecyclerView.setHasFixedSize(true); 98 | mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); 99 | mRecyclerView.setLayoutManager(mLayoutManager); 100 | mRecyclerView.addOnScrollListener(OnLoadMoreListener(mLayoutManager)); 101 | mAdapter = new HuaBanMeiziAdapter(mRecyclerView, meiziInfos); 102 | mRecyclerView.setAdapter(mAdapter); 103 | setRecycleScrollBug(); 104 | } 105 | 106 | 107 | private void showProgress() { 108 | 109 | mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); 110 | mSwipeRefreshLayout.postDelayed(() -> { 111 | 112 | mSwipeRefreshLayout.setRefreshing(true); 113 | mIsRefreshing = true; 114 | getHuaBanMeizi(); 115 | }, 500); 116 | 117 | mSwipeRefreshLayout.setOnRefreshListener(() -> { 118 | 119 | page = 1; 120 | meiziInfos.clear(); 121 | mIsRefreshing = true; 122 | getHuaBanMeizi(); 123 | }); 124 | } 125 | 126 | 127 | private void getHuaBanMeizi() { 128 | 129 | RetrofitHelper.getHuaBanMeiziApi() 130 | .getHuaBanMeizi(pageNum + "", page + "", 131 | ConstantUtil.APP_ID, cid + "", 132 | ConstantUtil.APP_SIGN) 133 | .compose(this.bindToLifecycle()) 134 | .map(responseBody -> { 135 | 136 | try { 137 | String string = responseBody.string(); 138 | 139 | return HuaBanMeizi.createFromJson(string); 140 | } catch (IOException e) { 141 | e.printStackTrace(); 142 | return null; 143 | } 144 | }) 145 | 146 | .subscribeOn(Schedulers.io()) 147 | .observeOn(AndroidSchedulers.mainThread()) 148 | .subscribe(huaBanMeizi -> { 149 | 150 | meiziInfos.addAll(huaBanMeizi.infos); 151 | finishTask(); 152 | }, throwable -> { 153 | 154 | mSwipeRefreshLayout.post(() -> mSwipeRefreshLayout.setRefreshing(false)); 155 | 156 | SnackbarUtil.showMessage(mRecyclerView, getString(R.string.error_message)); 157 | }); 158 | } 159 | 160 | 161 | private void finishTask() { 162 | 163 | if (page * pageNum - pageNum - 1 > 0) { 164 | mAdapter.notifyItemRangeChanged(page * pageNum - pageNum - 1, pageNum); 165 | } else { 166 | mAdapter.notifyDataSetChanged(); 167 | } 168 | if (mSwipeRefreshLayout.isRefreshing()) { 169 | mSwipeRefreshLayout.setRefreshing(false); 170 | } 171 | 172 | mIsRefreshing = false; 173 | 174 | mAdapter.setOnItemClickListener((position, holder) -> { 175 | 176 | Intent intent = SingleMeiziDetailsActivity 177 | .LuanchActivity(getActivity(), meiziInfos.get(position).getThumb(), 178 | meiziInfos.get(position).getTitle()); 179 | if (android.os.Build.VERSION.SDK_INT >= 21) { 180 | startActivity(intent, ActivityOptions 181 | .makeSceneTransitionAnimation(getActivity(), 182 | holder.getParentView().findViewById(R.id.item_img), 183 | "transitionImg").toBundle()); 184 | } else { 185 | startActivity(intent); 186 | } 187 | }); 188 | } 189 | 190 | 191 | RecyclerView.OnScrollListener OnLoadMoreListener(StaggeredGridLayoutManager layoutManager) { 192 | 193 | return new RecyclerView.OnScrollListener() { 194 | 195 | @Override 196 | public void onScrolled(RecyclerView rv, int dx, int dy) { 197 | 198 | boolean isBottom = mLayoutManager.findLastCompletelyVisibleItemPositions( 199 | new int[2])[1] >= mAdapter.getItemCount() - PRELOAD_SIZE; 200 | if (!mSwipeRefreshLayout.isRefreshing() && isBottom) { 201 | if (!mIsLoadMore) { 202 | mSwipeRefreshLayout.setRefreshing(true); 203 | page++; 204 | getHuaBanMeizi(); 205 | } else { 206 | mIsLoadMore = false; 207 | } 208 | } 209 | } 210 | }; 211 | } 212 | 213 | 214 | private void setRecycleScrollBug() { 215 | 216 | mRecyclerView.setOnTouchListener((v, event) -> mIsRefreshing); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/jiandan/JianDanMeiziFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.jiandan; 2 | 3 | import butterknife.Bind; 4 | import com.hotbitmapgg.moequest.R; 5 | import com.hotbitmapgg.moequest.adapter.JiandanMeiziAdapter; 6 | import com.hotbitmapgg.moequest.adapter.helper.EndlessRecyclerOnScrollListener; 7 | import com.hotbitmapgg.moequest.adapter.helper.HeaderViewRecyclerAdapter; 8 | import com.hotbitmapgg.moequest.base.RxBaseFragment; 9 | import com.hotbitmapgg.moequest.entity.jiandan.JianDanMeizi; 10 | import com.hotbitmapgg.moequest.module.commonality.SingleMeiziDetailsActivity; 11 | import com.hotbitmapgg.moequest.network.RetrofitHelper; 12 | import com.hotbitmapgg.moequest.utils.LogUtil; 13 | import com.hotbitmapgg.moequest.utils.SnackbarUtil; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import rx.android.schedulers.AndroidSchedulers; 17 | import rx.schedulers.Schedulers; 18 | 19 | import android.app.ActivityOptions; 20 | import android.content.Intent; 21 | import android.support.v4.widget.SwipeRefreshLayout; 22 | import android.support.v7.widget.LinearLayoutManager; 23 | import android.support.v7.widget.RecyclerView; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | 27 | /** 28 | * Created by hcc on 16/6/28 20:30 29 | * 100332338@qq.com 30 | *

31 | * 煎蛋妹子 32 | */ 33 | public class JianDanMeiziFragment extends RxBaseFragment { 34 | 35 | @Bind(R.id.recycle) 36 | RecyclerView mRecyclerView; 37 | 38 | @Bind(R.id.swipe_refresh) 39 | SwipeRefreshLayout mSwipeRefreshLayout; 40 | 41 | private int page = 1; 42 | 43 | private int count = 25; 44 | 45 | private List jianDanMeiziDataList = new ArrayList<>(); 46 | 47 | private HeaderViewRecyclerAdapter mHeaderViewRecyclerAdapter; 48 | 49 | private JiandanMeiziAdapter mAdapter; 50 | 51 | private View footView; 52 | 53 | private boolean mIsRefreshing = false; 54 | 55 | 56 | public static JianDanMeiziFragment newInstance() { 57 | 58 | return new JianDanMeiziFragment(); 59 | } 60 | 61 | 62 | @Override 63 | public int getLayoutId() { 64 | 65 | return R.layout.fragment_jiandan_meizi; 66 | } 67 | 68 | 69 | @Override 70 | public void initViews() { 71 | 72 | showProgress(); 73 | initRecycle(); 74 | } 75 | 76 | 77 | private void getJianDanMeizi() { 78 | 79 | RetrofitHelper.getJianDanApi() 80 | .getJianDanMeizi(page) 81 | .compose(this.bindToLifecycle()) 82 | .subscribeOn(Schedulers.io()) 83 | .observeOn(AndroidSchedulers.mainThread()) 84 | .subscribe(jianDanMeizi -> { 85 | 86 | List comments = jianDanMeizi.comments; 87 | if (comments.size() < count) { 88 | footView.setVisibility(View.GONE); 89 | } 90 | 91 | jianDanMeiziDataList.addAll(comments); 92 | finishTask(); 93 | }, throwable -> { 94 | 95 | LogUtil.all(throwable.getMessage()); 96 | mSwipeRefreshLayout.post(() -> mSwipeRefreshLayout.setRefreshing(false)); 97 | footView.setVisibility(View.GONE); 98 | SnackbarUtil.showMessage(mRecyclerView, getString(R.string.error_message)); 99 | }); 100 | } 101 | 102 | 103 | private void finishTask() { 104 | 105 | if (page * count - count - 1 > 0) { 106 | mAdapter.notifyItemRangeChanged(page * count - count - 1, count); 107 | } else { 108 | mAdapter.notifyDataSetChanged(); 109 | } 110 | 111 | if (mSwipeRefreshLayout.isRefreshing()) { 112 | mSwipeRefreshLayout.setRefreshing(false); 113 | } 114 | 115 | mIsRefreshing = false; 116 | 117 | mAdapter.setOnItemClickListener((position, holder) -> { 118 | 119 | Intent intent = SingleMeiziDetailsActivity.LuanchActivity(getActivity(), 120 | jianDanMeiziDataList.get(position).pics[0], 121 | jianDanMeiziDataList.get(position).commentAuthor); 122 | if (android.os.Build.VERSION.SDK_INT >= 21) { 123 | startActivity(intent, ActivityOptions. 124 | makeSceneTransitionAnimation(getActivity(), 125 | holder.getParentView().findViewById(R.id.item_fill_image), 126 | "transitionImg").toBundle()); 127 | } else { 128 | startActivity(intent); 129 | } 130 | }); 131 | } 132 | 133 | 134 | private void initRecycle() { 135 | 136 | mRecyclerView.setHasFixedSize(true); 137 | LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(getActivity()); 138 | mRecyclerView.setLayoutManager(mLinearLayoutManager); 139 | mAdapter = new JiandanMeiziAdapter(mRecyclerView, jianDanMeiziDataList); 140 | mHeaderViewRecyclerAdapter = new HeaderViewRecyclerAdapter(mAdapter); 141 | createFootView(); 142 | mRecyclerView.setAdapter(mHeaderViewRecyclerAdapter); 143 | mRecyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLinearLayoutManager) { 144 | 145 | @Override 146 | public void onLoadMore(int currentPage) { 147 | 148 | page++; 149 | getJianDanMeizi(); 150 | footView.setVisibility(View.VISIBLE); 151 | } 152 | }); 153 | setRecycleScrollBug(); 154 | } 155 | 156 | 157 | private void showProgress() { 158 | 159 | mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); 160 | mSwipeRefreshLayout.setOnRefreshListener(() -> { 161 | 162 | page = 1; 163 | jianDanMeiziDataList.clear(); 164 | mIsRefreshing = true; 165 | getJianDanMeizi(); 166 | }); 167 | mSwipeRefreshLayout.postDelayed(() -> { 168 | 169 | mSwipeRefreshLayout.setRefreshing(true); 170 | mIsRefreshing = true; 171 | getJianDanMeizi(); 172 | }, 500); 173 | } 174 | 175 | 176 | private void createFootView() { 177 | 178 | footView = LayoutInflater.from(getActivity()) 179 | .inflate(R.layout.load_more_foot_layout, mRecyclerView, false); 180 | mHeaderViewRecyclerAdapter.addFooterView(footView); 181 | footView.setVisibility(View.GONE); 182 | } 183 | 184 | 185 | private void setRecycleScrollBug() { 186 | 187 | mRecyclerView.setOnTouchListener((v, event) -> mIsRefreshing); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/meizitu/MeiziTuFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.meizitu; 2 | 3 | import butterknife.Bind; 4 | import com.flyco.tablayout.SlidingTabLayout; 5 | import com.hotbitmapgg.moequest.R; 6 | import com.hotbitmapgg.moequest.base.RxBaseFragment; 7 | import com.hotbitmapgg.moequest.utils.ConstantUtil; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | import android.support.v4.app.Fragment; 12 | import android.support.v4.app.FragmentManager; 13 | import android.support.v4.app.FragmentStatePagerAdapter; 14 | import android.support.v4.view.ViewPager; 15 | 16 | /** 17 | * Created by hcc on 16/7/19 20:39 18 | * 100332338@qq.com 19 | *

20 | * 妹子图 21 | */ 22 | public class MeiziTuFragment extends RxBaseFragment { 23 | 24 | @Bind(R.id.sliding_tabs) 25 | SlidingTabLayout mSlidingTabLayout; 26 | 27 | @Bind(R.id.view_pager) 28 | ViewPager mViewPager; 29 | 30 | private List titles = Arrays.asList("热门", "推荐", "清纯", "台湾", "日本", "性感"); 31 | 32 | private List types = Arrays.asList( 33 | ConstantUtil.HOT_MEIZI, 34 | ConstantUtil.TUIJIAN_MEIZI, 35 | ConstantUtil.QINGCHUN_MEIZI, 36 | ConstantUtil.TAIWAN_MEIZI, 37 | ConstantUtil.JAPAN_MEIZI, 38 | ConstantUtil.XINGGAN_MEIZI); 39 | 40 | 41 | public static MeiziTuFragment newInstance() { 42 | 43 | return new MeiziTuFragment(); 44 | } 45 | 46 | 47 | @Override 48 | public int getLayoutId() { 49 | 50 | return R.layout.fragment_meizitu; 51 | } 52 | 53 | 54 | @Override 55 | public void initViews() { 56 | 57 | initFragments(); 58 | } 59 | 60 | 61 | private void initFragments() { 62 | 63 | mViewPager.setAdapter(new MeiziTuPageAdapter(getChildFragmentManager())); 64 | mViewPager.setOffscreenPageLimit(1); 65 | mSlidingTabLayout.setViewPager(mViewPager); 66 | } 67 | 68 | 69 | private class MeiziTuPageAdapter extends FragmentStatePagerAdapter { 70 | 71 | public MeiziTuPageAdapter(FragmentManager fm) { 72 | 73 | super(fm); 74 | } 75 | 76 | 77 | @Override 78 | public Fragment getItem(int position) { 79 | 80 | return MeiziTuSimpleFragment.newInstance(types.get(position)); 81 | } 82 | 83 | 84 | @Override 85 | public CharSequence getPageTitle(int position) { 86 | 87 | return titles.get(position); 88 | } 89 | 90 | 91 | @Override 92 | public int getCount() { 93 | 94 | return titles.size(); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/taogirl/TaoFemaleFragment.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.taogirl; 2 | 3 | import butterknife.Bind; 4 | import com.hotbitmapgg.moequest.R; 5 | import com.hotbitmapgg.moequest.adapter.TaoFemaleAdapter; 6 | import com.hotbitmapgg.moequest.adapter.helper.EndlessRecyclerOnScrollListener; 7 | import com.hotbitmapgg.moequest.adapter.helper.HeaderViewRecyclerAdapter; 8 | import com.hotbitmapgg.moequest.base.RxBaseFragment; 9 | import com.hotbitmapgg.moequest.entity.taomodel.Contentlist; 10 | import com.hotbitmapgg.moequest.module.commonality.SingleMeiziDetailsActivity; 11 | import com.hotbitmapgg.moequest.network.RetrofitHelper; 12 | import com.hotbitmapgg.moequest.utils.ConstantUtil; 13 | import com.hotbitmapgg.moequest.utils.SnackbarUtil; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import rx.android.schedulers.AndroidSchedulers; 17 | import rx.schedulers.Schedulers; 18 | 19 | import android.app.ActivityOptions; 20 | import android.content.Intent; 21 | import android.support.v4.widget.SwipeRefreshLayout; 22 | import android.support.v7.widget.LinearLayoutManager; 23 | import android.support.v7.widget.RecyclerView; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | 27 | /** 28 | * Created by hcc on 16/6/25 19:48 29 | * 100332338@qq.com 30 | *

31 | * 淘女郎 32 | */ 33 | public class TaoFemaleFragment extends RxBaseFragment { 34 | 35 | @Bind(R.id.swipe_refresh) 36 | SwipeRefreshLayout mSwipeRefreshLayout; 37 | 38 | @Bind(R.id.recycle) 39 | RecyclerView mRecyclerView; 40 | 41 | private int page = 1; 42 | 43 | private int pageNum = 20; 44 | 45 | private View footView; 46 | 47 | private List datas = new ArrayList<>(); 48 | 49 | private HeaderViewRecyclerAdapter mHeaderViewRecyclerAdapter; 50 | 51 | private TaoFemaleAdapter mAdapter; 52 | 53 | private boolean mIsRefreshing = false; 54 | 55 | 56 | public static TaoFemaleFragment newInstance() { 57 | 58 | return new TaoFemaleFragment(); 59 | } 60 | 61 | 62 | @Override 63 | public int getLayoutId() { 64 | 65 | return R.layout.activity_tao_female; 66 | } 67 | 68 | 69 | @Override 70 | public void initViews() { 71 | 72 | initRefreshLayout(); 73 | initRecycleView(); 74 | } 75 | 76 | 77 | public void getTaoFemaleData() { 78 | 79 | RetrofitHelper.getTaoFemaleApi() 80 | .getTaoFemale(String.valueOf(page), 81 | ConstantUtil.APP_ID, ConstantUtil.APP_SIGN) 82 | .compose(this.bindToLifecycle()) 83 | .subscribeOn(Schedulers.io()) 84 | .observeOn(AndroidSchedulers.mainThread()) 85 | .subscribe(taoFemale -> { 86 | 87 | if (taoFemale.showapiResBody.pagebean.contentlist.size() < pageNum) { 88 | footView.setVisibility(View.GONE); 89 | } 90 | datas.addAll(taoFemale.showapiResBody.pagebean.contentlist); 91 | finishTask(); 92 | }, throwable -> { 93 | 94 | footView.setVisibility(View.GONE); 95 | SnackbarUtil.showMessage(mRecyclerView, getString(R.string.error_message)); 96 | mSwipeRefreshLayout.post(() -> mSwipeRefreshLayout.setRefreshing(false)); 97 | }); 98 | } 99 | 100 | 101 | private void finishTask() { 102 | 103 | if (page * pageNum - pageNum - 1 > 0) { 104 | mAdapter.notifyItemRangeChanged(page * pageNum - pageNum - 1, pageNum); 105 | } else { 106 | mAdapter.notifyDataSetChanged(); 107 | } 108 | 109 | if (mSwipeRefreshLayout.isRefreshing()) { 110 | mSwipeRefreshLayout.setRefreshing(false); 111 | } 112 | 113 | mIsRefreshing = false; 114 | 115 | mAdapter.setOnItemClickListener((position, holder) -> { 116 | 117 | Intent intent = SingleMeiziDetailsActivity. 118 | LuanchActivity(getActivity(), 119 | datas.get(position).avatarUrl, 120 | datas.get(position).realName); 121 | if (android.os.Build.VERSION.SDK_INT >= 21) { 122 | startActivity(intent, ActivityOptions. 123 | makeSceneTransitionAnimation(getActivity(), 124 | holder.getParentView().findViewById(R.id.tao_avatar), 125 | "transitionImg").toBundle()); 126 | } else { 127 | startActivity(intent); 128 | } 129 | }); 130 | } 131 | 132 | 133 | public void initRecycleView() { 134 | 135 | mRecyclerView.setHasFixedSize(true); 136 | LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(getActivity()); 137 | mRecyclerView.setLayoutManager(mLinearLayoutManager); 138 | mAdapter = new TaoFemaleAdapter(mRecyclerView, datas, getActivity()); 139 | mHeaderViewRecyclerAdapter = new HeaderViewRecyclerAdapter(mAdapter); 140 | createFootView(); 141 | mRecyclerView.setAdapter(mHeaderViewRecyclerAdapter); 142 | mRecyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(mLinearLayoutManager) { 143 | 144 | @Override 145 | public void onLoadMore(int currentPage) { 146 | 147 | page++; 148 | footView.setVisibility(View.VISIBLE); 149 | getTaoFemaleData(); 150 | } 151 | }); 152 | setRecycleScrollBug(); 153 | } 154 | 155 | 156 | private void createFootView() { 157 | 158 | footView = LayoutInflater.from(getActivity()) 159 | .inflate(R.layout.load_more_foot_layout, mRecyclerView, false); 160 | mHeaderViewRecyclerAdapter.addFooterView(footView); 161 | footView.setVisibility(View.GONE); 162 | } 163 | 164 | 165 | private void initRefreshLayout() { 166 | 167 | mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); 168 | mSwipeRefreshLayout.setOnRefreshListener(() -> { 169 | 170 | page = 1; 171 | datas.clear(); 172 | mIsRefreshing = true; 173 | getTaoFemaleData(); 174 | }); 175 | showRefreshProgress(); 176 | } 177 | 178 | 179 | public void showRefreshProgress() { 180 | 181 | mSwipeRefreshLayout.postDelayed(() -> { 182 | 183 | mSwipeRefreshLayout.setRefreshing(true); 184 | mIsRefreshing = true; 185 | getTaoFemaleData(); 186 | }, 500); 187 | } 188 | 189 | 190 | private void setRecycleScrollBug() { 191 | 192 | mRecyclerView.setOnTouchListener((v, event) -> mIsRefreshing); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/module/taogirl/TaoFemalePagerActivity.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.module.taogirl; 2 | 3 | import butterknife.Bind; 4 | import com.hotbitmapgg.moequest.R; 5 | import com.hotbitmapgg.moequest.base.RxBaseActivity; 6 | import com.hotbitmapgg.moequest.module.commonality.MeiziDetailsFragment; 7 | import com.hotbitmapgg.moequest.widget.DepthTransFormes; 8 | import java.util.ArrayList; 9 | 10 | import android.app.Activity; 11 | import android.content.Intent; 12 | import android.os.Bundle; 13 | import android.support.v4.app.Fragment; 14 | import android.support.v4.app.FragmentManager; 15 | import android.support.v4.app.FragmentStatePagerAdapter; 16 | import android.support.v4.view.ViewPager; 17 | import android.widget.TextView; 18 | 19 | /** 20 | * Created by hcc on 16/6/26 14:56 21 | * 100332338@qq.com 22 | *

23 | * 淘女郎大图浏览界面 24 | */ 25 | public class TaoFemalePagerActivity extends RxBaseActivity { 26 | 27 | @Bind(R.id.tv_index) 28 | TextView mIndex; 29 | 30 | @Bind(R.id.view_pager) 31 | ViewPager mViewPager; 32 | 33 | private static final String IMGLIST_KEY = "image_list_key"; 34 | 35 | private static final String POS_KEY = "pos_key"; 36 | 37 | private ArrayList imgList; 38 | 39 | private int pos; 40 | 41 | 42 | @Override 43 | public int getLayoutId() { 44 | 45 | return R.layout.activity_tao_pager; 46 | } 47 | 48 | 49 | @Override 50 | public void initViews(Bundle savedInstanceState) { 51 | 52 | Intent intent = getIntent(); 53 | if (intent != null) { 54 | imgList = intent.getStringArrayListExtra(IMGLIST_KEY); 55 | pos = intent.getIntExtra(POS_KEY, -1); 56 | } 57 | 58 | mIndex.setText((pos + 1) + " / " + imgList.size()); 59 | mViewPager.setAdapter(new TaoFemalePagerAdapter(getSupportFragmentManager())); 60 | mViewPager.setPageTransformer(true, new DepthTransFormes()); 61 | mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 62 | 63 | @Override 64 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 65 | 66 | } 67 | 68 | 69 | @Override 70 | public void onPageSelected(int position) { 71 | 72 | mIndex.setText((position + 1) + " / " + imgList.size()); 73 | } 74 | 75 | 76 | @Override 77 | public void onPageScrollStateChanged(int state) { 78 | 79 | } 80 | }); 81 | } 82 | 83 | 84 | @Override 85 | public void initToolBar() { 86 | 87 | } 88 | 89 | 90 | @Override 91 | protected void onResume() { 92 | 93 | super.onResume(); 94 | mViewPager.setCurrentItem(pos); 95 | } 96 | 97 | 98 | public static void luancher(Activity activity, ArrayList imageList, int pos) { 99 | 100 | Intent mIntent = new Intent(activity, TaoFemalePagerActivity.class); 101 | mIntent.putStringArrayListExtra(IMGLIST_KEY, imageList); 102 | mIntent.putExtra(POS_KEY, pos); 103 | activity.startActivity(mIntent); 104 | } 105 | 106 | 107 | public class TaoFemalePagerAdapter extends FragmentStatePagerAdapter { 108 | 109 | public TaoFemalePagerAdapter(FragmentManager fm) { 110 | 111 | super(fm); 112 | } 113 | 114 | 115 | @Override 116 | public Fragment getItem(int position) { 117 | 118 | return MeiziDetailsFragment.newInstance(imgList.get(position)); 119 | } 120 | 121 | 122 | @Override 123 | public int getCount() { 124 | 125 | return imgList.size(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/network/RetrofitHelper.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.network; 2 | 3 | import com.facebook.stetho.okhttp3.StethoInterceptor; 4 | import com.hotbitmapgg.moequest.MoeQuestApp; 5 | import com.hotbitmapgg.moequest.network.api.DoubanMeizhiApi; 6 | import com.hotbitmapgg.moequest.network.api.GankMeiziApi; 7 | import com.hotbitmapgg.moequest.network.api.HuaBanMeiziApi; 8 | import com.hotbitmapgg.moequest.network.api.JianDanMeiziApi; 9 | import com.hotbitmapgg.moequest.network.api.MeiziTuApi; 10 | import com.hotbitmapgg.moequest.network.api.TaoFemaleaApi; 11 | 12 | import java.io.File; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import okhttp3.Cache; 16 | import okhttp3.OkHttpClient; 17 | import okhttp3.logging.HttpLoggingInterceptor; 18 | import retrofit2.Retrofit; 19 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; 20 | import retrofit2.converter.gson.GsonConverterFactory; 21 | 22 | public class RetrofitHelper { 23 | 24 | private static final String BASE_GANK_URL = "http://gank.io/api/"; 25 | 26 | private static final String BASE_HUABAN_URL = "http://route.showapi.com/"; 27 | 28 | private static final String BASE_DOUBAN_URL = "http://www.dbmeinv.com/dbgroup/"; 29 | 30 | private static final String BASE_JIANDAN_URL = "http://jandan.net/"; 31 | 32 | private static final String BASE_MEIZITU_URL = "http://www.mzitu.com/"; 33 | 34 | private static OkHttpClient mOkHttpClient; 35 | 36 | 37 | static { 38 | initOkHttpClient(); 39 | } 40 | 41 | 42 | /** 43 | * Gank妹子Api 44 | */ 45 | public static GankMeiziApi getGankMeiziApi() { 46 | 47 | Retrofit retrofit = new Retrofit.Builder() 48 | .baseUrl(BASE_GANK_URL) 49 | .client(mOkHttpClient) 50 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 51 | .addConverterFactory(GsonConverterFactory.create()) 52 | .build(); 53 | 54 | return retrofit.create(GankMeiziApi.class); 55 | } 56 | 57 | 58 | /** 59 | * 花瓣Api 60 | */ 61 | public static HuaBanMeiziApi getHuaBanMeiziApi() { 62 | 63 | Retrofit retrofit = new Retrofit.Builder() 64 | .baseUrl(BASE_HUABAN_URL) 65 | .client(mOkHttpClient) 66 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 67 | .build(); 68 | 69 | return retrofit.create(HuaBanMeiziApi.class); 70 | } 71 | 72 | 73 | /** 74 | * 豆瓣Api 75 | */ 76 | public static DoubanMeizhiApi getDoubanMeiziApi() { 77 | 78 | Retrofit retrofit = new Retrofit.Builder() 79 | .baseUrl(BASE_DOUBAN_URL) 80 | .client(new OkHttpClient()) 81 | .build(); 82 | 83 | return retrofit.create(DoubanMeizhiApi.class); 84 | } 85 | 86 | 87 | /** 88 | * 淘女郎Api 89 | */ 90 | public static TaoFemaleaApi getTaoFemaleApi() { 91 | 92 | Retrofit retrofit = new Retrofit.Builder() 93 | .baseUrl(BASE_HUABAN_URL) 94 | .client(mOkHttpClient) 95 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 96 | .addConverterFactory(GsonConverterFactory.create()) 97 | .build(); 98 | 99 | return retrofit.create(TaoFemaleaApi.class); 100 | } 101 | 102 | 103 | /** 104 | * 煎蛋Api 105 | */ 106 | public static JianDanMeiziApi getJianDanApi() { 107 | 108 | Retrofit retrofit = new Retrofit.Builder() 109 | .baseUrl(BASE_JIANDAN_URL) 110 | .client(mOkHttpClient) 111 | .addConverterFactory(GsonConverterFactory.create()) 112 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 113 | .build(); 114 | 115 | return retrofit.create(JianDanMeiziApi.class); 116 | } 117 | 118 | 119 | /** 120 | * 获取妹子图Api 121 | */ 122 | public static MeiziTuApi getMeiziTuApi() { 123 | 124 | Retrofit retrofit = new Retrofit.Builder() 125 | .baseUrl(BASE_MEIZITU_URL) 126 | .client(mOkHttpClient) 127 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 128 | .addConverterFactory(GsonConverterFactory.create()) 129 | .build(); 130 | 131 | return retrofit.create(MeiziTuApi.class); 132 | } 133 | 134 | 135 | /** 136 | * 初始化OKHttpClient 137 | */ 138 | private static void initOkHttpClient() { 139 | 140 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); 141 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 142 | if (mOkHttpClient == null) { 143 | synchronized (RetrofitHelper.class) { 144 | if (mOkHttpClient == null) { 145 | //设置Http缓存 146 | Cache cache = new Cache(new File(MoeQuestApp.getContext().getCacheDir(), "HttpCache"), 147 | 1024 * 1024 * 100); 148 | 149 | mOkHttpClient = new OkHttpClient.Builder() 150 | .cache(cache) 151 | .addInterceptor(interceptor) 152 | .addNetworkInterceptor(new StethoInterceptor()) 153 | .retryOnConnectionFailure(true) 154 | .connectTimeout(20, TimeUnit.SECONDS) 155 | .build(); 156 | } 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/network/api/DoubanMeizhiApi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.network.api; 2 | 3 | import okhttp3.ResponseBody; 4 | import retrofit2.Call; 5 | import retrofit2.http.GET; 6 | import retrofit2.http.Query; 7 | 8 | public interface DoubanMeizhiApi { 9 | 10 | /** 11 | * 根据cid查询不同类型的妹子图片 12 | */ 13 | @GET("show.htm") 14 | Call getDoubanMeizi(@Query("cid") int cid, @Query("pager_offset") int pageNum); 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/network/api/GankMeiziApi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.network.api; 2 | 3 | import com.hotbitmapgg.moequest.entity.gank.GankMeiziResult; 4 | 5 | import retrofit2.http.GET; 6 | import retrofit2.http.Path; 7 | import rx.Observable; 8 | 9 | public interface GankMeiziApi { 10 | 11 | /** 12 | * gank妹子,福利 13 | */ 14 | @GET("data/福利/{number}/{page}") 15 | Observable getGankMeizi(@Path("number") int number, @Path("page") int page); 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/network/api/HuaBanMeiziApi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.network.api; 2 | 3 | import okhttp3.ResponseBody; 4 | import retrofit2.http.GET; 5 | import retrofit2.http.Query; 6 | import rx.Observable; 7 | 8 | public interface HuaBanMeiziApi { 9 | 10 | /** 11 | * 来自易源接口的花瓣妹子 12 | */ 13 | @GET("819-1") 14 | Observable getHuaBanMeizi(@Query("num") String num, 15 | @Query("page") String page, 16 | @Query("showapi_appid") String appId, 17 | @Query("type") String type, 18 | @Query("showapi_sign") String sign); 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/network/api/JianDanMeiziApi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.network.api; 2 | 3 | import com.hotbitmapgg.moequest.entity.jiandan.JianDanMeizi; 4 | 5 | import retrofit2.http.GET; 6 | import retrofit2.http.Query; 7 | import rx.Observable; 8 | 9 | public interface JianDanMeiziApi { 10 | 11 | /** 12 | * 煎蛋妹子请求Api 13 | * http://jandan.net/?oxwlxojflwblxbsapi=jandan.get_ooxx_comments&page= 14 | */ 15 | @GET("?oxwlxojflwblxbsapi=jandan.get_ooxx_comments") 16 | Observable getJianDanMeizi(@Query("page") int page); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/network/api/MeiziTuApi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.network.api; 2 | 3 | import okhttp3.ResponseBody; 4 | import retrofit2.http.GET; 5 | import retrofit2.http.Path; 6 | import rx.Observable; 7 | 8 | public interface MeiziTuApi { 9 | 10 | /** 11 | * 根据类型查询对应的妹子图 12 | */ 13 | @GET("{type}/page/{pageNum}") 14 | Observable getMeiziTuApi(@Path("type") String type, @Path("pageNum") int pageNum); 15 | 16 | /** 17 | * 分页查询对应的妹子图 18 | */ 19 | @GET("{type}/comment-page-{page}#comments") 20 | Observable getHomeMeiziApi(@Path("type") String type, @Path("page") int page); 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/network/api/TaoFemaleaApi.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.network.api; 2 | 3 | import com.hotbitmapgg.moequest.entity.taomodel.TaoFemale; 4 | 5 | import retrofit2.http.GET; 6 | import retrofit2.http.Query; 7 | import rx.Observable; 8 | 9 | public interface TaoFemaleaApi { 10 | 11 | /** 12 | * 来自易源接口的淘女郎 13 | */ 14 | @GET("126-2") 15 | Observable getTaoFemale(@Query("page") String page, 16 | @Query("showapi_appid") String appId, 17 | @Query("showapi_sign") String sign); 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/notice/Distance.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.notice; 2 | 3 | import android.content.Context; 4 | import android.hardware.SensorManager; 5 | import android.view.ViewConfiguration; 6 | 7 | public class Distance { 8 | 9 | private float mFlingFriction = ViewConfiguration.getScrollFriction(); 10 | 11 | private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9)); 12 | 13 | private static final float INFLEXION = 0.35f; 14 | 15 | private float mPhysicalCoeff; 16 | 17 | 18 | public Distance(Context context) { 19 | 20 | final float ppi = context.getResources().getDisplayMetrics().density * 160.0f; 21 | mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2) 22 | * 39.37f // inch/meter 23 | * ppi 24 | * 0.84f; // look and feel tuning 25 | } 26 | 27 | 28 | public double getSplineFlingDistance(int velocity) { 29 | 30 | final double l = getSplineDeceleration(velocity); 31 | final double decelMinusOne = DECELERATION_RATE - 1.0; 32 | return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l); 33 | } 34 | 35 | 36 | private double getSplineDeceleration(int velocity) { 37 | 38 | return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff)); 39 | } 40 | 41 | 42 | public int getSplineFlingDuration(int velocity) { 43 | 44 | final double l = getSplineDeceleration(velocity); 45 | final double decelMinusOne = DECELERATION_RATE - 1.0; 46 | return (int) (1000.0 * Math.exp(l / decelMinusOne)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/notice/HeadsUpManager.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.notice; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ObjectAnimator; 5 | import android.app.NotificationManager; 6 | import android.content.Context; 7 | import android.os.Build; 8 | import android.view.Gravity; 9 | import android.view.WindowManager; 10 | 11 | import java.util.HashMap; 12 | import java.util.LinkedList; 13 | import java.util.Map; 14 | import java.util.Queue; 15 | 16 | public class HeadsUpManager { 17 | 18 | private WindowManager wmOne; 19 | 20 | private FloatView floatView; 21 | 22 | private Queue msgQueue; 23 | 24 | private static HeadsUpManager manager; 25 | 26 | private Context context; 27 | 28 | private boolean isPolling = false; 29 | 30 | private Map map; 31 | 32 | private NotificationManager notificationManager = null; 33 | 34 | 35 | public static HeadsUpManager getInstant(Context c) { 36 | 37 | if (manager == null) { 38 | manager = new HeadsUpManager(c); 39 | } 40 | return manager; 41 | } 42 | 43 | 44 | private HeadsUpManager(Context context) { 45 | 46 | this.context = context; 47 | map = new HashMap(); 48 | msgQueue = new LinkedList(); 49 | wmOne = (WindowManager) context 50 | .getSystemService(Context.WINDOW_SERVICE); 51 | 52 | notificationManager = (NotificationManager) context.getSystemService( 53 | Context.NOTIFICATION_SERVICE); 54 | } 55 | 56 | 57 | public synchronized void notify(HeadsUp headsUp) { 58 | 59 | if (map.containsKey(headsUp.getCode())) { 60 | msgQueue.remove(map.get(headsUp.getCode())); 61 | } 62 | map.put(headsUp.getCode(), headsUp); 63 | msgQueue.add(headsUp); 64 | 65 | if (!isPolling) { 66 | poll(); 67 | } 68 | } 69 | 70 | 71 | public synchronized void notify(int code, HeadsUp headsUp) { 72 | 73 | headsUp.setCode(code); 74 | notify(headsUp); 75 | } 76 | 77 | 78 | public synchronized void cancel(HeadsUp headsUp) { 79 | 80 | cancel(headsUp.getCode()); 81 | } 82 | 83 | 84 | private synchronized void poll() { 85 | 86 | if (!msgQueue.isEmpty()) { 87 | HeadsUp headsUp = msgQueue.poll(); 88 | map.remove(headsUp.getCode()); 89 | 90 | if (Build.VERSION.SDK_INT < 21 || headsUp.getCustomView() != null || 91 | !headsUp.isActivateStatusBar()) { 92 | isPolling = true; 93 | show(headsUp); 94 | } else { 95 | //当 系统是 lollipop 以上,并且没有自定义布局以后,调用系统自己的 notification 96 | isPolling = false; 97 | notificationManager.notify(headsUp.getCode(), 98 | headsUp.getBuilder().setIcon(headsUp.getIcon()).build()); 99 | } 100 | } else { 101 | isPolling = false; 102 | } 103 | } 104 | 105 | 106 | private void show(HeadsUp headsUp) { 107 | 108 | floatView = new FloatView(context, 20); 109 | WindowManager.LayoutParams params = FloatView.winParams; 110 | params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 111 | | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_FULLSCREEN 112 | | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 113 | params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 114 | params.width = WindowManager.LayoutParams.MATCH_PARENT; 115 | params.height = WindowManager.LayoutParams.WRAP_CONTENT; 116 | params.format = -3; 117 | params.gravity = Gravity.CENTER | Gravity.TOP; 118 | params.x = floatView.originalLeft; 119 | params.y = 0; 120 | params.alpha = 1f; 121 | wmOne.addView(floatView, params); 122 | ObjectAnimator a = ObjectAnimator.ofFloat(floatView.rootView, "translationY", -700, 0); 123 | a.setDuration(600); 124 | a.start(); 125 | floatView.setNotification(headsUp); 126 | if (headsUp.getNotification() != null) { 127 | notificationManager.notify(headsUp.getCode(), headsUp.getNotification()); 128 | } 129 | } 130 | 131 | 132 | public void cancel() { 133 | 134 | if (floatView != null && floatView.getParent() != null) { 135 | 136 | floatView.cancel(); 137 | } 138 | } 139 | 140 | 141 | protected void dismiss() { 142 | 143 | if (floatView.getParent() != null) { 144 | wmOne.removeView(floatView); 145 | floatView.postDelayed(new Runnable() { 146 | 147 | @Override 148 | public void run() { 149 | 150 | poll(); 151 | } 152 | }, 1000); 153 | } 154 | } 155 | 156 | 157 | protected void animDismiss() { 158 | 159 | if (floatView != null && floatView.getParent() != null) { 160 | 161 | ObjectAnimator a = ObjectAnimator.ofFloat(floatView.rootView, "translationY", 0, -700); 162 | a.setDuration(700); 163 | a.start(); 164 | 165 | a.addListener(new Animator.AnimatorListener() { 166 | 167 | @Override 168 | public void onAnimationStart(Animator animator) { 169 | 170 | } 171 | 172 | 173 | @Override 174 | public void onAnimationEnd(Animator animator) { 175 | 176 | dismiss(); 177 | } 178 | 179 | 180 | @Override 181 | public void onAnimationCancel(Animator animator) { 182 | 183 | } 184 | 185 | 186 | @Override 187 | public void onAnimationRepeat(Animator animator) { 188 | 189 | } 190 | }); 191 | } 192 | } 193 | 194 | 195 | protected void animDismiss(HeadsUp headsUp) { 196 | 197 | if (floatView.getHeadsUp().getCode() == headsUp.getCode()) { 198 | animDismiss(); 199 | } 200 | } 201 | 202 | 203 | protected void silencerNotify(HeadsUp headsUp) { 204 | 205 | if (headsUp.getSilencerNotification() != null) { 206 | notificationManager.notify(headsUp.getCode(), headsUp.getSilencerNotification()); 207 | } 208 | } 209 | 210 | 211 | public void cancel(int code) { 212 | 213 | if (map.containsKey(code)) { 214 | msgQueue.remove(map.get(code)); 215 | } 216 | if (floatView != null && floatView.getHeadsUp().getCode() == code) { 217 | animDismiss(); 218 | } 219 | } 220 | 221 | 222 | public void close() { 223 | 224 | cancelAll(); 225 | manager = null; 226 | } 227 | 228 | 229 | public void cancelAll() { 230 | 231 | msgQueue.clear(); 232 | if (floatView != null && floatView.getParent() != null) { 233 | animDismiss(); 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/rx/RxBus.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.rx; 2 | 3 | import rx.Observable; 4 | import rx.subjects.PublishSubject; 5 | import rx.subjects.SerializedSubject; 6 | import rx.subjects.Subject; 7 | 8 | /** 9 | * RxBus第二种实现方法 10 | *

11 | * Subject同时充当了Observer和Observable的角色,Subject是非线程安全的, 12 | * 要避免该问题,需要将 Subject转换为一个 SerializedSubject , 13 | * 上述RxBus类中把线程非安全的PublishSubject包装成线程安全的Subject。 14 | * 15 | * PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者 16 | *

17 | * ofType操作符只发射指定类型的数据,其内部就是filter+cast 18 | */ 19 | public class RxBus { 20 | 21 | private static volatile RxBus mInstance; 22 | 23 | private final Subject bus; 24 | 25 | 26 | private RxBus() { 27 | 28 | bus = new SerializedSubject<>(PublishSubject.create()); 29 | } 30 | 31 | 32 | /** 33 | * 单例模式RxBus2 34 | */ 35 | public static RxBus getInstance() { 36 | 37 | RxBus rxBus = mInstance; 38 | if (mInstance == null) { 39 | synchronized (RxBus.class) { 40 | rxBus = mInstance; 41 | if (mInstance == null) { 42 | rxBus = new RxBus(); 43 | mInstance = rxBus; 44 | } 45 | } 46 | } 47 | 48 | return rxBus; 49 | } 50 | 51 | 52 | /** 53 | * 发送消息 54 | */ 55 | public void post(Object object) { 56 | 57 | bus.onNext(object); 58 | } 59 | 60 | 61 | /** 62 | * 接收消息 63 | */ 64 | public Observable toObserverable(Class eventType) { 65 | 66 | return bus.ofType(eventType); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/service/AlarmReceiver.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.service; 2 | 3 | import com.hotbitmapgg.moequest.R; 4 | import com.hotbitmapgg.moequest.module.commonality.MainActivity; 5 | import com.hotbitmapgg.moequest.utils.HeadsUpUtils; 6 | import com.hotbitmapgg.moequest.utils.PreferencesLoader; 7 | 8 | import android.content.BroadcastReceiver; 9 | import android.content.Context; 10 | import android.content.Intent; 11 | 12 | /** 13 | * Created by hcc on 16/6/25 18:05 14 | * 100332338@qq.com 15 | */ 16 | public class AlarmReceiver extends BroadcastReceiver { 17 | 18 | @Override 19 | public void onReceive(Context context, Intent intent) { 20 | 21 | PreferencesLoader loader = new PreferencesLoader(context); 22 | if (loader.getBoolean(R.string.action_notifiable, true)) { 23 | HeadsUpUtils.show(context, MainActivity.class, 24 | context.getString(R.string.headsup_title), 25 | context.getString(R.string.headsup_content), 26 | R.mipmap.ic_launcher, R.drawable.bow_tie, 123123); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/service/KeepAlarmLiveReceiver.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.service; 2 | 3 | import com.hotbitmapgg.moequest.utils.AlarmManagerUtils; 4 | 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | 9 | /** 10 | * Created by hcc on 16/6/25 18:05 11 | * 100332338@qq.com 12 | */ 13 | public class KeepAlarmLiveReceiver extends BroadcastReceiver { 14 | 15 | @Override 16 | public void onReceive(Context context, Intent intent) { 17 | 18 | if (intent != null && Intent.ACTION_USER_PRESENT.equals(intent.getAction())) { 19 | AlarmManagerUtils.register(context); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/AlarmManagerUtils.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import com.hotbitmapgg.moequest.service.AlarmReceiver; 4 | import java.util.Calendar; 5 | 6 | import android.app.AlarmManager; 7 | import android.app.PendingIntent; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | 11 | /** 12 | * Created by hcc on 16/6/25 18:05 13 | * 100332338@qq.com 14 | */ 15 | public class AlarmManagerUtils { 16 | 17 | public static void register(Context context) { 18 | 19 | Calendar today = Calendar.getInstance(); 20 | Calendar now = Calendar.getInstance(); 21 | 22 | today.set(Calendar.HOUR_OF_DAY, 12); 23 | today.set(Calendar.MINUTE, 30); 24 | today.set(Calendar.SECOND, 10); 25 | 26 | if (now.after(today)) { 27 | return; 28 | } 29 | 30 | Intent intent = new Intent("com.hotbitmapgg.moequest.alarm"); 31 | intent.setClass(context, AlarmReceiver.class); 32 | 33 | PendingIntent broadcast = PendingIntent.getBroadcast(context, 520, intent, 34 | PendingIntent.FLAG_UPDATE_CURRENT); 35 | AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 36 | 37 | manager.set(AlarmManager.RTC_WAKEUP, today.getTimeInMillis(), broadcast); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/ConstantUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | /** 4 | * 常量配置工具类 5 | * 6 | * @HotBitmapGG 7 | */ 8 | public class ConstantUtil { 9 | 10 | //易源接口AppId 11 | public static final String APP_ID = "15314"; 12 | 13 | //易源接口AppSign 14 | public static final String APP_SIGN = "d424376f51f1467da1b8c75debebf148"; 15 | 16 | //本地存储dir目录 17 | public static final String FILE_DIR = "moe_quest"; 18 | 19 | //腾讯buglyID 20 | public static final String BUGLY_ID = "900037370"; 21 | 22 | //性感妹子 23 | public static final String XINGGAN_MEIZI = "xinggan"; 24 | 25 | //日本妹子 26 | public static final String JAPAN_MEIZI = "japan"; 27 | 28 | //台湾妹子 29 | public static final String TAIWAN_MEIZI = "taiwan"; 30 | 31 | //清纯妹子 32 | public static final String QINGCHUN_MEIZI = "mm"; 33 | 34 | //推荐 35 | public static final String TUIJIAN_MEIZI = "best"; 36 | 37 | //热门 38 | public static final String HOT_MEIZI = "hot"; 39 | 40 | //每日更新 41 | public static final String UPDATE_MEIZI = "all"; 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/GlideDownloadImageUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import com.bumptech.glide.Glide; 4 | import com.bumptech.glide.request.target.Target; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.util.concurrent.ExecutionException; 9 | import rx.Observable; 10 | import rx.Subscriber; 11 | import rx.functions.Func1; 12 | import rx.schedulers.Schedulers; 13 | 14 | import android.content.Context; 15 | import android.content.Intent; 16 | import android.net.Uri; 17 | import android.os.Environment; 18 | 19 | /** 20 | * 使用Glide下载图片到本地工具类 21 | */ 22 | public class GlideDownloadImageUtil { 23 | 24 | public static Observable saveImageToLocal(final Context context, final String url) { 25 | 26 | return Observable.create(new Observable.OnSubscribe() { 27 | 28 | @Override 29 | public void call(Subscriber subscriber) { 30 | 31 | File file; 32 | try { 33 | LogUtil.all("download" + url); 34 | file = Glide.with(context) 35 | .load(url) 36 | .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) 37 | .get(); 38 | 39 | subscriber.onNext(file); 40 | } catch (InterruptedException | ExecutionException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | }).flatMap(new Func1>() { 45 | 46 | @Override 47 | public Observable call(File file) { 48 | 49 | File mFile = null; 50 | try { 51 | 52 | String path = Environment.getExternalStorageDirectory() + File.separator + 53 | ConstantUtil.FILE_DIR; 54 | File dir = new File(path); 55 | if (!dir.exists()) { 56 | dir.mkdirs(); 57 | } 58 | 59 | String fileName = System.currentTimeMillis() + ".jpg"; 60 | 61 | mFile = new File(dir, fileName); 62 | FileInputStream fis = new FileInputStream(file.getAbsolutePath()); 63 | 64 | int byteread; 65 | byte[] buf = new byte[1444]; 66 | 67 | FileOutputStream fos = new FileOutputStream(mFile.getAbsolutePath()); 68 | while ((byteread = fis.read(buf)) != -1) { 69 | fos.write(buf, 0, byteread); 70 | } 71 | 72 | fos.close(); 73 | fis.close(); 74 | } catch (Exception e) { 75 | e.printStackTrace(); 76 | LogUtil.all("图片下载失败"); 77 | } 78 | 79 | //更新本地图库 80 | Uri uri = Uri.fromFile(mFile); 81 | Intent mIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri); 82 | context.sendBroadcast(mIntent); 83 | 84 | return Observable.just(uri); 85 | } 86 | }).subscribeOn(Schedulers.io()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/HeadsUpUtils.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.hotbitmapgg.moequest.utils; 4 | 5 | import com.hotbitmapgg.moequest.notice.HeadsUp; 6 | import com.hotbitmapgg.moequest.notice.HeadsUpManager; 7 | 8 | import android.app.Notification; 9 | import android.app.PendingIntent; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | import android.graphics.BitmapFactory; 13 | import android.os.Build; 14 | 15 | public class HeadsUpUtils { 16 | 17 | public static void show(Context context, Class targetActivity, String title, String content, int largeIcon, int smallIcon, int code) { 18 | 19 | PendingIntent pendingIntent = PendingIntent.getActivity(context, 11, 20 | new Intent(context, targetActivity), PendingIntent.FLAG_UPDATE_CURRENT); 21 | HeadsUpManager manage = HeadsUpManager.getInstant(context); 22 | HeadsUp.Builder builder = new HeadsUp.Builder(context); 23 | builder.setContentTitle(title) 24 | .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_LIGHTS) 25 | .setContentIntent(pendingIntent) 26 | .setFullScreenIntent(pendingIntent, false) 27 | .setAutoCancel(true) 28 | .setContentText(content); 29 | 30 | if (Build.VERSION.SDK_INT >= 21) { 31 | builder.setLargeIcon( 32 | BitmapFactory.decodeResource(context.getResources(), largeIcon)) 33 | .setSmallIcon(smallIcon); 34 | } else { 35 | builder.setSmallIcon(largeIcon); 36 | } 37 | 38 | HeadsUp headsUp = builder.buildHeadUp(); 39 | headsUp.setSticky(true); 40 | manage.notify(code, headsUp); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/ImmersiveUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.os.Build; 6 | import android.view.View; 7 | 8 | /** 9 | * 控件NavBar显示隐藏的工具类 10 | */ 11 | public class ImmersiveUtil { 12 | 13 | public static void enter(Activity activity) { 14 | 15 | if (Build.VERSION.SDK_INT >= 19) { 16 | ImmersiveUtil19.enter(activity.getWindow().getDecorView()); 17 | } 18 | } 19 | 20 | 21 | public static void exit(Activity activity) { 22 | 23 | if (Build.VERSION.SDK_INT >= 19) { 24 | ImmersiveUtil19.exit(activity.getWindow().getDecorView()); 25 | } 26 | } 27 | 28 | 29 | @TargetApi(19) 30 | private static class ImmersiveUtil19 { 31 | 32 | private static final int FLAG_IMMERSIVE = View.SYSTEM_UI_FLAG_IMMERSIVE 33 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 34 | | View.SYSTEM_UI_FLAG_FULLSCREEN; 35 | 36 | 37 | public static void enter(View decor) { 38 | 39 | SystemUiVisibilityUtil.addFlags(decor, FLAG_IMMERSIVE); 40 | } 41 | 42 | 43 | public static void exit(View decor) { 44 | 45 | SystemUiVisibilityUtil.clearFlags(decor, FLAG_IMMERSIVE); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import android.util.Log; 4 | 5 | public class LogUtil { 6 | 7 | private static final String TAG = "LogUtil"; 8 | // 是否显示Log消息 9 | private static boolean isShow = true; 10 | 11 | 12 | public static boolean isShow() { 13 | return isShow; 14 | } 15 | 16 | 17 | public static void setShow(boolean show) { 18 | isShow = show; 19 | } 20 | 21 | 22 | public static void i(String tag, String msg) { 23 | if (isShow) { 24 | Log.i(tag, msg); 25 | } 26 | } 27 | 28 | 29 | public static void w(String tag, String msg) { 30 | if (isShow) { 31 | Log.w(tag, msg); 32 | } 33 | } 34 | 35 | 36 | public static void e(String tag, String msg) { 37 | if (isShow) { 38 | Log.e(tag, msg); 39 | } 40 | } 41 | 42 | 43 | public static void all(String msg) { 44 | if (isShow) { 45 | Log.e("all", msg); 46 | } 47 | } 48 | 49 | 50 | public static void i(String msg) { 51 | if (isShow) { 52 | Log.i(TAG, msg); 53 | } 54 | } 55 | 56 | 57 | public static void w(String msg) { 58 | if (isShow) { 59 | Log.w(TAG, msg); 60 | } 61 | } 62 | 63 | 64 | public static void e(String msg) { 65 | if (isShow) { 66 | Log.e(TAG, msg); 67 | } 68 | } 69 | 70 | 71 | public static void v(String msg) { 72 | if (isShow) { 73 | Log.v(TAG, msg); 74 | } 75 | } 76 | 77 | 78 | public static void d(String msg) { 79 | if (isShow) { 80 | Log.d(TAG, msg); 81 | } 82 | } 83 | 84 | 85 | public static void d(String tag, String msg) { 86 | if (isShow) { 87 | Log.d(tag, msg); 88 | } 89 | } 90 | 91 | 92 | public static void w(String tag, String msg, Exception e) { 93 | if (isShow) { 94 | Log.w(tag, msg, e); 95 | } 96 | } 97 | 98 | 99 | public static void v(String tag, String msg) { 100 | if (isShow) 101 | Log.v(tag, msg); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/MeiziUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import com.hotbitmapgg.moequest.entity.douban.DoubanMeizi; 4 | import com.hotbitmapgg.moequest.entity.gank.GankMeizi; 5 | import com.hotbitmapgg.moequest.entity.gank.GankMeiziInfo; 6 | import com.hotbitmapgg.moequest.entity.meizitu.MeiziTu; 7 | import io.realm.Realm; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import okhttp3.ResponseBody; 11 | import retrofit2.Response; 12 | 13 | import org.jsoup.Jsoup; 14 | import org.jsoup.nodes.Document; 15 | import org.jsoup.nodes.Element; 16 | import org.jsoup.select.Elements; 17 | 18 | /** 19 | * 萌妹纸工具类 20 | */ 21 | public class MeiziUtil { 22 | 23 | private static volatile MeiziUtil mCache; 24 | 25 | 26 | private MeiziUtil() { 27 | 28 | } 29 | 30 | 31 | public static MeiziUtil getInstance() { 32 | 33 | if (mCache == null) { 34 | synchronized (MeiziUtil.class) { 35 | if (mCache == null) { 36 | mCache = new MeiziUtil(); 37 | } 38 | } 39 | } 40 | 41 | return mCache; 42 | } 43 | 44 | 45 | /** 46 | * 保存gank妹子到数据库中 47 | */ 48 | 49 | public void putGankMeiziCache(List gankMeiziInfos) { 50 | 51 | GankMeizi meizi; 52 | Realm realm = Realm.getDefaultInstance(); 53 | realm.beginTransaction(); 54 | for (int i = 0; i < gankMeiziInfos.size(); i++) { 55 | meizi = new GankMeizi(); 56 | String url = gankMeiziInfos.get(i).url; 57 | String desc = gankMeiziInfos.get(i).desc; 58 | meizi.setUrl(url); 59 | meizi.setDesc(desc); 60 | realm.copyToRealm(meizi); 61 | } 62 | realm.commitTransaction(); 63 | realm.close(); 64 | } 65 | 66 | 67 | /** 68 | * 保存豆瓣妹子数据到数据库中 69 | */ 70 | public void putDoubanMeiziCache(int type, Response response) { 71 | 72 | try { 73 | 74 | Realm realm = Realm.getDefaultInstance(); 75 | realm.beginTransaction(); 76 | 77 | String string = response.body().string(); 78 | Document parse = Jsoup.parse(string); 79 | Elements elements = parse.select("div[class=thumbnail]>div[class=img_single]>a>img"); 80 | DoubanMeizi meizi; 81 | for (Element e : elements) { 82 | String src = e.attr("src"); 83 | String title = e.attr("title"); 84 | 85 | meizi = new DoubanMeizi(); 86 | meizi.setUrl(src); 87 | meizi.setTitle(title); 88 | meizi.setType(type); 89 | 90 | realm.copyToRealm(meizi); 91 | } 92 | 93 | realm.commitTransaction(); 94 | realm.close(); 95 | } catch (Exception e) { 96 | e.printStackTrace(); 97 | } 98 | } 99 | 100 | 101 | /** 102 | * 解析妹子图html 103 | */ 104 | public List parserMeiziTuHtml(String html, String type) { 105 | 106 | List list = new ArrayList<>(); 107 | Document doc = Jsoup.parse(html); 108 | Elements links = doc.select("li"); 109 | 110 | Element aelement; 111 | Element imgelement; 112 | for (int i = 7; i < links.size(); i++) { 113 | imgelement = links.get(i).select("img").first(); 114 | aelement = links.get(i).select("a").first(); 115 | MeiziTu bean = new MeiziTu(); 116 | bean.setOrder(i); 117 | 118 | bean.setTitle(imgelement.attr("alt")); 119 | bean.setType(type); 120 | bean.setHeight(354); 121 | bean.setWidth(236); 122 | bean.setImageurl(imgelement.attr("data-original")); 123 | bean.setUrl(aelement.attr("href")); 124 | bean.setGroupid(url2groupid(bean.getUrl())); 125 | list.add(bean); 126 | } 127 | return list; 128 | } 129 | 130 | 131 | /** 132 | * 解析自拍妹子Html 133 | */ 134 | public List parserMeiziTuByAutodyne(String html, String type) { 135 | 136 | List list = new ArrayList<>(); 137 | Document doc = Jsoup.parse(html); 138 | 139 | Elements p = doc.getElementsByTag("p"); 140 | MeiziTu meiziTu; 141 | Element img; 142 | for (int i = 0; i < 15; i++) { 143 | meiziTu = new MeiziTu(); 144 | img = p.get(i).select("img").first(); 145 | String src = img.attr("src"); 146 | String title = img.attr("alt"); 147 | meiziTu.setOrder(i); 148 | meiziTu.setType(type); 149 | meiziTu.setWidth(0); 150 | meiziTu.setHeight(0); 151 | meiziTu.setImageurl(src); 152 | meiziTu.setTitle(title); 153 | list.add(meiziTu); 154 | } 155 | return list; 156 | } 157 | 158 | 159 | /** 160 | * 获取妹子图的GroupId 161 | */ 162 | private int url2groupid(String url) { 163 | 164 | return Integer.parseInt(url.split("/")[3]); 165 | } 166 | 167 | 168 | /** 169 | * 保存妹子图数据到数据库中 170 | */ 171 | public void putMeiziTuCache(List list) { 172 | 173 | Realm realm = Realm.getDefaultInstance(); 174 | realm.beginTransaction(); 175 | realm.copyToRealmOrUpdate(list); 176 | realm.commitTransaction(); 177 | realm.close(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/PreferencesLoader.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.preference.PreferenceManager; 6 | 7 | /** 8 | * Created by hcc on 16/6/25 18:05 9 | * 100332338@qq.com 10 | */ 11 | public class PreferencesLoader { 12 | 13 | private SharedPreferences mSharedPreferences; 14 | 15 | private Context mContext; 16 | 17 | 18 | public PreferencesLoader(Context context) { 19 | 20 | mContext = context; 21 | mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); 22 | } 23 | 24 | 25 | public void saveBoolean(int keyResId, Boolean value) { 26 | 27 | String key = mContext.getString(keyResId); 28 | saveBoolean(key, value); 29 | } 30 | 31 | 32 | public void saveBoolean(String key, Boolean value) { 33 | 34 | SharedPreferences.Editor editor = mSharedPreferences.edit(); 35 | editor.putBoolean(key, value); 36 | editor.apply(); 37 | } 38 | 39 | 40 | public Boolean getBoolean(String key) { 41 | 42 | return mSharedPreferences.getBoolean(key, false); 43 | } 44 | 45 | 46 | public Boolean getBoolean(String key, boolean def) { 47 | 48 | return mSharedPreferences.getBoolean(key, def); 49 | } 50 | 51 | 52 | public Boolean getBoolean(int keyResId, boolean def) { 53 | 54 | String key = mContext.getString(keyResId); 55 | return mSharedPreferences.getBoolean(key, def); 56 | } 57 | 58 | 59 | public int getInt(String key) { 60 | 61 | return mSharedPreferences.getInt(key, 0); 62 | } 63 | 64 | 65 | public void saveInt(String key, int value) { 66 | 67 | SharedPreferences.Editor editor = mSharedPreferences.edit(); 68 | editor.putInt(key, value); 69 | editor.apply(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/ShareUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | 7 | /** 8 | * Created by hcc on 16/6/25 18:05 9 | * 100332338@qq.com 10 | */ 11 | public class ShareUtil { 12 | 13 | /** 14 | * 分享链接 15 | */ 16 | public static void shareLink(String url, String title, Context context) { 17 | 18 | Intent intent = new Intent(Intent.ACTION_SEND); 19 | intent.setType("text/plain"); 20 | intent.putExtra(Intent.EXTRA_SUBJECT, "分享"); 21 | intent.putExtra(Intent.EXTRA_TEXT, "来自「萌妹」的分享:" + url); 22 | context.startActivity(Intent.createChooser(intent, title)); 23 | } 24 | 25 | 26 | /** 27 | * 分享图片 28 | */ 29 | public static void sharePic(Uri uri, String desc, Context context) { 30 | 31 | Intent shareIntent = new Intent(); 32 | shareIntent.setAction(Intent.ACTION_SEND); 33 | shareIntent.putExtra(Intent.EXTRA_STREAM, uri); 34 | shareIntent.setType("image/jpeg"); 35 | context.startActivity(Intent.createChooser(shareIntent, desc)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/SnackbarUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import android.support.design.widget.Snackbar; 4 | import android.view.View; 5 | 6 | public class SnackbarUtil { 7 | 8 | public static void showMessage(View view, String text) { 9 | 10 | Snackbar.make(view, text, Snackbar.LENGTH_SHORT).show(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/utils/SystemUiVisibilityUtil.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.utils; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * 系统NavBar工具类 7 | */ 8 | public class SystemUiVisibilityUtil { 9 | 10 | public static void addFlags(View view, int flags) { 11 | 12 | view.setSystemUiVisibility(view.getSystemUiVisibility() | flags); 13 | } 14 | 15 | 16 | public static void clearFlags(View view, int flags) { 17 | 18 | view.setSystemUiVisibility(view.getSystemUiVisibility() & ~flags); 19 | } 20 | 21 | 22 | public static boolean hasFlags(View view, int flags) { 23 | 24 | return (view.getSystemUiVisibility() & flags) == flags; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/widget/DepthTransFormes.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.widget; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by hcc on 16/6/25 17:23 8 | * 100332338@qq.com 9 | *

10 | * Google官方ViewPager切换动画 11 | */ 12 | public class DepthTransFormes implements ViewPager.PageTransformer { 13 | 14 | private static final float MIN_SCALE = 0.75f; 15 | 16 | 17 | public void transformPage(View view, float position) { 18 | 19 | int pageWidth = view.getWidth(); 20 | 21 | if (position < -1) { // [-Infinity,-1) 22 | // This page is way off-screen to the left. 23 | view.setAlpha(0); 24 | } else if (position <= 0) { // [-1,0] 25 | // Use the default slide transition when moving to the left page 26 | view.setAlpha(1); 27 | view.setTranslationX(0); 28 | view.setScaleX(1); 29 | view.setScaleY(1); 30 | } else if (position <= 1) { // (0,1] 31 | // Fade the page out. 32 | view.setAlpha(1 - position); 33 | 34 | // Counteract the default slide transition 35 | view.setTranslationX(pageWidth * -position); 36 | 37 | // Scale the page down (between MIN_SCALE and 1) 38 | float scaleFactor = MIN_SCALE 39 | + (1 - MIN_SCALE) * (1 - Math.abs(position)); 40 | view.setScaleX(scaleFactor); 41 | view.setScaleY(scaleFactor); 42 | } else { // (1,+Infinity] 43 | // This page is way off-screen to the right. 44 | view.setAlpha(0); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/widget/HackyViewPager.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.widget; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | 8 | public class HackyViewPager extends ViewPager { 9 | 10 | public HackyViewPager(Context context) { 11 | 12 | super(context); 13 | } 14 | 15 | 16 | public HackyViewPager(Context context, AttributeSet attrs) { 17 | 18 | super(context, attrs); 19 | } 20 | 21 | 22 | @Override 23 | protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { 24 | 25 | if (v instanceof PhotoImageView) { 26 | return ((PhotoImageView) v).canScrollHorizontallyFroyo(-dx); 27 | } else { 28 | return super.canScroll(v, checkV, dx, x, y); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/hotbitmapgg/moequest/widget/RatioImageView.java: -------------------------------------------------------------------------------- 1 | package com.hotbitmapgg.moequest.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | public class RatioImageView extends ImageView { 8 | 9 | private int originalWidth; 10 | 11 | private int originalHeight; 12 | 13 | 14 | public RatioImageView(Context context) { 15 | 16 | super(context); 17 | } 18 | 19 | 20 | public RatioImageView(Context context, AttributeSet attrs) { 21 | 22 | super(context, attrs); 23 | } 24 | 25 | 26 | public RatioImageView(Context context, AttributeSet attrs, int defStyleAttr) { 27 | 28 | super(context, attrs, defStyleAttr); 29 | } 30 | 31 | 32 | public void setOriginalSize(int originalWidth, int originalHeight) { 33 | 34 | this.originalWidth = originalWidth; 35 | this.originalHeight = originalHeight; 36 | } 37 | 38 | 39 | @Override 40 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 41 | 42 | if (originalWidth > 0 && originalHeight > 0) { 43 | float ratio = (float) originalWidth / (float) originalHeight; 44 | 45 | int width = MeasureSpec.getSize(widthMeasureSpec); 46 | int height = MeasureSpec.getSize(heightMeasureSpec); 47 | 48 | if (width > 0) { 49 | height = (int) ((float) width / ratio); 50 | } 51 | 52 | setMeasuredDimension(width, height); 53 | } else { 54 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/bow_tie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/bow_tie.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/flower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/flower.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/high_importance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/high_importance.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/ic_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/ic_download.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_favorite_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/ic_favorite_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/ic_location.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/ic_share.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_slide_menu_avatar_no_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/ic_slide_menu_avatar_no_login.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/notification_bg3.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/notification_bg3.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/picture.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/placeholder_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/placeholder_image.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/share.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/wedding_dress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/wedding_dress.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/year_of_rooster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-hdpi/year_of_rooster.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar10.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar11.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar5.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar6.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar7.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar8.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ic_avatar9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-nodpi/ic_avatar9.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-xxhdpi/bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable-xxhdpi/ic_bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_card.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/drawable/bg_card.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_transparency_to_grey.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/notification_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shadow_gradient_reserve.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 18 | 19 | 27 | 28 | 29 | 30 | 31 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_meizi_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_meizi_pic.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 20 | 21 | 22 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_tao_female.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_tao_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/card_item_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 21 | 22 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_douban_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_gank_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_huaban_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 21 | 22 | 23 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_jiandan_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_meizi_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_meizitu.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_simple_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_huaban_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 21 | 22 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_jiandan_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 16 | 17 | 23 | 24 | 28 | 29 | 37 | 38 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_tao_female.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 16 | 17 | 18 | 26 | 27 | 28 | 37 | 38 | 46 | 47 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 81 | 82 | 83 | 84 | 85 | 91 | 92 | 93 | 99 | 100 | 101 | 107 | 108 | 114 | 115 | 116 | 117 | 118 | 124 | 125 | 126 | 132 | 133 | 134 | 140 | 141 | 142 | 143 | 144 | 151 | 152 | 153 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/load_more_foot_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nav_header_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 15 | 16 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/notification.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 16 | 17 | 28 | 29 | 39 | 40 | 41 | 52 | 53 | 62 | 63 | 71 | 72 | 79 | 80 | 87 | 88 | 96 | 97 | 98 | 105 | 106 | 113 | 114 | 123 | 124 | 125 | 132 | 133 | 140 | 141 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /app/src/main/res/layout/notification_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_meizi.xml: -------------------------------------------------------------------------------- 1 | 2 |

4 | 5 | 6 | 12 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_nav.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 16 | 17 | 22 | 26 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/MoeQuest/d53ad3f0b409cadff610e4a79ea6e694326503f0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v19/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 19 | 20 | 21 | 29 | 30 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/attr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #fb7299 4 | #b85671 5 | #99f0486c 6 | #555555 7 | #dd000000 8 | #808080 9 | #e0e0e0 10 | #00000000 11 | #ffffff 12 | #212121 13 | #727272 14 | #B6B6B6 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 206dp 4 | 300dp 5 | 6 | 3dp 7 | 300dp 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 萌妹纸 3 | Open navigation drawer 4 | Close navigation drawer 5 | 哎呀,加载失败了,请检查下网络或者下拉重新刷新下~ 6 | 图片加载失败啦~ 7 | 再按一次退出萌妹纸 8 | 萌妹纸 9 | 妹纸图 10 | 淘女郎 11 | 豆瓣妹纸 12 | 花瓣妹纸 13 | 煎蛋妹纸 14 | 每天中午提醒 15 | 萌妹 16 | 今天的妹纸已经准备好了,快来享用吧~ 17 | app icon 18 | 「萌妹纸」- 每日更新妹纸福利图 19 | 关于我 20 | 联系我 21 | 介绍与帮助 22 | 微博:HotBitmapGG\n\nQQ:100332338 23 | 1.0 24 | https://github.com/HotBitmapGG/MoeQuest 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 16 | 17 | 20 | 21 |