├── app ├── .gitignore ├── my.jks ├── src │ ├── main │ │ ├── ic_launcher-web.png │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_nav_icon.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── ids.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── xml │ │ │ │ └── network_security_config.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── drawable │ │ │ │ ├── shape_bg_about_text_green.xml │ │ │ │ ├── shape_bg_about_text_purple.xml │ │ │ │ ├── shape_bg_about_text.xml │ │ │ │ ├── ic_menu_weather.xml │ │ │ │ ├── ic_menu_tools.xml │ │ │ │ ├── ic_menu_about.xml │ │ │ │ ├── ic_fab_love.xml │ │ │ │ ├── ic_menu_news.xml │ │ │ │ ├── ic_menu_sister.xml │ │ │ │ ├── ic_menu_subway.xml │ │ │ │ ├── ic_menu_setting.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── anim │ │ │ │ ├── anim_fab_out.xml │ │ │ │ └── anim_fab_in.xml │ │ │ ├── layout │ │ │ │ ├── content_main.xml │ │ │ │ ├── item_mz.xml │ │ │ │ ├── fragment_news.xml │ │ │ │ ├── fragment_tools.xml │ │ │ │ ├── fragment_subway.xml │ │ │ │ ├── fragment_weather.xml │ │ │ │ ├── activity_picture_detail.xml │ │ │ │ ├── app_bar_main.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── activity_splash.xml │ │ │ │ ├── activity_about.xml │ │ │ │ ├── activity_setting.xml │ │ │ │ ├── fragment_mz_content.xml │ │ │ │ ├── nav_header_main.xml │ │ │ │ ├── fragment_little_sister.xml │ │ │ │ ├── fragment_about.xml │ │ │ │ └── fragment_setting.xml │ │ │ └── menu │ │ │ │ └── activity_main_drawer.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── coderpig │ │ │ │ └── drysisters │ │ │ │ ├── utils │ │ │ │ ├── ResUtils.java │ │ │ │ ├── SizeUtils.java │ │ │ │ ├── ToastUtils.java │ │ │ │ ├── NetworkUtils.java │ │ │ │ ├── PackageUtils.java │ │ │ │ └── RxSchedulers.java │ │ │ │ ├── DryConstant.java │ │ │ │ ├── DrySisterApp.java │ │ │ │ ├── ui │ │ │ │ ├── fragment │ │ │ │ │ ├── NewsFragment.java │ │ │ │ │ ├── ToolsFragment.java │ │ │ │ │ ├── SubwayFragment.java │ │ │ │ │ ├── WeatherFragment.java │ │ │ │ │ ├── AboutFragment.java │ │ │ │ │ ├── SettingFragment.java │ │ │ │ │ ├── LittleSisterFragment.java │ │ │ │ │ └── GankMZFragment.java │ │ │ │ ├── activity │ │ │ │ │ ├── SplashActivity.java │ │ │ │ │ ├── PictureDetailActivity.java │ │ │ │ │ ├── AboutActivity.java │ │ │ │ │ ├── SettingActivity.java │ │ │ │ │ └── MainActivity.java │ │ │ │ └── adapter │ │ │ │ │ └── GankMZAdapter.java │ │ │ │ ├── data │ │ │ │ ├── result │ │ │ │ │ └── GankResult.java │ │ │ │ └── dto │ │ │ │ │ └── GankMeizi.java │ │ │ │ ├── widget │ │ │ │ ├── RatioImageView.java │ │ │ │ └── GlideRoundTransform.java │ │ │ │ ├── DryInit.java │ │ │ │ └── net │ │ │ │ └── APIService.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── coderpig │ │ │ └── com │ │ │ └── drysisters │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── coderpig │ │ └── com │ │ └── drysisters │ │ └── ApplicationTest.java ├── build.gradle └── proguard-rules.pro ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── README.md ├── config └── dependencies.gradle ├── gradlew.bat ├── gradlew └── LICENSE /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/my.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/app/my.jks -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_nav_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/app/src/main/res/mipmap-xhdpi/ic_nav_icon.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coder-pig/DrySister/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jun 05 19:27:09 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 240dp 6 | 0dp 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_about_text_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_about_text_purple.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_bg_about_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/test/java/coderpig/com/drysisters/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package coderpig.com.drysisters; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/utils/ResUtils.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.utils; 2 | 3 | import com.coderpig.drysisters.DrySisterApp; 4 | 5 | /** 6 | * 描述:获取文件资源工具类 7 | * 8 | * @author CoderPig on 2018/02/14 11:07. 9 | */ 10 | 11 | public class ResUtils { 12 | /* 获取文件资源 */ 13 | public static String getString(int strId) { 14 | return DrySisterApp.getContext().getResources().getString(strId); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/androidTest/java/coderpig/com/drysisters/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package coderpig.com.drysisters; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_fab_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/DryConstant.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters; 2 | 3 | /** 4 | * 描述:相关常量 5 | * 6 | * @author CoderPig on 2018/02/13 16:22. 7 | */ 8 | 9 | public class DryConstant { 10 | public final static String FG_LITTLE_SISTER = "FG_LITTLE_SISTER"; 11 | public final static String FG_NEWS = "FG_NEWS"; 12 | public final static String FG_WEATHER = "FG_WEATHER"; 13 | public final static String FG_SUBWAY = "FG_SUBWAY"; 14 | public final static String FG_TOOLS = "FG_TOOLS"; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #5A78EA 5 | #FF4081 6 | #FFFFFF 7 | #000000 8 | #474747 9 | #E5E5E5 10 | #EEEEEE 11 | #C89EC4 12 | #67D5B5 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/DrySisterApp.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * 描述:Application类 7 | * 8 | * @author coder-pig: 2016/08/07 15:07 9 | */ 10 | public class DrySisterApp extends Application { 11 | 12 | private static DrySisterApp context; 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | context = this; 18 | DryInit.initTimber(); 19 | DryInit.initOKHttp(this); 20 | } 21 | 22 | public static DrySisterApp getContext() { 23 | return context; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | 4 | # generated files 5 | bin/ 6 | gen/ 7 | out/ 8 | build/ 9 | 10 | # Local configuration file (sdk path, etc) 11 | local.properties 12 | 13 | # Eclipse project files 14 | .classpath 15 | .project 16 | 17 | # Windows thumbnail db 18 | .DS_Store 19 | Thumbs.db 20 | 21 | # Proguard folder generated by Eclipse 22 | proguard/ 23 | 24 | # IDEA/Android Studio project files, because 25 | # the project can be imported from settings.gradle 26 | .idea 27 | *.iml 28 | 29 | # Old-style IDEA project files 30 | *.ipr 31 | *.iws 32 | 33 | # Gradle cache 34 | .gradle 35 | 36 | # Sandbox stuff 37 | _sandbox 38 | 39 | # Backup files 40 | *~ 41 | *.bak 42 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_fab_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_mz.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/utils/SizeUtils.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.utils; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * 描述:尺寸转换工具类 7 | * 8 | * @author coder-pig: 2016/08/17 11:47 9 | */ 10 | public class SizeUtils { 11 | 12 | /** dp转px */ 13 | public static int dp2px(Context context, float dpValue) { 14 | final float scale = context.getResources().getDisplayMetrics().density; 15 | return (int) (dpValue * scale + 0.5f); 16 | } 17 | /** px转dp */ 18 | public static int px2dp(Context context, float pxValue) { 19 | final float scale = context.getResources().getDisplayMetrics().density; 20 | return (int) (pxValue / scale + 0.5f); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_news.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tools.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_subway.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_weather.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/utils/ToastUtils.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.utils; 2 | 3 | import android.view.Gravity; 4 | import android.widget.Toast; 5 | 6 | import com.coderpig.drysisters.DrySisterApp; 7 | 8 | /** 9 | * 描述:Toast 工具类 10 | * 11 | * @author CoderPig on 2018/02/14 11:06. 12 | */ 13 | 14 | public class ToastUtils { 15 | public static void shortToast(String msg) { 16 | Toast toast = Toast.makeText(DrySisterApp.getContext(),msg, Toast.LENGTH_SHORT); 17 | toast.setGravity(Gravity.BOTTOM, 0, 40); 18 | toast.show(); 19 | } 20 | 21 | public static void longToast(String msg) { 22 | Toast toast = Toast.makeText(DrySisterApp.getContext(),msg, Toast.LENGTH_LONG); 23 | toast.setGravity(Gravity.BOTTOM, 0, 40); 24 | toast.show(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/utils/NetworkUtils.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.utils; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | /** 8 | * 描述:网络相关工具类 9 | * 10 | * @author coder-pig: 2016/08/22 10:24 11 | */ 12 | public class NetworkUtils { 13 | /** 获取网络信息 */ 14 | private static NetworkInfo getActiveNetworkInfo(Context context) { 15 | ConnectivityManager cm = (ConnectivityManager) context 16 | .getSystemService(Context.CONNECTIVITY_SERVICE); 17 | return cm.getActiveNetworkInfo(); 18 | } 19 | 20 | /** 判断网络是否可用 */ 21 | public static boolean isAvailable(Context context) { 22 | NetworkInfo info = getActiveNetworkInfo(context); 23 | return info != null && info.isAvailable(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_picture_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/NewsFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.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.coderpig.drysisters.R; 11 | 12 | /** 13 | * 描述:看资讯的Fragment 14 | * 15 | * @author jay on 2018/1/12 12:19 16 | */ 17 | 18 | public class NewsFragment extends Fragment { 19 | 20 | public static NewsFragment newInstance() { 21 | NewsFragment fragment = new NewsFragment(); 22 | return fragment; 23 | } 24 | 25 | @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 | return inflater.inflate(R.layout.fragment_news, container,false); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/ToolsFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.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.coderpig.drysisters.R; 11 | 12 | /** 13 | * 描述:小工具的Fragment 14 | * 15 | * @author jay on 2018/1/12 12:19 16 | */ 17 | 18 | public class ToolsFragment extends Fragment { 19 | 20 | public static ToolsFragment newInstance() { 21 | ToolsFragment fragment = new ToolsFragment(); 22 | return fragment; 23 | } 24 | 25 | @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 | return inflater.inflate(R.layout.fragment_tools, container,false); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/SubwayFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.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.coderpig.drysisters.R; 11 | 12 | /** 13 | * 描述:看天气的Fragment 14 | * 15 | * @author jay on 2018/1/12 12:19 16 | */ 17 | 18 | public class SubwayFragment extends Fragment { 19 | 20 | public static SubwayFragment newInstance() { 21 | SubwayFragment fragment = new SubwayFragment(); 22 | return fragment; 23 | } 24 | 25 | @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 | return inflater.inflate(R.layout.fragment_subway, container,false); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/WeatherFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.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.coderpig.drysisters.R; 11 | 12 | /** 13 | * 描述:看天气的Fragment 14 | * 15 | * @author jay on 2018/1/12 12:19 16 | */ 17 | 18 | public class WeatherFragment extends Fragment { 19 | 20 | public static WeatherFragment newInstance() { 21 | WeatherFragment fragment = new WeatherFragment(); 22 | return fragment; 23 | } 24 | 25 | @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 | return inflater.inflate(R.layout.fragment_weather, container,false); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_bar_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/activity/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.widget.TextView; 8 | 9 | import com.coderpig.drysisters.R; 10 | 11 | /** 12 | * 描述:闪屏页 13 | * 14 | * @author CoderPig on 2018/02/13 15:23. 15 | */ 16 | 17 | public class SplashActivity extends AppCompatActivity{ 18 | @Override 19 | protected void onCreate(@Nullable Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_splash); 22 | TextView tv_logo = findViewById(R.id.tv_logo); 23 | tv_logo.postDelayed(this::jump,500L); 24 | 25 | } 26 | 27 | /* 完成一些初始化操作 */ 28 | private void init() { 29 | 30 | } 31 | 32 | /* 页面逻辑跳转 */ 33 | private void jump() { 34 | startActivity(new Intent(this, MainActivity.class)); 35 | finish(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/data/result/GankResult.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.data.result; 2 | 3 | import com.coderpig.drysisters.data.dto.GankMeizi; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * 描述:Gank.io返回的结果集 9 | * 10 | * @author CoderPig on 2018/02/14 10:52. 11 | */ 12 | 13 | public class GankResult { 14 | private Boolean error; 15 | private ArrayList results; 16 | 17 | public GankResult() { } 18 | 19 | public GankResult(Boolean error, ArrayList results) { 20 | this.error = error; 21 | this.results = results; 22 | } 23 | 24 | public Boolean getError() { 25 | return error; 26 | } 27 | 28 | public void setError(Boolean error) { 29 | this.error = error; 30 | } 31 | 32 | public ArrayList getResults() { 33 | return results; 34 | } 35 | 36 | public void setResults(ArrayList results) { 37 | this.results = results; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "GankResult{" + 43 | "error=" + error + 44 | ", results=" + results.toString() + 45 | '}'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/activity/PictureDetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.widget.ImageView; 7 | 8 | import com.bumptech.glide.Glide; 9 | import com.coderpig.drysisters.R; 10 | import com.r0adkll.slidr.Slidr; 11 | 12 | /** 13 | * 描述:图片详情页 14 | * 15 | * @author CoderPig on 2018/02/28 10:39. 16 | */ 17 | 18 | public class PictureDetailActivity extends AppCompatActivity{ 19 | 20 | private ImageView img_picture; 21 | private String picUrl; 22 | 23 | @Override 24 | protected void onCreate(@Nullable Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_picture_detail); 27 | Slidr.attach(this); 28 | initData(); 29 | initView(); 30 | } 31 | 32 | private void initData() { 33 | picUrl = getIntent().getStringExtra("pic_url"); 34 | } 35 | 36 | private void initView() { 37 | img_picture = findViewById(R.id.img_picture); 38 | if(picUrl != null) { 39 | Glide.with(this).load(picUrl).into(img_picture); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/utils/PackageUtils.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.utils; 2 | 3 | import android.content.pm.PackageInfo; 4 | import android.content.pm.PackageManager; 5 | 6 | import com.coderpig.drysisters.DrySisterApp; 7 | 8 | /** 9 | * 描述:应用包相关的工具类 10 | * 11 | * @author CoderPig on 2018/02/28 18:01. 12 | */ 13 | 14 | public class PackageUtils { 15 | 16 | public static int packageCode() { 17 | PackageManager manager = DrySisterApp.getContext().getPackageManager(); 18 | int code = 0; 19 | try { 20 | PackageInfo info = manager.getPackageInfo(DrySisterApp.getContext().getPackageName(), 0); 21 | code = info.versionCode; 22 | } catch (PackageManager.NameNotFoundException e) { 23 | e.printStackTrace(); 24 | } 25 | return code; 26 | } 27 | 28 | public static String packageName() { 29 | PackageManager manager = DrySisterApp.getContext().getPackageManager(); 30 | String name = null; 31 | try { 32 | PackageInfo info = manager.getPackageInfo(DrySisterApp.getContext().getPackageName(), 0); 33 | name = info.versionName; 34 | } catch (PackageManager.NameNotFoundException e) { 35 | e.printStackTrace(); 36 | } 37 | return name; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/activity/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.Toolbar; 7 | 8 | import com.coderpig.drysisters.R; 9 | import com.coderpig.drysisters.ui.fragment.AboutFragment; 10 | import com.r0adkll.slidr.Slidr; 11 | 12 | /** 13 | * 描述:关于的Activity 14 | * 15 | * @author jay on 2018/1/12 14:01 16 | */ 17 | 18 | public class AboutActivity extends AppCompatActivity{ 19 | 20 | private Toolbar toolbar; 21 | 22 | @Override 23 | protected void onCreate(@Nullable Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_about); 26 | Slidr.attach(this); 27 | initData(); 28 | initView(); 29 | } 30 | 31 | private void initData() { 32 | 33 | } 34 | 35 | private void initView() { 36 | toolbar = findViewById(R.id.toolbar); 37 | toolbar.setTitle("关于"); 38 | setSupportActionBar(toolbar); 39 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 40 | toolbar.setNavigationOnClickListener(view -> finish()); 41 | 42 | getSupportFragmentManager().beginTransaction().replace(R.id.cly_root, AboutFragment.newInstance()).commit(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/widget/RatioImageView.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | /** 7 | * 描述:根据宽度自适应的ImageView 8 | * 9 | * @author CoderPig on 2018/02/14 16:25. 10 | */ 11 | 12 | public class RatioImageView extends android.support.v7.widget.AppCompatImageView{ 13 | private int originalWidth; 14 | private int originalHeight; 15 | 16 | 17 | public RatioImageView(Context context) { 18 | super(context); 19 | } 20 | 21 | 22 | public RatioImageView(Context context, AttributeSet attrs) { 23 | super(context, attrs); 24 | } 25 | 26 | 27 | public RatioImageView(Context context, AttributeSet attrs, int defStyleAttr) { 28 | super(context, attrs, defStyleAttr); 29 | } 30 | 31 | 32 | public void setOriginalSize(int originalWidth, int originalHeight) { 33 | this.originalWidth = originalWidth; 34 | this.originalHeight = originalHeight; 35 | } 36 | 37 | 38 | @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 39 | if (originalWidth > 0 && originalHeight > 0) { 40 | int width = MeasureSpec.getSize(widthMeasureSpec); 41 | setMeasuredDimension(width, width); 42 | } else { 43 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/activity/SettingActivity.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.Toolbar; 7 | 8 | import com.coderpig.drysisters.R; 9 | import com.coderpig.drysisters.ui.fragment.SettingFragment; 10 | import com.r0adkll.slidr.Slidr; 11 | 12 | /** 13 | * 描述:设置的Activity 14 | * 15 | * @author jay on 2018/1/12 14:01 16 | */ 17 | 18 | public class SettingActivity extends AppCompatActivity{ 19 | 20 | private Toolbar toolbar; 21 | 22 | @Override 23 | protected void onCreate(@Nullable Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_setting); 26 | Slidr.attach(this); 27 | initData(); 28 | initView(); 29 | } 30 | 31 | private void initData() { 32 | 33 | } 34 | 35 | private void initView() { 36 | toolbar = findViewById(R.id.toolbar); 37 | toolbar.setTitle("设置"); 38 | setSupportActionBar(toolbar); 39 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 40 | toolbar.setNavigationOnClickListener(view -> finish()); 41 | 42 | getSupportFragmentManager().beginTransaction().replace(R.id.cly_root, SettingFragment.newInstance()).commit(); 43 | 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/DryInit.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters; 2 | 3 | import android.app.Application; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import okhttp3.OkHttpClient; 8 | import okhttp3.logging.HttpLoggingInterceptor; 9 | import timber.log.Timber; 10 | 11 | /** 12 | * 描述:完成一些基本构造 13 | * 14 | * @author CoderPig on 2018/02/14 10:36. 15 | */ 16 | 17 | public class DryInit { 18 | private static Long HTTP_CONNECT_TIMEOUT = 30L; 19 | private static Long HTTP_WRITE_TIMEOUT = 30L; 20 | private static Long HTTP_READ_TIMEOUT = 30L; 21 | 22 | public static OkHttpClient mOkHttpClient; 23 | 24 | /* 初始化OkHttpClient */ 25 | static void initOKHttp(Application app) { 26 | HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> Timber.tag("OkHttps").d(message)); 27 | logging.setLevel(HttpLoggingInterceptor.Level.BODY); 28 | OkHttpClient.Builder builder = new OkHttpClient.Builder() 29 | .connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS) 30 | .writeTimeout(HTTP_WRITE_TIMEOUT, TimeUnit.SECONDS) 31 | .readTimeout(HTTP_READ_TIMEOUT, TimeUnit.SECONDS) 32 | .addInterceptor(logging); 33 | mOkHttpClient = builder.build(); 34 | } 35 | 36 | /* 初始化Timber */ 37 | static void initTimber() { 38 | if (BuildConfig.DEBUG) { 39 | Timber.plant(new Timber.DebugTree()); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DrySister更新记录 2 | 3 | 4 | ---------- 5 | 6 | ## 版本:1.0.2 7 | 8 | > 9 | - 1.重新设计应用的UI,依旧是Material Design 风格,配色改为了蕾姆蓝,灰白; 10 | 界面更加简洁精致,把侧滑菜单的菜单替换了一组很萌的图表集; 11 | - 2.界面支持右滑关闭 12 | - 3.新增设置与关于页面 13 | 14 | **界面效果图**: 15 | 16 | ![][1] 17 | 18 | ![][2] 19 | 20 | ---------- 21 | 22 | 23 | ## 版本:1.0.1 24 | 25 | > 26 | - 1.新版Material Design主界面搭建:[编码记录](http://blog.csdn.net/coder_pig/article/details/78988143) —— 2018.1.6 27 | 28 | **界面效果图** 29 | 30 | ![](http://static.zybuluo.com/coder-pig/22zyowvmgl05ttvav19m3dz4/12.png) 31 | 32 | --- 33 | 34 | ## 版本:1.0.0 35 | 36 | 37 | 38 | > 39 | - 1.完成项目搭建,托管Github,添加分支管理:[编码记录](http://blog.csdn.net/coder_pig/article/details/52135399) —— 2016.8.5 40 | - 2.把图片数据来源改成解析后台数据,使用自带抠脚Json解析:[编码记录](http://blog.csdn.net/coder_pig/article/details/52143980) —— 2016.8.7 41 | - 3.优化图片加载,编写图片异步加载框架SisterLoader:[编码记录](http://blog.csdn.net/coder_pig/article/details/52235436) —— 2016.8.18 42 | - 4.添加数据缓存,使用SQLite存储后台返回的数据:[编码记录](http://blog.csdn.net/coder_pig/article/details/52278625) —— 2016.8.22 43 | - 5.代码回顾,切换到AS3.0上代码调整,编写日志工具类:[编码记录](http://blog.csdn.net/coder_pig/article/details/78855294) —— 2017.12.20 44 | - 6.图标制作,代码混淆,签名打包,APK瘦身,应用发布: [编码记录](http://blog.csdn.net/coder_pig/article/details/78868926) —— 2017.12.21 45 | 46 | **界面效果图** 47 | 48 | ![](http://static.zybuluo.com/coder-pig/flyiktvb6aiezjvf5woplmi2/11.png) 49 | 50 | 51 | ---------- 52 | 53 | 54 | [1]: http://static.zybuluo.com/coder-pig/us0jtehvornlgambkii7eaor/1.png 55 | [2]: http://static.zybuluo.com/coder-pig/gy11wi6ywre783a4wmlj9aac/2.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 22 | 23 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 23 | 24 | 25 | 26 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 23 | 24 | 25 | 26 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_mz_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 18 | 19 | 20 | 21 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/net/APIService.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.net; 2 | 3 | import com.coderpig.drysisters.DryInit; 4 | import com.coderpig.drysisters.data.result.GankResult; 5 | 6 | import io.reactivex.Flowable; 7 | import retrofit2.Retrofit; 8 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 9 | import retrofit2.converter.gson.GsonConverterFactory; 10 | import retrofit2.http.GET; 11 | import retrofit2.http.Path; 12 | 13 | /** 14 | * 描述:API 请求接口 15 | * 16 | * @author CoderPig on 2018/02/14 10:40. 17 | */ 18 | 19 | public class APIService { 20 | 21 | private static String BASE_URL = "http://www.coderpig.com/"; //未启用 22 | 23 | public APIs apis; 24 | 25 | private static APIService instance; 26 | 27 | public static APIService getInstance() { 28 | if (instance == null) { 29 | instance = new APIService(); 30 | } 31 | return instance; 32 | } 33 | 34 | private APIService() { 35 | Retrofit storeRestAPI = new Retrofit.Builder().baseUrl(BASE_URL) 36 | .client(DryInit.mOkHttpClient) 37 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 38 | .addConverterFactory(GsonConverterFactory.create()) 39 | .build(); 40 | apis = storeRestAPI.create(APIs.class); 41 | } 42 | 43 | public interface APIs{ 44 | 45 | /* Gank.io 妹子图 */ 46 | @GET("http://gank.io/api/data/福利/{count}/{page}") 47 | Flowable fetchGankMZ( 48 | @Path("count") int count, 49 | @Path("page") int page 50 | ); 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/utils/RxSchedulers.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.utils; 2 | 3 | import com.coderpig.drysisters.R; 4 | import com.google.gson.JsonSyntaxException; 5 | 6 | import java.net.ConnectException; 7 | import java.net.SocketException; 8 | import java.net.SocketTimeoutException; 9 | import java.net.UnknownHostException; 10 | 11 | import io.reactivex.ObservableTransformer; 12 | import io.reactivex.android.schedulers.AndroidSchedulers; 13 | import io.reactivex.schedulers.Schedulers; 14 | import timber.log.Timber; 15 | 16 | /** 17 | * 描述:Rx 处理工具类 18 | * 19 | * @author CoderPig on 2018/02/14 11:06. 20 | */ 21 | 22 | public class RxSchedulers { 23 | public static ObservableTransformer compose() { 24 | return upstream -> 25 | upstream.subscribeOn(Schedulers.io()) 26 | .observeOn(AndroidSchedulers.mainThread()); 27 | } 28 | 29 | public static void processRequestException(Throwable e) { 30 | if(e instanceof ConnectException || e instanceof SocketException) { 31 | ToastUtils.shortToast(ResUtils.getString(R.string.network_connected_exception)); 32 | } else if(e instanceof SocketTimeoutException) { 33 | ToastUtils.shortToast(ResUtils.getString(R.string.network_socket_time_out)); 34 | } else if(e instanceof JsonSyntaxException) { 35 | ToastUtils.shortToast(ResUtils.getString(R.string.network_json_syntax_exception)); 36 | } else if(e instanceof UnknownHostException) { 37 | ToastUtils.shortToast(ResUtils.getString(R.string.network_unknown_host)); 38 | } else { 39 | Timber.d(e.getMessage()); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/AboutFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.coderpig.drysisters.R; 13 | import com.coderpig.drysisters.utils.PackageUtils; 14 | import com.coderpig.drysisters.utils.ResUtils; 15 | 16 | /** 17 | * 描述: 关于的Fragment 18 | * 19 | * @author CoderPig on 2018/02/28 14:33. 20 | */ 21 | 22 | public class AboutFragment extends Fragment { 23 | 24 | private TextView tv_app_version; 25 | 26 | public static AboutFragment newInstance() { 27 | AboutFragment fragment = new AboutFragment(); 28 | return fragment; 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | View view = inflater.inflate(R.layout.fragment_about, container, false); 35 | tv_app_version = view.findViewById(R.id.tv_app_version); 36 | return view; 37 | } 38 | 39 | @Override 40 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 41 | super.onViewCreated(view, savedInstanceState); 42 | String version = PackageUtils.packageName(); 43 | if(version != null) { 44 | String msg = String.format(ResUtils.getString(R.string.app_version), version); 45 | tv_app_version.setText(msg); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/SettingFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.coderpig.drysisters.R; 13 | import com.coderpig.drysisters.utils.PackageUtils; 14 | import com.coderpig.drysisters.utils.ResUtils; 15 | 16 | /** 17 | * 描述: 应用设置的Fragment 18 | * 19 | * @author CoderPig on 2018/02/28 13:56. 20 | */ 21 | 22 | public class SettingFragment extends Fragment { 23 | 24 | private TextView tv_app_version; 25 | 26 | public static SettingFragment newInstance() { 27 | SettingFragment fragment = new SettingFragment(); 28 | return fragment; 29 | } 30 | 31 | @Nullable 32 | @Override 33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 34 | View view = inflater.inflate(R.layout.fragment_setting, container, false); 35 | tv_app_version = view.findViewById(R.id.tv_app_version); 36 | return view; 37 | } 38 | 39 | @Override 40 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 41 | super.onViewCreated(view, savedInstanceState); 42 | String version = PackageUtils.packageName(); 43 | if(version != null) { 44 | String msg = String.format(ResUtils.getString(R.string.cur_version), version); 45 | tv_app_version.setText(msg); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_weather.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 17 | 18 | 22 | 23 | 27 | 28 | 29 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nav_header_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 28 | 29 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/data/dto/GankMeizi.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.data.dto; 2 | 3 | /** 4 | * 描述:Gank.io 返回的妹子 5 | * 6 | * @author CoderPig on 2018/02/14 10:53. 7 | */ 8 | 9 | public class GankMeizi { 10 | private String _id; 11 | private String createdAt; 12 | private String desc; 13 | private String publishedAt; 14 | private String source; 15 | private String url; 16 | private Boolean used; 17 | private String who; 18 | 19 | public String get_id() { 20 | return _id; 21 | } 22 | 23 | public void set_id(String _id) { 24 | this._id = _id; 25 | } 26 | 27 | public String getCreatedAt() { 28 | return createdAt; 29 | } 30 | 31 | public void setCreatedAt(String createdAt) { 32 | this.createdAt = createdAt; 33 | } 34 | 35 | public String getDesc() { 36 | return desc; 37 | } 38 | 39 | public void setDesc(String desc) { 40 | this.desc = desc; 41 | } 42 | 43 | public String getPublishedAt() { 44 | return publishedAt; 45 | } 46 | 47 | public void setPublishedAt(String publishedAt) { 48 | this.publishedAt = publishedAt; 49 | } 50 | 51 | public String getSource() { 52 | return source; 53 | } 54 | 55 | public void setSource(String source) { 56 | this.source = source; 57 | } 58 | 59 | public Boolean getUsed() { 60 | return used; 61 | } 62 | 63 | public void setUsed(Boolean used) { 64 | this.used = used; 65 | } 66 | 67 | public String getWho() { 68 | return who; 69 | } 70 | 71 | public void setWho(String who) { 72 | this.who = who; 73 | } 74 | 75 | public String getUrl() { 76 | return url; 77 | } 78 | 79 | public void setUrl(String url) { 80 | this.url = url; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_tools.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_about.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fab_love.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_news.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_sister.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/activity_main_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_little_sister.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 23 | 24 | 32 | 33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /config/dependencies.gradle: -------------------------------------------------------------------------------- 1 | def junitVersion = "4.12" 2 | def supportVersion = "27.0.2" 3 | def constraintVersion = "1.0.2" 4 | def phoneViewVersion = "2.1.3" 5 | def slidrVersion = "2.0.6" 6 | def roundImageViewVersion = "2.3.0" 7 | def rxJavaVersion = "2.1.9" 8 | def rxAndroidVersion = "2.0.1" 9 | def okhttpVersion = "3.9.1" 10 | def retrofitVersion = "2.3.0" 11 | def glideVersion = "4.6.1" 12 | def timberViersion = "4.6.1" 13 | 14 | 15 | project.ext { 16 | depend_android = [ 17 | compileSdkVersion: 28, 18 | minSdkVersion : 21, 19 | targetSdkVersion : 28, 20 | ] 21 | 22 | depend_lib = [ 23 | "junit" : "junit:junit:${junitVersion}", 24 | "appcompat-v7" : "com.android.support:appcompat-v7:${supportVersion}", 25 | "design" : "com.android.support:design:${supportVersion}", 26 | "cardview" : "com.android.support:cardview-v7:${supportVersion}", 27 | "constraint-layout" : "com.android.support.constraint:constraint-layout:${constraintVersion}", 28 | "phoneView" : "com.github.chrisbanes:PhotoView:${phoneViewVersion}", 29 | "slidr" : "com.r0adkll:slidableactivity:${slidrVersion}", 30 | "roundedimageview" : "com.makeramen:roundedimageview:${roundImageViewVersion}", 31 | 32 | "rxjava" : "io.reactivex.rxjava2:rxjava:${rxJavaVersion}", 33 | "rxandroid" : "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}", 34 | 35 | "okhttp" : "com.squareup.okhttp3:okhttp:${okhttpVersion}", 36 | "okhttp-interceptor": "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}", 37 | "retrofit" : "com.squareup.retrofit2:retrofit:${retrofitVersion}", 38 | "converter-gson" : "com.squareup.retrofit2:converter-gson:${retrofitVersion}", 39 | "rxjava2-adapter" : "com.squareup.retrofit2:adapter-rxjava2:${retrofitVersion}", 40 | "glide" : "com.github.bumptech.glide:glide:${glideVersion}", 41 | "glide-compiler" : "com.github.bumptech.glide:compiler:${glideVersion}", 42 | 43 | "timber" : "com.jakewharton.timber:timber:${timberViersion}" 44 | 45 | ] 46 | } -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | def depend_android = rootProject.ext.depend_android 4 | def depend_lib = rootProject.ext.depend_lib 5 | 6 | 7 | android { 8 | signingConfigs { 9 | release { 10 | storeFile file('my.jks') 11 | storePassword '123456' 12 | keyAlias 'DrySister' 13 | keyPassword '654321' 14 | } 15 | } 16 | compileSdkVersion depend_android["compileSdkVersion"] 17 | defaultConfig { 18 | applicationId "com.coderpig.drysisters" 19 | minSdkVersion depend_android["minSdkVersion"] 20 | targetSdkVersion depend_android["targetSdkVersion"] 21 | versionCode 3 22 | versionName "1.0.2" 23 | } 24 | buildTypes { 25 | debug { 26 | minifyEnabled false 27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 28 | } 29 | release { 30 | signingConfig signingConfigs.release 31 | // minifyEnabled true 32 | // shrinkResources true 33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 34 | } 35 | } 36 | compileOptions { 37 | targetCompatibility 1.8 38 | sourceCompatibility 1.8 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(include: ['*.jar'], dir: 'libs') 44 | testImplementation depend_lib["junit"] 45 | implementation depend_lib["appcompat-v7"] 46 | implementation depend_lib["design"] 47 | implementation depend_lib["cardview"] 48 | implementation depend_lib["constraint-layout"] 49 | implementation depend_lib["phoneView"] 50 | implementation depend_lib["slidr"] 51 | implementation depend_lib["roundedimageview"] 52 | implementation depend_lib["rxjava"] 53 | implementation depend_lib["rxandroid"] 54 | implementation depend_lib["okhttp"] 55 | implementation depend_lib["okhttp-interceptor"] 56 | implementation depend_lib["retrofit"] 57 | implementation depend_lib["converter-gson"] 58 | implementation depend_lib["rxjava2-adapter"] 59 | implementation depend_lib["glide"] 60 | annotationProcessor depend_lib["glide-compiler"] 61 | implementation depend_lib["timber"] 62 | 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /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:\Software\Coding\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 | -dontnote android.net.http.* 13 | -dontnote org.apache.commons.codec.** 14 | -dontnote org.apache.http.** 15 | 16 | #指定压缩级别 17 | -optimizationpasses 5 18 | 19 | #不跳过非公共的库的类成员 20 | -dontskipnonpubliclibraryclassmembers 21 | 22 | #混淆时采用的算法 23 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 24 | 25 | #把混淆类中的方法名也混淆了 26 | -useuniqueclassmembernames 27 | 28 | #优化时允许访问并修改有修饰符的类和类的成员 29 | -allowaccessmodification 30 | 31 | #将文件来源重命名为“SourceFile”字符串 32 | -renamesourcefileattribute SourceFile 33 | #保留行号 34 | -keepattributes SourceFile,LineNumberTable 35 | #保持泛型 36 | -keepattributes Signature 37 | 38 | #保持所有实现 Serializable 接口的类成员 39 | -keepclassmembers class * implements java.io.Serializable { 40 | static final long serialVersionUID; 41 | private static final java.io.ObjectStreamField[] serialPersistentFields; 42 | private void writeObject(java.io.ObjectOutputStream); 43 | private void readObject(java.io.ObjectInputStream); 44 | java.lang.Object writeReplace(); 45 | java.lang.Object readResolve(); 46 | } 47 | 48 | #Fragment不需要在AndroidManifest.xml中注册,需要额外保护下 49 | -keep public class * extends android.support.v4.app.Fragment 50 | -keep public class * extends android.app.Fragment 51 | 52 | # 保持测试相关的代码 53 | -dontnote junit.framework.** 54 | -dontnote junit.runner.** 55 | -dontwarn android.test.** 56 | -dontwarn android.support.test.** 57 | -dontwarn org.junit.** 58 | 59 | 60 | # Okhttp3 混淆 61 | -dontwarn okhttp3.** 62 | -dontwarn okio.** 63 | -dontwarn javax.annotation.** 64 | 65 | 66 | 67 | # Glide混淆 68 | -keep public class * implements com.bumptech.glide.module.GlideModule 69 | -keep public class * extends com.bumptech.glide.module.AppGlideModule 70 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { 71 | **[] $VALUES; 72 | public *; 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_subway.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/widget/GlideRoundTransform.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapShader; 7 | import android.graphics.Canvas; 8 | import android.graphics.Paint; 9 | import android.graphics.RectF; 10 | 11 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 12 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 13 | import com.bumptech.glide.load.resource.bitmap.TransformationUtils; 14 | 15 | import java.security.MessageDigest; 16 | 17 | /** 18 | * 描述: 19 | * 20 | * @author CoderPig on 2018/02/14 16:50. 21 | */ 22 | 23 | public class GlideRoundTransform extends BitmapTransformation { 24 | 25 | private static float radius = 0f; 26 | 27 | public GlideRoundTransform(Context context) { 28 | this(context, 4); 29 | } 30 | 31 | public GlideRoundTransform(Context context, int dp) { 32 | super(context); 33 | this.radius = Resources.getSystem().getDisplayMetrics().density * dp; 34 | } 35 | 36 | @Override 37 | protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { 38 | Bitmap bitmap = TransformationUtils.centerCrop(pool, toTransform, outWidth, outHeight); 39 | return roundCrop(pool, bitmap); 40 | } 41 | 42 | private static Bitmap roundCrop(BitmapPool pool, Bitmap source) { 43 | if (source == null) return null; 44 | 45 | Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); 46 | if (result == null) { 47 | result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); 48 | } 49 | 50 | Canvas canvas = new Canvas(result); 51 | Paint paint = new Paint(); 52 | paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); 53 | paint.setAntiAlias(true); 54 | RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight()); 55 | canvas.drawRoundRect(rectF, radius, radius, paint); 56 | return result; 57 | } 58 | 59 | public String getId() { 60 | return getClass().getName() + Math.round(radius); 61 | } 62 | 63 | @Override 64 | public void updateDiskCacheKey(MessageDigest messageDigest) { 65 | 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/adapter/GankMZAdapter.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.v7.widget.RecyclerView; 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.request.RequestOptions; 13 | import com.coderpig.drysisters.R; 14 | import com.coderpig.drysisters.data.dto.GankMeizi; 15 | import com.coderpig.drysisters.ui.activity.PictureDetailActivity; 16 | 17 | import java.util.ArrayList; 18 | 19 | /** 20 | * 描述: 21 | * 22 | * @author CoderPig on 2018/02/14 12:15. 23 | */ 24 | 25 | public class GankMZAdapter extends RecyclerView.Adapter { 26 | 27 | private Context mContext; 28 | private ArrayList mzs = new ArrayList<>(); 29 | 30 | public GankMZAdapter(Context mContext, ArrayList mzs) { 31 | this.mContext = mContext; 32 | this.mzs = mzs; 33 | } 34 | 35 | public void addAll(ArrayList data) { 36 | mzs.clear(); 37 | mzs.addAll(data); 38 | notifyDataSetChanged(); 39 | } 40 | 41 | public void loadMore(ArrayList data) { 42 | mzs.addAll(data); 43 | } 44 | 45 | @Override 46 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 47 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_mz, parent, false)); 48 | } 49 | 50 | @Override 51 | public void onBindViewHolder(ViewHolder holder, int position) { 52 | holder.bind(mzs.get(position)); 53 | } 54 | 55 | @Override 56 | public int getItemCount() { 57 | return mzs.size(); 58 | } 59 | 60 | class ViewHolder extends RecyclerView.ViewHolder { 61 | 62 | ImageView img_content; 63 | 64 | ViewHolder(View itemView) { 65 | super(itemView); 66 | img_content = itemView.findViewById(R.id.img_content); 67 | } 68 | 69 | void bind(GankMeizi data) { 70 | Glide.with(mContext) 71 | .load(data.getUrl()) 72 | .apply(new RequestOptions() 73 | .centerCrop()) 74 | .into(img_content); 75 | img_content.setOnClickListener(view -> { 76 | Intent intent = new Intent(mContext, PictureDetailActivity.class); 77 | intent.putExtra("pic_url", data.getUrl()); 78 | mContext.startActivity(intent); 79 | }); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_setting.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/LittleSisterFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.design.widget.TabLayout; 8 | import android.support.v4.app.Fragment; 9 | import android.support.v4.app.FragmentManager; 10 | import android.support.v4.app.FragmentPagerAdapter; 11 | import android.support.v4.view.ViewPager; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | 16 | import com.coderpig.drysisters.R; 17 | 18 | import io.reactivex.disposables.CompositeDisposable; 19 | 20 | 21 | /** 22 | * 描述:妹看小姐姐的Fragment 23 | * 24 | * @author jay on 2018/1/12 12:19 25 | */ 26 | 27 | public class LittleSisterFragment extends Fragment{ 28 | 29 | private Context mContext; 30 | private TabLayout tl_little_sister; 31 | private ViewPager vp_content; 32 | protected CompositeDisposable mSubscriptions; 33 | 34 | public static LittleSisterFragment newInstance() { 35 | LittleSisterFragment fragment = new LittleSisterFragment(); 36 | return fragment; 37 | } 38 | 39 | @Nullable @Override 40 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 41 | View view = inflater.inflate(R.layout.fragment_little_sister, container, false); 42 | tl_little_sister = view.findViewById(R.id.tl_little_sister); 43 | vp_content = view.findViewById(R.id.vp_content); 44 | return view; 45 | } 46 | 47 | @Override 48 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 49 | super.onViewCreated(view, savedInstanceState); 50 | mContext = getActivity(); 51 | mSubscriptions = new CompositeDisposable(); 52 | TabFragmentPagerAdapter adapter = new TabFragmentPagerAdapter(this.getChildFragmentManager()); 53 | vp_content.setAdapter(adapter); 54 | tl_little_sister.setupWithViewPager(vp_content); 55 | } 56 | 57 | @Override public void onDestroy() { 58 | super.onDestroy(); 59 | mSubscriptions.clear(); 60 | } 61 | 62 | private class TabFragmentPagerAdapter extends FragmentPagerAdapter { 63 | private final String[] mTitles = {"Gank.io"}; 64 | 65 | private TabFragmentPagerAdapter(FragmentManager fm) { 66 | super(fm); 67 | } 68 | 69 | @Override 70 | public Fragment getItem(int position) { 71 | return GankMZFragment.newInstance(); 72 | } 73 | 74 | @Override 75 | public int getCount() { 76 | return mTitles.length; 77 | } 78 | 79 | @Override 80 | public CharSequence getPageTitle(int position) { 81 | return mTitles[position]; 82 | } 83 | } 84 | 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DrySisters 3 | Dry 4 | 下一个 5 | 上一个 6 | 抽屉打开 7 | 抽屉关闭 8 | 天天吃肉吃不胖,天天DrySister身体棒 9 | 10 | 11 | 看看 12 | 看小姐姐 13 | 读书看报 14 | 15 | 用用 16 | 查查天气 17 | 查查地铁 18 | 小工具箱 19 | 20 | 其他 21 | 设置 22 | 关于 23 | DrySister Version: %1$s 24 | 25 | 26 | 前方正在施工… 27 | 28 | 29 | 尚未连接网络,请打开网络重新加载! 30 | 网络连接异常,请稍后重试! 31 | 网络请求超时,请检查网络状态! 32 | 服务器数据异常,请稍候重试! 33 | 当前网络不可用,请检查网络情况! 34 | 35 | 36 | 刷新成功! 37 | 嘤嘤嘤,新增%1$d枚%2$s! 38 | 39 | 40 | 仅在WIFI下加载图片 41 | 清空缓存 42 | 当前缓存 %1$f mb 43 | 检查更新 44 | 当前版本 %1$s 45 | 给个好评 46 | 问题反馈 47 | 推荐给好基友 48 | 联系我 49 | 50 | 51 | Version %1$s 52 | 关于DrySister 53 | 54 | DrySister,直译干妹子,是小猪2016年写的Android基础入门教程附带的实战项目, 55 | 项目开源,遵循GPL v3协议, 56 | \n\n仓库地址:https://github.com/coder-pig/DrySister 57 | \n\n前期代码实现有详细的实现讲解,后面可能只说下遇到的问题以及难点。妹子源会慢慢增加, 58 | 除此之外还会添加一些新的小工具,敬请期待!项目仅用于技术交流学习,请勿用于商业用途! 59 | \n\n如果你在使用过程中有任何建议或者大胆的想法, 60 | \n欢迎加QQ群:518568422 进行反馈, 61 | \n或者在酷安评论区留言与小猪激烈摔♂跤; 62 | \n\n依次谢谢: 63 | \n\n 1.代码家提供的Gank.API 64 | \n 2.Drakeet的开源项目Meizhi 65 | \n 3.小荳的阿里健康品牌图标库的SVG图标,链接: 66 | \n http://iconfont.cn/collections/detail?cid=1312 67 | \n 很萌的一组图标,嘤嘤嘤! 68 | 69 | 关于我 70 | 71 | 一个三流Android开发者,会点Python, 72 | \n喜欢写有趣的文章,写过一套Android入门教程; 73 | \n博客:http://blog.csdn.net/coder_pig 74 | \nGitHub:https://github.com/coder-pig 75 | \n掘金和简书:太长不贴,自己搜coder-pig 76 | 77 | 用到的开源库(闲了再补充协议) 78 | 79 | com.android.support:appcompat-v7 80 | \ncom.android.support:design 81 | \ncom.android.support:cardview-v7 82 | \ncom.android.support.constraint:constraint-layout 83 | \ncom.github.chrisbanes:PhotoView 84 | \ncom.r0adkll:slidableactivity 85 | \ncom.makeramen:roundedimageview 86 | \nio.reactivex.rxjava2:rxjava 87 | \nio.reactivex.rxjava2:rxandroid 88 | \ncom.squareup.okhttp3:okhttp 89 | \ncom.squareup.okhttp3:logging-interceptor 90 | \ncom.squareup.retrofit2:retrofit 91 | \ncom.squareup.retrofit2:converter-gson 92 | \ncom.squareup.retrofit2:adapter-rxjava2 93 | \ncom.github.bumptech.glide:glide 94 | \ncom.github.bumptech.glide:compiler 95 | \ncom.jakewharton.timber:timber 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.constraint.ConstraintLayout; 7 | import android.support.design.widget.NavigationView; 8 | import android.support.v4.app.FragmentManager; 9 | import android.support.v4.view.GravityCompat; 10 | import android.support.v4.widget.DrawerLayout; 11 | import android.support.v7.app.ActionBarDrawerToggle; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.support.v7.widget.Toolbar; 14 | import android.view.MenuItem; 15 | import android.widget.TextView; 16 | 17 | import com.coderpig.drysisters.DryConstant; 18 | import com.coderpig.drysisters.R; 19 | import com.coderpig.drysisters.ui.fragment.LittleSisterFragment; 20 | import com.coderpig.drysisters.ui.fragment.NewsFragment; 21 | import com.coderpig.drysisters.ui.fragment.SubwayFragment; 22 | import com.coderpig.drysisters.ui.fragment.ToolsFragment; 23 | import com.coderpig.drysisters.ui.fragment.WeatherFragment; 24 | import com.coderpig.drysisters.utils.PackageUtils; 25 | import com.coderpig.drysisters.utils.ResUtils; 26 | 27 | public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { 28 | 29 | private Toolbar toolbar; 30 | private DrawerLayout drawer_layout; 31 | private NavigationView nav_view; 32 | private TextView tv_nav_title; 33 | private ConstraintLayout cly_main_content; 34 | private FragmentManager mFgManager; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_main); 40 | mFgManager = getSupportFragmentManager(); 41 | initView(); 42 | initData(); 43 | } 44 | 45 | private void initView() { 46 | toolbar = findViewById(R.id.toolbar); 47 | nav_view = findViewById(R.id.nav_view); 48 | tv_nav_title = nav_view.getHeaderView(0).findViewById(R.id.tv_nav_title); 49 | drawer_layout = findViewById(R.id.drawer_layout); 50 | cly_main_content = findViewById(R.id.cly_main_content); 51 | 52 | setSupportActionBar(toolbar); 53 | nav_view.setItemIconTintList(null); 54 | nav_view.setNavigationItemSelectedListener(this); 55 | 56 | ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( 57 | this, drawer_layout, toolbar, R.string.drawer_open, R.string.drawer_close); 58 | drawer_layout.addDrawerListener(toggle); 59 | toggle.syncState(); 60 | } 61 | 62 | private void initData() { 63 | mFgManager.beginTransaction().replace(R.id.cly_main_content, 64 | LittleSisterFragment.newInstance(), DryConstant.FG_LITTLE_SISTER).commit(); 65 | toolbar.setTitle(ResUtils.getString(R.string.menu_see_little_sister)); 66 | String version = PackageUtils.packageName(); 67 | if(version != null) { 68 | String msg = String.format(ResUtils.getString(R.string.menu_drysister_version), version); 69 | tv_nav_title.setText(msg); 70 | } 71 | } 72 | 73 | @Override 74 | public boolean onNavigationItemSelected(@NonNull MenuItem item) { 75 | switch (item.getItemId()) { 76 | case R.id.nav_see_little_sister: 77 | if (mFgManager.findFragmentByTag(DryConstant.FG_LITTLE_SISTER) == null) { 78 | mFgManager.beginTransaction().replace(R.id.cly_main_content, 79 | LittleSisterFragment.newInstance(), DryConstant.FG_LITTLE_SISTER).commit(); 80 | toolbar.setTitle(ResUtils.getString(R.string.menu_see_little_sister)); 81 | } 82 | break; 83 | case R.id.nav_see_news: 84 | if (mFgManager.findFragmentByTag(DryConstant.FG_NEWS) == null) { 85 | mFgManager.beginTransaction().replace(R.id.cly_main_content, 86 | NewsFragment.newInstance(), DryConstant.FG_NEWS).commit(); 87 | toolbar.setTitle(ResUtils.getString(R.string.menu_see_news)); 88 | } 89 | break; 90 | case R.id.nav_use_check_weather: 91 | if (mFgManager.findFragmentByTag(DryConstant.FG_WEATHER) == null) { 92 | mFgManager.beginTransaction().replace(R.id.cly_main_content, 93 | WeatherFragment.newInstance(), DryConstant.FG_WEATHER).commit(); 94 | toolbar.setTitle(ResUtils.getString(R.string.menu_use_check_weather)); 95 | } 96 | break; 97 | case R.id.nav_use_check_subway: 98 | if (mFgManager.findFragmentByTag(DryConstant.FG_SUBWAY) == null) { 99 | mFgManager.beginTransaction().replace(R.id.cly_main_content, 100 | SubwayFragment.newInstance(), DryConstant.FG_SUBWAY).commit(); 101 | toolbar.setTitle(ResUtils.getString(R.string.menu_use_check_subway)); 102 | } 103 | break; 104 | case R.id.nav_use_tools: 105 | if (mFgManager.findFragmentByTag(DryConstant.FG_TOOLS) == null) { 106 | mFgManager.beginTransaction().replace(R.id.cly_main_content, 107 | ToolsFragment.newInstance(), DryConstant.FG_TOOLS).commit(); 108 | toolbar.setTitle(ResUtils.getString(R.string.menu_use_tools)); 109 | } 110 | break; 111 | case R.id.nav_else_setting: 112 | startActivity(new Intent(this, SettingActivity.class)); 113 | break; 114 | case R.id.nav_else_about: 115 | startActivity(new Intent(this, AboutActivity.class)); 116 | break; 117 | } 118 | drawer_layout.closeDrawer(GravityCompat.START); 119 | return true; 120 | } 121 | 122 | @Override 123 | public void onBackPressed() { 124 | if (drawer_layout.isDrawerOpen(GravityCompat.START)) { 125 | drawer_layout.closeDrawer(GravityCompat.START); 126 | } else { 127 | super.onBackPressed(); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 23 | 24 | 34 | 35 | 44 | 45 | 56 | 57 | 58 | 73 | 74 | 85 | 86 | 101 | 102 | 113 | 114 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /app/src/main/java/com/coderpig/drysisters/ui/fragment/GankMZFragment.java: -------------------------------------------------------------------------------- 1 | package com.coderpig.drysisters.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | import android.support.design.widget.FloatingActionButton; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.view.ViewCompat; 9 | import android.support.v4.view.ViewPropertyAnimatorListener; 10 | import android.support.v4.view.animation.FastOutSlowInInterpolator; 11 | import android.support.v4.widget.SwipeRefreshLayout; 12 | import android.support.v7.widget.GridLayoutManager; 13 | import android.support.v7.widget.LinearLayoutManager; 14 | import android.support.v7.widget.RecyclerView; 15 | import android.view.LayoutInflater; 16 | import android.view.View; 17 | import android.view.ViewGroup; 18 | import android.view.animation.Interpolator; 19 | 20 | import com.coderpig.drysisters.R; 21 | import com.coderpig.drysisters.data.dto.GankMeizi; 22 | import com.coderpig.drysisters.net.APIService; 23 | import com.coderpig.drysisters.ui.adapter.GankMZAdapter; 24 | import com.coderpig.drysisters.utils.ResUtils; 25 | import com.coderpig.drysisters.utils.RxSchedulers; 26 | import com.coderpig.drysisters.utils.ToastUtils; 27 | 28 | import java.util.ArrayList; 29 | 30 | import io.reactivex.android.schedulers.AndroidSchedulers; 31 | import io.reactivex.disposables.CompositeDisposable; 32 | import io.reactivex.disposables.Disposable; 33 | import io.reactivex.schedulers.Schedulers; 34 | 35 | /** 36 | * 描述:Gank.io妹子Fragment 37 | * 38 | * @author CoderPig on 2018/02/14 09:49. 39 | */ 40 | 41 | public class GankMZFragment extends Fragment { 42 | 43 | private static final String TAG = "GankMZFragment"; 44 | private SwipeRefreshLayout srl_refresh; 45 | private FloatingActionButton fab_top; 46 | private RecyclerView rec_mz; 47 | private CompositeDisposable mSubscriptions; 48 | private GankMZAdapter mAdapter; 49 | private static final int PRELOAD_SIZE = 6; 50 | private int mCurPage = 1; 51 | private ArrayList mData; 52 | private final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator(); 53 | 54 | public static GankMZFragment newInstance() { 55 | return new GankMZFragment(); 56 | } 57 | 58 | 59 | @Nullable 60 | @Override 61 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 62 | View view = inflater.inflate(R.layout.fragment_mz_content, container, false); 63 | srl_refresh = view.findViewById(R.id.srl_refresh); 64 | rec_mz = view.findViewById(R.id.rec_mz); 65 | fab_top = view.findViewById(R.id.fab_top); 66 | srl_refresh.setOnRefreshListener(() -> { 67 | mCurPage = 1; 68 | fetchGankMZ(true); 69 | }); 70 | final GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 2); 71 | rec_mz.setLayoutManager(layoutManager); 72 | rec_mz.addOnScrollListener(new RecyclerView.OnScrollListener() { 73 | @Override 74 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 75 | super.onScrollStateChanged(recyclerView, newState); 76 | LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); 77 | if (newState == RecyclerView.SCROLL_STATE_IDLE) {//加载更多 78 | if (layoutManager.getItemCount() - recyclerView.getChildCount() <= layoutManager.findFirstVisibleItemPosition()) { 79 | ++mCurPage; 80 | fetchGankMZ(false); 81 | } 82 | } 83 | if (layoutManager.findFirstVisibleItemPosition() != 0) { 84 | fabInAnim(); 85 | } else { 86 | fabOutAnim(); 87 | } 88 | } 89 | }); 90 | fab_top.setOnClickListener(v -> { 91 | LinearLayoutManager manager = (LinearLayoutManager) rec_mz.getLayoutManager(); 92 | //如果超过50项直接跳到开头,不然要滚好久 93 | if(manager.findFirstVisibleItemPosition() < 50) { 94 | rec_mz.smoothScrollToPosition(0); 95 | } else { 96 | rec_mz.scrollToPosition(0); 97 | fabOutAnim(); 98 | } 99 | }); 100 | return view; 101 | } 102 | 103 | @Override 104 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 105 | super.onViewCreated(view, savedInstanceState); 106 | mSubscriptions = new CompositeDisposable(); 107 | mData = new ArrayList<>(); 108 | mAdapter = new GankMZAdapter(getActivity(), mData); 109 | rec_mz.setAdapter(mAdapter); 110 | srl_refresh.setRefreshing(true); 111 | fetchGankMZ(true); 112 | } 113 | 114 | 115 | @Override 116 | public void onDestroy() { 117 | super.onDestroy(); 118 | mSubscriptions.clear(); 119 | } 120 | 121 | /* 拉取妹子数据 */ 122 | private void fetchGankMZ(boolean isRefresh) { 123 | Disposable subscribe = APIService.getInstance().apis.fetchGankMZ(20, mCurPage) 124 | .subscribeOn(Schedulers.io()) 125 | .observeOn(AndroidSchedulers.mainThread()) 126 | .doOnSubscribe(subscription -> srl_refresh.setRefreshing(true)) 127 | .doFinally(() -> srl_refresh.setRefreshing(false)) 128 | .subscribe(data -> { 129 | if(data != null && data.getResults() != null && data.getResults().size() > 0) { 130 | ArrayList results = data.getResults(); 131 | if (isRefresh) { 132 | mAdapter.addAll(results); 133 | ToastUtils.shortToast(ResUtils.getString(R.string.refresh_success)); 134 | } else { 135 | mAdapter.loadMore(results); 136 | String msg = String.format(ResUtils.getString(R.string.load_more_num),results.size(),"妹子"); 137 | ToastUtils.shortToast(msg); 138 | } 139 | } 140 | }, RxSchedulers::processRequestException); 141 | mSubscriptions.add(subscribe); 142 | } 143 | 144 | /* 悬浮按钮显示动画 */ 145 | private void fabInAnim() { 146 | if (fab_top.getVisibility() == View.GONE) { 147 | fab_top.setVisibility(View.VISIBLE); 148 | ViewCompat.animate(fab_top).scaleX(1.0F).scaleY(1.0F).alpha(1.0F) 149 | .setInterpolator(INTERPOLATOR).withLayer().setListener(null).start(); 150 | } 151 | } 152 | 153 | /* 悬浮图标隐藏动画 */ 154 | private void fabOutAnim() { 155 | if (fab_top.getVisibility() == View.VISIBLE) { 156 | ViewCompat.animate(fab_top).scaleX(0.0F).scaleY(0.0F).alpha(0.0F) 157 | .setInterpolator(INTERPOLATOR).withLayer().setListener(new ViewPropertyAnimatorListener() { 158 | @Override 159 | public void onAnimationStart(View view) { 160 | 161 | } 162 | 163 | @Override 164 | public void onAnimationEnd(View view) { 165 | fab_top.setVisibility(View.GONE); 166 | } 167 | 168 | @Override 169 | public void onAnimationCancel(View view) { 170 | 171 | } 172 | }).start(); 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 28 | 29 | 37 | 38 | 47 | 48 | 58 | 59 | 68 | 69 | 78 | 79 | 80 | 90 | 91 | 100 | 101 | 110 | 111 | 121 | 122 | 131 | 132 | 142 | 143 | 152 | 153 | 163 | 164 | 173 | 174 | 184 | 185 | 194 | 195 | --------------------------------------------------------------------------------