├── .gitignore ├── LICENSE.txt ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── tencentX5WebView.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── cnsunrun │ │ └── debugdemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── cnsunrun │ │ │ └── debugdemo │ │ │ ├── DebugDemoApp.java │ │ │ ├── app │ │ │ ├── AppConstant.java │ │ │ ├── ApplicationComponent.java │ │ │ └── ApplicationModule.java │ │ │ ├── mvp │ │ │ ├── base │ │ │ │ ├── IBasePresenter.java │ │ │ │ └── IBaseView.java │ │ │ ├── contract │ │ │ │ ├── CopyListContract.java │ │ │ │ └── QuanziListContract.java │ │ │ ├── model │ │ │ │ ├── bean │ │ │ │ │ ├── CopyDetailsInfo.java │ │ │ │ │ ├── CopyInfo.java │ │ │ │ │ ├── QuanziDetailsInfo.java │ │ │ │ │ ├── QuanziInfo.java │ │ │ │ │ └── base │ │ │ │ │ │ └── BaseResponseInfo.java │ │ │ │ └── network │ │ │ │ │ ├── RetrofitHelper.java │ │ │ │ │ └── api │ │ │ │ │ ├── ICopyService.java │ │ │ │ │ └── IQuanziService.java │ │ │ ├── presenter │ │ │ │ ├── CopyListPresenter.java │ │ │ │ ├── QuanziListPresenter.java │ │ │ │ └── base │ │ │ │ │ └── PresenterComponent.java │ │ │ └── ui │ │ │ │ ├── activity │ │ │ │ ├── CopyDetailsActivity.java │ │ │ │ ├── ImageDetailsActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── QuanziDetailsActivity.java │ │ │ │ ├── component │ │ │ │ │ ├── CopyListComponent.java │ │ │ │ │ └── QuanziListComponent.java │ │ │ │ └── module │ │ │ │ │ ├── CopyListModule.java │ │ │ │ │ └── QuanziListModule.java │ │ │ │ ├── adapter │ │ │ │ ├── CommentAdapter.java │ │ │ │ ├── CopyAdapter.java │ │ │ │ ├── CopyDetailsAdapter.java │ │ │ │ ├── QuanziAdapter.java │ │ │ │ └── base │ │ │ │ │ ├── AbsRecyclerViewAdapter.java │ │ │ │ │ ├── EndlessRecyclerOnScrollListener.java │ │ │ │ │ └── HeaderViewRecyclerAdapter.java │ │ │ │ └── fragment │ │ │ │ ├── CommunityFragment.java │ │ │ │ ├── CopyListFragment.java │ │ │ │ ├── ImageDetailsFragment.java │ │ │ │ ├── MineFragment.java │ │ │ │ └── QuanziListFragment.java │ │ │ ├── utils │ │ │ ├── ActivityScoped.java │ │ │ ├── ActivityUtils.java │ │ │ ├── DisplayUtil.java │ │ │ └── ImgUrlUtil.java │ │ │ └── widget │ │ │ ├── CircleImageView.java │ │ │ ├── CircleProgressView.java │ │ │ └── MomentPicView.java │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_logo.png │ │ ├── ic_tab_community.png │ │ ├── ic_tab_home.png │ │ ├── ic_tab_mine.png │ │ └── ic_tab_quanzi.png │ │ ├── drawable-xhdpi │ │ └── ic_placeholder.png │ │ ├── drawable-xxhdpi │ │ ├── bg_announcement.9.png │ │ ├── ic_arrow_right_gray.png │ │ ├── ic_event_album.png │ │ ├── ic_event_bbs.png │ │ ├── ic_event_tag.png │ │ ├── ic_event_time.png │ │ ├── ic_event_topic.png │ │ ├── ic_event_user.png │ │ ├── ic_hot_topic_detail.png │ │ ├── ic_no_module.png │ │ ├── ic_original_topic_detail.png │ │ ├── ic_tag.png │ │ ├── ic_uncomment_chart.png │ │ ├── ic_unfavour_heart.png │ │ └── ic_water_comment.png │ │ ├── drawable │ │ ├── bg_message_board_in_online_event.xml │ │ ├── bg_tag_secondary.xml │ │ ├── bg_topic_tag.xml │ │ ├── bg_type.xml │ │ └── divider_gray.xml │ │ ├── layout │ │ ├── activity_copy_details.xml │ │ ├── activity_image_details.xml │ │ ├── activity_main.xml │ │ ├── activity_quanzi_details.xml │ │ ├── fragment_community.xml │ │ ├── fragment_copy_list.xml │ │ ├── fragment_image_details.xml │ │ ├── fragment_mine.xml │ │ ├── fragment_quanzi_list.xml │ │ ├── item_comment.xml │ │ ├── item_copy.xml │ │ ├── item_copy_details.xml │ │ ├── item_quanzi.xml │ │ ├── layout_head_copy_details.xml │ │ ├── layout_item_tag.xml │ │ ├── layout_load_more.xml │ │ ├── layout_loading.xml │ │ └── layout_toolbar.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 │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── cnsunrun │ └── debugdemo │ └── ExampleUnitTest.java ├── art ├── 01.png ├── 02.png └── 03.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 | .externalNativeBuild 10 | 11 | .idea/compiler.xml 12 | 13 | .idea/copyright/profiles_settings.xml 14 | 15 | .idea/dictionaries/hcc.xml 16 | 17 | .idea/encodings.xml 18 | 19 | .idea/gradle.xml 20 | 21 | .idea/misc.xml 22 | 23 | .idea/modules.xml 24 | 25 | .idea/runConfigurations.xml 26 | .idea/vcs.xml 27 | .idea/workspace.xml___jb_tmp___ 28 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | 3 | Everyone is permitted to copy and distribute verbatim or modified 4 | copies of this license document, and changing it is allowed as long 5 | as the name is changed. 6 | 7 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 8 | 9 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 10 | 11 | 0. You just DO WHAT THE FUCK YOU WANT TO. 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Acg 2 | 3 | A acg community of app 4 | 5 | ## Screenshots 6 | 7 | 8 | 9 | ## instructions 10 | 11 | This app is fetching JUJU network apis to implement a acg community projects, like a friend to a star support, thank you. 12 | 13 | ## About me 14 | 15 | [![Wercker](https://img.shields.io/badge/weibo-HotBitmapGG-blue.svg)](http://weibo.com/3223089177/profile?topnav=1&wvr=6&is_all=1) 16 | 17 | An android developer in Wuhan. 18 | 19 | If you want to make friends with me, You can focus on my weibo. 20 | 21 | 22 | ## License 23 | 24 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 25 | 26 | Everyone is permitted to copy and distribute verbatim or modified 27 | copies of this license document, and changing it is allowed as long 28 | as the name is changed. 29 | 30 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 31 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 32 | 33 | You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /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 'com.neenbedankt.gradle.plugins:android-apt:1.8' 8 | classpath 'me.tatarka:gradle-retrolambda:3.2.5' 9 | } 10 | } 11 | apply plugin: 'com.android.application' 12 | apply plugin: 'com.neenbedankt.android-apt' 13 | apply plugin: 'me.tatarka.retrolambda' 14 | 15 | android { 16 | compileSdkVersion 25 17 | buildToolsVersion "25.0.2" 18 | defaultConfig { 19 | applicationId "com.example.cnsunrun.debugdemo" 20 | minSdkVersion 19 21 | targetSdkVersion 25 22 | versionCode 1 23 | versionName "1.0" 24 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 25 | } 26 | buildTypes { 27 | release { 28 | minifyEnabled false 29 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 30 | } 31 | } 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | } 38 | 39 | dependencies { 40 | compile fileTree(include: ['*.jar'], dir: 'libs') 41 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 42 | exclude group: 'com.android.support', module: 'support-annotations' 43 | }) 44 | testCompile 'junit:junit:4.12' 45 | //Android Libs 46 | compile 'com.android.support:appcompat-v7:25.3.1' 47 | compile 'com.android.support:cardview-v7:25.3.1' 48 | compile 'com.android.support:design:25.3.1' 49 | //Retrofit2 50 | compile 'com.squareup.retrofit2:retrofit:2.2.0' 51 | compile 'com.squareup.retrofit2:converter-gson:2.0.1' 52 | compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' 53 | //OkHttp3 54 | compile 'com.squareup.okhttp3:okhttp:3.6.0' 55 | compile 'com.squareup.okhttp3:logging-interceptor:3.6.0' 56 | //RxJava2 57 | compile 'io.reactivex.rxjava2:rxjava:2.0.2' 58 | compile 'io.reactivex.rxjava2:rxandroid:2.0.1' 59 | //黄油刀注解7.x 60 | compile 'com.jakewharton:butterknife:7.0.1' 61 | //Glide 图片加载库 62 | compile 'com.github.bumptech.glide:glide:3.7.0' 63 | compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar' 64 | //stream流式操作辅助库 65 | compile 'com.annimon:stream:1.1.4' 66 | //BottomNavigationView 67 | compile 'com.aurelhubert:ahbottomnavigation:2.0.1' 68 | //RecyclerView Load More 69 | compile 'com.github.nukc:loadmorewrapper:1.6' 70 | //标签布局 71 | compile 'com.zhy:flowlayout-lib:1.0.3' 72 | //PhotoView 73 | compile 'com.github.chrisbanes:PhotoView:1.2.6' 74 | //Dagger2 依赖注入库 75 | apt 'com.google.dagger:dagger-compiler:2.2' 76 | compile 'com.google.dagger:dagger:2.2' 77 | provided 'javax.annotation:jsr250-api:1.0' 78 | } 79 | -------------------------------------------------------------------------------- /app/libs/tencentX5WebView.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/libs/tencentX5WebView.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/cnsunrun/debugdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.example.cnsunrun.debugdemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/DebugDemoApp.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo; 2 | 3 | import android.app.Application; 4 | import android.os.StrictMode; 5 | 6 | import com.example.cnsunrun.debugdemo.app.ApplicationComponent; 7 | import com.example.cnsunrun.debugdemo.app.ApplicationModule; 8 | import com.example.cnsunrun.debugdemo.app.DaggerApplicationComponent; 9 | 10 | /** 11 | * Created by cnsunrun on 2017/3/15. 12 | */ 13 | 14 | public class DebugDemoApp extends Application { 15 | 16 | private static DebugDemoApp mAppContext; 17 | 18 | private ApplicationComponent applicationComponent; 19 | 20 | @Override 21 | public void onCreate() { 22 | super.onCreate(); 23 | mAppContext = this; 24 | init(); 25 | } 26 | 27 | private void init() { 28 | if (BuildConfig.DEBUG) { 29 | StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); 30 | StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build()); 31 | } 32 | 33 | applicationComponent = DaggerApplicationComponent.builder() 34 | .applicationModule(new ApplicationModule(this)) 35 | .build(); 36 | } 37 | 38 | public static DebugDemoApp getAppContext() { 39 | return mAppContext; 40 | } 41 | 42 | public ApplicationComponent getApplicationComponent() { 43 | return applicationComponent; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/app/AppConstant.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.app; 2 | 3 | /** 4 | * Created by cnsunrun on 2017/4/18. 5 | *

6 | * 13489841 13489375 7 | */ 8 | 9 | public class AppConstant { 10 | 11 | public static final String SUCCESS_CODE = "10000"; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/app/ApplicationComponent.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.app; 2 | 3 | import android.content.Context; 4 | 5 | import com.example.cnsunrun.debugdemo.DebugDemoApp; 6 | 7 | import javax.inject.Singleton; 8 | 9 | import dagger.Component; 10 | 11 | 12 | @Singleton 13 | @Component(modules = {ApplicationModule.class}) 14 | public interface ApplicationComponent { 15 | 16 | DebugDemoApp getApplication(); 17 | 18 | Context getContext(); 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/app/ApplicationModule.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.app; 2 | 3 | import android.content.Context; 4 | 5 | import com.example.cnsunrun.debugdemo.DebugDemoApp; 6 | 7 | import javax.inject.Singleton; 8 | 9 | import dagger.Module; 10 | import dagger.Provides; 11 | 12 | 13 | @Module 14 | public class ApplicationModule { 15 | 16 | private Context context; 17 | 18 | public ApplicationModule(Context context) { 19 | 20 | this.context = context; 21 | } 22 | 23 | @Provides 24 | @Singleton 25 | DebugDemoApp provideApplication() { 26 | 27 | return (DebugDemoApp) context.getApplicationContext(); 28 | } 29 | 30 | @Provides 31 | @Singleton 32 | Context provideContext() { 33 | 34 | return context; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/base/IBasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.base; 2 | 3 | /** 4 | * presenter interface,所有Presenter必须实现此接口 5 | */ 6 | public interface IBasePresenter { 7 | 8 | void subscribe(); 9 | 10 | void unSubscribe(); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/base/IBaseView.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.base; 2 | 3 | /** 4 | * view interface,所有View(此项目中的View主要是Fragment和自定义的ViewGroup)必须实现此接口 5 | */ 6 | 7 | public interface IBaseView { 8 | void setPresenter(T presenter); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/contract/CopyListContract.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.contract; 2 | 3 | import com.example.cnsunrun.debugdemo.mvp.base.IBasePresenter; 4 | import com.example.cnsunrun.debugdemo.mvp.base.IBaseView; 5 | import com.example.cnsunrun.debugdemo.mvp.model.bean.CopyInfo; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Created by cnsunrun on 2017/4/19. 11 | */ 12 | 13 | public interface CopyListContract { 14 | 15 | interface View extends IBaseView { 16 | void displayData(List copyInfos); 17 | } 18 | 19 | interface Presenter extends IBasePresenter { 20 | void loadData(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/contract/QuanziListContract.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.contract; 2 | 3 | import com.example.cnsunrun.debugdemo.mvp.base.IBasePresenter; 4 | import com.example.cnsunrun.debugdemo.mvp.base.IBaseView; 5 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziInfo; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Created by cnsunrun on 2017/3/17. 11 | */ 12 | 13 | public interface QuanziListContract { 14 | 15 | interface View extends IBaseView { 16 | void displayData(List quanziInfos); 17 | } 18 | 19 | interface Presenter extends IBasePresenter { 20 | void loadData(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/model/bean/CopyInfo.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.model.bean; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by cnsunrun on 2017/4/19. 9 | *

10 | * 副本列表模型类 11 | */ 12 | 13 | public class CopyInfo { 14 | 15 | 16 | @SerializedName("activityo.hasnotice") 17 | private String activityoHasnotice; 18 | @SerializedName("activityo.list") 19 | private List activityoListBeans; 20 | 21 | public String getActivityoHasnotice() { 22 | return activityoHasnotice; 23 | } 24 | 25 | public void setActivityoHasnotice(String activityoHasnotice) { 26 | this.activityoHasnotice = activityoHasnotice; 27 | } 28 | 29 | public List getActivityoListBeans() { 30 | return activityoListBeans; 31 | } 32 | 33 | public void setActivityoListBeans(List activityoListBeans) { 34 | this.activityoListBeans = activityoListBeans; 35 | } 36 | 37 | public static class ActivityoListBean { 38 | /** 39 | * activityid : 1002549 40 | * picture : http://juheadpic.juju.la/group/cc10a9ad5460f3715d6baaf76bd91065.png 41 | * name : 刀剑乱舞国服 42 | * user_name : JUJU审核菌 43 | * timestr : null 44 | * form : 其他 45 | * counter : 132 46 | * iscreate : -1 47 | */ 48 | 49 | private String activityid; 50 | private String picture; 51 | private String name; 52 | private String user_name; 53 | private Object timestr; 54 | private String form; 55 | private String counter; 56 | private int iscreate; 57 | 58 | public String getActivityid() { 59 | return activityid; 60 | } 61 | 62 | public void setActivityid(String activityid) { 63 | this.activityid = activityid; 64 | } 65 | 66 | public String getPicture() { 67 | return picture; 68 | } 69 | 70 | public void setPicture(String picture) { 71 | this.picture = picture; 72 | } 73 | 74 | public String getName() { 75 | return name; 76 | } 77 | 78 | public void setName(String name) { 79 | this.name = name; 80 | } 81 | 82 | public String getUser_name() { 83 | return user_name; 84 | } 85 | 86 | public void setUser_name(String user_name) { 87 | this.user_name = user_name; 88 | } 89 | 90 | public Object getTimestr() { 91 | return timestr; 92 | } 93 | 94 | public void setTimestr(Object timestr) { 95 | this.timestr = timestr; 96 | } 97 | 98 | public String getForm() { 99 | return form; 100 | } 101 | 102 | public void setForm(String form) { 103 | this.form = form; 104 | } 105 | 106 | public String getCounter() { 107 | return counter; 108 | } 109 | 110 | public void setCounter(String counter) { 111 | this.counter = counter; 112 | } 113 | 114 | public int getIscreate() { 115 | return iscreate; 116 | } 117 | 118 | public void setIscreate(int iscreate) { 119 | this.iscreate = iscreate; 120 | } 121 | 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/model/bean/base/BaseResponseInfo.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.model.bean.base; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * Created by cnsunrun on 2017/3/15. 7 | */ 8 | 9 | public class BaseResponseInfo { 10 | 11 | @SerializedName("code") 12 | public String code; 13 | @SerializedName("message") 14 | public String message; 15 | @SerializedName("result") 16 | public T result; 17 | @SerializedName("sid") 18 | public String sid; 19 | 20 | public String getCode() { 21 | return code; 22 | } 23 | 24 | public String getMessage() { 25 | return message; 26 | } 27 | 28 | 29 | public T getBaseResult() { 30 | return result; 31 | } 32 | 33 | 34 | public String getSid() { 35 | return sid; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/model/network/RetrofitHelper.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.model.network; 2 | 3 | import com.example.cnsunrun.debugdemo.DebugDemoApp; 4 | import com.example.cnsunrun.debugdemo.mvp.model.network.api.ICopyService; 5 | import com.example.cnsunrun.debugdemo.mvp.model.network.api.IQuanziService; 6 | import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 7 | 8 | import java.io.File; 9 | import java.util.concurrent.TimeUnit; 10 | 11 | import okhttp3.Cache; 12 | import okhttp3.OkHttpClient; 13 | import okhttp3.logging.HttpLoggingInterceptor; 14 | import retrofit2.Retrofit; 15 | import retrofit2.converter.gson.GsonConverterFactory; 16 | 17 | /** 18 | * Created by cnsunrun on 2017/3/11. 19 | */ 20 | 21 | public class RetrofitHelper { 22 | 23 | private static OkHttpClient mOkHttpClient; 24 | 25 | public static final String BASE_URL = "http://server.juju.la/"; 26 | 27 | static { 28 | initOkHttpClient(); 29 | } 30 | 31 | /** 32 | * 创建圈子网络请求 33 | * 34 | * @return 35 | */ 36 | public static IQuanziService createQuanziService() { 37 | Retrofit retrofit = new Retrofit.Builder() 38 | .baseUrl(BASE_URL) 39 | .client(mOkHttpClient) 40 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 41 | .addConverterFactory(GsonConverterFactory.create()) 42 | .build(); 43 | return retrofit.create(IQuanziService.class); 44 | } 45 | 46 | 47 | /** 48 | * 创建副本网络请求 49 | * 50 | * @return 51 | */ 52 | public static ICopyService createCopyService() { 53 | Retrofit retrofit = new Retrofit.Builder() 54 | .baseUrl(BASE_URL) 55 | .client(mOkHttpClient) 56 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 57 | .addConverterFactory(GsonConverterFactory.create()) 58 | .build(); 59 | return retrofit.create(ICopyService.class); 60 | } 61 | 62 | 63 | /** 64 | * 初始化OKHttpClient 65 | */ 66 | private static void initOkHttpClient() { 67 | 68 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); 69 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 70 | if (mOkHttpClient == null) { 71 | synchronized (RetrofitHelper.class) { 72 | if (mOkHttpClient == null) { 73 | //设置Http缓存 74 | Cache cache = new Cache( 75 | new File(DebugDemoApp.getAppContext().getCacheDir(), "HttpCache"), 76 | 1024 * 1024 * 100); 77 | 78 | mOkHttpClient = new OkHttpClient.Builder() 79 | .cache(cache) 80 | // .addNetworkInterceptor(new CacheInterceptor()) 81 | .addInterceptor(interceptor) 82 | .retryOnConnectionFailure(true) 83 | .connectTimeout(15, TimeUnit.SECONDS) 84 | .build(); 85 | } 86 | } 87 | } 88 | } 89 | 90 | 91 | // /** 92 | // * 添加Okhttp缓存拦截器 93 | // */ 94 | // private static class CacheInterceptor implements Interceptor { 95 | // 96 | // @Override 97 | // public Response intercept(Chain chain) throws IOException { 98 | // 99 | // // 有网络时 设置缓存超时时间1个小时 100 | // int maxAge = 60 * 60; 101 | // // 无网络时,设置超时为1天 102 | // int maxStale = 60 * 60 * 24; 103 | // Request request = chain.request(); 104 | // if (NetWorkUtil.isNetworkConnected()) { 105 | // //有网络时只从网络获取 106 | // request = request.newBuilder() 107 | // .cacheControl(CacheControl.FORCE_NETWORK) 108 | // .build(); 109 | // } else { 110 | // //无网络时只从缓存中读取 111 | // request = request.newBuilder() 112 | // .cacheControl(CacheControl.FORCE_CACHE) 113 | // .build(); 114 | // } 115 | // Response response = chain.proceed(request); 116 | // if (NetWorkUtil.isNetworkConnected()) { 117 | // response = response.newBuilder() 118 | // .removeHeader("Pragma") 119 | // .header("Cache-Control", "public, max-age=" + maxAge) 120 | // .build(); 121 | // } else { 122 | // response = response.newBuilder() 123 | // .removeHeader("Pragma") 124 | // .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) 125 | // .build(); 126 | // } 127 | // return response; 128 | // } 129 | // } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/model/network/api/ICopyService.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.model.network.api; 2 | 3 | import com.example.cnsunrun.debugdemo.mvp.model.bean.CopyDetailsInfo; 4 | import com.example.cnsunrun.debugdemo.mvp.model.bean.CopyInfo; 5 | import com.example.cnsunrun.debugdemo.mvp.model.bean.base.BaseResponseInfo; 6 | 7 | import io.reactivex.Flowable; 8 | import retrofit2.http.GET; 9 | import retrofit2.http.Headers; 10 | import retrofit2.http.Query; 11 | 12 | /** 13 | * Created by cnsunrun on 2017/4/19. 14 | *

15 | * http://server.juju.la/activityo/activityolist?pageid=1&form=1&sid=d89a68bddc0784e750f6f841eeb61647# 16 | */ 17 | 18 | public interface ICopyService { 19 | 20 | /** 21 | * 获取副本列表 22 | * 23 | * @param pageId 24 | * @param form 25 | * @param sid 26 | * @return 27 | */ 28 | @Headers({"Juju-Token: e2768897c0e5b4ba9e13ed7edf1ef8da", "Juju-Banben: A262", "User-Agent: Juju Android Client"}) 29 | @GET("activityo/activityolist") 30 | Flowable> getCopys(@Query("pageid") int pageId, 31 | @Query("form") int form, 32 | @Query("sid") String sid); 33 | 34 | /** 35 | * 获取副本详情 36 | * 37 | * @param activityid 38 | * @param sid 39 | * @return 40 | */ 41 | @Headers({"Juju-Token: e2768897c0e5b4ba9e13ed7edf1ef8da", "Juju-Banben: A262", "User-Agent: Juju Android Client"}) 42 | @GET("activityo/activityodetail") 43 | Flowable getCopyDetails(@Query("activityid") String activityid, 44 | @Query("sid") String sid); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/model/network/api/IQuanziService.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.model.network.api; 2 | 3 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziDetailsInfo; 4 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziInfo; 5 | import com.example.cnsunrun.debugdemo.mvp.model.bean.base.BaseResponseInfo; 6 | 7 | import io.reactivex.Flowable; 8 | import retrofit2.http.GET; 9 | import retrofit2.http.Headers; 10 | import retrofit2.http.Query; 11 | 12 | /** 13 | * Created by cnsunrun on 2017/3/11. 14 | *

15 | * lastid=-1&activityid=-1&hotlastid=-1&type=1&userid=-1&dynamicuserids=1111&sid=dbe5b18fe665dbc25d22cdeb2d5cc436# 16 | */ 17 | 18 | public interface IQuanziService { 19 | 20 | /** 21 | * 获取圈子列表数据 22 | * 23 | * @param lastid 24 | * @param activityid 25 | * @param hotlastid 26 | * @param type 27 | * @param userid 28 | * @param dynamicuserids 29 | * @param sid 30 | * @return 31 | */ 32 | @Headers({"Juju-Token: e2768897c0e5b4ba9e13ed7edf1ef8da", "Juju-Banben: A262", "User-Agent: Juju Android Client"}) 33 | @GET("newblog/bloglist") 34 | Flowable> getQuanziInfos(@Query("lastid") long lastid, 35 | @Query("activityid") long activityid, 36 | @Query("hotlastid") long hotlastid, 37 | @Query("type") int type, 38 | @Query("userid") int userid, 39 | @Query("dynamicuserids") int dynamicuserids, 40 | @Query("sid") String sid); 41 | 42 | 43 | /** 44 | * 获取圈子详情数据 45 | * 46 | * @param blogid 47 | * @param sid 48 | * @return 49 | */ 50 | @Headers({"Juju-Token: e2768897c0e5b4ba9e13ed7edf1ef8da", "Juju-Banben: A262", "User-Agent: Juju Android Client"}) 51 | @GET("newblog/blogview") 52 | Flowable> getQuanziDetailsInfo(@Query("blogid") String blogid, 53 | @Query("sid") String sid); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/presenter/CopyListPresenter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.presenter; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.example.cnsunrun.debugdemo.app.AppConstant; 7 | import com.example.cnsunrun.debugdemo.app.ApplicationModule; 8 | import com.example.cnsunrun.debugdemo.mvp.contract.CopyListContract; 9 | import com.example.cnsunrun.debugdemo.mvp.model.network.RetrofitHelper; 10 | import com.example.cnsunrun.debugdemo.mvp.presenter.base.DaggerPresenterComponent; 11 | import com.example.cnsunrun.debugdemo.utils.ActivityScoped; 12 | 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import javax.inject.Inject; 16 | 17 | import io.reactivex.android.schedulers.AndroidSchedulers; 18 | import io.reactivex.disposables.CompositeDisposable; 19 | import io.reactivex.disposables.Disposable; 20 | import io.reactivex.schedulers.Schedulers; 21 | 22 | /** 23 | * Created by cnsunrun on 2017/4/19. 24 | */ 25 | @ActivityScoped 26 | public class CopyListPresenter implements CopyListContract.Presenter { 27 | 28 | private CopyListContract.View view; 29 | 30 | private CompositeDisposable compositeDisposable; 31 | 32 | @Inject 33 | CopyListPresenter(Context context, CopyListContract.View view) { 34 | this.view = view; 35 | view.setPresenter(this); 36 | compositeDisposable = new CompositeDisposable(); 37 | 38 | DaggerPresenterComponent.builder() 39 | .applicationModule(new ApplicationModule(context)) 40 | .build().inject(this); 41 | } 42 | 43 | @Override 44 | public void subscribe() { 45 | loadData(); 46 | } 47 | 48 | @Override 49 | public void unSubscribe() { 50 | compositeDisposable.clear(); 51 | } 52 | 53 | @Override 54 | public void loadData() { 55 | 56 | Disposable subscribe = RetrofitHelper.createCopyService() 57 | .getCopys(1, 1, "d89a68bddc0784e750f6f841eeb61647#") 58 | .delay(1000, TimeUnit.MILLISECONDS) 59 | .filter(copyInfoBaseResponseInfo -> copyInfoBaseResponseInfo.getCode().equals(AppConstant.SUCCESS_CODE)) 60 | .map(copyInfoBaseResponseInfo -> copyInfoBaseResponseInfo.getBaseResult().getActivityoListBeans()) 61 | .subscribeOn(Schedulers.io()) 62 | .observeOn(AndroidSchedulers.mainThread()) 63 | .subscribe(activityoListBeen -> view.displayData(activityoListBeen), 64 | throwable -> Log.e("tag", throwable.getMessage())); 65 | 66 | compositeDisposable.add(subscribe); 67 | } 68 | 69 | public void loadMoreData(int page) { 70 | Disposable subscribe = RetrofitHelper.createCopyService() 71 | .getCopys(page, 1, "d89a68bddc0784e750f6f841eeb61647#") 72 | .delay(1000, TimeUnit.MILLISECONDS) 73 | .filter(copyInfoBaseResponseInfo -> copyInfoBaseResponseInfo.getCode().equals(AppConstant.SUCCESS_CODE)) 74 | .map(copyInfoBaseResponseInfo -> copyInfoBaseResponseInfo.getBaseResult().getActivityoListBeans()) 75 | .subscribeOn(Schedulers.io()) 76 | .observeOn(AndroidSchedulers.mainThread()) 77 | .subscribe(activityoListBeen -> view.displayData(activityoListBeen), 78 | throwable -> Log.e("tag", throwable.getMessage())); 79 | 80 | compositeDisposable.add(subscribe); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/presenter/QuanziListPresenter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.presenter; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.example.cnsunrun.debugdemo.app.AppConstant; 7 | import com.example.cnsunrun.debugdemo.app.ApplicationModule; 8 | import com.example.cnsunrun.debugdemo.mvp.contract.QuanziListContract; 9 | import com.example.cnsunrun.debugdemo.mvp.model.network.RetrofitHelper; 10 | import com.example.cnsunrun.debugdemo.mvp.presenter.base.DaggerPresenterComponent; 11 | import com.example.cnsunrun.debugdemo.utils.ActivityScoped; 12 | 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import javax.inject.Inject; 16 | 17 | import io.reactivex.android.schedulers.AndroidSchedulers; 18 | import io.reactivex.disposables.CompositeDisposable; 19 | import io.reactivex.disposables.Disposable; 20 | import io.reactivex.schedulers.Schedulers; 21 | 22 | /** 23 | * Created by cnsunrun on 2017/3/17. 24 | */ 25 | @ActivityScoped 26 | public class QuanziListPresenter implements QuanziListContract.Presenter { 27 | 28 | private QuanziListContract.View view; 29 | 30 | private CompositeDisposable subscription; 31 | 32 | @Inject 33 | QuanziListPresenter(Context context, QuanziListContract.View view) { 34 | this.view = view; 35 | view.setPresenter(this); 36 | subscription = new CompositeDisposable(); 37 | 38 | DaggerPresenterComponent.builder() 39 | .applicationModule(new ApplicationModule(context)) 40 | .build().inject(this); 41 | } 42 | 43 | @Override 44 | public void subscribe() { 45 | Log.e("tag","加载数据 subscribe"); 46 | loadData(); 47 | } 48 | 49 | @Override 50 | public void unSubscribe() { 51 | subscription.clear(); 52 | } 53 | 54 | @Override 55 | public void loadData() { 56 | Log.e("tag","加载数据 loadData"); 57 | Disposable subscribe = RetrofitHelper.createQuanziService() 58 | .getQuanziInfos(-1, -1, -1, 1, -1, 1111, "dbe5b18fe665dbc25d22cdeb2d5cc436#") 59 | .delay(1000, TimeUnit.MILLISECONDS) 60 | .filter(quanziInfoBaseResponseInfo -> quanziInfoBaseResponseInfo.getCode().equals(AppConstant.SUCCESS_CODE)) 61 | .map(quanziInfoBaseResponseInfo -> quanziInfoBaseResponseInfo.getBaseResult().getBlogList()) 62 | .subscribeOn(Schedulers.io()) 63 | .observeOn(AndroidSchedulers.mainThread()) 64 | .subscribe(blogListBeen -> view.displayData(blogListBeen), 65 | throwable -> Log.e("tag", throwable.getMessage())); 66 | 67 | subscription.add(subscribe); 68 | } 69 | 70 | public void loadMoreData(long lastId, long hotLastId) { 71 | Log.e("tag","加载数据 loadMoreData"); 72 | Disposable subscribe = RetrofitHelper.createQuanziService() 73 | .getQuanziInfos(lastId, -1, hotLastId, 1, -1, 1111, "dbe5b18fe665dbc25d22cdeb2d5cc436#") 74 | .delay(1000, TimeUnit.MILLISECONDS) 75 | .filter(quanziInfoBaseResponseInfo -> quanziInfoBaseResponseInfo.getCode().equals(AppConstant.SUCCESS_CODE)) 76 | .map(quanziInfoBaseResponseInfo -> quanziInfoBaseResponseInfo.getBaseResult().getBlogList()) 77 | .subscribeOn(Schedulers.io()) 78 | .observeOn(AndroidSchedulers.mainThread()) 79 | .subscribe(blogListBeen -> view.displayData(blogListBeen), 80 | throwable -> Log.e("tag", throwable.getMessage())); 81 | 82 | subscription.add(subscribe); 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/presenter/base/PresenterComponent.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.presenter.base; 2 | 3 | import com.example.cnsunrun.debugdemo.app.ApplicationModule; 4 | import com.example.cnsunrun.debugdemo.mvp.presenter.CopyListPresenter; 5 | import com.example.cnsunrun.debugdemo.mvp.presenter.QuanziListPresenter; 6 | 7 | import javax.inject.Singleton; 8 | 9 | import dagger.Component; 10 | 11 | 12 | @Singleton 13 | @Component(modules = {ApplicationModule.class}) 14 | public interface PresenterComponent { 15 | 16 | void inject(QuanziListPresenter presenter); 17 | 18 | void inject(CopyListPresenter presenter); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/activity/ImageDetailsActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentManager; 7 | import android.support.v4.app.FragmentPagerAdapter; 8 | import android.support.v4.view.ViewPager; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.widget.TextView; 11 | 12 | import com.example.cnsunrun.debugdemo.R; 13 | import com.example.cnsunrun.debugdemo.mvp.ui.fragment.ImageDetailsFragment; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import butterknife.Bind; 19 | import butterknife.ButterKnife; 20 | 21 | /** 22 | * Created by cnsunrun on 2017/4/24. 23 | */ 24 | 25 | public class ImageDetailsActivity extends AppCompatActivity { 26 | 27 | 28 | @Bind(R.id.tv_index) 29 | TextView mIndex; 30 | @Bind(R.id.view_pager) 31 | ViewPager mViewPager; 32 | private ArrayList images_url; 33 | private int index; 34 | 35 | @Override 36 | protected void onCreate(@Nullable Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_image_details); 39 | ButterKnife.bind(this); 40 | index = getIntent().getIntExtra("index", -1); 41 | images_url = getIntent().getStringArrayListExtra("images_url"); 42 | 43 | initView(); 44 | } 45 | 46 | private void initView() { 47 | mIndex.setText((index + 1) + " / " + images_url.size()); 48 | ImageViewPagerAdapter mAdapter = new ImageViewPagerAdapter(getSupportFragmentManager(), images_url); 49 | mViewPager.setAdapter(mAdapter); 50 | mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 51 | @Override 52 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 53 | 54 | } 55 | 56 | @Override 57 | public void onPageSelected(int position) { 58 | mIndex.setText((position + 1) + " / " + images_url.size()); 59 | } 60 | 61 | @Override 62 | public void onPageScrollStateChanged(int state) { 63 | 64 | } 65 | }); 66 | } 67 | 68 | @Override 69 | protected void onResume() { 70 | super.onResume(); 71 | mViewPager.setCurrentItem(index); 72 | } 73 | 74 | private static class ImageViewPagerAdapter extends FragmentPagerAdapter { 75 | 76 | private List urls; 77 | 78 | public ImageViewPagerAdapter(FragmentManager fm, List urls) { 79 | super(fm); 80 | this.urls = urls; 81 | } 82 | 83 | @Override 84 | public Fragment getItem(int position) { 85 | return ImageDetailsFragment.newInstance(urls.get(position)); 86 | } 87 | 88 | @Override 89 | public int getCount() { 90 | return urls.size(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentTransaction; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | 10 | import com.aurelhubert.ahbottomnavigation.AHBottomNavigation; 11 | import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem; 12 | import com.example.cnsunrun.debugdemo.R; 13 | import com.example.cnsunrun.debugdemo.mvp.ui.fragment.CommunityFragment; 14 | import com.example.cnsunrun.debugdemo.mvp.ui.fragment.CopyListFragment; 15 | import com.example.cnsunrun.debugdemo.mvp.ui.fragment.MineFragment; 16 | import com.example.cnsunrun.debugdemo.mvp.ui.fragment.QuanziListFragment; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import butterknife.Bind; 22 | import butterknife.ButterKnife; 23 | 24 | /** 25 | * Created by cnsunrun on 2017/4/19. 26 | */ 27 | 28 | public class MainActivity extends AppCompatActivity { 29 | 30 | @Bind(R.id.toolbar) 31 | Toolbar mToolbar; 32 | @Bind(R.id.bottom_navigation) 33 | AHBottomNavigation mAhBottomNavigation; 34 | 35 | private int currentTabIndex; 36 | private List fragments = new ArrayList<>(); 37 | 38 | @Override 39 | protected void onCreate(@Nullable Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_main); 42 | ButterKnife.bind(this); 43 | 44 | mToolbar.setTitle(""); 45 | setSupportActionBar(mToolbar); 46 | fragments.add(CopyListFragment.newInstance()); 47 | fragments.add(QuanziListFragment.newInstance()); 48 | fragments.add(CommunityFragment.newInstance()); 49 | fragments.add(MineFragment.newInstance()); 50 | showFragment(fragments.get(0)); 51 | initBottomNav(); 52 | 53 | } 54 | 55 | private void showFragment(Fragment fragment) { 56 | 57 | getSupportFragmentManager() 58 | .beginTransaction() 59 | .replace(R.id.content, fragment) 60 | .commit(); 61 | } 62 | 63 | private void initBottomNav() { 64 | 65 | AHBottomNavigationItem item1 = new AHBottomNavigationItem("主页", 66 | R.drawable.ic_tab_home); 67 | AHBottomNavigationItem item2 = new AHBottomNavigationItem("圈子", 68 | R.drawable.ic_tab_quanzi); 69 | AHBottomNavigationItem item3 = new AHBottomNavigationItem("社区", 70 | R.drawable.ic_tab_community); 71 | AHBottomNavigationItem item4 = new AHBottomNavigationItem("我的", 72 | R.drawable.ic_tab_mine); 73 | 74 | mAhBottomNavigation.addItem(item1); 75 | mAhBottomNavigation.addItem(item2); 76 | mAhBottomNavigation.addItem(item3); 77 | mAhBottomNavigation.addItem(item4); 78 | 79 | mAhBottomNavigation.setColored(false); 80 | mAhBottomNavigation.setForceTint(false); 81 | mAhBottomNavigation.setBehaviorTranslationEnabled(true); 82 | mAhBottomNavigation.setTitleState(AHBottomNavigation.TitleState.ALWAYS_SHOW); 83 | mAhBottomNavigation.setAccentColor(getResources().getColor(R.color.colorPrimaryDark)); 84 | mAhBottomNavigation.setInactiveColor(getResources().getColor(R.color.colorPrimaryDark)); 85 | mAhBottomNavigation.setCurrentItem(0); 86 | mAhBottomNavigation.setDefaultBackgroundColor( 87 | getResources().getColor(R.color.colorPrimary)); 88 | 89 | mAhBottomNavigation.setOnTabSelectedListener((position, wasSelected) -> { 90 | 91 | if (currentTabIndex != position) { 92 | FragmentTransaction trx = getSupportFragmentManager().beginTransaction(); 93 | trx.hide(fragments.get(currentTabIndex)); 94 | if (!fragments.get(position).isAdded()) { 95 | trx.add(R.id.content, fragments.get(position)); 96 | } 97 | trx.show(fragments.get(position)).commit(); 98 | } 99 | currentTabIndex = position; 100 | 101 | return true; 102 | }); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/activity/QuanziDetailsActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.activity; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v4.widget.NestedScrollView; 7 | import android.support.v7.app.ActionBar; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.LinearLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.support.v7.widget.Toolbar; 12 | import android.util.Log; 13 | import android.view.MenuItem; 14 | import android.view.View; 15 | import android.widget.ImageView; 16 | import android.widget.LinearLayout; 17 | import android.widget.TextView; 18 | 19 | import com.bumptech.glide.Glide; 20 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 21 | import com.example.cnsunrun.debugdemo.R; 22 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziDetailsInfo; 23 | import com.example.cnsunrun.debugdemo.mvp.model.bean.base.BaseResponseInfo; 24 | import com.example.cnsunrun.debugdemo.mvp.model.network.RetrofitHelper; 25 | import com.example.cnsunrun.debugdemo.mvp.ui.adapter.CommentAdapter; 26 | import com.example.cnsunrun.debugdemo.widget.CircleImageView; 27 | import com.example.cnsunrun.debugdemo.widget.CircleProgressView; 28 | import com.example.cnsunrun.debugdemo.widget.MomentPicView; 29 | 30 | import java.util.ArrayList; 31 | import java.util.List; 32 | 33 | import butterknife.Bind; 34 | import butterknife.ButterKnife; 35 | import io.reactivex.android.schedulers.AndroidSchedulers; 36 | import io.reactivex.disposables.Disposable; 37 | import io.reactivex.schedulers.Schedulers; 38 | 39 | public class QuanziDetailsActivity extends AppCompatActivity { 40 | 41 | @Bind(R.id.multi_image) 42 | MomentPicView momentPicView; 43 | @Bind(R.id.toolbar) 44 | Toolbar mToolbar; 45 | @Bind(R.id.iv_head_image) 46 | CircleImageView mHeadImage; 47 | @Bind(R.id.tv_user_name) 48 | TextView mUserName; 49 | @Bind(R.id.tv_date) 50 | TextView mDate; 51 | @Bind(R.id.tv_content) 52 | TextView mContent; 53 | @Bind(R.id.tv_tags) 54 | TextView mTags; 55 | @Bind(R.id.tv_like_num) 56 | TextView mLikeNum; 57 | @Bind(R.id.tv_comments) 58 | TextView mComments; 59 | @Bind(R.id.recycler_view) 60 | RecyclerView mRecyclerView; 61 | @Bind(R.id.circle_progress) 62 | CircleProgressView mCircleProgressView; 63 | @Bind(R.id.root_layout) 64 | LinearLayout mRootLayout; 65 | @Bind(R.id.nested_scroll_view) 66 | NestedScrollView mNestedScrollView; 67 | @Bind(R.id.single_image) 68 | ImageView mSingleImage; 69 | 70 | private String id; 71 | private QuanziDetailsInfo mQuanziDetailsInfo; 72 | private Disposable subscribe; 73 | private String title; 74 | 75 | @Override 76 | protected void onCreate(Bundle savedInstanceState) { 77 | super.onCreate(savedInstanceState); 78 | setContentView(R.layout.activity_quanzi_details); 79 | ButterKnife.bind(this); 80 | mNestedScrollView.setNestedScrollingEnabled(true); 81 | Intent intent = getIntent(); 82 | if (intent != null) { 83 | id = intent.getStringExtra("id"); 84 | title = intent.getStringExtra("title"); 85 | } 86 | initToolBar(); 87 | loadData(); 88 | } 89 | 90 | private void initToolBar() { 91 | mToolbar.setTitle(title); 92 | setSupportActionBar(mToolbar); 93 | ActionBar supportActionBar = getSupportActionBar(); 94 | if (supportActionBar != null) { 95 | supportActionBar.setDisplayHomeAsUpEnabled(true); 96 | } 97 | } 98 | 99 | @Override 100 | public boolean onOptionsItemSelected(MenuItem item) { 101 | if (item.getItemId() == android.R.id.home) { 102 | onBackPressed(); 103 | } 104 | return super.onOptionsItemSelected(item); 105 | } 106 | 107 | private void loadData() { 108 | subscribe = RetrofitHelper.createQuanziService() 109 | .getQuanziDetailsInfo(id, "dbe5b18fe665dbc25d22cdeb2d5cc436#") 110 | .doOnSubscribe(subscription -> { 111 | mRootLayout.setVisibility(View.GONE); 112 | mCircleProgressView.setVisibility(View.VISIBLE); 113 | mCircleProgressView.spin(); 114 | }) 115 | .filter(quanziDetailsInfoBaseResponseInfo -> quanziDetailsInfoBaseResponseInfo.getCode().equals("10000")) 116 | .map(BaseResponseInfo::getBaseResult) 117 | .subscribeOn(Schedulers.io()) 118 | .observeOn(AndroidSchedulers.mainThread()) 119 | .doOnComplete(() -> { 120 | mRootLayout.setVisibility(View.VISIBLE); 121 | mCircleProgressView.setVisibility(View.GONE); 122 | mCircleProgressView.stopSpinning(); 123 | }) 124 | .subscribe(quanziDetailsInfo -> { 125 | mQuanziDetailsInfo = quanziDetailsInfo; 126 | finishTask(); 127 | }, throwable -> Log.e("tag", throwable.getMessage())); 128 | 129 | } 130 | 131 | @SuppressLint("SetTextI18n") 132 | private void finishTask() { 133 | //设置详情数据 134 | QuanziDetailsInfo.BlogBean blog = mQuanziDetailsInfo.getBlog(); 135 | QuanziDetailsInfo.UserBean user = mQuanziDetailsInfo.getUser(); 136 | List commentList = mQuanziDetailsInfo.getCommentList(); 137 | //设置用户信息 138 | Glide.with(this) 139 | .load(user.getHeadpic()) 140 | .centerCrop() 141 | .diskCacheStrategy(DiskCacheStrategy.ALL) 142 | .dontAnimate() 143 | .into(mHeadImage); 144 | mUserName.setText(user.getNicename()); 145 | mDate.setText(blog.getJointime()); 146 | //设置内容 147 | mContent.setText(blog.getContent()); 148 | //设置图片 149 | List picturelist = blog.getPicturelist(); 150 | if (picturelist != null && picturelist.size() > 0) { 151 | if (picturelist.size() > 1) { 152 | //设置多张图片展示 153 | mSingleImage.setVisibility(View.GONE); 154 | momentPicView.setImageUrls(picturelist); 155 | momentPicView.setOnClickItemListener((i, url) -> { 156 | Intent intent = new Intent(QuanziDetailsActivity.this, ImageDetailsActivity.class); 157 | intent.putExtra("index", i); 158 | intent.putExtra("images_url", url); 159 | QuanziDetailsActivity.this.startActivity(intent); 160 | }); 161 | } else { 162 | //单张图片展示 163 | mSingleImage.setVisibility(View.VISIBLE); 164 | Glide.with(this) 165 | .load(picturelist.get(0)) 166 | .centerCrop() 167 | .diskCacheStrategy(DiskCacheStrategy.ALL) 168 | .crossFade(0) 169 | .into(mSingleImage); 170 | mSingleImage.setOnClickListener(v -> { 171 | ArrayList urls = new ArrayList<>(); 172 | urls.add(picturelist.get(0)); 173 | Intent intent = new Intent(QuanziDetailsActivity.this, ImageDetailsActivity.class); 174 | intent.putExtra("index", 0); 175 | intent.putExtra("images_url", urls); 176 | QuanziDetailsActivity.this.startActivity(intent); 177 | }); 178 | } 179 | 180 | } 181 | //设置标签 182 | List tagnames = blog.getTagnames(); 183 | tagnames.forEach(tagnamesBean -> mTags.append(tagnamesBean.getName() + ",")); 184 | //设置喜欢数量 185 | mLikeNum.setText(blog.getFavour_counter()); 186 | //设置评论数量 187 | mComments.setText("评论 " + blog.getComment_counter()); 188 | //设置评论列表 189 | if (commentList != null && commentList.size() > 0) { 190 | mComments.setVisibility(View.VISIBLE); 191 | mRecyclerView.setHasFixedSize(false); 192 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 193 | mRecyclerView.setNestedScrollingEnabled(false); 194 | CommentAdapter mAdapter = new CommentAdapter(); 195 | mAdapter.setDataSources(commentList); 196 | mRecyclerView.setAdapter(mAdapter); 197 | } else { 198 | mComments.setVisibility(View.GONE); 199 | } 200 | 201 | } 202 | 203 | @Override 204 | protected void onDestroy() { 205 | ButterKnife.unbind(this); 206 | if (subscribe != null && !subscribe.isDisposed()) { 207 | subscribe.dispose(); 208 | } 209 | super.onDestroy(); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/activity/component/CopyListComponent.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.activity.component; 2 | 3 | import com.example.cnsunrun.debugdemo.app.ApplicationComponent; 4 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.module.CopyListModule; 5 | import com.example.cnsunrun.debugdemo.mvp.ui.fragment.CopyListFragment; 6 | import com.example.cnsunrun.debugdemo.utils.ActivityScoped; 7 | 8 | import dagger.Component; 9 | 10 | /** 11 | * Created by cnsunrun on 2017/4/19. 12 | */ 13 | @ActivityScoped 14 | @Component(modules = CopyListModule.class, dependencies = ApplicationComponent.class) 15 | public interface CopyListComponent { 16 | 17 | void inject(CopyListFragment copyListFragment); 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/activity/component/QuanziListComponent.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.activity.component; 2 | 3 | import com.example.cnsunrun.debugdemo.app.ApplicationComponent; 4 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.module.QuanziListModule; 5 | import com.example.cnsunrun.debugdemo.mvp.ui.fragment.QuanziListFragment; 6 | import com.example.cnsunrun.debugdemo.utils.ActivityScoped; 7 | 8 | import dagger.Component; 9 | 10 | /** 11 | * Created by cnsunrun on 2017/3/17. 12 | */ 13 | @ActivityScoped 14 | @Component(modules = QuanziListModule.class, dependencies = ApplicationComponent.class) 15 | public interface QuanziListComponent { 16 | 17 | void inject(QuanziListFragment quanziListFragment); 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/activity/module/CopyListModule.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.activity.module; 2 | 3 | import com.example.cnsunrun.debugdemo.mvp.contract.CopyListContract; 4 | 5 | import dagger.Module; 6 | import dagger.Provides; 7 | 8 | /** 9 | * Created by cnsunrun on 2017/4/19. 10 | */ 11 | @Module 12 | public class CopyListModule { 13 | 14 | private CopyListContract.View view; 15 | 16 | public CopyListModule(CopyListContract.View view) { 17 | this.view = view; 18 | } 19 | 20 | @Provides 21 | CopyListContract.View provideCopyListContractView() { 22 | return view; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/activity/module/QuanziListModule.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.activity.module; 2 | 3 | import com.example.cnsunrun.debugdemo.mvp.contract.QuanziListContract; 4 | 5 | import dagger.Module; 6 | import dagger.Provides; 7 | 8 | /** 9 | * Created by cnsunrun on 2017/3/17. 10 | */ 11 | @Module 12 | public class QuanziListModule { 13 | 14 | private QuanziListContract.View view; 15 | 16 | public QuanziListModule(QuanziListContract.View view) { 17 | this.view = view; 18 | } 19 | 20 | @Provides 21 | QuanziListContract.View provideQuanziListContractView() { 22 | return view; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/adapter/CommentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.adapter; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.TextView; 7 | 8 | import com.bumptech.glide.Glide; 9 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 10 | import com.example.cnsunrun.debugdemo.R; 11 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziDetailsInfo; 12 | import com.example.cnsunrun.debugdemo.mvp.ui.adapter.base.AbsRecyclerViewAdapter; 13 | import com.example.cnsunrun.debugdemo.widget.CircleImageView; 14 | 15 | /** 16 | * Created by cnsunrun on 2017/4/20. 17 | */ 18 | 19 | public class CommentAdapter extends AbsRecyclerViewAdapter { 20 | 21 | @Override 22 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 23 | if (holder instanceof ItemViewHolder) { 24 | ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 25 | QuanziDetailsInfo.CommentListBean commentListBean = mDataSources.get(position); 26 | Glide.with(getContext()) 27 | .load(commentListBean.getHeadpic()) 28 | .centerCrop() 29 | .diskCacheStrategy(DiskCacheStrategy.ALL) 30 | .dontAnimate() 31 | .into(itemViewHolder.mHeadImage); 32 | itemViewHolder.mUserName.setText(commentListBean.getNicename()); 33 | itemViewHolder.mDate.setText(commentListBean.getJointime()); 34 | itemViewHolder.mContent.setText(commentListBean.getContent()); 35 | } 36 | super.onBindViewHolder(holder, position); 37 | } 38 | 39 | @Override 40 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 41 | bindContext(parent.getContext()); 42 | return new ItemViewHolder(LayoutInflater.from(getContext()) 43 | .inflate(R.layout.item_comment, parent, false)); 44 | } 45 | 46 | private class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 47 | CircleImageView mHeadImage; 48 | TextView mUserName; 49 | TextView mDate; 50 | TextView mContent; 51 | 52 | public ItemViewHolder(View itemView) { 53 | super(itemView); 54 | mHeadImage = $(R.id.item_head_image); 55 | mUserName = $(R.id.item_user_name); 56 | mDate = $(R.id.item_date); 57 | mContent = $(R.id.item_content); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/adapter/CopyAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.adapter; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import com.bumptech.glide.Glide; 11 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 12 | import com.example.cnsunrun.debugdemo.R; 13 | import com.example.cnsunrun.debugdemo.mvp.model.bean.CopyInfo; 14 | import com.example.cnsunrun.debugdemo.mvp.ui.adapter.base.AbsRecyclerViewAdapter; 15 | 16 | /** 17 | * Created by cnsunrun on 2017/4/19. 18 | */ 19 | 20 | public class CopyAdapter extends AbsRecyclerViewAdapter { 21 | 22 | @SuppressLint("SetTextI18n") 23 | @Override 24 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 25 | if (holder instanceof ItemViewHolder) { 26 | ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 27 | CopyInfo.ActivityoListBean activityoListBean = mDataSources.get(position); 28 | Glide.with(getContext()) 29 | .load(activityoListBean.getPicture()) 30 | .centerCrop() 31 | .diskCacheStrategy(DiskCacheStrategy.ALL) 32 | .crossFade() 33 | .into(itemViewHolder.mCopyImage); 34 | itemViewHolder.mCopyName.setText("副本:" + activityoListBean.getName()); 35 | itemViewHolder.mCopyFounder.setText("队长:" + activityoListBean.getUser_name()); 36 | } 37 | super.onBindViewHolder(holder, position); 38 | } 39 | 40 | @Override 41 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 42 | bindContext(parent.getContext()); 43 | return new ItemViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.item_copy, parent, false)); 44 | } 45 | 46 | private class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 47 | ImageView mCopyImage; 48 | TextView mCopyName; 49 | TextView mCopyFounder; 50 | 51 | public ItemViewHolder(View itemView) { 52 | super(itemView); 53 | mCopyImage = $(R.id.item_image); 54 | mCopyName = $(R.id.item_copy_name); 55 | mCopyFounder = $(R.id.item_copy_founder); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/adapter/CopyDetailsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.adapter; 2 | 3 | import android.content.Intent; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.bumptech.glide.Glide; 10 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 11 | import com.example.cnsunrun.debugdemo.R; 12 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziInfo; 13 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.ImageDetailsActivity; 14 | import com.example.cnsunrun.debugdemo.mvp.ui.adapter.base.AbsRecyclerViewAdapter; 15 | import com.example.cnsunrun.debugdemo.widget.CircleImageView; 16 | import com.example.cnsunrun.debugdemo.widget.MomentPicView; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * Created by cnsunrun on 2017/4/24. 22 | */ 23 | 24 | public class CopyDetailsAdapter extends AbsRecyclerViewAdapter { 25 | 26 | @Override 27 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 28 | if (holder instanceof ItemViewHolder) { 29 | ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 30 | QuanziInfo.BlogListBean blogListBean = mDataSources.get(position); 31 | Glide.with(getContext()) 32 | .load(blogListBean.getHeadpic()) 33 | .centerCrop() 34 | .diskCacheStrategy(DiskCacheStrategy.ALL) 35 | .dontAnimate() 36 | .into(itemViewHolder.mUserPhoto); 37 | itemViewHolder.mUserName.setText(blogListBean.getNicename()); 38 | itemViewHolder.mTime.setText(blogListBean.getJointime()); 39 | itemViewHolder.mContent.setText(blogListBean.getContent()); 40 | List tagnames = blogListBean.getTagnames(); 41 | if (!tagnames.isEmpty()) 42 | itemViewHolder.mTags.setText(tagnames.get(0).getName()); 43 | if (blogListBean.getPicturelist() != null && blogListBean.getPicturelist().size() > 0) { 44 | itemViewHolder.momentPicView.setImageUrls(blogListBean.getPicturelist()); 45 | itemViewHolder.momentPicView.setOnClickItemListener((i, url) -> { 46 | Intent intent = new Intent(getContext(), ImageDetailsActivity.class); 47 | intent.putExtra("index", i); 48 | intent.putExtra("images_url", url); 49 | getContext().startActivity(intent); 50 | }); 51 | } 52 | itemViewHolder.mForwardedNum.setText(blogListBean.getZhuanfa_counter().equals("0") ? "转发" : blogListBean.getZhuanfa_counter()); 53 | itemViewHolder.mCommentNum.setText(blogListBean.getComment_counter().equals("0") ? "评论" : blogListBean.getComment_counter()); 54 | itemViewHolder.mLikeNum.setText(blogListBean.getFavour_counter().equals("0") ? "喜欢" : blogListBean.getFavour_counter()); 55 | } 56 | super.onBindViewHolder(holder, position); 57 | } 58 | 59 | @Override 60 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 61 | bindContext(parent.getContext()); 62 | return new ItemViewHolder(LayoutInflater.from(getContext()) 63 | .inflate(R.layout.item_copy_details, parent, false)); 64 | } 65 | 66 | private class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 67 | CircleImageView mUserPhoto; 68 | TextView mUserName; 69 | TextView mTime; 70 | TextView mContent; 71 | MomentPicView momentPicView; 72 | TextView mTags; 73 | TextView mForwardedNum; 74 | TextView mCommentNum; 75 | TextView mLikeNum; 76 | 77 | 78 | public ItemViewHolder(View itemView) { 79 | super(itemView); 80 | mUserPhoto = $(R.id.item_author_avatar); 81 | mUserName = $(R.id.item_author_name); 82 | mTime = $(R.id.item_time); 83 | mContent = $(R.id.item_content); 84 | momentPicView = $(R.id.item_multi_image); 85 | mTags = $(R.id.item_tag); 86 | mForwardedNum = $(R.id.tv_forwarded); 87 | mCommentNum = $(R.id.tv_comment_count); 88 | mLikeNum = $(R.id.tv_favour_count); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/adapter/QuanziAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.adapter; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | import com.bumptech.glide.Glide; 10 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 11 | import com.example.cnsunrun.debugdemo.R; 12 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziInfo; 13 | import com.example.cnsunrun.debugdemo.mvp.ui.adapter.base.AbsRecyclerViewAdapter; 14 | import com.example.cnsunrun.debugdemo.widget.CircleImageView; 15 | 16 | /** 17 | * Created by cnsunrun on 2017/3/11. 18 | */ 19 | 20 | public class QuanziAdapter extends AbsRecyclerViewAdapter { 21 | 22 | @Override 23 | public ClickableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 24 | bindContext(parent.getContext()); 25 | return new ItemViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.item_quanzi, parent, false)); 26 | } 27 | 28 | @Override 29 | public void onBindViewHolder(ClickableViewHolder holder, int position) { 30 | if (holder instanceof ItemViewHolder) { 31 | final ItemViewHolder itemViewHolder = (ItemViewHolder) holder; 32 | QuanziInfo.BlogListBean blogListBean = mDataSources.get(position); 33 | Glide.with(getContext()) 34 | .load(blogListBean.getPicture()) 35 | .centerCrop() 36 | .diskCacheStrategy(DiskCacheStrategy.ALL) 37 | .into(itemViewHolder.mCoverImage); 38 | Glide.with(getContext()) 39 | .load(blogListBean.getHeadpic()) 40 | .centerCrop() 41 | .diskCacheStrategy(DiskCacheStrategy.ALL) 42 | .dontAnimate() 43 | .into(itemViewHolder.mHeadImage); 44 | itemViewHolder.mContent.setText(blogListBean.getContent()); 45 | itemViewHolder.mUserName.setText(blogListBean.getNicename()); 46 | itemViewHolder.mDate.setText(blogListBean.getJointime()); 47 | itemViewHolder.mForwardingNum.setText(blogListBean.getZhuanfa_counter()); 48 | itemViewHolder.mCommentNum.setText(blogListBean.getComment_counter()); 49 | itemViewHolder.mLikeNum.setText(blogListBean.getFavour_counter()); 50 | } 51 | super.onBindViewHolder(holder, position); 52 | } 53 | 54 | 55 | public class ItemViewHolder extends AbsRecyclerViewAdapter.ClickableViewHolder { 56 | 57 | ImageView mCoverImage; 58 | CircleImageView mHeadImage; 59 | TextView mUserName; 60 | TextView mDate; 61 | TextView mContent; 62 | TextView mForwardingNum; 63 | TextView mCommentNum; 64 | TextView mLikeNum; 65 | 66 | public ItemViewHolder(View itemView) { 67 | super(itemView); 68 | mCoverImage = $(R.id.item_image); 69 | mContent = $(R.id.item_text); 70 | mHeadImage = $(R.id.item_head_image); 71 | mUserName = $(R.id.item_user_name); 72 | mDate = $(R.id.item_date); 73 | mForwardingNum = $(R.id.item_forwarding); 74 | mCommentNum = $(R.id.item_comment); 75 | mLikeNum = $(R.id.item_like); 76 | 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/adapter/base/AbsRecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.adapter.base; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.IdRes; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | import java.util.List; 9 | 10 | 11 | public abstract class AbsRecyclerViewAdapter 12 | extends RecyclerView.Adapter { 13 | 14 | private Context context; 15 | 16 | public List mDataSources; 17 | 18 | private OnItemClickListener itemClickListener; 19 | 20 | private OnItemLongClickListener itemLongClickListener; 21 | 22 | 23 | public void setOnItemClickListener(OnItemClickListener listener) { 24 | 25 | this.itemClickListener = listener; 26 | } 27 | 28 | 29 | public void setOnItemLongClickListener(OnItemLongClickListener listener) { 30 | 31 | this.itemLongClickListener = listener; 32 | } 33 | 34 | 35 | /** 36 | * 设置RecyclerView数据源 37 | */ 38 | public void setDataSources(List dataSources) { 39 | 40 | this.mDataSources = dataSources; 41 | } 42 | 43 | 44 | /** 45 | * 设置RecyclerView的count 46 | */ 47 | @Override 48 | public int getItemCount() { 49 | 50 | return mDataSources == null ? 0 : mDataSources.size(); 51 | } 52 | 53 | 54 | /** 55 | * 设置Context 56 | */ 57 | public void bindContext(Context context) { 58 | 59 | this.context = context; 60 | } 61 | 62 | 63 | /** 64 | * 获取Context 65 | */ 66 | public Context getContext() { 67 | 68 | return this.context; 69 | } 70 | 71 | 72 | /** 73 | * 重写onBindViewHolder设置item的点击和长按事件的监听 74 | */ 75 | @Override 76 | public void onBindViewHolder(final ClickableViewHolder holder, final int position) { 77 | 78 | holder.getParentView().setOnClickListener(new View.OnClickListener() { 79 | @Override 80 | public void onClick(View v) { 81 | if (itemClickListener != null) { 82 | itemClickListener.onItemClick(position, holder); 83 | } 84 | } 85 | }); 86 | } 87 | 88 | 89 | /** 90 | * Item点击事件接口 91 | */ 92 | public interface OnItemClickListener { 93 | 94 | void onItemClick(int position, ClickableViewHolder holder); 95 | } 96 | 97 | /** 98 | * Item长按事件接口 99 | */ 100 | public interface OnItemLongClickListener { 101 | 102 | boolean onItemLongClick(int position, ClickableViewHolder holder); 103 | } 104 | 105 | public static class ClickableViewHolder extends RecyclerView.ViewHolder { 106 | 107 | private View parentView; 108 | 109 | 110 | public ClickableViewHolder(View itemView) { 111 | 112 | super(itemView); 113 | this.parentView = itemView; 114 | } 115 | 116 | 117 | public View getParentView() { 118 | 119 | return parentView; 120 | } 121 | 122 | 123 | @SuppressWarnings("unchecked") 124 | public T $(@IdRes int id) { 125 | 126 | return (T) parentView.findViewById(id); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/adapter/base/EndlessRecyclerOnScrollListener.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.adapter.base; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | 6 | /** 7 | * Created by cnsunrun on 2017/4/24. 8 | */ 9 | 10 | public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener { 11 | 12 | private int previousTotal = 0; 13 | 14 | private boolean loading = true; 15 | 16 | private int currentPage = 1; 17 | 18 | private LinearLayoutManager mLinearLayoutManager; 19 | 20 | 21 | protected EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) { 22 | 23 | this.mLinearLayoutManager = linearLayoutManager; 24 | } 25 | 26 | 27 | @Override 28 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 29 | 30 | super.onScrolled(recyclerView, dx, dy); 31 | 32 | if (dy == 0) { 33 | return; 34 | } 35 | 36 | int visibleItemCount = recyclerView.getChildCount(); 37 | int totalItemCount = mLinearLayoutManager.getItemCount(); 38 | int lastCompletelyVisiableItemPosition 39 | = mLinearLayoutManager.findLastCompletelyVisibleItemPosition(); 40 | 41 | if (loading) { 42 | if (totalItemCount > previousTotal) { 43 | loading = false; 44 | previousTotal = totalItemCount; 45 | } 46 | } 47 | 48 | if (!loading && (visibleItemCount > 0) && 49 | (lastCompletelyVisiableItemPosition >= totalItemCount - 1)) { 50 | currentPage++; 51 | onLoadMore(currentPage); 52 | loading = true; 53 | } 54 | } 55 | 56 | 57 | public void refresh() { 58 | 59 | loading = true; 60 | previousTotal = 0; 61 | currentPage = 1; 62 | } 63 | 64 | 65 | public abstract void onLoadMore(int currentPage); 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/adapter/base/HeaderViewRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.adapter.base; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * Created by hcc on 16/8/7 21:18 14 | * 100332338@qq.com 15 | *

16 | * RecyclerView添加HeadAndFoot辅助类 17 | */ 18 | public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter { 19 | 20 | private static final int HEADERS_START = Integer.MIN_VALUE; 21 | 22 | private static final int FOOTERS_START = Integer.MIN_VALUE + 10; 23 | 24 | private static final int ITEMS_START = Integer.MIN_VALUE + 20; 25 | 26 | private static final int ADAPTER_MAX_TYPES = 100; 27 | 28 | private RecyclerView.Adapter mWrappedAdapter; 29 | 30 | private List mHeaderViews, mFooterViews; 31 | 32 | private Map mItemTypesOffset; 33 | 34 | 35 | public HeaderViewRecyclerAdapter(RecyclerView.Adapter adapter) { 36 | 37 | mHeaderViews = new ArrayList<>(); 38 | mFooterViews = new ArrayList<>(); 39 | mItemTypesOffset = new HashMap<>(); 40 | setWrappedAdapter(adapter); 41 | } 42 | 43 | 44 | public void setAdapter(RecyclerView.Adapter adapter) { 45 | 46 | if (mWrappedAdapter != null && mWrappedAdapter.getItemCount() > 0) { 47 | notifyItemRangeRemoved(getHeaderCount(), mWrappedAdapter.getItemCount()); 48 | } 49 | setWrappedAdapter(adapter); 50 | notifyItemRangeInserted(getHeaderCount(), mWrappedAdapter.getItemCount()); 51 | } 52 | 53 | 54 | @Override 55 | public int getItemViewType(int position) { 56 | 57 | int hCount = getHeaderCount(); 58 | if (position < hCount) { 59 | return HEADERS_START + position; 60 | } else { 61 | int itemCount = mWrappedAdapter.getItemCount(); 62 | if (position < hCount + itemCount) { 63 | return getAdapterTypeOffset() + mWrappedAdapter.getItemViewType(position - hCount); 64 | } else { 65 | return FOOTERS_START + position - hCount - itemCount; 66 | } 67 | } 68 | } 69 | 70 | 71 | @Override 72 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { 73 | 74 | if (viewType < HEADERS_START + getHeaderCount()) { 75 | return new StaticViewHolder(mHeaderViews.get(viewType - HEADERS_START)); 76 | } else if (viewType < FOOTERS_START + getFooterCount()) { 77 | return new StaticViewHolder(mFooterViews.get(viewType - FOOTERS_START)); 78 | } else { 79 | return mWrappedAdapter.onCreateViewHolder(viewGroup, viewType - getAdapterTypeOffset()); 80 | } 81 | } 82 | 83 | 84 | @Override 85 | public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { 86 | 87 | int hCount = getHeaderCount(); 88 | if (position >= hCount && position < hCount + mWrappedAdapter.getItemCount()) { 89 | mWrappedAdapter.onBindViewHolder(viewHolder, position - hCount); 90 | } 91 | } 92 | 93 | 94 | public void addHeaderView(View view) { 95 | 96 | mHeaderViews.add(view); 97 | } 98 | 99 | 100 | public void addFooterView(View view) { 101 | 102 | mFooterViews.add(view); 103 | } 104 | 105 | 106 | public void removeHeadView() { 107 | 108 | mHeaderViews.clear(); 109 | } 110 | 111 | 112 | public void removeFootView() { 113 | mFooterViews.clear(); 114 | } 115 | 116 | 117 | @Override 118 | public int getItemCount() { 119 | 120 | return getHeaderCount() + getFooterCount() + getWrappedItemCount(); 121 | } 122 | 123 | 124 | private int getWrappedItemCount() { 125 | 126 | return mWrappedAdapter.getItemCount(); 127 | } 128 | 129 | 130 | private int getHeaderCount() { 131 | 132 | return mHeaderViews.size(); 133 | } 134 | 135 | 136 | private int getFooterCount() { 137 | 138 | return mFooterViews.size(); 139 | } 140 | 141 | 142 | private void setWrappedAdapter(RecyclerView.Adapter adapter) { 143 | 144 | if (mWrappedAdapter != null) mWrappedAdapter.unregisterAdapterDataObserver(mDataObserver); 145 | mWrappedAdapter = adapter; 146 | Class adapterClass = mWrappedAdapter.getClass(); 147 | if (!mItemTypesOffset.containsKey(adapterClass)) putAdapterTypeOffset(adapterClass); 148 | mWrappedAdapter.registerAdapterDataObserver(mDataObserver); 149 | } 150 | 151 | 152 | private void putAdapterTypeOffset(Class adapterClass) { 153 | 154 | mItemTypesOffset.put(adapterClass, ITEMS_START + mItemTypesOffset.size() * ADAPTER_MAX_TYPES); 155 | } 156 | 157 | 158 | private int getAdapterTypeOffset() { 159 | 160 | return mItemTypesOffset.get(mWrappedAdapter.getClass()); 161 | } 162 | 163 | 164 | private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() { 165 | 166 | @Override 167 | public void onChanged() { 168 | 169 | super.onChanged(); 170 | notifyDataSetChanged(); 171 | } 172 | 173 | 174 | @Override 175 | public void onItemRangeChanged(int positionStart, int itemCount) { 176 | 177 | super.onItemRangeChanged(positionStart, itemCount); 178 | notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount); 179 | } 180 | 181 | 182 | @Override 183 | public void onItemRangeInserted(int positionStart, int itemCount) { 184 | 185 | super.onItemRangeInserted(positionStart, itemCount); 186 | notifyItemRangeInserted(positionStart + getHeaderCount(), itemCount); 187 | } 188 | 189 | 190 | @Override 191 | public void onItemRangeRemoved(int positionStart, int itemCount) { 192 | 193 | super.onItemRangeRemoved(positionStart, itemCount); 194 | notifyItemRangeRemoved(positionStart + getHeaderCount(), itemCount); 195 | } 196 | 197 | 198 | @Override 199 | public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { 200 | 201 | super.onItemRangeMoved(fromPosition, toPosition, itemCount); 202 | int hCount = getHeaderCount(); 203 | // TODO: No notifyItemRangeMoved method? 204 | notifyItemRangeChanged(fromPosition + hCount, toPosition + hCount + itemCount); 205 | } 206 | }; 207 | 208 | private static class StaticViewHolder extends RecyclerView.ViewHolder { 209 | 210 | StaticViewHolder(View itemView) { 211 | 212 | super(itemView); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/fragment/CommunityFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.example.cnsunrun.debugdemo.R; 11 | 12 | /** 13 | * Created by cnsunrun on 2017/4/19. 14 | */ 15 | 16 | public class CommunityFragment extends Fragment { 17 | 18 | 19 | public static CommunityFragment newInstance() { 20 | return new CommunityFragment(); 21 | } 22 | 23 | @Nullable 24 | @Override 25 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 | View view = inflater.inflate(R.layout.fragment_community, container, false); 27 | return view; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/fragment/CopyListFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.fragment; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v4.widget.SwipeRefreshLayout; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | import com.example.cnsunrun.debugdemo.DebugDemoApp; 15 | import com.example.cnsunrun.debugdemo.R; 16 | import com.example.cnsunrun.debugdemo.mvp.contract.CopyListContract; 17 | import com.example.cnsunrun.debugdemo.mvp.model.bean.CopyInfo; 18 | import com.example.cnsunrun.debugdemo.mvp.presenter.CopyListPresenter; 19 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.CopyDetailsActivity; 20 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.component.DaggerCopyListComponent; 21 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.module.CopyListModule; 22 | import com.example.cnsunrun.debugdemo.mvp.ui.adapter.CopyAdapter; 23 | import com.github.nukc.LoadMoreWrapper.LoadMoreWrapper; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import javax.inject.Inject; 29 | 30 | import butterknife.Bind; 31 | import butterknife.ButterKnife; 32 | 33 | /** 34 | * Created by cnsunrun on 2017/4/19. 35 | */ 36 | 37 | public class CopyListFragment extends Fragment implements CopyListContract.View { 38 | 39 | @Bind(R.id.recycler_view) 40 | RecyclerView mRecyclerView; 41 | @Bind(R.id.swipe_refresh) 42 | SwipeRefreshLayout mSwipeRefreshLayout; 43 | 44 | @Inject 45 | CopyListPresenter copyListPresenter; 46 | 47 | private List datas = new ArrayList<>(); 48 | private CopyAdapter mAdapter; 49 | private int page = 1; 50 | 51 | public static CopyListFragment newInstance() { 52 | return new CopyListFragment(); 53 | } 54 | 55 | 56 | @Override 57 | public void onCreate(@Nullable Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | DaggerCopyListComponent.builder() 60 | .applicationComponent(DebugDemoApp.getAppContext().getApplicationComponent()) 61 | .copyListModule(new CopyListModule(this)) 62 | .build().inject(this); 63 | } 64 | 65 | @Nullable 66 | @Override 67 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 68 | View view = inflater.inflate(R.layout.fragment_copy_list, container, false); 69 | ButterKnife.bind(this, view); 70 | initSwipeRefreshLayout(); 71 | initRecyclerView(); 72 | copyListPresenter.subscribe(); 73 | return view; 74 | } 75 | 76 | private void initSwipeRefreshLayout() { 77 | mSwipeRefreshLayout.setColorSchemeResources(R.color.colorControlNormal); 78 | mSwipeRefreshLayout.setOnRefreshListener(() -> { 79 | datas.clear(); 80 | copyListPresenter.loadData(); 81 | }); 82 | } 83 | 84 | private void initRecyclerView() { 85 | mRecyclerView.setHasFixedSize(true); 86 | mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); 87 | mAdapter = new CopyAdapter(); 88 | mRecyclerView.setAdapter(mAdapter); 89 | mAdapter.setOnItemClickListener((position, holder) -> { 90 | CopyInfo.ActivityoListBean activityoListBean = datas.get(position); 91 | Intent intent = new Intent(getActivity(), CopyDetailsActivity.class); 92 | intent.putExtra("activityId",activityoListBean.getActivityid()); 93 | getActivity().startActivity(intent); 94 | }); 95 | LoadMoreWrapper.with(mAdapter) 96 | .setFooterView(R.layout.layout_load_more) 97 | .setShowNoMoreEnabled(true) 98 | .setListener(enabled -> { 99 | page++; 100 | copyListPresenter.loadMoreData(page); 101 | }).into(mRecyclerView); 102 | } 103 | 104 | @Override 105 | public void setPresenter(CopyListContract.Presenter presenter) { 106 | } 107 | 108 | @Override 109 | public void displayData(List copyInfos) { 110 | mSwipeRefreshLayout.setRefreshing(false); 111 | datas.addAll(copyInfos); 112 | mAdapter.setDataSources(datas); 113 | mAdapter.notifyDataSetChanged(); 114 | 115 | } 116 | 117 | @Override 118 | public void onDestroyView() { 119 | super.onDestroyView(); 120 | ButterKnife.unbind(this); 121 | copyListPresenter.unSubscribe(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/fragment/ImageDetailsFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import com.bumptech.glide.Glide; 12 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 13 | import com.bumptech.glide.load.resource.drawable.GlideDrawable; 14 | import com.bumptech.glide.request.RequestListener; 15 | import com.bumptech.glide.request.target.Target; 16 | import com.example.cnsunrun.debugdemo.R; 17 | import com.example.cnsunrun.debugdemo.widget.CircleProgressView; 18 | 19 | import butterknife.Bind; 20 | import butterknife.ButterKnife; 21 | import uk.co.senab.photoview.PhotoViewAttacher; 22 | 23 | /** 24 | * Created by cnsunrun on 2017/4/24. 25 | */ 26 | 27 | public class ImageDetailsFragment extends Fragment implements RequestListener { 28 | 29 | @Bind(R.id.circle_progress) 30 | CircleProgressView mCircleProgressView; 31 | 32 | @Bind(R.id.iv_image_details) 33 | ImageView mImageView; 34 | 35 | private String url; 36 | private PhotoViewAttacher mPhotoViewAttacher; 37 | 38 | public static ImageDetailsFragment newInstance(String url) { 39 | ImageDetailsFragment fragment = new ImageDetailsFragment(); 40 | Bundle bundle = new Bundle(); 41 | bundle.putString("url", url); 42 | fragment.setArguments(bundle); 43 | return fragment; 44 | } 45 | 46 | @Nullable 47 | @Override 48 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 49 | View view = inflater.inflate(R.layout.fragment_image_details, container, false); 50 | ButterKnife.bind(this, view); 51 | url = getArguments().getString("url"); 52 | initView(); 53 | return view; 54 | } 55 | 56 | private void initView() { 57 | mCircleProgressView.setVisibility(View.VISIBLE); 58 | mCircleProgressView.spin(); 59 | 60 | Glide.with(this).load(url) 61 | .diskCacheStrategy(DiskCacheStrategy.ALL) 62 | .crossFade(0) 63 | .listener(this) 64 | .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL); 65 | } 66 | 67 | @Override 68 | public boolean onException(Exception e, String model, Target target, boolean isFirstResource) { 69 | mCircleProgressView.setVisibility(View.GONE); 70 | mCircleProgressView.stopSpinning(); 71 | return false; 72 | } 73 | 74 | @Override 75 | public boolean onResourceReady(GlideDrawable resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { 76 | mCircleProgressView.setVisibility(View.GONE); 77 | mCircleProgressView.stopSpinning(); 78 | mImageView.setImageDrawable(resource); 79 | mPhotoViewAttacher = new PhotoViewAttacher(mImageView); 80 | mPhotoViewAttacher.setOnViewTapListener((view, v, v1) -> getActivity().finish()); 81 | 82 | return false; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/fragment/MineFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.example.cnsunrun.debugdemo.R; 12 | 13 | /** 14 | * Created by cnsunrun on 2017/4/19. 15 | */ 16 | 17 | public class MineFragment extends Fragment { 18 | 19 | public static MineFragment newInstance() { 20 | return new MineFragment(); 21 | } 22 | 23 | @Nullable 24 | @Override 25 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 | View view = inflater.inflate(R.layout.fragment_mine, container, false); 27 | TextView mTextView = (TextView) view.findViewById(R.id.tv_test); 28 | mTextView.setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View v) { 31 | 32 | } 33 | }); 34 | return view; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/mvp/ui/fragment/QuanziListFragment.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.mvp.ui.fragment; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v4.widget.SwipeRefreshLayout; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.support.v7.widget.StaggeredGridLayoutManager; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | import com.example.cnsunrun.debugdemo.DebugDemoApp; 15 | import com.example.cnsunrun.debugdemo.R; 16 | import com.example.cnsunrun.debugdemo.mvp.contract.QuanziListContract; 17 | import com.example.cnsunrun.debugdemo.mvp.model.bean.QuanziInfo; 18 | import com.example.cnsunrun.debugdemo.mvp.presenter.QuanziListPresenter; 19 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.QuanziDetailsActivity; 20 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.component.DaggerQuanziListComponent; 21 | import com.example.cnsunrun.debugdemo.mvp.ui.activity.module.QuanziListModule; 22 | import com.example.cnsunrun.debugdemo.mvp.ui.adapter.QuanziAdapter; 23 | import com.github.nukc.LoadMoreWrapper.LoadMoreWrapper; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import javax.inject.Inject; 29 | 30 | import butterknife.Bind; 31 | import butterknife.ButterKnife; 32 | 33 | /** 34 | * Created by cnsunrun on 2017/4/18. 35 | */ 36 | 37 | public class QuanziListFragment extends Fragment implements QuanziListContract.View { 38 | 39 | 40 | @Bind(R.id.recycler_view) 41 | RecyclerView mRecyclerView; 42 | @Bind(R.id.swipe_refresh) 43 | SwipeRefreshLayout mSwipeRefreshLayout; 44 | 45 | @Inject 46 | QuanziListPresenter quanziListPresenter; 47 | 48 | private QuanziAdapter mAdapter; 49 | private List blogList = new ArrayList<>(); 50 | 51 | public static QuanziListFragment newInstance() { 52 | return new QuanziListFragment(); 53 | } 54 | 55 | @Override 56 | public void onCreate(@Nullable Bundle savedInstanceState) { 57 | super.onCreate(savedInstanceState); 58 | 59 | DaggerQuanziListComponent.builder() 60 | .applicationComponent(DebugDemoApp.getAppContext().getApplicationComponent()) 61 | .quanziListModule(new QuanziListModule(this)) 62 | .build().inject(this); 63 | } 64 | 65 | @Nullable 66 | @Override 67 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 68 | View view = inflater.inflate(R.layout.fragment_quanzi_list, container, false); 69 | ButterKnife.bind(this, view); 70 | initSwipeRefreshLayout(); 71 | initRecyclerView(); 72 | quanziListPresenter.subscribe(); 73 | return view; 74 | } 75 | 76 | private void initSwipeRefreshLayout() { 77 | mSwipeRefreshLayout.setColorSchemeResources(R.color.colorControlNormal); 78 | mSwipeRefreshLayout.setOnRefreshListener(() -> { 79 | blogList.clear(); 80 | quanziListPresenter.loadData(); 81 | }); 82 | } 83 | 84 | private void initRecyclerView() { 85 | mRecyclerView.setHasFixedSize(true); 86 | mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); 87 | mAdapter = new QuanziAdapter(); 88 | mRecyclerView.setAdapter(mAdapter); 89 | mAdapter.setOnItemClickListener((position, holder) -> { 90 | Intent intent = new Intent(getActivity(), QuanziDetailsActivity.class); 91 | intent.putExtra("id", blogList.get(position).getBlog_id()); 92 | intent.putExtra("title",blogList.get(position).getContent()); 93 | getActivity().startActivity(intent); 94 | }); 95 | LoadMoreWrapper.with(mAdapter) 96 | .setFooterView(R.layout.layout_load_more) 97 | .setLoadMoreEnabled(true) 98 | .setListener(enabled -> { 99 | long lastId = -1; 100 | long hotLastId = -1; 101 | int size = blogList.size(); 102 | if (size >= 2) { 103 | lastId = Long.valueOf(blogList.get(blogList.size() - 2).getBlog_id()); 104 | hotLastId = Long.valueOf(blogList.get(blogList.size() - 1).getBlog_id()); 105 | quanziListPresenter.loadMoreData(lastId, hotLastId); 106 | } 107 | }) 108 | .into(mRecyclerView); 109 | } 110 | 111 | @Override 112 | public void setPresenter(QuanziListContract.Presenter presenter) { 113 | } 114 | 115 | 116 | @Override 117 | public void displayData(List quanziInfos) { 118 | mSwipeRefreshLayout.setRefreshing(false); 119 | blogList.addAll(quanziInfos); 120 | mAdapter.setDataSources(blogList); 121 | mAdapter.notifyDataSetChanged(); 122 | } 123 | 124 | @Override 125 | public void onDestroyView() { 126 | super.onDestroyView(); 127 | ButterKnife.unbind(this); 128 | quanziListPresenter.unSubscribe(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/utils/ActivityScoped.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.utils; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | import javax.inject.Scope; 8 | 9 | 10 | @Scope 11 | @Documented 12 | @Retention(RetentionPolicy.RUNTIME) 13 | public @interface ActivityScoped { 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/utils/ActivityUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.utils; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentTransaction; 6 | 7 | /** 8 | * Created by cnsunrun on 2017/4/18. 9 | */ 10 | 11 | public class ActivityUtils { 12 | 13 | public static void addFragmentToActivity(FragmentManager fragmentManager, Fragment fragment, int frameId) { 14 | FragmentTransaction transaction = fragmentManager.beginTransaction(); 15 | transaction.add(frameId, fragment); 16 | transaction.commit(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/utils/DisplayUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Project Name: juju_android 3 | * Package Name: la.juju.android.util 4 | * File Name: DisplayUtil.java 5 | * Created Time: 2014-10-6 下午2:28:12 6 | * Copyright (c) 2014, imRock.juju.la All Rights Reserved. 7 | */ 8 | package com.example.cnsunrun.debugdemo.utils; 9 | 10 | import android.content.Context; 11 | import android.content.res.Resources; 12 | import android.util.DisplayMetrics; 13 | import android.util.TypedValue; 14 | import android.view.Display; 15 | import android.view.WindowManager; 16 | 17 | import java.lang.reflect.Field; 18 | 19 | import static android.util.Log.w; 20 | 21 | /** 22 | * Utils for getting display metrics such as screen size, dp, sp and px... 23 | * depend on different user device. 24 | *

This class is thread safe.

25 | * 26 | * @author imRock, *rockyoungljy@gmail.com* 27 | * @version DisplayUtil, v 0.1 28 | */ 29 | public class DisplayUtil { 30 | 31 | private static final String DEBUG_TAG = DisplayUtil.class.getSimpleName(); 32 | 33 | private static Context appContext; 34 | 35 | private static int screenWidth; 36 | private static int screenHeight; 37 | 38 | private static int statusBarHeight; 39 | 40 | private DisplayUtil() { 41 | } 42 | 43 | /** 44 | * If want to use the more convenient method like {@link #getScreenWidth()}, 45 | * {@link #getScreenHeight()} and {@link #getStatusBarHeight()}, should call this 46 | * with application context before. it's good to initialize in the application's 47 | * onCreate call back. 48 | * 49 | * @param appContext must be application context for best practise 50 | */ 51 | public synchronized static void init(Context appContext) { 52 | DisplayUtil.appContext = appContext; 53 | int[] size = getScreenSize(appContext); 54 | screenWidth = size[0]; 55 | screenHeight = size[1]; 56 | statusBarHeight = getStatusBarHeight(appContext); 57 | } 58 | 59 | /** 60 | * This method is guaranteed to get the proper screen width and height. 61 | * 62 | * @param context any activity or application context 63 | * @return the size with width and height pixels of screen 64 | */ 65 | public synchronized static int[] getScreenSize(Context context) { 66 | final String name = Context.WINDOW_SERVICE; 67 | final Object service = context.getSystemService(name); 68 | final WindowManager wm = (WindowManager) service; 69 | final Display display = wm.getDefaultDisplay(); 70 | final DisplayMetrics dm = new DisplayMetrics(); 71 | display.getMetrics(dm); 72 | screenWidth = dm.widthPixels; 73 | screenHeight = dm.heightPixels; 74 | int[] size = new int[2]; 75 | size[0] = screenWidth; 76 | size[1] = screenHeight; 77 | // Log.d("screenWidth of size[0]", String.valueOf(size[0])); 78 | // Log.d("screenHeight of size[1]", String.valueOf(size[1])); 79 | return size; 80 | } 81 | 82 | private static final String DIMEN_CLASS_NAME = "com.android.internal.R$dimen"; 83 | private static final String SB_HEIGHT_FIELD_NAME = "status_bar_height"; 84 | 85 | /** 86 | * Get the proper system status bar's height using reflection. 87 | * 88 | * @param context any activity or application context 89 | * @return the height in pixel of system status bar 90 | */ 91 | public synchronized static int getStatusBarHeight(Context context) { 92 | try { 93 | final Class theClass = Class.forName(DIMEN_CLASS_NAME); 94 | final Object classObj = theClass.newInstance(); 95 | final Field field = theClass.getField(SB_HEIGHT_FIELD_NAME); 96 | final Object idObj = field.get(classObj); 97 | final String idStr = idObj.toString(); 98 | final int id = Integer.parseInt(idStr); 99 | final Resources resources = context.getResources(); 100 | statusBarHeight = resources.getDimensionPixelSize(id); 101 | } catch (Exception e) { 102 | e.printStackTrace(); 103 | } 104 | // Log.d("statusBarHeight", String.valueOf(statusBarHeight)); 105 | return statusBarHeight; 106 | } 107 | 108 | /** 109 | * Get the user device's screen width, the correctness is not guaranteed, 110 | * because it's depend on the calling sequence. 111 | * WARNING: Should calling {@link #init(Context)} or {@link #getScreenSize(Context)} before, 112 | * or you may get 0 as result. 113 | * 114 | * @return the pixel width of screen, return 0 if the call order is wrong 115 | */ 116 | public synchronized static int getScreenWidth() { 117 | if (screenWidth == 0 && appContext != null) { 118 | int[] size = getScreenSize(appContext); 119 | screenWidth = size[0]; 120 | screenHeight = size[1]; 121 | } 122 | return screenWidth; 123 | } 124 | 125 | /** 126 | * Get the user device's screen height, the correctness is not guaranteed, 127 | * because it's depend on the calling sequence. 128 | * WARNING: Should calling {@link #init(Context)} or {@link #getScreenSize(Context)} before, 129 | * or you may get 0 as result. 130 | * 131 | * @return the pixel height of screen, return 0 if the call order is wrong 132 | */ 133 | public synchronized static int getScreenHeight() { 134 | if (screenHeight == 0 && appContext != null) { 135 | int[] size = getScreenSize(appContext); 136 | screenWidth = size[0]; 137 | screenHeight = size[1]; 138 | } 139 | return screenHeight; 140 | } 141 | 142 | public synchronized static float getScreenRate() { 143 | if ((screenWidth == 0 || screenHeight == 0) && appContext != null) { 144 | int[] size = getScreenSize(appContext); 145 | screenWidth = size[0]; 146 | screenHeight = size[1]; 147 | } 148 | return (float) screenHeight / (float) screenWidth; 149 | } 150 | 151 | /** 152 | * Get the system status bar's height, the correctness is not guaranteed, 153 | * because it's depend on the calling sequence. 154 | * WARNING: Should calling {@link #init(Context)} or {@link #getStatusBarHeight(Context)} before, 155 | * or you may get 0 as result. 156 | * 157 | * @return the pixel height of system status bar, return 0 if the call order is wrong 158 | */ 159 | public synchronized static int getStatusBarHeight() { 160 | if (statusBarHeight == 0 && appContext != null) { 161 | statusBarHeight = getStatusBarHeight(appContext); 162 | } 163 | return statusBarHeight; 164 | } 165 | 166 | 167 | private static final String WARNING_MSG0 = "Should call init(Context appContext) before this!"; 168 | private static final String WARNING_MSG1 = "The result from this method is WRONG basically!"; 169 | 170 | /** 171 | * Another way to convert dp(density-independent pixels) unit to equivalent px(pixels), 172 | * depending on device {@link DisplayMetrics}, using {@link TypedValue}. 173 | * This method is more recommended compared to {@link #convertDpToPx(float, Context)}. 174 | * 175 | * @param dp value in dp unit which will be converted into px 176 | * @param context context to get resources and device specific display metrics 177 | * @return a float value to represent px equivalent to dp 178 | */ 179 | public synchronized static float dpToPx(float dp, Context context) { 180 | final Resources resources = context.getResources(); 181 | final DisplayMetrics metrics = resources.getDisplayMetrics(); 182 | final int unit = TypedValue.COMPLEX_UNIT_DIP; 183 | return TypedValue.applyDimension(unit, dp, metrics); 184 | } 185 | 186 | /** 187 | * Calling this instead of {@link #dpToPx(float, Context)} for convenience, ONLY 188 | * IF you have {@link #init(Context)} with the application context before. 189 | * WARNING: Will return the original value passed in by @param dp when calling 190 | * sequence is wrong! 191 | * 192 | * @param dp value in dp unit which will be converted into px 193 | * @return a float value to represent px equivalent to dp 194 | */ 195 | public synchronized static float dpToPx(float dp) { 196 | if (appContext != null) { 197 | return dpToPx(dp, appContext); 198 | } else { 199 | w(DEBUG_TAG + ".dpToPx()", WARNING_MSG0); 200 | w(DEBUG_TAG + ".dpToPx()", WARNING_MSG1); 201 | return dp; 202 | } 203 | } 204 | 205 | /** 206 | * Convert dp(density-independent pixels) unit to equivalent px(pixels), depending on 207 | * device densityDpi of {@link DisplayMetrics}. 208 | * 209 | * @param dp value in dp unit which will be converted into px 210 | * @param context context to get resources and device specific display metrics 211 | * @return a float value to represent px equivalent to dp 212 | */ 213 | public synchronized static float convertDpToPx(float dp, Context context) { 214 | Resources resources = context.getResources(); 215 | DisplayMetrics metrics = resources.getDisplayMetrics(); 216 | final int densityDpi = metrics.densityDpi; 217 | return dp * (densityDpi / 160f); 218 | } 219 | 220 | /** 221 | * Calling this instead of {@link #convertDpToPx(float, Context)} for convenience, 222 | * ONLY IF you have {@link #init(Context)} with the application context before. 223 | * WARNING: Will return the original value passed in by @param dp when calling 224 | * sequence is wrong! 225 | * 226 | * @param dp value in dp unit which will be converted into px 227 | * @return a float value to represent px equivalent to dp 228 | */ 229 | public synchronized static float convertDpToPx(float dp) { 230 | if (appContext != null) { 231 | return convertDpToPx(dp, appContext); 232 | } else { 233 | w(DEBUG_TAG + ".convertDpToPixel()", WARNING_MSG0); 234 | w(DEBUG_TAG + ".convertDpToPixel()", WARNING_MSG1); 235 | return dp; 236 | } 237 | } 238 | 239 | /** 240 | * Convert px(pixels) unit to equivalent dp(density-independent pixels), depending on 241 | * device densityDpi of {@link DisplayMetrics}. 242 | * 243 | * @param px value in px unit which will be converted into dp 244 | * @param context context to get resources and device specific display metrics 245 | * @return a float value to represent dp equivalent to px 246 | */ 247 | public synchronized static float convertPxToDp(float px, Context context) { 248 | Resources resources = context.getResources(); 249 | DisplayMetrics metrics = resources.getDisplayMetrics(); 250 | final int densityDpi = metrics.densityDpi; 251 | return px / (densityDpi / 160f); 252 | } 253 | 254 | /** 255 | * Calling this instead of {@link #convertPxToDp(float, Context)} for convenience, 256 | * ONLY IF you have {@link #init(Context)} with the application context before. 257 | * WARNING: Will return the original value passed in by @param px when calling 258 | * sequence is wrong! 259 | * 260 | * @param px value in px unit which will be converted into dp 261 | * @return a float value to represent dp equivalent to px 262 | */ 263 | public synchronized static float convertPxToDp(float px) { 264 | if (appContext != null) { 265 | return convertPxToDp(px, appContext); 266 | } else { 267 | w(DEBUG_TAG + ".convertPixelsToDp()", WARNING_MSG0); 268 | w(DEBUG_TAG + ".convertPixelsToDp()", WARNING_MSG1); 269 | return px; 270 | } 271 | } 272 | 273 | /** 274 | * Convert sp(scale-independent pixels) unit to equivalent px(pixels), depending on 275 | * device scaledDensity of {@link DisplayMetrics}. 276 | * 277 | * @param sp value in sp unit which will be converted into px 278 | * @param context context to get resources and device specific display metrics 279 | * @return a float value to represent px equivalent to sp 280 | */ 281 | public synchronized static float convertSpToPx(float sp, Context context) { 282 | final Resources resources = context.getResources(); 283 | final DisplayMetrics metrics = resources.getDisplayMetrics(); 284 | final float fontScale = metrics.scaledDensity; 285 | return sp * fontScale; 286 | } 287 | 288 | /** 289 | * Calling this instead of {@link #convertSpToPx(float, Context)} for convenience, 290 | * ONLY IF you have {@link #init(Context)} with the application context before. 291 | * WARNING: Will return the original value passed in by @param px when calling 292 | * sequence is wrong! 293 | * 294 | * @param sp value in sp unit which will be converted into px 295 | * @return a float value to represent px equivalent to sp 296 | */ 297 | public synchronized static float convertSpToPx(float sp) { 298 | if (appContext != null) { 299 | return convertSpToPx(sp, appContext); 300 | } else { 301 | w(DEBUG_TAG + ".spToPx()", WARNING_MSG0); 302 | w(DEBUG_TAG + ".spToPx()", WARNING_MSG1); 303 | return sp; 304 | } 305 | } 306 | 307 | /** 308 | * Convert px(pixels) unit to equivalent sp(scale-independent pixels), depending on 309 | * device scaledDensity of {@link DisplayMetrics}. 310 | * 311 | * @param px value in px unit which will be converted into sp 312 | * @param context context to get resources and device specific display metrics 313 | * @return a float value to represent sp equivalent to px 314 | */ 315 | public synchronized static float convertPxToSp(float px, Context context) { 316 | final Resources resources = context.getResources(); 317 | final DisplayMetrics metrics = resources.getDisplayMetrics(); 318 | final float fontScale = metrics.scaledDensity; 319 | return px / fontScale; 320 | } 321 | 322 | /** 323 | * Calling this instead of {@link #convertPxToSp(float, Context)} for convenience, 324 | * ONLY IF you have {@link #init(Context)} with the application context before. 325 | * WARNING: Will return the original value passed in by @param px when calling 326 | * sequence is wrong! 327 | * 328 | * @param px value in px unit which will be converted into sp 329 | * @return a float value to represent sp equivalent to px 330 | */ 331 | public synchronized static float convertPxToSp(float px) { 332 | if (appContext != null) { 333 | return convertPxToSp(px, appContext); 334 | } else { 335 | w(DEBUG_TAG + ".pxToSp()", WARNING_MSG0); 336 | w(DEBUG_TAG + ".pxToSp()", WARNING_MSG1); 337 | return px; 338 | } 339 | } 340 | 341 | } 342 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/utils/ImgUrlUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.File; 6 | 7 | 8 | /** 9 | * Created by imRock on 15/6/30. 10 | * Under package la.juju.android.util. 11 | */ 12 | public class ImgUrlUtil { 13 | 14 | public static String TOPIC_DOWNLOAD_BASE_URL = "http://juju.inbbuy.cn"; 15 | public static String COMMENT_DOWNLOAD_BASE_URL = "http://juju1.inbbuy.cn"; 16 | public static String AVATAR_DOWNLOAD_BASE_URL = "http://juju2.inbbuy.cn"; 17 | public static String PIC_QUALITY_KEY = "pic_quality"; 18 | 19 | public static int quality; 20 | public static final int LOW_QUALITY = 40; 21 | public static final int MIDDLE_QUALITY = 60; 22 | public static final int HIGH_QUALITY = 90; 23 | 24 | public enum QUALITY { 25 | L, // 40Q 26 | M, // 60Q 27 | H, // 80Q 28 | X, // 90Q 29 | O, // 100Q 30 | } 31 | 32 | private ImgUrlUtil() { 33 | } 34 | 35 | // public synchronized boolean isValidUrl() { 36 | // 37 | // } 38 | 39 | public enum AVATAR_NORMS { 40 | /** 41 | *

0dp < size < 36dp
42 | */ 43 | SMALL, 44 | /** 45 | *
36dp <= size < 66dp
46 | */ 47 | NORMAL, 48 | /** 49 | *
66dp < size
50 | */ 51 | LARGE 52 | } 53 | 54 | public synchronized static String getAvatarImgUrl(String urlOrOssKey, float dpSize) { 55 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.AVATAR); 56 | if (sb.length() == 0) { 57 | return sb.toString(); // TODO should return a default failure pic url 58 | } 59 | float realToGetDpSize; 60 | if (0f < dpSize && dpSize < 36f) { 61 | realToGetDpSize = 24f; // small 62 | } else if (36f <= dpSize && dpSize < 66f) { 63 | realToGetDpSize = 48f; // normal 64 | } else if (66f < dpSize) { 65 | realToGetDpSize = 84f; // large 66 | } else { 67 | realToGetDpSize = 48f; //normal 68 | } 69 | final float sizeFloat = DisplayUtil.dpToPx(realToGetDpSize); 70 | int size = resizeQuality((int) Math.ceil(sizeFloat), quality); 71 | sb.append("@"); 72 | sb.append(size); 73 | sb.append("w_"); 74 | sb.append(size); 75 | sb.append("h_"); 76 | sb.append(quality); 77 | sb.append("Q_"); 78 | sb.append("2o_"); 79 | sb.append("1e_1c.src");// 按短边缩放并自动中间裁减 80 | return sb.toString(); 81 | } 82 | 83 | public synchronized static String getAvatarImgUrl(String urlOrOssKey) { 84 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.AVATAR); 85 | if (sb.length() == 0) { 86 | return sb.toString(); // TODO should return a default failure pic url 87 | } 88 | return sb.toString(); 89 | } 90 | 91 | 92 | public synchronized static String getTopicImgUrlInWaterFlow(String urlOrOssKey, int pxh) { 93 | // final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.TOPIC); 94 | // if (sb.length() == 0) { 95 | // return sb.toString(); // TODO should return a default failure pic url 96 | // } 97 | final int screenWidth = DisplayUtil.getScreenWidth(); 98 | final float gapsDp = 33.75f; 99 | final float gapsPx = DisplayUtil.dpToPx(gapsDp); 100 | final int pxw = (int) Math.ceil((screenWidth - gapsPx) / 2f); 101 | int heightC = (int) Math.ceil(((double) pxw * 1.5)); 102 | if (pxh > 0) 103 | if (pxh > heightC) { 104 | pxh = heightC; 105 | } 106 | return getTopicImgUrl(urlOrOssKey, pxw, pxh); 107 | // sb.append("@"); 108 | // sb.append(pxw); 109 | // sb.append("w_"); 110 | // sb.append(quality); 111 | // sb.append("Q_"); 112 | // sb.append("1l.jpg");// 如果目标缩略图大于原图不处理 113 | // return sb.toString(); 114 | } 115 | 116 | public synchronized static String getTopicImgUrl(String urlOrOssKey) { 117 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.TOPIC); 118 | if (sb.length() == 0) { 119 | return sb.toString(); // TODO should return a default failure pic url 120 | } 121 | return sb.toString(); 122 | } 123 | 124 | public synchronized static String getTopicImgUrl(String urlOrOssKey, int pxw) { 125 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.TOPIC); 126 | if (sb.length() == 0) { 127 | return sb.toString(); // TODO should return a default failure pic url 128 | } 129 | sb.append("@"); 130 | sb.append(resizeQuality(pxw, quality)); 131 | sb.append("w_"); 132 | sb.append(quality); 133 | sb.append("Q_"); 134 | sb.append("2o_"); 135 | sb.append("1l.src");// 如果目标缩略图大于原图不处理 136 | return sb.toString(); 137 | } 138 | 139 | public synchronized static String getTopicSourceImgUrl(String urlOrOssKey) { 140 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.TOPIC); 141 | if (sb.length() == 0) { 142 | return sb.toString(); // TODO should return a default failure pic url 143 | } 144 | sb.append("@"); 145 | sb.append(DisplayUtil.getScreenWidth()); 146 | sb.append("w_"); 147 | sb.append(100); 148 | sb.append("Q_"); 149 | sb.append("2o_"); 150 | sb.append("1l.src");// 如果目标缩略图大于原图不处理 151 | return sb.toString(); 152 | } 153 | 154 | public synchronized static String getAvatarSourceImgUrl(String urlOrOssKey) { 155 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.AVATAR); 156 | if (sb.length() == 0) { 157 | return sb.toString(); // TODO should return a default failure pic url 158 | } 159 | sb.append("@"); 160 | sb.append(DisplayUtil.getScreenWidth()); 161 | sb.append("w_"); 162 | sb.append(100); 163 | sb.append("Q_"); 164 | sb.append("2o_"); 165 | sb.append("1l.src");// 如果目标缩略图大于原图不处理 166 | return sb.toString(); 167 | } 168 | 169 | public synchronized static String getCommentSourceImgUrl(String urlOrOssKey) { 170 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.COMMENT); 171 | if (sb.length() == 0) { 172 | return sb.toString(); // TODO should return a default failure pic url 173 | } 174 | sb.append("@"); 175 | sb.append(DisplayUtil.getScreenWidth()); 176 | sb.append("w_"); 177 | sb.append(100); 178 | sb.append("Q_"); 179 | sb.append("2o_"); 180 | sb.append("1l.src");// 如果目标缩略图大于原图不处理 181 | return sb.toString(); 182 | } 183 | 184 | public synchronized static String getEventImgUrl(String urlOrOssKey, int pxw, int pxh) { 185 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.AVATAR); 186 | if (sb.length() == 0) { 187 | return sb.toString(); // TODO should return a default failure pic url 188 | } 189 | sb.append("@"); 190 | sb.append(resizeQuality(pxw, quality)); 191 | sb.append("w_"); 192 | sb.append(resizeQuality(pxh, quality)); 193 | sb.append("h_"); 194 | sb.append(quality); 195 | sb.append("Q_"); 196 | sb.append("2o_"); 197 | sb.append("1l_1c.src");// 自动中间裁减, 如果目标缩略图大于原图不处理 198 | return sb.toString(); 199 | } 200 | 201 | 202 | public synchronized static String getTopicImgUrl(String urlOrOssKey, int pxw, int pxh) { 203 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.TOPIC); 204 | if (sb.length() == 0) { 205 | return sb.toString(); // TODO should return a default failure pic url 206 | } 207 | sb.append("@"); 208 | sb.append(resizeQuality(pxw, quality)); 209 | sb.append("w_"); 210 | sb.append(resizeQuality(pxh, quality)); 211 | sb.append("h_"); 212 | sb.append(quality); 213 | sb.append("Q_"); 214 | sb.append("2o_"); 215 | sb.append("1l_1c.src");// 自动中间裁减, 如果目标缩略图大于原图不处理 216 | return sb.toString(); 217 | } 218 | 219 | public synchronized static String getMomentTopicImgUrl(String urlOrOssKey, int pxw, int pxh) { 220 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.TOPIC); 221 | if (sb.length() == 0) { 222 | return sb.toString(); // TODO should return a default failure pic url 223 | } 224 | sb.append("@"); 225 | sb.append(resizeQuality(pxw, quality)); 226 | sb.append("w_"); 227 | sb.append(resizeQuality(pxh, quality)); 228 | sb.append("h_"); 229 | sb.append(quality); 230 | sb.append("Q_"); 231 | sb.append("2o_"); 232 | sb.append("1l.src");// 如果目标缩略图大于原图不处理 233 | return sb.toString(); 234 | } 235 | 236 | 237 | public synchronized static String getCommentImgUrl(String urlOrOssKey, int pxw, int pxh) { 238 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.COMMENT); 239 | if (sb.length() == 0) { 240 | return sb.toString(); // TODO should return a default failure pic url 241 | } 242 | sb.append("@"); 243 | sb.append(resizeQuality(pxw, quality)); 244 | sb.append("w_"); 245 | sb.append(resizeQuality(pxh, quality)); 246 | sb.append("h_"); 247 | sb.append(quality); 248 | sb.append("Q_"); 249 | sb.append("2o_"); 250 | sb.append("1l_1c.src");// 自动中间裁减, 如果目标缩略图大于原图不处理 251 | return sb.toString(); 252 | } 253 | 254 | public synchronized static String getCommentImgUrl(String urlOrOssKey, int pxw) { 255 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.COMMENT); 256 | if (sb.length() == 0) { 257 | return sb.toString(); // TODO should return a default failure pic url 258 | } 259 | sb.append("@"); 260 | sb.append(resizeQuality(pxw, quality)); 261 | sb.append("w_"); 262 | sb.append(quality); 263 | sb.append("Q_"); 264 | sb.append("2o_"); 265 | sb.append("1l.src");// 如果目标缩略图大于原图不处理 266 | return sb.toString(); 267 | } 268 | 269 | public synchronized static String getCommentImgUrl(String urlOrOssKey) { 270 | final StringBuilder sb = ossKeyToUrl(urlOrOssKey, IMG_TYPE.COMMENT); 271 | if (sb.length() == 0) { 272 | return sb.toString(); // TODO should return a default failure pic url 273 | } 274 | return sb.toString(); 275 | } 276 | 277 | public enum IMG_TYPE { 278 | AVATAR, TOPIC, COMMENT 279 | } 280 | 281 | private static int resizeQuality(int size, int quality) { 282 | switch (quality) { 283 | case LOW_QUALITY: 284 | size = size / 2; 285 | break; 286 | case MIDDLE_QUALITY: 287 | size = (int) (size / 1.5); 288 | break; 289 | case HIGH_QUALITY: 290 | break; 291 | } 292 | return size; 293 | } 294 | 295 | 296 | public synchronized static String getImgUrl(String urlOrOssKey, IMG_TYPE type, boolean isOrigin) { 297 | if (type==null){ 298 | return urlOrOssKey; 299 | } 300 | switch (type) { 301 | case AVATAR: 302 | return isOrigin ? getAvatarImgUrl(urlOrOssKey) : getAvatarSourceImgUrl(urlOrOssKey); 303 | case TOPIC: 304 | return isOrigin ? getTopicImgUrl(urlOrOssKey) : getTopicSourceImgUrl(urlOrOssKey); 305 | case COMMENT: 306 | return isOrigin ? getCommentImgUrl(urlOrOssKey) : getCommentSourceImgUrl(urlOrOssKey); 307 | default: 308 | return ""; 309 | } 310 | } 311 | 312 | // 兼容老板版数据 313 | public synchronized static StringBuilder ossKeyToUrl(String urlOrOssKey, IMG_TYPE type) { 314 | final StringBuilder sb = new StringBuilder(); 315 | if (TextUtils.isEmpty(urlOrOssKey)) { 316 | return sb; 317 | } 318 | if (urlOrOssKey.startsWith("http")) { 319 | sb.append(urlOrOssKey); 320 | } else { 321 | switch (type) { 322 | case AVATAR: 323 | sb.append(AVATAR_DOWNLOAD_BASE_URL); 324 | break; 325 | case TOPIC: 326 | sb.append(TOPIC_DOWNLOAD_BASE_URL); 327 | break; 328 | case COMMENT: 329 | sb.append(COMMENT_DOWNLOAD_BASE_URL); 330 | break; 331 | } 332 | final String fs = File.separator; 333 | final int p = urlOrOssKey.indexOf(fs); 334 | if (0 != p) { 335 | sb.append(fs); 336 | } 337 | sb.append(urlOrOssKey); 338 | } 339 | return sb; 340 | } 341 | 342 | } 343 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/widget/CircleImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.widget; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapShader; 8 | import android.graphics.Canvas; 9 | import android.graphics.Color; 10 | import android.graphics.ColorFilter; 11 | import android.graphics.Matrix; 12 | import android.graphics.Paint; 13 | import android.graphics.RectF; 14 | import android.graphics.Shader; 15 | import android.graphics.drawable.BitmapDrawable; 16 | import android.graphics.drawable.ColorDrawable; 17 | import android.graphics.drawable.Drawable; 18 | import android.net.Uri; 19 | import android.support.annotation.ColorRes; 20 | import android.support.annotation.DrawableRes; 21 | import android.util.AttributeSet; 22 | import android.widget.ImageView; 23 | 24 | import com.example.cnsunrun.debugdemo.R; 25 | 26 | /** 27 | * Created by hcc on 16/8/7 21:18 28 | * 100332338@qq.com 29 | *

30 | * 圆形头像 31 | */ 32 | @SuppressLint("AppCompatCustomView") 33 | public class CircleImageView extends ImageView { 34 | 35 | private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; 36 | 37 | private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; 38 | 39 | private static final int COLORDRAWABLE_DIMENSION = 2; 40 | 41 | private static final int DEFAULT_BORDER_WIDTH = 0; 42 | 43 | private static final int DEFAULT_BORDER_COLOR = Color.BLACK; 44 | 45 | private static final boolean DEFAULT_BORDER_OVERLAY = false; 46 | 47 | private final RectF mDrawableRect = new RectF(); 48 | 49 | private final RectF mBorderRect = new RectF(); 50 | 51 | private final Matrix mShaderMatrix = new Matrix(); 52 | 53 | private final Paint mBitmapPaint = new Paint(); 54 | 55 | private final Paint mBorderPaint = new Paint(); 56 | 57 | private int mBorderColor = DEFAULT_BORDER_COLOR; 58 | 59 | private int mBorderWidth = DEFAULT_BORDER_WIDTH; 60 | 61 | private Bitmap mBitmap; 62 | 63 | private BitmapShader mBitmapShader; 64 | 65 | private int mBitmapWidth; 66 | 67 | private int mBitmapHeight; 68 | 69 | private float mDrawableRadius; 70 | 71 | private float mBorderRadius; 72 | 73 | private ColorFilter mColorFilter; 74 | 75 | private boolean mReady; 76 | 77 | private boolean mSetupPending; 78 | 79 | private boolean mBorderOverlay; 80 | 81 | 82 | public CircleImageView(Context context) { 83 | 84 | super(context); 85 | 86 | init(); 87 | } 88 | 89 | 90 | public CircleImageView(Context context, AttributeSet attrs) { 91 | 92 | this(context, attrs, 0); 93 | } 94 | 95 | 96 | public CircleImageView(Context context, AttributeSet attrs, int defStyle) { 97 | 98 | super(context, attrs, defStyle); 99 | 100 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); 101 | 102 | mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, 103 | DEFAULT_BORDER_WIDTH); 104 | mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR); 105 | mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_border_overlay, 106 | DEFAULT_BORDER_OVERLAY); 107 | 108 | a.recycle(); 109 | 110 | init(); 111 | } 112 | 113 | 114 | private void init() { 115 | 116 | super.setScaleType(SCALE_TYPE); 117 | mReady = true; 118 | 119 | if (mSetupPending) { 120 | setup(); 121 | mSetupPending = false; 122 | } 123 | } 124 | 125 | 126 | @Override 127 | public ScaleType getScaleType() { 128 | 129 | return SCALE_TYPE; 130 | } 131 | 132 | 133 | @Override 134 | public void setScaleType(ScaleType scaleType) { 135 | 136 | if (scaleType != SCALE_TYPE) { 137 | throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); 138 | } 139 | } 140 | 141 | 142 | @Override 143 | public void setAdjustViewBounds(boolean adjustViewBounds) { 144 | 145 | if (adjustViewBounds) { 146 | throw new IllegalArgumentException("adjustViewBounds not supported."); 147 | } 148 | } 149 | 150 | 151 | @Override 152 | protected void onDraw(Canvas canvas) { 153 | 154 | if (getDrawable() == null) { 155 | return; 156 | } 157 | 158 | canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); 159 | if (mBorderWidth != 0) { 160 | canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); 161 | } 162 | } 163 | 164 | 165 | @Override 166 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 167 | 168 | super.onSizeChanged(w, h, oldw, oldh); 169 | setup(); 170 | } 171 | 172 | 173 | public int getBorderColor() { 174 | 175 | return mBorderColor; 176 | } 177 | 178 | 179 | public void setBorderColor(int borderColor) { 180 | 181 | if (borderColor == mBorderColor) { 182 | return; 183 | } 184 | 185 | mBorderColor = borderColor; 186 | mBorderPaint.setColor(mBorderColor); 187 | invalidate(); 188 | } 189 | 190 | 191 | public void setBorderColorResource(@ColorRes int borderColorRes) { 192 | 193 | setBorderColor(getContext().getResources().getColor(borderColorRes)); 194 | } 195 | 196 | 197 | public int getBorderWidth() { 198 | 199 | return mBorderWidth; 200 | } 201 | 202 | 203 | public void setBorderWidth(int borderWidth) { 204 | 205 | if (borderWidth == mBorderWidth) { 206 | return; 207 | } 208 | 209 | mBorderWidth = borderWidth; 210 | setup(); 211 | } 212 | 213 | 214 | public boolean isBorderOverlay() { 215 | 216 | return mBorderOverlay; 217 | } 218 | 219 | 220 | public void setBorderOverlay(boolean borderOverlay) { 221 | 222 | if (borderOverlay == mBorderOverlay) { 223 | return; 224 | } 225 | 226 | mBorderOverlay = borderOverlay; 227 | setup(); 228 | } 229 | 230 | 231 | @Override 232 | public void setImageBitmap(Bitmap bm) { 233 | 234 | super.setImageBitmap(bm); 235 | mBitmap = bm; 236 | setup(); 237 | } 238 | 239 | 240 | @Override 241 | public void setImageDrawable(Drawable drawable) { 242 | 243 | super.setImageDrawable(drawable); 244 | mBitmap = getBitmapFromDrawable(drawable); 245 | setup(); 246 | } 247 | 248 | 249 | @Override 250 | public void setImageResource(@DrawableRes int resId) { 251 | 252 | super.setImageResource(resId); 253 | mBitmap = getBitmapFromDrawable(getDrawable()); 254 | setup(); 255 | } 256 | 257 | 258 | @Override 259 | public void setImageURI(Uri uri) { 260 | 261 | super.setImageURI(uri); 262 | mBitmap = getBitmapFromDrawable(getDrawable()); 263 | setup(); 264 | } 265 | 266 | 267 | @Override 268 | public void setColorFilter(ColorFilter cf) { 269 | 270 | if (cf == mColorFilter) { 271 | return; 272 | } 273 | 274 | mColorFilter = cf; 275 | mBitmapPaint.setColorFilter(mColorFilter); 276 | invalidate(); 277 | } 278 | 279 | 280 | private Bitmap getBitmapFromDrawable(Drawable drawable) { 281 | 282 | if (drawable == null) { 283 | return null; 284 | } 285 | 286 | if (drawable instanceof BitmapDrawable) { 287 | return ((BitmapDrawable) drawable).getBitmap(); 288 | } 289 | 290 | try { 291 | Bitmap bitmap; 292 | 293 | if (drawable instanceof ColorDrawable) { 294 | bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, 295 | BITMAP_CONFIG); 296 | } else { 297 | bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), 298 | BITMAP_CONFIG); 299 | } 300 | 301 | Canvas canvas = new Canvas(bitmap); 302 | drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 303 | drawable.draw(canvas); 304 | return bitmap; 305 | } catch (OutOfMemoryError e) { 306 | return null; 307 | } 308 | } 309 | 310 | 311 | private void setup() { 312 | 313 | if (!mReady) { 314 | mSetupPending = true; 315 | return; 316 | } 317 | 318 | if (mBitmap == null) { 319 | return; 320 | } 321 | 322 | mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 323 | 324 | mBitmapPaint.setAntiAlias(true); 325 | mBitmapPaint.setShader(mBitmapShader); 326 | 327 | mBorderPaint.setStyle(Paint.Style.STROKE); 328 | mBorderPaint.setAntiAlias(true); 329 | mBorderPaint.setColor(mBorderColor); 330 | mBorderPaint.setStrokeWidth(mBorderWidth); 331 | 332 | mBitmapHeight = mBitmap.getHeight(); 333 | mBitmapWidth = mBitmap.getWidth(); 334 | 335 | mBorderRect.set(0, 0, getWidth(), getHeight()); 336 | mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, 337 | (mBorderRect.width() - mBorderWidth) / 2); 338 | 339 | mDrawableRect.set(mBorderRect); 340 | if (!mBorderOverlay) { 341 | mDrawableRect.inset(mBorderWidth, mBorderWidth); 342 | } 343 | mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); 344 | 345 | updateShaderMatrix(); 346 | invalidate(); 347 | } 348 | 349 | 350 | private void updateShaderMatrix() { 351 | 352 | float scale; 353 | float dx = 0; 354 | float dy = 0; 355 | 356 | mShaderMatrix.set(null); 357 | 358 | if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { 359 | scale = mDrawableRect.height() / (float) mBitmapHeight; 360 | dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; 361 | } else { 362 | scale = mDrawableRect.width() / (float) mBitmapWidth; 363 | dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; 364 | } 365 | 366 | mShaderMatrix.setScale(scale, scale); 367 | mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, 368 | (int) (dy + 0.5f) + mDrawableRect.top); 369 | 370 | mBitmapShader.setLocalMatrix(mShaderMatrix); 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/cnsunrun/debugdemo/widget/MomentPicView.java: -------------------------------------------------------------------------------- 1 | package com.example.cnsunrun.debugdemo.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.BitmapShader; 8 | import android.graphics.Canvas; 9 | import android.graphics.Color; 10 | import android.graphics.Matrix; 11 | import android.graphics.Paint; 12 | import android.graphics.Rect; 13 | import android.graphics.RectF; 14 | import android.graphics.Shader; 15 | import android.util.AttributeSet; 16 | import android.view.MotionEvent; 17 | import android.view.View; 18 | import android.view.ViewConfiguration; 19 | 20 | import com.bumptech.glide.Glide; 21 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 22 | import com.bumptech.glide.request.animation.GlideAnimation; 23 | import com.bumptech.glide.request.target.SimpleTarget; 24 | import com.bumptech.glide.request.target.Target; 25 | import com.example.cnsunrun.debugdemo.R; 26 | import com.example.cnsunrun.debugdemo.utils.DisplayUtil; 27 | 28 | import java.util.ArrayList; 29 | import java.util.Arrays; 30 | import java.util.Collection; 31 | import java.util.Collections; 32 | 33 | 34 | 35 | 36 | /** 37 | * Created by fan on 16/3/16. 38 | */ 39 | public class MomentPicView extends View { 40 | 41 | private String[] mImageUrls; 42 | private Bitmap[] mBitmaps; 43 | private Bitmap mPlaceHolder; 44 | private int mHorizontalSpace = 10; 45 | private int mVerticalSpace = 10; 46 | private int mRadius = 0; 47 | private int mImageWidth = 0; 48 | private int mImageHeight = 0; 49 | private float mRatio = 1f; 50 | private int mColumns; 51 | private int mRows; 52 | private Matrix matrix = new Matrix(); 53 | private final Paint mPaint = new Paint(); 54 | private final Paint mTextPaint = new Paint(); 55 | private final Paint mTextBgPaint = new Paint(); 56 | private OnClickItemListener onClickItemListener; 57 | private MotionEvent mEventDown; 58 | private int mDown; 59 | private RectF[] mDrawRects; 60 | private boolean haveRule;//是否4列 61 | private Target[] mTargets = new Target[0]; 62 | 63 | 64 | public MomentPicView(Context context) { 65 | this(context, null); 66 | } 67 | 68 | public MomentPicView(Context context, AttributeSet attrs) { 69 | this(context, attrs, 0); 70 | } 71 | 72 | public MomentPicView(Context context, AttributeSet attrs, int defStyleAttr) { 73 | super(context, attrs, defStyleAttr); 74 | if (attrs != null) { 75 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MomentPicView); 76 | try { 77 | for (int i = 0; i < a.getIndexCount(); i++) { 78 | int attr = a.getIndex(i); 79 | switch (attr) { 80 | case R.styleable.MomentPicView_mpvHorizontalSpace: 81 | mHorizontalSpace = a.getDimensionPixelSize(attr, mHorizontalSpace); 82 | break; 83 | case R.styleable.MomentPicView_mpvVerticalSpace: 84 | mVerticalSpace = a.getDimensionPixelSize(attr, mVerticalSpace); 85 | break; 86 | case R.styleable.MomentPicView_mpvRadius: 87 | mRadius = a.getDimensionPixelSize(attr, mRadius); 88 | break; 89 | case R.styleable.MomentPicView_mpvRatio: 90 | mRatio = a.getFloat(attr, mRatio); 91 | break; 92 | } 93 | } 94 | } finally { 95 | a.recycle(); 96 | } 97 | } 98 | 99 | mPaint.setAntiAlias(true); 100 | mTextPaint.setAntiAlias(true); 101 | mPlaceHolder = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_placeholder); 102 | 103 | setImageUrls(null); 104 | } 105 | 106 | @Override 107 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 108 | super.onLayout(changed, left, top, right, bottom); 109 | for (int i = 0; i < mImageUrls.length; i++) { 110 | loadBitmap(i, mImageUrls[i]); 111 | } 112 | } 113 | 114 | @Override 115 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 116 | if (mImageUrls.length != 0) { 117 | int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); 118 | mImageWidth = (width - (mColumns - 1) * mHorizontalSpace - getPaddingLeft() - getPaddingRight()) / mColumns; 119 | mImageHeight = (int) (mImageWidth * mRatio); 120 | mRows = (int) Math.ceil(mImageUrls.length * 1f / mColumns); 121 | int height = mImageHeight * mRows + (mRows - 1) * mVerticalSpace + getPaddingTop() + getPaddingBottom(); 122 | setMeasuredDimension(width, height); 123 | } else { 124 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 125 | } 126 | } 127 | 128 | 129 | @Override 130 | protected void onDraw(Canvas canvas) { 131 | super.onDraw(canvas); 132 | if (mBitmaps.length != 0) { 133 | for (int row = 0; row < mRows; row++) { 134 | for (int column = 0; column < mColumns; column++) { 135 | int i = row * mColumns + column; 136 | boolean isGif; 137 | if (i >= mImageUrls.length) { 138 | break; 139 | } else { 140 | isGif = mImageUrls[i].toLowerCase().contains(".gif"); 141 | } 142 | Bitmap bitmap = mBitmaps[i]; 143 | if (bitmap == null) { 144 | bitmap = mPlaceHolder; 145 | } 146 | 147 | 148 | float left = getPaddingLeft() + column * mHorizontalSpace + column * mImageWidth; 149 | float top = getPaddingTop() + row * mVerticalSpace + row * mImageHeight; 150 | float scale; 151 | float dx = 0, dy = 0; 152 | 153 | int dwidth = bitmap.getWidth(); 154 | int dheight = bitmap.getHeight(); 155 | int vwidth = mImageWidth; 156 | int vheight = mImageHeight; 157 | if (dwidth * vheight > vwidth * dheight) { 158 | scale = (float) vheight / (float) dheight; 159 | dx = (vwidth - dwidth * scale) * 0.5f; 160 | } else { 161 | scale = (float) vwidth / (float) dwidth; 162 | dy = (vheight - dheight * scale) * 0.5f; 163 | } 164 | 165 | matrix.setScale(scale, scale); 166 | matrix.postTranslate(left + Math.round(dx), top + Math.round(dy)); 167 | 168 | BitmapShader mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 169 | mBitmapShader.setLocalMatrix(matrix); 170 | mPaint.setShader(mBitmapShader); 171 | RectF rectF = new RectF(); 172 | rectF.set(left, top, left + mImageWidth, top + mImageHeight); 173 | mDrawRects[i] = rectF; 174 | canvas.drawRoundRect(rectF, mRadius, mRadius, mPaint); 175 | if (isGif) { 176 | String gifString = "GIF"; 177 | mTextPaint.setTextSize(DisplayUtil.dpToPx(12)); 178 | mTextPaint.setColor(Color.WHITE); 179 | Rect bounds = new Rect(); 180 | mTextPaint.getTextBounds(gifString, 0, gifString.length(), bounds); 181 | mTextBgPaint.setColor(Color.BLACK); 182 | mTextBgPaint.setAlpha(60); 183 | RectF rectB = new RectF(); 184 | rectB.set(left + DisplayUtil.dpToPx(6), top + DisplayUtil.dpToPx(6), 185 | left + DisplayUtil.dpToPx(6) * 2 + bounds.width(), top + DisplayUtil.dpToPx(6) * 2 + bounds.height()); 186 | canvas.drawRoundRect(rectB, mRadius, mRadius, mTextBgPaint); 187 | canvas.drawText(gifString, left + DisplayUtil.dpToPx(9), top + DisplayUtil.dpToPx(9) + bounds.height(), mTextPaint); 188 | } 189 | } 190 | } 191 | } 192 | } 193 | 194 | 195 | @Override 196 | public boolean onTouchEvent(MotionEvent event) { 197 | boolean isClickItem = false; 198 | int action = event.getActionMasked(); 199 | switch (action) { 200 | case MotionEvent.ACTION_DOWN: 201 | mEventDown = MotionEvent.obtain(event); 202 | mDown = getClickItem(mEventDown); 203 | isClickItem = mDown > -1; 204 | break; 205 | case MotionEvent.ACTION_UP: 206 | if (mEventDown != null) { 207 | float distance = (float) Math.sqrt(Math.pow((event.getX() - mEventDown.getX()), 2) + Math.pow((event.getY() - mEventDown.getY()), 2)); 208 | if (distance < ViewConfiguration.getTouchSlop()) { 209 | int iUp = getClickItem(event); 210 | if (mDown == iUp && iUp > -1) { 211 | isClickItem = true; 212 | if (onClickItemListener != null) { 213 | onClickItemListener.onClick(iUp, new ArrayList<>(Arrays.asList(mImageUrls))); 214 | } 215 | } 216 | } 217 | } 218 | break; 219 | } 220 | return isClickItem || super.onTouchEvent(event); 221 | } 222 | 223 | private int getClickItem(MotionEvent event) { 224 | for (int i = 0; i < mDrawRects.length; i++) { 225 | if (mDrawRects[i] != null && mDrawRects[i].contains(event.getX(), event.getY())) { 226 | return i; 227 | } 228 | } 229 | return -1; 230 | } 231 | 232 | 233 | public interface OnClickItemListener { 234 | void onClick(int i, ArrayList url); 235 | } 236 | 237 | private void loadBitmap(final int i, final String url) { 238 | Glide.with(getContext()) 239 | .load(url) 240 | .asBitmap() 241 | .diskCacheStrategy(DiskCacheStrategy.ALL) 242 | .override(mImageWidth, mImageHeight) 243 | .into(mTargets[i]); 244 | } 245 | 246 | 247 | public void setImageUrls(Collection imageUrls) { 248 | // clean up outdated stuff 249 | for (Target target : mTargets) { 250 | Glide.clear(target); // clears mBitmaps[i] as well 251 | } 252 | if (imageUrls == null) imageUrls = Collections.emptyList(); 253 | int newSize = imageUrls.size(); 254 | mImageUrls = imageUrls.toArray(new String[newSize]); 255 | mBitmaps = new Bitmap[newSize]; 256 | mDrawRects = new RectF[newSize]; 257 | mTargets = new Target[newSize]; 258 | if (!haveRule) { 259 | mColumns = imageUrls.size() <= 4 ? 2 : 3; 260 | } 261 | for (int i = 0; i < imageUrls.size(); i++) { 262 | mTargets[i] = new PositionTarget(i); 263 | } 264 | requestLayout(); 265 | } 266 | 267 | 268 | public void setColumns(int columns) { 269 | mColumns = columns; 270 | haveRule = true; 271 | } 272 | 273 | 274 | public void setOnClickItemListener(OnClickItemListener onClickItemListener) { 275 | this.onClickItemListener = onClickItemListener; 276 | } 277 | 278 | private void setImageRect(int pos) { 279 | int column = pos / mColumns; 280 | int row = pos % mColumns; 281 | 282 | int left = getPaddingLeft() + column * mHorizontalSpace + column * mImageWidth; 283 | int top = getPaddingTop() + row * mVerticalSpace + mImageHeight; 284 | invalidate(left, top, left + mImageWidth, top + mImageHeight); 285 | } 286 | 287 | private class PositionTarget extends SimpleTarget { 288 | private final int i; 289 | 290 | PositionTarget(int i) { 291 | this.i = i; 292 | } 293 | 294 | @Override 295 | public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { 296 | mBitmaps[i] = resource; 297 | setImageRect(i); 298 | } 299 | 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-hdpi/ic_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_tab_community.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-hdpi/ic_tab_community.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_tab_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-hdpi/ic_tab_home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_tab_mine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-hdpi/ic_tab_mine.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_tab_quanzi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-hdpi/ic_tab_quanzi.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xhdpi/ic_placeholder.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/bg_announcement.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/bg_announcement.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_arrow_right_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_arrow_right_gray.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_event_album.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_event_album.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_event_bbs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_event_bbs.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_event_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_event_tag.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_event_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_event_time.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_event_topic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_event_topic.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_event_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_event_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hot_topic_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_hot_topic_detail.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_no_module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_no_module.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_original_topic_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_original_topic_detail.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_tag.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_uncomment_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_uncomment_chart.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_unfavour_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_unfavour_heart.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_water_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/drawable-xxhdpi/ic_water_comment.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_message_board_in_online_event.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tag_secondary.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_topic_tag.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_type.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/divider_gray.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_copy_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_image_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 17 | 18 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 21 | 22 | 23 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_quanzi_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | 25 | 26 | 33 | 34 | 39 | 40 | 52 | 53 | 65 | 66 | 67 | 68 | 69 | 74 | 75 | 80 | 81 | 90 | 91 | 95 | 96 | 102 | 103 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 122 | 123 | 124 | 130 | 131 | 139 | 140 | 146 | 147 | 148 | 155 | 156 | 169 | 170 | 181 | 182 | 183 | 184 | 188 | 189 | 190 | 199 | 200 | 204 | 205 | 206 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_community.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_copy_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_image_details.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_mine.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_quanzi_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_comment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 26 | 27 | 28 | 32 | 33 | 39 | 40 | 47 | 48 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_copy.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 17 | 18 | 23 | 24 | 25 | 29 | 30 | 40 | 41 | 42 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_copy_details.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 16 | 17 | 22 | 23 | 35 | 36 | 48 | 49 | 50 | 51 | 52 | 57 | 58 | 62 | 63 | 68 | 69 | 80 | 81 | 94 | 95 | 96 | 97 | 111 | 112 | 122 | 123 | 124 | 132 | 133 | 139 | 140 | 150 | 151 | 152 | 157 | 158 | 162 | 163 | 168 | 169 | 179 | 180 | 181 | 186 | 187 | 197 | 198 | 199 | 204 | 205 | 215 | 216 | 217 | 218 | 219 | 223 | 224 | 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_quanzi.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 17 | 18 | 23 | 24 | 33 | 34 | 38 | 39 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 64 | 65 | 74 | 75 | 80 | 81 | 91 | 92 | 102 | 103 | 104 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_item_tag.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_load_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HotBitmapGG/Acg/25414834e776fb555d2b73e4dc39e9d00472c711/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | #ededed 5 | 6 | #ffffff 7 | #bf000000 8 | #f1f1f1 9 | @color/colorPrimaryDark_below_23 10 | #000000 11 | #123123 12 | #ff292929 13 | #ffdedede 14 | 15 | #ffffff 16 | #00000000 17 | 18 | #ff000000 19 | #787474 20 | #a5abb5 21 | #000000 22 | #de6c6969 23 | #ffee483c 24 | #ff4dcbff 25 | #ff333333 26 | 27 | #432e2a 28 | 29 | #90ffffff 30 | #f2f2f2 31 | @color/white 32 | #48000000 33 | #ededed 34 | 35 | 36 | @color/white 37 | @android:color/black 38 | @android:color/black 39 | @android:color/black 40 | @color/toolbarBackground 41 | @color/toolbarTextColor 42 | @color/window_background 43 | #ffffff 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | おたく、 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 16 | 17 | 18 |