[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Files for the Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\nbuild/\n.idea/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# Intellij\n*.iml\n\n# Keystore files\n*.jks\n\n# =========================\n# Operating System Files\n# =========================\n\n# OSX\n# =========================\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n# Windows\n# =========================\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n"
  },
  {
    "path": "DesignResCollection_MVC/README.md",
    "content": "## Model-View-Controller 结构  \n经典MVC模式。  \nLeanCloud作为后端，网络框架+图片框架，一起组成了一个普通App最基础的部分。可以参考本项目框架实现自己各种idea~    \n最好自己去申请个LeanCloud或者Bmob的账号应用，两个平台的Restful-API由于是一毛一样的，所以可以随意切换~  \n\n\n## 使用框架\n * 使用LeanCloud的Restful-API接口作为后端服务。\n * 网络框架部分使用Retrofit2.0\n * 图片框架部分使用Glide。\n * 响应式编程RxJava + RxBinding\n\n"
  },
  {
    "path": "DesignResCollection_MVC/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.boredream.designrescollection\"\n\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n\n        versionCode 70\n        versionName \"0.7.0\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'\n        }\n    }\n\n    packagingOptions {\n        exclude 'META-INF/DEPENDENCIES'\n        exclude 'META-INF/LICENSE'\n        exclude 'META-INF/NOTICE'\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\n    android.applicationVariants.all { variant ->\n        renameAPK(variant, defaultConfig, \"release\")\n    }\n}\n\ndef renameAPK(variant, defaultConfig, buildType) {\n    variant.outputs.each { output ->\n        def applicationName = 'DesignResCollection'\n        def formattedDate = new Date().format('yyyyMMdd')\n        def file = output.packageApplication.outputFile\n        def fileName = applicationName + \"_v\" + defaultConfig.versionName + \"_\" + formattedDate + \"_\" + buildType + \".apk\"\n        output.packageApplication.outputFile = new File(file.parent, fileName)\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(path: ':bdcodehelper')\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/proguard.cfg",
    "content": "######################## 固定部分 ########################\n\n#1.基本指令区\n-optimizationpasses 5\n-dontusemixedcaseclassnames\n-dontskipnonpubliclibraryclasses\n-dontskipnonpubliclibraryclassmembers\n-dontpreverify\n-verbose\n-ignorewarning\n-printmapping proguardMapping.txt\n-optimizations !code/simplification/cast,!field/*,!class/merging/*\n-keepattributes *Annotation*,InnerClasses\n-keepattributes Signature\n-keepattributes SourceFile,LineNumberTable\n\n#2.默认保留区\n-keep public class * extends android.app.Activity\n-keep public class * extends android.app.Application\n-keep public class * extends android.app.Service\n-keep public class * extends android.content.BroadcastReceiver\n-keep public class * extends android.content.ContentProvider\n-keep public class * extends android.app.backup.BackupAgentHelper\n-keep public class * extends android.preference.Preference\n-keep public class * extends android.view.View\n-keep public class com.android.vending.licensing.ILicensingService\n-keep class android.support.** {*;}\n\n-keepclasseswithmembernames class * {\n    native <methods>;\n}\n-keepclassmembers class * extends android.app.Activity{\n    public void *(android.view.View);\n}\n-keepclassmembers enum * {\n    public static **[] values();\n    public static ** valueOf(java.lang.String);\n}\n-keep public class * extends android.view.View{\n    *** get*();\n    void set*(***);\n    public <init>(android.content.Context);\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keepclasseswithmembers class * {\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keep class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n-keepclassmembers class * implements java.io.Serializable {\n    static final long serialVersionUID;\n    private static final java.io.ObjectStreamField[] serialPersistentFields;\n    private void writeObject(java.io.ObjectOutputStream);\n    private void readObject(java.io.ObjectInputStream);\n    java.lang.Object writeReplace();\n    java.lang.Object readResolve();\n}\n-keep class **.R$* {\n *;\n}\n-keepclassmembers class * {\n    void *(**On*Event);\n}\n\n#3.webview\n-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n   public *;\n}\n-keepclassmembers class * extends android.webkit.webViewClient {\n    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);\n    public boolean *(android.webkit.WebView, java.lang.String);\n}\n-keepclassmembers class * extends android.webkit.webViewClient {\n    public void *(android.webkit.webView, jav.lang.String);\n}\n\n######################## 非固定部分 ########################\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/androidTest/java/com/boredream/designrescollection/ApplicationTest.java",
    "content": "package com.boredream.designrescollection;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.boredream.designrescollection\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_LOGS\" />\n    <uses-permission android:name=\"android.permission.CALL_PHONE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n\n    <application\n        android:name=\".base.BaseApplication\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".activity.MainActivity\"\n            android:launchMode=\"singleTask\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\".activity.RegisterStep1Activity\" />\n        <activity android:name=\".activity.RegisterStep2Activity\" />\n        <activity android:name=\".activity.LoginActivity\" />\n        <activity android:name=\".activity.SettingActivity\" />\n        <activity android:name=\".activity.AboutActivity\" />\n        <activity android:name=\".activity.UserInfoEditActivity\" />\n        <activity android:name=\".activity.UsernameModifyActivity\" />\n        <activity android:name=\".activity.FeedBackActivity\" />\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/AboutActivity.java",
    "content": "package com.boredream.designrescollection.activity;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.SpannableString;\nimport android.text.Spanned;\nimport android.text.method.LinkMovementMethod;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\n\npublic class AboutActivity extends BaseActivity {\n\n    private TextView tv_version;\n    private TextView tv_about;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_about);\n        initView();\n    }\n\n    private void initView() {\n        initBackTitle(\"关于我\");\n\n        tv_version = (TextView) findViewById(R.id.tv_version);\n        tv_about = (TextView) findViewById(R.id.tv_about);\n\n        tv_version.setText(\"Version \" + AppUtils.getAppVersionName(this));\n\n        SpannableString ss = getAboutString();\n        tv_about.setMovementMethod(LinkMovementMethod.getInstance());\n        tv_about.setText(ss);\n    }\n\n    private SpannableString getAboutString() {\n        final String githubLink = getString(R.string.github);\n        String format = String.format(getString(R.string.about), githubLink);\n        SpannableString ss = new SpannableString(format);\n        // 网址部分可点击,跳转到网页\n        StringUtils.PrimaryClickableSpan span = new StringUtils.PrimaryClickableSpan(this) {\n            @Override\n            public void onClick(View widget) {\n                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(githubLink));\n                startActivity(intent);\n            }\n        };\n        int start = format.indexOf(githubLink);\n        ss.setSpan(span, start, start + githubLink.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        return ss;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/FeedBackActivity.java",
    "content": "package com.boredream.designrescollection.activity;\n\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\n\nimport rx.Observable;\n\npublic class FeedBackActivity extends BaseActivity {\n\n    private EditText et_content;\n    private EditText et_email;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_feed_back);\n\n        initView();\n    }\n\n    private void initView() {\n        initBackTitle(\"意见反馈\")\n                .setRightText(\"提交\")\n                .setRightOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        submit();\n                    }\n                });\n\n        et_content = (EditText) findViewById(R.id.et_content);\n        et_email = (EditText) findViewById(R.id.et_email);\n\n    }\n\n    private void submit() {\n        // 开始验证输入内容\n        String content = et_content.getText().toString().trim();\n        if (TextUtils.isEmpty(content)) {\n            Toast.makeText(this, \"反馈内容不能为空\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        String email = et_email.getText().toString().trim();\n        if (TextUtils.isEmpty(email)) {\n            Toast.makeText(this, \"请输入邮箱地址,方便我们对您的意见进行及时回复\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        // 使用自定义对象存至云平台,作为简易版的反馈意见收集\n        FeedBack fb = new FeedBack();\n        fb.setContent(content);\n        fb.setEmail(email);\n\n        showProgressDialog();\n        Observable<BaseEntity> observable = HttpRequest.getApiService().addFeedBack(fb);\n        ObservableDecorator.decorate(observable).subscribe(\n                new SimpleSubscriber<BaseEntity>(this) {\n                    @Override\n                    public void onNext(BaseEntity entity) {\n                        dismissProgressDialog();\n                        showToast(\"反馈成功\");\n                        finish();\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        super.onError(throwable);\n                        dismissProgressDialog();\n                    }\n                });\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/LoginActivity.java",
    "content": "package com.boredream.designrescollection.activity;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\n\nimport rx.Observable;\n\npublic class LoginActivity extends BaseActivity implements View.OnClickListener {\n\n    private EditText et_username;\n    private EditText et_password;\n    private Button btn_login;\n    private LinearLayout ll_regist;\n\n    /**\n     * 是否为验证登录,true-登录成功后,直接finish返回到来源页 false-登录成功后跳转到主页\n     */\n    private boolean checkLogin;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_login);\n\n        initExtras();\n        initView();\n    }\n\n    private void initExtras() {\n        checkLogin = getIntent().getBooleanExtra(\"checkLogin\", false);\n    }\n\n    private void initView() {\n        initBackTitle(\"登录\");\n\n        et_username = (EditText) findViewById(R.id.et_username);\n        et_password = (EditText) findViewById(R.id.et_password);\n        btn_login = (Button) findViewById(R.id.btn_login);\n        ll_regist = (LinearLayout) findViewById(R.id.ll_regist);\n\n        btn_login.setOnClickListener(this);\n        ll_regist.setOnClickListener(this);\n    }\n\n    private void login() {\n        // validate\n        String username = et_username.getText().toString().trim();\n        if (TextUtils.isEmpty(username)) {\n            Toast.makeText(this, \"请输入手机号\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        String password = et_password.getText().toString().trim();\n        if (TextUtils.isEmpty(password)) {\n            Toast.makeText(this, \"请输入密码\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        showProgressDialog();\n        Observable<User> observable = HttpRequest.login(username, password);\n        ObservableDecorator.decorate(observable)\n                .subscribe(new SimpleSubscriber<User>(this) {\n                    @Override\n                    public void onNext(User user) {\n                        dismissProgressDialog();\n\n                        if (checkLogin) {\n                            // 是验证登录,登录成功后,直接finish返回到来源页\n                            finish();\n                        } else {\n                            // 不是验证登录,登录成功后跳转到主页\n                            intent2Activity(MainActivity.class);\n                        }\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        super.onError(throwable);\n                        dismissProgressDialog();\n                    }\n                });\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_login:\n                login();\n                break;\n            case R.id.ll_regist:\n                intent2Activity(RegisterStep1Activity.class);\n                break;\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/MainActivity.java",
    "content": "package com.boredream.designrescollection.activity;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\n\nimport com.boredream.bdcodehelper.fragment.FragmentController;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.fragment.HomeFragment;\nimport com.boredream.designrescollection.fragment.UserFragment;\nimport com.boredream.designrescollection.utils.UpdateUtils;\n\nimport java.util.ArrayList;\n\n\npublic class MainActivity extends BaseActivity implements RadioGroup.OnCheckedChangeListener {\n\n    private RadioGroup rg_bottom_tab;\n    private RadioButton rb1;\n    private FragmentController controller;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        initView();\n        initData();\n    }\n\n    private void initView() {\n        setCouldDoubleBackExit(true);\n\n        rg_bottom_tab = (RadioGroup) findViewById(R.id.rg_bottom_tab);\n        rb1 = (RadioButton) findViewById(R.id.rb1);\n\n        rg_bottom_tab.setOnCheckedChangeListener(this);\n    }\n\n    private void initData() {\n        ArrayList<Fragment> fragments = new ArrayList<>();\n        fragments.add(new HomeFragment());\n        fragments.add(new UserFragment());\n\n        controller = new FragmentController(this, R.id.fl_content, fragments);\n\n        // 默认Fragment\n        rb1.setChecked(true);\n        controller.showFragment(0);\n\n        UpdateUtils.checkUpdate(this, false);\n    }\n\n    @Override\n    public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {\n        switch (checkedId) {\n            case R.id.rb1:\n                controller.showFragment(0);\n                break;\n            case R.id.rb2:\n                controller.showFragment(1);\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/RegisterStep1Activity.java",
    "content": "package com.boredream.designrescollection.activity;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\n\n/**\n * 注册页面步骤一\n */\npublic class RegisterStep1Activity extends BaseActivity implements View.OnClickListener {\n\n    private EditText et_username;\n    private EditText et_password;\n    private Button btn_next;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_register_step1);\n\n        initView();\n    }\n\n    private void initView() {\n        initBackTitle(\"注册\");\n\n        et_username = (EditText) findViewById(R.id.et_username);\n        et_password = (EditText) findViewById(R.id.et_password);\n        btn_next = (Button) findViewById(R.id.btn_next);\n\n        btn_next.setOnClickListener(this);\n    }\n\n    private void next() {\n        // validate\n        final String username = et_username.getText().toString().trim();\n        if (TextUtils.isEmpty(username)) {\n            Toast.makeText(this, \"请输入用户名\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        final String password = et_password.getText().toString().trim();\n        if (TextUtils.isEmpty(password) || password.length() < 6) {\n            Toast.makeText(this, \"请设置登录密码，不少于6位\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        // FIXME: 短信有限，所以直接模拟验证码发送成功，使用不验证的注册\n        // requestSmsCode(phone, password);\n        toValidateStep2(username, password);\n    }\n\n    // 短信验证码发送成功后,跳转到短信验证页,同时传递所需数据\n    private void  toValidateStep2(String phone, String password) {\n        Intent intent = new Intent(RegisterStep1Activity.this, RegisterStep2Activity.class);\n        intent.putExtra(\"phone\", phone);\n        intent.putExtra(\"password\", password);\n        startActivity(intent);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_next:\n                next();\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/RegisterStep2Activity.java",
    "content": "package com.boredream.designrescollection.activity;\n\n\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.CountDownTimer;\nimport android.support.v7.app.AlertDialog;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.DateUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport rx.Observable;\n\n/**\n * 注册页面步骤二\n */\npublic class RegisterStep2Activity extends BaseActivity implements View.OnClickListener {\n\n    // 总倒计时60秒\n    private static final long TOTCAL_TIME = 60 * DateUtils.ONE_SECOND_MILLIONS;\n    // 每次减少1秒\n    private static final long COUNT_DOWN_INTERVAL = DateUtils.ONE_SECOND_MILLIONS;\n\n    private EditText et_verification_code;\n    private Button btn_code_info;\n    private Button btn_next;\n\n    private String phone;\n    private String password;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_register_step2);\n\n        initExtras();\n        initView();\n        initData();\n    }\n\n    private void initExtras() {\n        Intent intent = getIntent();\n        phone = intent.getStringExtra(\"phone\");\n        password = intent.getStringExtra(\"password\");\n    }\n\n    private void initView() {\n        initBackTitle(\"手机号验证\");\n\n        et_verification_code = (EditText) findViewById(R.id.et_verification_code);\n        btn_code_info = (Button) findViewById(R.id.btn_code_info);\n        btn_next = (Button) findViewById(R.id.btn_next);\n\n        btn_code_info.setOnClickListener(this);\n        btn_next.setOnClickListener(this);\n    }\n\n    private void initData() {\n        startCountDown();\n    }\n\n    /**\n     * 开始倒计时\n     */\n    private void startCountDown() {\n        showToast(\"短信验证码发送成功\");\n\n        btn_code_info.setText(\"60秒\");\n        btn_code_info.setEnabled(false);\n\n        // 倒计时开始,共60秒,每次减少1秒\n        CountDownTimer timer = new CountDownTimer(TOTCAL_TIME, COUNT_DOWN_INTERVAL) {\n            @Override\n            public void onTick(long l) {\n                // 重新获取(60)\n                String restTime = (int) (l / COUNT_DOWN_INTERVAL) + \"秒\";\n                btn_code_info.setText(restTime);\n            }\n\n            @Override\n            public void onFinish() {\n                // 倒计时结束,重置按钮\n                btn_code_info.setText(\"重新获取\");\n                btn_code_info.setEnabled(true);\n            }\n        };\n        timer.start();\n    }\n\n    /**\n     * 根据类型提交注册或重置密码接口\n     */\n    private void submit() {\n        // validate\n        String code = et_verification_code.getText().toString().trim();\n        if (TextUtils.isEmpty(code)) {\n            Toast.makeText(this, \"请输入验证码\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        register(code);\n    }\n\n    /**\n     * 注册\n     */\n    private void register(String code) {\n        User user = new User();\n        user.setMobilePhoneNumber(phone);\n        user.setUsername(phone);\n        user.setPassword(password);\n        user.setSmsCode(code);\n        Observable<User> observable = HttpRequest.getApiService().register(user);\n        showProgressDialog();\n        ObservableDecorator.decorate(observable)\n                .subscribe(new SimpleSubscriber<User>(this) {\n                    @Override\n                    public void onNext(User user) {\n                        // include token\n                        dismissProgressDialog();\n                        UserInfoKeeper.setCurrentUser(user);\n                        // 注册成功,显示成功提示框\n                        showRegistSuccessDialog();\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        super.onError(throwable);\n                        dismissProgressDialog();\n                    }\n                });\n\n    }\n\n    /**\n     * 注册成功提示框,提醒用户完善资料\n     */\n    private void showRegistSuccessDialog() {\n        new AlertDialog.Builder(this)\n                .setMessage(\"注册成功，你可以在个人详情中修改或完善用户信息。\")\n                .setPositiveButton(\"确定\", null)\n                .setOnDismissListener(new DialogInterface.OnDismissListener() {\n                    @Override\n                    public void onDismiss(DialogInterface dialog) {\n                        // 确定或者返回键关闭对话框都走此\n                        intent2Activity(MainActivity.class);\n                    }\n                })\n                .setCancelable(false) // cancelable设为false,防止用户点击返回键关闭对话框停留在当前页面\n                .show();\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_code_info:\n                // FIXME: 短信有限，所以直接模拟验证码发送成功，使用不验证的注册\n                // resendSmsCode();\n                startCountDown();\n                break;\n            case R.id.btn_next:\n                submit();\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/SettingActivity.java",
    "content": "package com.boredream.designrescollection.activity;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.Button;\n\nimport com.boredream.bdcodehelper.adapter.SettingRecyclerAdapter;\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.utils.UpdateUtils;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SettingActivity extends BaseActivity implements View.OnClickListener, AdapterView.OnItemClickListener {\n\n    private RecyclerView rv_setting;\n    private Button btn_logout;\n\n    private SettingRecyclerAdapter adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_setting);\n        initView();\n        initData();\n    }\n\n    private void initView() {\n        initBackTitle(\"设置\");\n\n        rv_setting = (RecyclerView) findViewById(R.id.rv_setting);\n        btn_logout = (Button) findViewById(R.id.btn_logout);\n\n        btn_logout.setOnClickListener(this);\n    }\n\n    private void initData() {\n        // 使用列表显示多个选项条\n        List<SettingItem> items = new ArrayList<>();\n\n        items.add(new SettingItem(\n                R.mipmap.ic_cached_grey600_24dp,\n                \"检查更新\",\n                AppUtils.getAppVersionName(this),\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n        items.add(new SettingItem(\n                R.mipmap.ic_announcement_grey600_24dp,\n                \"反馈\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n\n        adapter = new SettingRecyclerAdapter(items, this);\n        rv_setting.setAdapter(adapter);\n\n        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(\n                this, LinearLayoutManager.VERTICAL, false);\n        rv_setting.setLayoutManager(linearLayoutManager);\n        // 每个item之间的分割线\n        rv_setting.addItemDecoration(new DividerItemDecoration(this));\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        switch (position) {\n            case 0:\n                showProgressDialog();\n                // 强制检查更新,并添加额外回调用于处理进度框\n                UpdateUtils.checkUpdate(this, true);\n                break;\n            case 1:\n                if(UserInfoKeeper.checkLogin(this)) {\n                    // 一般意见反馈不需要登录，这里模拟下需登录场景的处理方法\n                    intent2Activity(FeedBackActivity.class);\n                }\n                break;\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_logout:\n                // 登出,清理用户数据同时跳转到主页\n                UserInfoKeeper.logout();\n                intent2Activity(MainActivity.class);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/UserInfoEditActivity.java",
    "content": "package com.boredream.designrescollection.activity;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ImageUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.GlideHelper;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport rx.Observable;\n\npublic class UserInfoEditActivity extends BaseActivity implements View.OnClickListener {\n\n    private ImageView iv_avatar;\n    private LinearLayout ll_avatar;\n    private TextView tv_username;\n    private LinearLayout ll_username;\n\n    private User currentUser;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_user_info_edit);\n\n        initView();\n    }\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n        // 如果跳转到二级页面修改了用户信息,则再次返回到该页面时显示最新的用户数据\n        initData();\n    }\n\n    private void initData() {\n        currentUser = UserInfoKeeper.getCurrentUser();\n        showUserAvatar();\n        tv_username.setText(currentUser.getUsername());\n    }\n\n    private void showUserAvatar() {\n        GlideHelper.showAvatar(this, currentUser.getAvatar(), iv_avatar);\n    }\n\n    private void initView() {\n        initBackTitle(\"修改个人资料\");\n\n        iv_avatar = (ImageView) findViewById(R.id.iv_avatar);\n        ll_avatar = (LinearLayout) findViewById(R.id.ll_avatar);\n        tv_username = (TextView) findViewById(R.id.tv_username);\n        ll_username = (LinearLayout) findViewById(R.id.ll_username);\n\n        ll_avatar.setOnClickListener(this);\n        ll_username.setOnClickListener(this);\n    }\n\n    /**\n     * 上传用户头像图片\n     *\n     * @param uri 头像图片uri\n     */\n    private void uploadUserAvatarImage(Uri uri) {\n        showProgressDialog();\n\n        // 第一步,上传头像文件到服务器\n        HttpRequest.fileUpload(this, uri,\n                iv_avatar.getWidth(), iv_avatar.getHeight(),\n                new SimpleSubscriber<FileUploadResponse>(this) {\n                    @Override\n                    public void onNext(FileUploadResponse fileUploadResponse) {\n                        // 第二步,将上传图片返回的url地址更新至用户对象中\n                        uploadUserAvatarImage(HttpRequest.FILE_HOST + fileUploadResponse.getUrl());\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        super.onError(throwable);\n                        dismissProgressDialog();\n                    }\n                });\n    }\n\n    /**\n     * 更新用户头像\n     *\n     * @param avatarUrl 头像图片地址\n     */\n    private void uploadUserAvatarImage(final String avatarUrl) {\n        Map<String, Object> updateMap = new HashMap<>();\n        updateMap.put(\"avatar\", avatarUrl);\n\n        Observable<BaseEntity> observable = HttpRequest.getApiService().updateUserById(\n                currentUser.getObjectId(), updateMap);\n        ObservableDecorator.decorate(observable)\n                .subscribe(new SimpleSubscriber<BaseEntity>(this) {\n                    @Override\n                    public void onNext(BaseEntity entity) {\n                        dismissProgressDialog();\n\n                        // 成功后更新当前用户的头像数据\n                        currentUser.setAvatar(avatarUrl);\n                        UserInfoKeeper.setCurrentUser(currentUser);\n                        showUserAvatar();\n\n                        showToast(\"头像修改成功\");\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        super.onError(throwable);\n                        dismissProgressDialog();\n                    }\n                });\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.ll_avatar:\n                ImageUtils.showImagePickDialog(this);\n                break;\n            case R.id.ll_username:\n                intent2Activity(UsernameModifyActivity.class);\n                break;\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n\n        Uri uri;\n        switch (requestCode) {\n            case ImageUtils.REQUEST_CODE_FROM_ALBUM:\n                // 从相册选择\n                uri = data.getData();\n                // 选择后裁剪\n                ImageUtils.cropImage(this, uri);\n                break;\n            case ImageUtils.REQUEST_CODE_FROM_CAMERA:\n                // 相机拍照\n                uri = ImageUtils.imageUriFromCamera;\n                // 拍照后裁剪\n                ImageUtils.cropImage(this, uri);\n                break;\n            case ImageUtils.REQUEST_CODE_CROP_IMAGE:\n                // 裁剪完成后上传图片\n                uploadUserAvatarImage(ImageUtils.cropImageUri);\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/activity/UsernameModifyActivity.java",
    "content": "package com.boredream.designrescollection.activity;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport rx.Observable;\n\n/**\n * 修改用户名输入框页面\n */\npublic class UsernameModifyActivity extends BaseActivity {\n\n    private EditText et;\n    private User currentUser;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_input);\n\n        initView();\n        initData();\n    }\n\n    private void initView() {\n        initBackTitle(\"昵称修改\")\n                .setRightText(\"保存\")\n                .setRightOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        submit();\n                    }\n                });\n        et = (EditText) findViewById(R.id.et);\n    }\n\n    private void initData() {\n        currentUser = UserInfoKeeper.getCurrentUser();\n        et.setText(currentUser.getUsername());\n    }\n\n    private void submit() {\n        // validate\n        final String username = et.getText().toString().trim();\n        if (TextUtils.isEmpty(username)) {\n            Toast.makeText(this, \"昵称不能为空\", Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        // 修改用户的username\n        Map<String, Object> updateMap = new HashMap<>();\n        updateMap.put(\"username\", username);\n\n        showProgressDialog();\n        Observable<BaseEntity> observable = HttpRequest.getApiService()\n                .updateUserById(currentUser.getObjectId(), updateMap);\n        ObservableDecorator.decorate(observable)\n                .subscribe(new SimpleSubscriber<BaseEntity>(this) {\n                    @Override\n                    public void onNext(BaseEntity entity) {\n                        dismissProgressDialog();\n\n                        // 修改成功后更新当前用户的昵称\n                        currentUser.setUsername(username);\n                        UserInfoKeeper.setCurrentUser(currentUser);\n\n                        showToast(\"昵称修改成功\");\n                        finish();\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        super.onError(throwable);\n\n                        dismissProgressDialog();\n                    }\n                });\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/adapter/DesignResAdapter.java",
    "content": "package com.boredream.designrescollection.adapter;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.activity.WebViewActivity;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.net.GlideHelper;\n\nimport java.util.ArrayList;\n\npublic class DesignResAdapter extends RecyclerView.Adapter<DesignResAdapter.ViewHolder> {\n\n    private Context context;\n    private ArrayList<DesignRes> datas;\n\n    public DesignResAdapter(Context context, ArrayList<DesignRes> datas) {\n        this.context = context;\n        this.datas = datas;\n    }\n\n    @Override\n    public int getItemCount() {\n        return datas.size();\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        public ImageView iv_image;\n        public TextView tv_name;\n\n        public ViewHolder(View rootView) {\n            super(rootView);\n\n            this.iv_image = (ImageView) rootView.findViewById(R.id.iv_image);\n            this.tv_name = (TextView) rootView.findViewById(R.id.tv_name);\n        }\n\n    }\n\n    @Override\n    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(context).inflate(R.layout.item_design_res, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(ViewHolder holder, int position) {\n        final DesignRes data = datas.get(position);\n\n        GlideHelper.showImage(context, data.getImgUrl(), holder.iv_image);\n        String str = String.format(\"[%s] %s\", data.getSrcTag(), data.getName());\n        holder.tv_name.setText(str);\n\n        holder.itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Intent intent = new Intent(context, WebViewActivity.class);\n                intent.putExtra(WebViewActivity.EXTRA_TITLE, data.getName());\n                intent.putExtra(WebViewActivity.EXTRA_URL, data.getSrcLink());\n                context.startActivity(intent);\n            }\n        });\n    }\n\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/adapter/MoreRecyclerAdapter.java",
    "content": "package com.boredream.designrescollection.adapter;\n\nimport android.content.Intent;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.adapter.SettingRecyclerAdapter;\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.activity.LoginActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.GlideHelper;\n\nimport java.util.List;\n\n/**\n * 更多选项列表适配器\n * <p>\n * 第一个位置为HEADER类型,对应用户信息<br/>\n * 其他位置为LIST类型,对应选项item\n */\npublic class MoreRecyclerAdapter extends SettingRecyclerAdapter {\n\n    private static final int ITEM_VIEW_TYPE_HEADER = 0;\n\n    private User user;\n\n    public MoreRecyclerAdapter(List<SettingItem> datas, OnItemClickListener listener) {\n        super(datas, listener);\n    }\n\n    @Override\n    public int getItemCount() {\n        // header + 1\n        return datas.size() + 1;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return position == 0 ? ITEM_VIEW_TYPE_HEADER : super.getItemViewType(position);\n    }\n\n    public void setUser(User user) {\n        this.user = user;\n    }\n\n    public static class ViewHolderUserHeader extends RecyclerView.ViewHolder {\n\n        public View include_more_header;\n        public ImageView iv_avatar;\n        public TextView tv_name;\n        // not login\n        public View include_more_no_header;\n        public Button btn_login;\n\n        public ViewHolderUserHeader(final View itemView) {\n            super(itemView);\n\n            include_more_header = itemView.findViewById(R.id.include_more_header);\n            iv_avatar = (ImageView) itemView.findViewById(R.id.iv_avatar);\n            tv_name = (TextView) itemView.findViewById(R.id.tv_name);\n            include_more_no_header = itemView.findViewById(R.id.include_more_no_header);\n            btn_login = (Button) itemView.findViewById(R.id.btn_login);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        if (viewType == ITEM_VIEW_TYPE_HEADER) {\n            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_more_header, parent, false);\n            return new ViewHolderUserHeader(v);\n        } else {\n            return super.onCreateViewHolder(parent, viewType);\n        }\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {\n        int itemViewType = getItemViewType(position);\n        if (itemViewType == ITEM_VIEW_TYPE_HEADER) {\n            // header\n            ViewHolderUserHeader viewHolderHeader = (ViewHolderUserHeader) holder;\n            if (user != null) {\n                // 如果已登录,用户数据非空,则显示用户信息\n                viewHolderHeader.include_more_header.setVisibility(View.VISIBLE);\n                viewHolderHeader.include_more_no_header.setVisibility(View.GONE);\n\n                GlideHelper.showAvatar(holder.itemView.getContext(), user.getAvatar(), viewHolderHeader.iv_avatar);\n                viewHolderHeader.tv_name.setText(user.getUsername());\n\n                viewHolderHeader.itemView.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        if (mOnItemClickListener != null) {\n                            // header使用特殊的position -1\n                            mOnItemClickListener.onItemClick(null, view, -1, -1);\n                        }\n                    }\n                });\n            } else {\n                // 未登录,提供登录按钮,点击进入登录页\n                viewHolderHeader.include_more_header.setVisibility(View.GONE);\n                viewHolderHeader.include_more_no_header.setVisibility(View.VISIBLE);\n\n                viewHolderHeader.btn_login.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        Intent intent = new Intent(view.getContext(), LoginActivity.class);\n                        view.getContext().startActivity(intent);\n                    }\n                });\n            }\n        } else {\n            // setting item\n            // 第一个位置多了个HEADER,所以position差1\n            super.onBindViewHolder(holder, position - 1);\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/base/BaseActivity.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\n\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.designrescollection.activity.MainActivity;\nimport com.boredream.designrescollection.constants.CommonConstants;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\nimport rx.functions.Action1;\n\npublic class BaseActivity extends BoreBaseActivity {\n\n    public BaseApplication application;\n    public SharedPreferences sp;\n\n    private boolean couldDoubleBackExit;\n    private boolean doubleBackExitPressedOnce;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // 如果是退出应用flag,则直接关闭当前页面,不加载UI\n        boolean exit = getIntent().getBooleanExtra(\"exit\", false);\n        if (exit) {\n            finish();\n            return;\n        }\n\n        application = (BaseApplication) getApplication();\n        sp = getSharedPreferences(CommonConstants.SP_NAME, MODE_PRIVATE);\n    }\n\n    /**\n     * 设置是否可以双击返回退出，需要有该功能的页面set true即可\n     *\n     * @param couldDoubleBackExit true-开启双击退出\n     */\n    public void setCouldDoubleBackExit(boolean couldDoubleBackExit) {\n        this.couldDoubleBackExit = couldDoubleBackExit;\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (!couldDoubleBackExit) {\n            // 非双击退出状态，使用原back逻辑\n            super.onBackPressed();\n            return;\n        }\n\n        // 双击返回键关闭程序\n        // 如果两秒重置时间内再次点击返回,则退出程序\n        if (doubleBackExitPressedOnce) {\n            exit();\n            return;\n        }\n\n        doubleBackExitPressedOnce = true;\n        showToast(\"再按一次返回键关闭程序\");\n        Observable.just(null)\n                .delay(2, TimeUnit.SECONDS)\n                .subscribe(new Action1<Object>() {\n                    @Override\n                    public void call(Object o) {\n                        // 延迟两秒后重置标志位为false\n                        doubleBackExitPressedOnce = false;\n                    }\n                });\n    }\n\n    /**\n     * 退出程序\n     */\n    protected void exit() {\n        // 退出程序方法有多种\n        // 这里使用clear + new task的方式清空整个任务栈,只保留新打开的Main页面\n        // 然后Main页面接收到退出的标志位exit=true,finish自己,这样就关闭了全部页面\n        Intent intent = new Intent(this, MainActivity.class);\n        intent.putExtra(\"exit\", true);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);\n        startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/base/BaseApplication.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.app.Application;\n\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.integration.okhttp.OkHttpUrlLoader;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.squareup.okhttp.OkHttpClient;\n\nimport java.io.InputStream;\n\npublic class BaseApplication extends Application {\n\n    private static BaseApplication instance;\n\n    public static BaseApplication getInstance() {\n        return instance;\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        instance = this;\n\n        initGlide();\n    }\n\n    /**\n     * 图片加载框架Glide,使用OkHttp处理网络请求\n     */\n    private void initGlide() {\n        OkHttpClient okHttpClient = HttpRequest.getHttpClient();\n        Glide.get(this).register(GlideUrl.class, InputStream.class,\n                new OkHttpUrlLoader.Factory(okHttpClient));\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/base/BaseEntity.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class BaseEntity extends BoreBaseEntity {\n\n    @Override\n    public boolean equals(Object o) {\n        if (o instanceof BaseEntity) {\n            BaseEntity oEntity = (BaseEntity) o;\n            return this.objectId.equals(oEntity.objectId);\n        }\n        return super.equals(o);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/base/BaseFragment.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\npublic abstract class BaseFragment extends Fragment {\n\n    protected String TAG;\n    protected BaseActivity activity;\n    // progressDialog/sp/application 等使用activity.xx 调用\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        TAG = getClass().getSimpleName();\n\n        activity = (BaseActivity) getActivity();\n    }\n\n    protected void intent2Activity(Class<? extends Activity> tarActivity) {\n        Intent intent = new Intent(activity, tarActivity);\n        startActivity(intent);\n    }\n\n    protected void showToast(String msg) {\n        ToastUtils.showToast(activity, msg, Toast.LENGTH_SHORT);\n    }\n\n    protected void showLog(String msg) {\n        Log.i(TAG, msg);\n    }\n\n    protected void showProgressDialog() {\n        activity.showProgressDialog();\n    }\n\n    protected void dismissProgressDialog() {\n        activity.dismissProgressDialog();\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/constants/CommonConstants.java",
    "content": "package com.boredream.designrescollection.constants;\n\n/**\n * 通用常量\n */\npublic class CommonConstants {\n\n    private CommonConstants() {\n    }\n\n    /**\n     * SharedPreferences 名称\n     */\n    public static final String SP_NAME = \"config\";\n\n    /**\n     * 每页加载的数量\n     */\n    public static final int COUNT_OF_PAGE = 20;\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/entity/Comment.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class Comment extends BaseEntity {\n    /**\n     * 所属资源\n     */\n    private DesignRes designRes;\n\n    /**\n     * 发送用户, Pointer or User\n     */\n    private User user;\n\n    /**\n     * 评论内容\n     */\n    private String content;\n\n    public DesignRes getDesignRes() {\n        return designRes;\n    }\n\n    public void setDesignRes(DesignRes designRes) {\n        this.designRes = designRes;\n    }\n\n    public User getUser() {\n        return user;\n    }\n\n    public void setUser(User user) {\n        this.user = user;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/entity/DesignRes.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\n/**\n * 设计资源\n */\npublic class DesignRes extends BaseEntity {\n\n    private String desc;\n    private String srcTag;\n    private String name;\n    private String imgUrl;\n    private String srcLink;\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getSrcTag() {\n        return srcTag;\n    }\n\n    public void setSrcTag(String srcTag) {\n        this.srcTag = srcTag;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getImgUrl() {\n        return imgUrl;\n    }\n\n    public void setImgUrl(String imgUrl) {\n        this.imgUrl = imgUrl;\n    }\n\n    public String getSrcLink() {\n        return srcLink;\n    }\n\n    public void setSrcLink(String srcLink) {\n        this.srcLink = srcLink;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/entity/FeedBack.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class FeedBack extends BaseEntity {\n\n    private String content;\n    private String email;\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/entity/User.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class User extends BaseEntity {\n\n    private String sessionToken;\n\n    private String nickname;\n\n    private String username;\n\n    /**\n     * 验证手机号\n     */\n    private String mobilePhoneNumber;\n\n    /**\n     * 密码\n     */\n    private String password;\n\n    /**\n     * 手机号验证码,发送短信验证时请求使用\n     */\n    private String smsCode;\n\n    /**\n     * 头像图片地址\n     */\n    private String avatar;\n\n    private String company;\n\n    public String getSessionToken() {\n        return sessionToken;\n    }\n\n    public void setSessionToken(String sessionToken) {\n        this.sessionToken = sessionToken;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n\n    public String getAvatar() {\n        return avatar;\n    }\n\n    public void setAvatar(String avatar) {\n        this.avatar = avatar;\n    }\n\n    public String getSmsCode() {\n        return smsCode;\n    }\n\n    public void setSmsCode(String smsCode) {\n        this.smsCode = smsCode;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getMobilePhoneNumber() {\n        return mobilePhoneNumber;\n    }\n\n    public void setMobilePhoneNumber(String mobilePhoneNumber) {\n        this.mobilePhoneNumber = mobilePhoneNumber;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getNickname() {\n        return nickname;\n    }\n\n    public void setNickname(String nickname) {\n        this.nickname = nickname;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/fragment/HomeFragment.java",
    "content": "package com.boredream.designrescollection.fragment;\n\n\nimport android.os.Bundle;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.view.GridSpacingDecorator;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.adapter.DesignResAdapter;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.constants.CommonConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\n\nimport java.util.ArrayList;\n\nimport rx.Observable;\n\npublic class HomeFragment extends BaseFragment {\n\n    private View view;\n    private SwipeRefreshLayout srl;\n    private RecyclerView rv;\n\n    private int curPage = 1;\n    private ArrayList<DesignRes> datas = new ArrayList<>();\n    private LoadMoreAdapter adapter;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        view = View.inflate(activity, R.layout.frag_home, null);\n        initView();\n        initData();\n        return view;\n    }\n\n    private void initView() {\n        new TitleBuilder(view).setTitleText(getString(R.string.tab1));\n\n        srl = (SwipeRefreshLayout) view.findViewById(R.id.srl);\n        srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {\n            @Override\n            public void onRefresh() {\n                loadData(1);\n            }\n        });\n\n        rv = (RecyclerView) view.findViewById(R.id.rv);\n        rv.addItemDecoration(new GridSpacingDecorator(DisplayUtils.dp2px(activity, 8)));\n        GridLayoutManager gridLayoutManager = new GridLayoutManager(activity, 2);\n        rv.setLayoutManager(gridLayoutManager);\n\n        adapter = new LoadMoreAdapter(rv,\n                new DesignResAdapter(activity, datas),\n                new LoadMoreAdapter.OnLoadMoreListener() {\n                    @Override\n                    public void onLoadMore() {\n                        loadData(curPage + 1);\n                    }\n                });\n        rv.setAdapter(adapter);\n    }\n\n    private void initData() {\n        showProgressDialog();\n        loadData(1);\n    }\n\n    private void loadData(final int page) {\n        Observable<ListResponse<DesignRes>> observable = HttpRequest.getDesignRes(page);\n        ObservableDecorator.decorate(observable).subscribe(\n                new SimpleSubscriber<ListResponse<DesignRes>>(activity) {\n                    @Override\n                    public void onNext(ListResponse<DesignRes> response) {\n                        curPage = page;\n\n                        srl.setRefreshing(false);\n                        dismissProgressDialog();\n\n                        if (page == 1) {\n                            datas.clear();\n                        }\n                        setResponse(response);\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        super.onError(throwable);\n\n                        srl.setRefreshing(false);\n                        dismissProgressDialog();\n                    }\n                });\n    }\n\n    private void setResponse(ListResponse<DesignRes> response) {\n        datas.addAll(response.getResults());\n\n        // 设置是否已加载完全部数据状态\n        adapter.setStatus(response.getResults().size() == CommonConstants.COUNT_OF_PAGE\n                ? LoadMoreAdapter.STATUS_HAVE_MORE : LoadMoreAdapter.STATUS_LOADED_ALL);\n        adapter.notifyDataSetChanged();\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/fragment/UserFragment.java",
    "content": "package com.boredream.designrescollection.fragment;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\n\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\nimport com.boredream.bdcodehelper.view.EmptyItemDecoration;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.activity.AboutActivity;\nimport com.boredream.designrescollection.activity.SettingActivity;\nimport com.boredream.designrescollection.activity.UserInfoEditActivity;\nimport com.boredream.designrescollection.adapter.MoreRecyclerAdapter;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class UserFragment extends BaseFragment implements AdapterView.OnItemClickListener {\n\n    private RecyclerView rv_user;\n    private MoreRecyclerAdapter adapter;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = View.inflate(activity, R.layout.frag_user, null);\n        initView(view);\n        initData();\n        return view;\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n\n        // 如果未登录进入本页面,然后跳转登录页面成功后返回,此时应该再次更新用户信息\n        adapter.setUser(UserInfoKeeper.getCurrentUser());\n        adapter.notifyDataSetChanged();\n    }\n\n    private void initView(View view) {\n        new TitleBuilder(view).setTitleText(\"更多\");\n\n        rv_user = (RecyclerView) view.findViewById(R.id.rv_user);\n    }\n\n    private void initData() {\n        // more items\n        List<SettingItem> items = new ArrayList<>();\n        items.add(new SettingItem(\n                R.mipmap.ic_info_grey600_24dp,\n                \"关于\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n        items.add(new SettingItem(\n                R.mipmap.ic_settings_grey600_24dp,\n                \"设置\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n\n        adapter = new MoreRecyclerAdapter(items, this);\n        rv_user.setAdapter(adapter);\n\n        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(\n                activity, LinearLayoutManager.VERTICAL, false);\n        rv_user.setLayoutManager(linearLayoutManager);\n        // 每个item之间的分割线\n        rv_user.addItemDecoration(new DividerItemDecoration(activity));\n        // 每组item之间的分割间隔\n        rv_user.addItemDecoration(new EmptyItemDecoration(\n                new Integer[]{0, 1}, DisplayUtils.dp2px(activity, 16)));\n\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        switch (position) {\n            case -1:\n                // 给特殊的用户信息header位置设为了position=-1的item click事件\n                intent2Activity(UserInfoEditActivity.class);\n                break;\n            case 0:\n                intent2Activity(AboutActivity.class);\n                break;\n            case 1:\n                intent2Activity(SettingActivity.class);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/net/GlideHelper.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.content.Context;\nimport android.widget.ImageView;\n\nimport com.boredream.bdcodehelper.net.GlideCircleTransform;\nimport com.boredream.designrescollection.R;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\n\n/**\n * Glide\n */\npublic class GlideHelper {\n\n    public static void showAvatar(Context context, String avatar, ImageView iv) {\n        Glide.with(context)\n                .load(avatar)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .transform(new GlideCircleTransform(context))\n                .crossFade()\n                .into(iv);\n    }\n\n    public static void showImage(Context context, String imageUrl, ImageView iv) {\n        Glide.with(context)\n                .load(imageUrl)\n                .asBitmap()\n                .animate(android.R.anim.fade_in)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n                .into(iv);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/net/HttpRequest.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.text.TextUtils;\n\nimport com.boredream.bdcodehelper.entity.AppUpdateInfo;\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.constants.CommonConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.request.animation.GlideAnimation;\nimport com.bumptech.glide.request.target.SimpleTarget;\nimport com.squareup.okhttp.Interceptor;\nimport com.squareup.okhttp.MediaType;\nimport com.squareup.okhttp.OkHttpClient;\nimport com.squareup.okhttp.Request;\nimport com.squareup.okhttp.RequestBody;\nimport com.squareup.okhttp.Response;\nimport com.squareup.okhttp.logging.HttpLoggingInterceptor;\n\nimport java.io.IOException;\nimport java.util.Map;\n\nimport retrofit.GsonConverterFactory;\nimport retrofit.Retrofit;\nimport retrofit.RxJavaCallAdapterFactory;\nimport retrofit.http.Body;\nimport retrofit.http.GET;\nimport retrofit.http.POST;\nimport retrofit.http.PUT;\nimport retrofit.http.Path;\nimport retrofit.http.Query;\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.functions.Action1;\n\npublic class HttpRequest {\n    // LeanCloud\n    public static final String HOST = \"https://api.leancloud.cn\";\n    public static final String FILE_HOST = \"\";\n\n    private static final String APP_ID_NAME = \"X-LC-Id\";\n    private static final String API_KEY_NAME = \"X-LC-Key\";\n    public static final String SESSION_TOKEN_KEY = \"X-LC-Session\";\n\n    private static final String APP_ID_VALUE = \"iaEH7ObIA4sPY8RSs3VCVXBg-gzGzoHsz\";\n    private static final String API_KEY_VALUE = \"dXfhXIVyeWMN2czJkd4ehwzs\";\n\n    private static Retrofit retrofit;\n    private static OkHttpClient httpClient;\n\n    public static OkHttpClient getHttpClient() {\n        return httpClient;\n    }\n\n    static {\n        // OkHttpClient\n        httpClient = new OkHttpClient();\n\n        // 统一添加的Header\n        httpClient.networkInterceptors().add(new Interceptor() {\n            @Override\n            public Response intercept(Chain chain) throws IOException {\n                Request request = chain.request().newBuilder()\n                        .addHeader(\"Content-Type\", \"application/json\")\n                        .addHeader(APP_ID_NAME, APP_ID_VALUE)\n                        .addHeader(API_KEY_NAME, API_KEY_VALUE)\n                        .addHeader(SESSION_TOKEN_KEY, UserInfoKeeper.getToken())\n                        .build();\n                return chain.proceed(request);\n            }\n        });\n\n        // log\n        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();\n        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);\n        httpClient.interceptors().add(interceptor);\n\n        // Retrofit\n        retrofit = new Retrofit.Builder()\n                .baseUrl(HOST)\n                .addConverterFactory(GsonConverterFactory.create()) // gson\n                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // rxjava\n                .client(httpClient)\n                .callbackExecutor(AsyncTask.THREAD_POOL_EXECUTOR)\n                .build();\n    }\n\n    public interface AppService {\n        ////////////////////////////// 通用接口 //////////////////////////////\n        // 登录用户\n        @GET(\"/1/login\")\n        Observable<User> login(\n                @Query(\"username\") String username,\n                @Query(\"password\") String password);\n\n        // 注册用户\n        @POST(\"/1/users\")\n        Observable<User> register(\n                @Body User user);\n\n        // 修改用户详情(注意, 提交什么参数修改什么参数)\n        @PUT(\"/1/users/{objectId}\")\n        Observable<BaseEntity> updateUserById(\n                @Path(\"objectId\") String userId,\n                @Body Map<String, Object> updateInfo);\n\n        // 上传图片接口\n        @POST(\"/1/files/{fileName}\")\n        Observable<FileUploadResponse> fileUpload(\n                @Path(\"fileName\") String fileName,\n                @Body RequestBody image);\n\n        // 查询app更新信息\n        @GET(\"/1/classes/AppUpdateInfo\")\n        Observable<ListResponse<AppUpdateInfo>> getAppUpdateInfo();\n\n        // 提交意见反馈\n        @POST(\"/1/classes/FeedBack\")\n        Observable<BaseEntity> addFeedBack(\n                @Body FeedBack feedBack);\n\n\n        ////////////////////////////// 业务接口 //////////////////////////////\n\n        // 查询设计资源\n        @GET(\"/1/classes/DesignRes\")\n        Observable<ListResponse<DesignRes>> getDesignRes(\n                @Query(\"limit\") int perPageCount,\n                @Query(\"skip\") int page,\n                @Query(\"where\") String where,\n                @Query(\"include\") String include);\n    }\n\n    public static AppService getApiService() {\n        return retrofit.create(AppService.class);\n    }\n\n    ////////////////////////////// 业务接口方法 //////////////////////////////\n\n    /**\n     * 查询设计资源\n     */\n    public static Observable<ListResponse<DesignRes>> getDesignRes(int page) {\n        AppService service = getApiService();\n        String where = \"{}\";\n        return service.getDesignRes(CommonConstants.COUNT_OF_PAGE,\n                (page - 1) * CommonConstants.COUNT_OF_PAGE, where, null);\n    }\n\n    /**\n     * 查询设计资源\n     *\n     * @param page\n     * @param name 搜索名称\n     */\n    public static Observable<ListResponse<DesignRes>> getDesignRes(int page, String name) {\n        AppService service = getApiService();\n        String whereName = \"{}\";\n        if (!TextUtils.isEmpty(name)) {\n            whereName = \"{\\\"name\\\":{\\\"$regex\\\":\\\".*\" + name + \".*\\\"}}\";\n        }\n        String where = whereName;\n        return service.getDesignRes(CommonConstants.COUNT_OF_PAGE,\n                (page - 1) * CommonConstants.COUNT_OF_PAGE, where, null);\n    }\n\n\n    ////////////////////////////// 通用接口方法 //////////////////////////////\n\n    /**\n     * 登录用户\n     *\n     * @param username 用户名\n     * @param password 密码\n     */\n    public static Observable<User> login(String username, String password) {\n        AppService service = getApiService();\n        return service.login(username, password)\n                .doOnNext(new Action1<User>() {\n                    @Override\n                    public void call(User user) {\n                        // 保存登录用户数据以及token信息\n                        UserInfoKeeper.setCurrentUser(user);\n                    }\n                });\n    }\n\n    /**\n     * 上传图片\n     *\n     * @param call    上传成功回调\n     * @param context\n     * @param uri     图片uri\n     * @param reqW    上传图片需要压缩的宽度\n     * @param reqH    上传图片需要压缩的高度\n     * @param call\n     */\n    public static void fileUpload(final Context context, Uri uri, int reqW, int reqH, final Subscriber<FileUploadResponse> call) {\n        final AppService service = getApiService();\n        final String filename = \"avatar_\" + System.currentTimeMillis() + \".jpg\";\n\n        // 先从本地获取图片,利用Glide压缩图片后获取byte[]\n        Glide.with(context).load(uri).asBitmap().toBytes().into(\n                new SimpleTarget<byte[]>(reqW, reqH) {\n                    @Override\n                    public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {\n                        // 上传图片\n                        RequestBody requestBody = RequestBody.create(MediaType.parse(\"image/jpeg\"), resource);\n\n                        Observable<FileUploadResponse> observable = service.fileUpload(filename, requestBody);\n                        ObservableDecorator.decorate(observable)\n                                .subscribe(call);\n                    }\n\n                    @Override\n                    public void onLoadFailed(Exception e, Drawable errorDrawable) {\n                        super.onLoadFailed(e, errorDrawable);\n                        call.onError(new Throwable(\"图片解析失败\"));\n                    }\n                });\n    }\n\n}\n\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/net/SimpleSubscriber.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\nimport rx.Subscriber;\n\n/**\n * 通用订阅者,用于统一处理回调\n */\npublic class SimpleSubscriber<T> extends Subscriber<T> {\n\n    private Context context;\n\n    public SimpleSubscriber(Context context) {\n        this.context = context;\n    }\n\n    @Override\n    public void onCompleted() {\n        // sub\n    }\n\n    @Override\n    public void onError(Throwable throwable) {\n        // 统一处理错误回调，显示Toast\n        String errorInfo = ErrorInfoUtils.parseHttpErrorInfo(throwable);\n        ToastUtils.showToast(context, errorInfo);\n    }\n\n    @Override\n    public void onNext(T t) {\n        // sub\n    }\n\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/utils/UpdateUtils.java",
    "content": "package com.boredream.designrescollection.utils;\n\n\nimport android.app.Activity;\nimport android.app.DownloadManager;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.support.annotation.NonNull;\nimport android.support.v7.app.AlertDialog;\n\nimport com.boredream.bdcodehelper.entity.AppUpdateInfo;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.DialogUtils;\nimport com.boredream.bdcodehelper.utils.NetUtils;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\n\nimport java.util.ArrayList;\nimport java.util.Locale;\n\nimport rx.Observable;\n\n/**\n * 检查更新工具类\n */\npublic class UpdateUtils {\n\n    public static final int DOWNLOAD_STATUS_NEED_LOAD = 1;\n    public static final int DOWNLOAD_STATUS_RUNNING = 2;\n    public static final int DOWNLOAD_STATUS_LOADED = 3;\n\n    /**\n     * 检测版本更新\n     *\n     * @param context\n     * @param isForceCheck 是否强制检测更新\n     *                     true强制 - 无论什么网络环境都会提示更新\n     *                     false非强制 - WiFi情况下才提示更新\n     */\n    public static void checkUpdate(final BaseActivity context, final boolean isForceCheck) {\n        if (!NetUtils.isConnected(context)) {\n            // 无网络时\n            if (isForceCheck) {\n                // 手动强制检测更新时，提示文字\n                ToastUtils.showToast(context, \"请检查网络连接\");\n            } else {\n                // 非强制不做操作\n            }\n            return;\n        }\n\n        // 开始检测更新\n\n        if (isForceCheck) {\n            // 强制更新时，才提示进度框\n            context.showProgressDialog();\n        }\n\n        Observable<ListResponse<AppUpdateInfo>> observable = HttpRequest.getApiService().getAppUpdateInfo();\n        ObservableDecorator.decorate(observable).subscribe(\n                new SimpleSubscriber<ListResponse<AppUpdateInfo>>(context) {\n                    @Override\n                    public void onError(Throwable throwable) {\n                        if (isForceCheck) {\n                            // 强制更新时，才提示错误\n                            super.onError(throwable);\n                        }\n                        context.dismissProgressDialog();\n                    }\n\n                    @Override\n                    public void onNext(ListResponse<AppUpdateInfo> response) {\n                        context.dismissProgressDialog();\n\n                        ArrayList<AppUpdateInfo> results = response.getResults();\n                        if (results.size() == 0) {\n                            if (isForceCheck) {\n                                ToastUtils.showToast(context, \"当前已经是最新版本\");\n                            }\n                        }\n\n\n                        AppUpdateInfo newestUpdateInfo = results.get(0);\n                        for (AppUpdateInfo updateInfo : results) {\n                            if (updateInfo.getVersion() > newestUpdateInfo.getVersion()) {\n                                // 取最大版本号的作为最新版本\n                                newestUpdateInfo = updateInfo;\n                            }\n                        }\n\n                        if (newestUpdateInfo.getVersion() <= AppUtils.getAppVersionCode(context)) {\n                            if (isForceCheck) {\n                                ToastUtils.showToast(context, \"当前已经是最新版本\");\n                            }\n                        } else {\n                            showUpdateConfirmDialog(context, newestUpdateInfo);\n                        }\n                    }\n                }\n        );\n    }\n\n    /**\n     * 无Wifi状态确认更新对话框\n     */\n    private static void showNoWifiConfirmDialog(final BaseActivity context, final AppUpdateInfo updateInfo) {\n        DialogUtils.showCommonDialog(context, \"没有wifi连接，是否继续选择更新？\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        startDownload(context, updateInfo);\n                    }\n                });\n    }\n\n    /**\n     * 显示更新对话框,包含版本相关信息\n     */\n    private static void showUpdateConfirmDialog(final BaseActivity context, final AppUpdateInfo updateInfo) {\n        String content = String.format(Locale.CHINESE,\n                context.getResources().getString(R.string.update_info),\n                updateInfo.getVersionName(),\n                updateInfo.getUpdateInfo() == null ? \"无\" : updateInfo.getUpdateInfo());\n\n        new AlertDialog.Builder(context)\n                .setTitle(\"发现新版本\")\n                .setMessage(content)\n                .setPositiveButton(\"立即更新\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        if (NetUtils.isWifi(context)) {\n                            startDownload(context, updateInfo);\n                        } else {\n                            showNoWifiConfirmDialog(context, updateInfo);\n                        }\n                    }\n                })\n                .setNegativeButton(\"以后再说\", null)\n                .show();\n    }\n\n    /**\n     * 开始下载\n     *\n     * @param context\n     * @param updateInfo\n     */\n    private static void startDownload(BaseActivity context, AppUpdateInfo updateInfo) {\n        int status = getDownloadStatus(context, updateInfo);\n        if (status != DOWNLOAD_STATUS_NEED_LOAD) {\n            // 不用下载则无需下列操作\n            return;\n        }\n\n        ToastUtils.showToast(context, \"开始下载安装包...\");\n\n        // parse url\n        Uri mUri = Uri.parse(updateInfo.getFileUrl());\n\n        // create request\n        DownloadManager.Request r = new DownloadManager.Request(mUri);\n\n        // set request property\n        String apkName = getDownloadApkName(context, updateInfo);\n        r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);\n        r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);\n\n        // create manager\n        DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);\n\n        // key code, set mine type\n        r.setMimeType(\"application/vnd.android.package-archive\");\n\n        // add to queue\n        dm.enqueue(r);\n    }\n\n    @NonNull\n    private static String getDownloadApkName(BaseActivity context, AppUpdateInfo updateInfo) {\n        return context.getString(R.string.app_name) + \"_\" + updateInfo.getVersionName() + \".apk\";\n    }\n\n    /**\n     * 判断当前版本文件下载状态\n     *\n     * @param context\n     * @param updateInfo\n     * @return\n     */\n    private static int getDownloadStatus(BaseActivity context, AppUpdateInfo updateInfo) {\n        DownloadManager.Query query = new DownloadManager.Query();\n        DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);\n        Cursor c = dm.query(query);\n\n        if (!c.moveToFirst()) {\n            // 无下载内容\n            return DOWNLOAD_STATUS_NEED_LOAD;\n        }\n\n        do {\n            int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));\n            String title = c.getString(c.getColumnIndex(DownloadManager.COLUMN_TITLE));\n            String apkName = getDownloadApkName(context, updateInfo);\n            if (title.equals(apkName)) {\n                // 如果下载列表中文件是当前版本应用，则继续判断下载状态\n                if (status == DownloadManager.STATUS_SUCCESSFUL) {\n                    // 如果已经下载，返回状态，同时直接提示安装\n                    String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));\n                    AppUtils.promptInstall(context, Uri.parse(uri));\n                    return DOWNLOAD_STATUS_LOADED;\n                } else if (status == DownloadManager.STATUS_RUNNING\n                        || status == DownloadManager.STATUS_PAUSED\n                        || status == DownloadManager.STATUS_PENDING) {\n                    return DOWNLOAD_STATUS_RUNNING;\n                } else {\n                    // 失败也视为可以再次下载\n                    return DOWNLOAD_STATUS_NEED_LOAD;\n                }\n            }\n        } while (c.moveToNext());\n\n        return DOWNLOAD_STATUS_NEED_LOAD;\n    }\n\n    /**\n     * 根据下载队列id获取下载Uri\n     *\n     * @param enqueueId\n     * @return null-获取不到\n     */\n    public static Uri getDownloadUriById(Context context, long enqueueId) {\n        DownloadManager.Query query = new DownloadManager.Query();\n        query.setFilterById(enqueueId);\n        DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);\n        Cursor c = dm.query(query);\n        if (c.moveToFirst()) {\n            int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);\n            if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {\n                String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));\n                return Uri.parse(uri);\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/java/com/boredream/designrescollection/utils/UserInfoKeeper.java",
    "content": "package com.boredream.designrescollection.utils;\n\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport com.boredream.designrescollection.activity.LoginActivity;\nimport com.boredream.designrescollection.entity.User;\n\n/**\n * 用户信息保存工具\n */\npublic class UserInfoKeeper {\n\n    private static User currentUser;\n\n    /**\n     * 获取当前登录用户\n     */\n    public static User getCurrentUser() {\n        return currentUser;\n    }\n\n    /**\n     * 保存设置当前登录用户\n     */\n    public static void setCurrentUser(User user) {\n        currentUser = user;\n    }\n\n    /**\n     * 清空当前登录用户\n     */\n    public static void clearCurrentUser() {\n        currentUser = null;\n    }\n\n    public static String getToken() {\n        // 统一Header配置时用的token,没有的话要用空字符串,不能为null\n        String token = \"\";\n        if (currentUser != null && currentUser.getSessionToken() != null) {\n            token = currentUser.getSessionToken();\n        }\n        return token;\n    }\n\n    /**\n     * 登出\n     */\n    public static void logout() {\n        clearCurrentUser();\n    }\n\n    /**\n     * 检测登录状态\n     *\n     * @return true-已登录 false-未登录,会自动跳转至登录页\n     */\n    public static boolean checkLogin(Context context) {\n        if (currentUser == null) {\n            Intent intent = new Intent(context, LoginActivity.class);\n            intent.putExtra(\"checkLogin\", true);\n            context.startActivity(intent);\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/anim/loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <rotate\n        android:duration=\"500\"\n        android:fromDegrees=\"0\"\n        android:pivotX=\"50%\"\n        android:pivotY=\"50%\"\n        android:repeatCount=\"-1\"\n        android:toDegrees=\"359\" />\n</set>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/color/txt_blue2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@color/txt_link_blue\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/drawable/ic_fav_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_favorite_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_favorite_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/drawable/ic_home_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_home_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_home_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/drawable/ic_more_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_timer_auto_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_timer_auto_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/drawable/ic_search_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_search_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_search_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/drawable/ic_settings_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_settings_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_settings_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/drawable/oval_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/bg_pull_to_refresh\" />\n\n    <item>\n        <rotate\n            android:drawable=\"@mipmap/ic_loading\"\n            android:fromDegrees=\"0\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n            android:toDegrees=\"360\" />\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center_horizontal\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <ImageView\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@mipmap/ic_launcher\" />\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:text=\"@string/app_name\" />\n\n        <TextView\n            android:id=\"@+id/tv_version\"\n            style=\"@style/TextViewCaption\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_tiny\"\n            android:text=\"Version 1.0.0\" />\n\n        <TextView\n            android:id=\"@+id/tv_about\"\n            style=\"@style/TextViewBody\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:gravity=\"center\"\n            android:text=\"@string/about\"\n            android:textColor=\"@color/txt_gray\" />\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_feed_back.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/white\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/margin_medium\">\n\n        <EditText\n            android:id=\"@+id/et_content\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"top\"\n            android:hint=\"请输入您的意见反馈\"\n            android:maxLines=\"10\"\n            android:minLines=\"3\"\n            android:padding=\"@dimen/margin_medium\" />\n\n        <EditText\n            android:id=\"@+id/et_email\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"请输入您的邮箱\" />\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <TextView\n        style=\"@style/TextViewSubhead\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:text=\"名字不得超过12个字符\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <EditText\n        android:id=\"@+id/et\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"48dp\"\n        android:layout_margin=\"@dimen/margin_medium\"\n        android:maxLength=\"12\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <EditText\n            android:id=\"@+id/et_username\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入账号\" />\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"请输入密码\"\n            android:inputType=\"textPassword\" />\n\n        <Button\n            android:id=\"@+id/btn_login\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"登录\" />\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\" />\n\n        <LinearLayout\n            android:id=\"@+id/ll_regist\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/margin_medium\"\n            android:clickable=\"true\"\n            android:gravity=\"center\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                style=\"@style/TextViewBody\"\n                android:text=\"还没有账号?  赶紧\"\n                android:textColor=\"@color/txt_light_gray\" />\n\n            <TextView\n                style=\"@style/TextViewBody\"\n                android:text=\"注册\"\n                android:textColor=\"@color/colorPrimary\" />\n\n        </LinearLayout>\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:id=\"@+id/fl_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\">\n    </FrameLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <include layout=\"@layout/include_bottom_tab\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_regist.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <EditText\n            android:id=\"@+id/et_username\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入手机号\"\n            android:inputType=\"number\"\n            android:maxEms=\"11\" />\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"设置登录密码，不少于6位\"\n            android:inputType=\"textPassword\" />\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_register_step1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <EditText\n            android:id=\"@+id/et_username\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入手机号\"\n            android:inputType=\"number\"\n            android:maxEms=\"11\" />\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"设置登录密码，不少于6位\"\n            android:inputType=\"textPassword\" />\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_register_step2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <TextView\n            style=\"@style/TextViewBody\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"你会收到一条带验证码的短信，请输入验证码：\"\n            android:textColor=\"@color/txt_gray\" />\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\">\n\n            <EditText\n                android:id=\"@+id/et_verification_code\"\n                style=\"@style/EditTextSingleLine\"\n                android:hint=\"请输入验证码\"\n                android:inputType=\"number\"\n                android:maxEms=\"10\" />\n\n            <Button\n                android:id=\"@+id/btn_code_info\"\n                style=\"@style/TextViewBody\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:background=\"@null\"\n                android:text=\"60秒\"\n                android:textColor=\"@color/txt_blue2gray_sel\" />\n        </RelativeLayout>\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv_setting\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:layout_weight=\"1\"></android.support.v7.widget.RecyclerView>\n\n    <Button\n        android:id=\"@+id/btn_logout\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/margin_large\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_medium\"\n        android:text=\"退出登录\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/activity_user_info_edit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_avatar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"72dp\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:background=\"@drawable/bg_white2gray_sel\"\n        android:clickable=\"true\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\">\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"头像\" />\n\n        <ImageView\n            android:id=\"@+id/iv_avatar\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@mipmap/ic_launcher\" />\n\n        <ImageView\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_username\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:background=\"@drawable/bg_white2gray_sel\"\n        android:clickable=\"true\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\">\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"昵称\" />\n\n        <TextView\n            android:id=\"@+id/tv_username\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"boredream\"\n            android:textColor=\"@color/txt_gray\" />\n\n        <ImageView\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/frag_home.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <include layout=\"@layout/include_refresh_list\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/frag_user.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv_user\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginTop=\"@dimen/margin_medium\">\n    </android.support.v7.widget.RecyclerView>\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/include_bottom_tab.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RadioGroup xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/rg_bottom_tab\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:background=\"@android:color/white\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\">\n\n    <com.boredream.bdcodehelper.view.DrawableRadioButton\n        android:id=\"@+id/rb1\"\n        style=\"@style/RadioButtonBottomTab\"\n        android:drawableTop=\"@drawable/ic_home_grey2black_sel\"\n        app:drawableHeight=\"40dp\"\n        app:drawableWidth=\"40dp\" />\n\n    <com.boredream.bdcodehelper.view.DrawableRadioButton\n        android:id=\"@+id/rb2\"\n        style=\"@style/RadioButtonBottomTab\"\n        android:drawableTop=\"@drawable/ic_more_grey2black_sel\"\n        app:drawableHeight=\"40dp\"\n        app:drawableWidth=\"40dp\" />\n</RadioGroup>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/include_more_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"96dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <ImageView\n        android:id=\"@+id/iv_avatar\"\n        android:layout_width=\"68dp\"\n        android:layout_height=\"68dp\"\n        android:scaleType=\"centerCrop\" />\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"68dp\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/tv_name\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <ImageView\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/include_more_no_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"96dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"尚未登录，无法进行收藏等操作。\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <Button\n        android:id=\"@+id/btn_login\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"120dp\"\n        android:layout_height=\"40dp\"\n        android:layout_marginTop=\"@dimen/margin_small\"\n        android:text=\"立即登录\" />\n\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/item_design_res.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"vertical\">\n\n    <ImageView\n        android:id=\"@+id/iv_image\"\n        android:layout_width=\"172dp\"\n        android:layout_height=\"172dp\"\n        android:scaleType=\"centerCrop\" />\n\n    <TextView\n        android:id=\"@+id/tv_name\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"@dimen/margin_tiny\"\n        android:lines=\"2\" />\n\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/layout/item_more_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <include\n        android:id=\"@+id/include_more_header\"\n        layout=\"@layout/include_more_header\" />\n\n    <include\n        android:id=\"@+id/include_more_no_header\"\n        layout=\"@layout/include_more_no_header\" />\n\n</FrameLayout>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">DesignResCollection</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"tab1\">首页</string>\n    <string name=\"tab2\">搜索</string>\n    <string name=\"tab3\">收藏</string>\n    <string name=\"tab4\">我</string>\n    <string name=\"about\">\n        使用LeanCloud的Restful API作为后端支持\\n\n        使用LeanCloud的定时云代码，自动按时爬取数据并保存至LeanCloud中\\n\n        使用Retrofit2.0 + RxJava 实现网络请求部分\\n\n        使用Glide实现图片部分\\n\n        \\n\n        开源项目, 地址为\\n\n        %1$s\\n\n        \\n\n        欢迎follow我以及star项目\\n\n        有任何应用问题可以在反馈中提出\\n\n        对于项目代码有任何疑问,也可以在github项目中提issue\n    </string>\n    <string name=\"github\">https://github.com/boredream/DesignResCollection</string>\n    <string name=\"update_info\">\n        最新版本：%1$s\n        \\n\\n更新内容：\\n%2$s\n    </string>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/values/styles.xml",
    "content": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVC/app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVC/app/src/test/java/com/boredream/designrescollection/ExampleUnitTest.java",
    "content": "package com.boredream.designrescollection;\n\n/**\n * To work on unit tests, switch the Test Artifact in the Build Variants view.\n */\npublic class ExampleUnitTest {\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/README.md",
    "content": "# BDCodeHelper 代码助手\nCode Helper Model for android develper (Android Studio)  \n代码为Android Studio 的 Model，不是完整App应用。需要主项目依赖导入作为辅助开发工具。\n\n---\n# 功能介绍\nModel封装了应用中常用的功能，包括\n####adapter包\n* **LoadMoreAdapter** 加载更多适配器，用于包装普通RecyclerView.Adapter增添一个加载更多功能。适用于所有LayoutManager。  \n装饰器设计模式。无需自定义控件，无需写一大堆监听代码，包装即用~   \n感谢[飞飞大神](https://github.com/jeffreyhappy)的贡献，我在他代码基础上做了简单修改。\n\n* **SettingRecyclerAdapter** 设置选项列表适配器  。\nItem通用样式为：左侧图标、中间文字、右侧文字、右侧图标。  \n使用数据类SettingItem，不同字段对应不同控件，图片资源为-1或者字符为null时，对应位置控件不显示。\n\n####fragment包\n* **FragmentController** fragment切换控制器。  \n初始化时直接add全部fragment, 然后利用show和hide进行切换控制。\n\n####utils包\n大部分常用工具类，比较特殊的单独介绍下\n* **TitleBuilder** 标题栏构造器。\n使用构造器模式设置标题栏，结合layout中的include_titlebar.xml一起使用，先在布局中include引入标题栏布局，  \n再于Activity或Fragment中使用TitleBuilder设置标题栏内容，标题栏格式为：标题文字、左右各自是文字/图片按钮。\n\n####views包\n封装了一些有用的自定义控件\n* **BottomTabRadioButton** 底部导航栏选项卡RadioButton\n利用onDraw绘制红色圆点、带数字的红色圆圈，提供各种自定义attrs属性可以对红点的颜色、数字大小、数字颜色等进行配置。\n感谢[程序媛大神燕姐](https://github.com/xiaoxuyan)的贡献，我在他代码基础上做了简单修改。\n\n\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n\n        versionCode 1\n        versionName \"1.0\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\n// App dependencies\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n\n    // Android support\n    compile \"com.android.support:appcompat-v7:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:cardview-v7:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:design:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion\"\n\n    // Retrofit\n    compile \"com.squareup.retrofit:retrofit:$rootProject.retrofitVersion\"\n    compile \"com.squareup.retrofit:converter-gson:$rootProject.retrofitVersion\"\n    compile \"com.squareup.retrofit:adapter-rxjava:$rootProject.retrofitVersion\"\n    compile \"com.squareup.okhttp:logging-interceptor:$rootProject.okhttploggingVersion\"\n\n    // RxJava\n    compile \"io.reactivex:rxandroid:$rootProject.rxjavaVersion\"\n    compile \"com.jakewharton.rxbinding:rxbinding:$rootProject.rxbindingVersion\"\n\n    // Glide\n    compile \"com.github.bumptech.glide:glide:$rootProject.glideVersion\"\n    compile \"com.github.bumptech.glide:okhttp-integration:$rootProject.glideokhttpVersion\"\n\n    // Others\n    compile \"com.commit451:PhotoView:$rootProject.photoviewVersion\"\n    compile \"com.github.promeg:tinypinyin:1.0.0\"\n    compile \"org.greenrobot:eventbus:3.0.0\"\n}\n\n// copy to rootProject build.gradle\n//// Define versions in a single place\n//ext {\n//    // Sdk and tools\n//    minSdkVersion = 15\n//    targetSdkVersion = 23\n//    compileSdkVersion = 23\n//    buildToolsVersion = '23.0.3'\n//\n//    // App dependencies\n//    supportLibraryVersion = '23.4.0'\n//    guavaVersion = '18.0'\n//    junitVersion = '4.12'\n//    mockitoVersion = '1.10.19'\n//    powerMockito = '1.6.2'\n//    hamcrestVersion = '1.3'\n//    runnerVersion = '0.4.1'\n//    rulesVersion = '0.4.1'\n//    espressoVersion = '2.2.1'\n//    retrofitVersion = '2.0.0-beta2'\n//    okhttploggingVersion = '2.6.0'\n//    rxjavaVersion = '1.1.0'\n//    rxbindingVersion = '0.2.0'\n//    glideVersion = '3.6.1'\n//    glideokhttpVersion = '1.3.1'\n//    photoviewVersion = '1.2.4'\n//}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\adt-bundle-windows-x86_64-20140702\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/androidTest/java/com/boredream/bdcodehelper/ApplicationTest.java",
    "content": "package com.boredream.bdcodehelper;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.boredream.bdcodehelper\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:supportsRtl=\"true\">\n\n        <activity android:name=\".activity.ImageBrowserActivity\" />\n        <activity android:name=\".activity.WebViewActivity\" />\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/activity/ImageBrowserActivity.java",
    "content": "package com.boredream.bdcodehelper.activity;\n\n\nimport android.os.Bundle;\nimport android.support.v4.view.ViewPager;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.ImageBrowserAdapter;\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\n\nimport java.util.ArrayList;\n\npublic class ImageBrowserActivity extends BoreBaseActivity {\n\n    private ViewPager vp_image_brower;\n    private TextView tv_image_index;\n\n    private int position;\n    private ImageBrowserAdapter adapter;\n    private ArrayList<? extends ImageUrlInterface> images;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_image_browser);\n\n        initData();\n        initView();\n        setData();\n    }\n\n    private void initData() {\n        images = (ArrayList<ImageUrlInterface>) getIntent().getSerializableExtra(\"images\");\n        position = getIntent().getIntExtra(\"position\", 0);\n    }\n\n    private void initView() {\n        vp_image_brower = (ViewPager) findViewById(R.id.vp_image_brower);\n        tv_image_index = (TextView) findViewById(R.id.tv_image_index);\n    }\n\n    private void setData() {\n        adapter = new ImageBrowserAdapter(this, images);\n        vp_image_brower.setAdapter(adapter);\n\n        final int size = images.size();\n//        int initPosition = Integer.MAX_VALUE / 2 / size * size + position;\n        int initPosition = position;\n\n        if (size > 1) {\n            tv_image_index.setVisibility(View.VISIBLE);\n            tv_image_index.setText((position + 1) + \"/\" + size);\n        } else {\n            tv_image_index.setVisibility(View.GONE);\n        }\n\n        vp_image_brower.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n\n            @Override\n            public void onPageSelected(int arg0) {\n                int index = arg0 % size;\n                tv_image_index.setText((index + 1) + \"/\" + size);\n            }\n\n            @Override\n            public void onPageScrolled(int arg0, float arg1, int arg2) {\n\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int arg0) {\n\n            }\n        });\n\n        vp_image_brower.setCurrentItem(initPosition);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/activity/WebViewActivity.java",
    "content": "package com.boredream.bdcodehelper.activity;\n\nimport android.annotation.SuppressLint;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.webkit.WebSettings;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\n\npublic class WebViewActivity extends BoreBaseActivity {\n\n    public static final String EXTRA_TITLE = \"title\";\n    public static final String EXTRA_URL = \"url\";\n\n    private WebView webview;\n    private String title;\n    private TitleBuilder titleBuilder;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_web_view);\n\n        title = getIntent().getStringExtra(EXTRA_TITLE);\n        String url = getIntent().getStringExtra(EXTRA_URL);\n\n        initView();\n\n        showProgressDialog();\n        webview.loadUrl(url);\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\")\n    private void initView() {\n        titleBuilder = initBackTitle(title);\n        titleBuilder.getRootView().setOnLongClickListener(new View.OnLongClickListener() {\n            @Override\n            public boolean onLongClick(View v) {\n                String url = webview.getUrl();\n                if(!TextUtils.isEmpty(url)) {\n                    AppUtils.copy2clipboard(WebViewActivity.this, url);\n                    showToast(\"网址已经复制到剪贴板\");\n                }\n                return false;\n            }\n        });\n\n        webview = (WebView) findViewById(R.id.webview);\n        webview.setWebViewClient(new MyWebClient());\n\n        WebSettings settings = webview.getSettings();\n        settings.setJavaScriptEnabled(true);\n        settings.setSupportZoom(false);\n        settings.setBuiltInZoomControls(false);\n        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);\n    }\n\n    private class MyWebClient extends WebViewClient {\n\n        @Override\n        public void onPageStarted(WebView view, String url, Bitmap favicon) {\n            super.onPageStarted(view, url, favicon);\n        }\n\n        @Override\n        public void onPageFinished(WebView view, String url) {\n            super.onPageFinished(view, url);\n            titleBuilder.setTitleText(view.getTitle());\n            dismissProgressDialog();\n        }\n\n        public boolean shouldOverrideUrlLoading(WebView view, String url) {\n            webview.loadUrl(url);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/BannerPagerAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.support.v4.view.PagerAdapter;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.activity.ImageBrowserActivity;\nimport com.boredream.bdcodehelper.activity.WebViewActivity;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\n\nimport java.util.ArrayList;\n\npublic class BannerPagerAdapter extends PagerAdapter {\n\n    private Context context;\n    private ArrayList<? extends ImageUrlInterface> images;\n\n    public BannerPagerAdapter(Context context, ArrayList<? extends ImageUrlInterface> images) {\n        this.context = context;\n        this.images = images;\n    }\n\n    @Override\n    public int getCount() {\n        if (images.size() > 1) {\n            return Integer.MAX_VALUE;\n        }\n        return images.size();\n    }\n\n    @Override\n    public boolean isViewFromObject(View arg0, Object arg1) {\n        return arg0 == arg1;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        container.removeView((View) object);\n    }\n\n    @Override\n    public Object instantiateItem(ViewGroup container, final int position) {\n        final ImageUrlInterface image = images.get(position % images.size());\n\n        View view = View.inflate(context, R.layout.item_image_banner, null);\n        TextView tv_title = (TextView) view.findViewById(R.id.tv_title);\n        final ImageView iv = (ImageView) view.findViewById(R.id.iv_image);\n\n        String title = image.getImageTitle();\n        if (TextUtils.isEmpty(title)) {\n            tv_title.setVisibility(View.GONE);\n        } else {\n            tv_title.setVisibility(View.VISIBLE);\n            tv_title.setText(title);\n        }\n\n        final String url = image.getImageUrl();\n        Glide.with(context)\n                .load(url)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n//                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n//                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .centerCrop()\n                .crossFade()\n                .into(iv);\n\n        iv.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (!TextUtils.isEmpty(image.getImageLink())) {\n//                    Intent intent = new Intent();\n//                    intent.setAction(Intent.ACTION_VIEW);\n//                    Uri url = Uri.parse(link);\n//                    intent.setData(url);\n//                    context.startActivity(intent);\n                    Intent intent = new Intent(context, WebViewActivity.class);\n                    intent.putExtra(\"title\", image.getImageTitle());\n                    intent.putExtra(\"url\", image.getImageLink());\n                    context.startActivity(intent);\n                } else {\n                    Intent intent = new Intent(context, ImageBrowserActivity.class);\n                    intent.putExtra(\"images\", images);\n                    intent.putExtra(\"position\", position);\n                    context.startActivity(intent);\n                }\n            }\n        });\n\n        container.addView(view);\n        return view;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/ImageBrowserAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.app.Activity;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.PagerAdapter;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\nimport com.bumptech.glide.load.resource.drawable.GlideDrawable;\nimport com.bumptech.glide.request.animation.GlideAnimation;\nimport com.bumptech.glide.request.target.SimpleTarget;\n\nimport java.util.List;\n\nimport uk.co.senab.photoview.PhotoViewAttacher;\n\npublic class ImageBrowserAdapter extends PagerAdapter {\n\n    private Activity context;\n    private List<? extends ImageUrlInterface> picUrls;\n\n    public ImageBrowserAdapter(Activity context, List<? extends ImageUrlInterface> picUrls) {\n        this.context = context;\n        this.picUrls = picUrls;\n    }\n\n    @Override\n    public int getCount() {\n        if (picUrls.size() > 1) {\n            return Integer.MAX_VALUE;\n        }\n        return picUrls.size();\n    }\n\n    @Override\n    public boolean isViewFromObject(View view, Object object) {\n        return view == object;\n    }\n\n    @Override\n    public View instantiateItem(final ViewGroup container, int position) {\n        final View rootView = View.inflate(context, R.layout.item_image_browser, null);\n\n        int index = position % picUrls.size();\n        final ProgressBar pb_loading = (ProgressBar) rootView.findViewById(R.id.pb_loading);\n        final ImageView iv_image_browser = (ImageView) rootView.findViewById(R.id.iv_image_browser);\n        final PhotoViewAttacher pva = new PhotoViewAttacher(iv_image_browser);\n        String url = picUrls.get(index).getImageUrl();\n\n        Glide.with(context)\n                .load(url)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n//                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n//                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .centerCrop()\n                .crossFade()\n                .into(new SimpleTarget<GlideDrawable>() {\n\n                    @Override\n                    public void onLoadFailed(Exception e, Drawable errorDrawable) {\n                        super.onLoadFailed(e, errorDrawable);\n                        pb_loading.setVisibility(View.GONE);\n                        iv_image_browser.setVisibility(View.VISIBLE);\n                    }\n\n                    @Override\n                    public void onLoadStarted(Drawable placeholder) {\n                        super.onLoadStarted(placeholder);\n                        pb_loading.setVisibility(View.VISIBLE);\n                        iv_image_browser.setVisibility(View.GONE);\n                    }\n\n                    @Override\n                    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {\n                        pb_loading.setVisibility(View.GONE);\n                        iv_image_browser.setVisibility(View.VISIBLE);\n\n                        iv_image_browser.setImageDrawable(resource);\n                        pva.update();\n                    }\n                });\n\n        pva.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {\n            @Override\n            public void onPhotoTap(View view, float x, float y) {\n                context.onBackPressed();\n            }\n        });\n\n        container.addView(rootView);\n        return rootView;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        container.removeView((View) object);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/ListDropDownAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.util.List;\n\npublic class ListDropDownAdapter extends BaseAdapter {\n\n    private Context context;\n    private List<String> list;\n    private int checkItemPosition = 0;\n\n    public void setCheckItem(int position) {\n        checkItemPosition = position;\n        notifyDataSetChanged();\n    }\n\n    public ListDropDownAdapter(Context context, List<String> list) {\n        this.context = context;\n        this.list = list;\n    }\n\n    @Override\n    public int getCount() {\n        return list.size();\n    }\n\n    @Override\n    public Object getItem(int position) {\n        return null;\n    }\n\n    @Override\n    public long getItemId(int position) {\n        return position;\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n        ViewHolder viewHolder;\n        if (convertView != null) {\n            viewHolder = (ViewHolder) convertView.getTag();\n        } else {\n            convertView = LayoutInflater.from(context).inflate(R.layout.item_default_drop_down, null);\n            viewHolder = new ViewHolder(convertView);\n            convertView.setTag(viewHolder);\n        }\n        fillValue(position, viewHolder);\n        return convertView;\n    }\n\n    private void fillValue(int position, ViewHolder viewHolder) {\n        viewHolder.tv_title.setText(list.get(position));\n        if (checkItemPosition != -1) {\n            if (checkItemPosition == position) {\n                viewHolder.tv_title.setTextColor(context.getResources().getColor(R.color.drop_down_selected));\n                viewHolder.tv_title.setBackgroundResource(R.color.check_bg);\n            } else {\n                viewHolder.tv_title.setTextColor(context.getResources().getColor(R.color.drop_down_unselected));\n                viewHolder.tv_title.setBackgroundResource(R.color.white);\n            }\n        }\n    }\n\n    static class ViewHolder {\n        TextView tv_title;\n\n        ViewHolder(View view) {\n            tv_title = (TextView) view.findViewById(R.id.tv_title);\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/LoadMoreAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.graphics.drawable.Drawable;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 加载更多装饰适配器,用于包装普通RecyclerView.Adapter增添一个加载更多功能\n */\npublic class LoadMoreAdapter extends RecyclerView.Adapter {\n\n    /**\n     * 下拉状态 - 无内容。footer位置不做任何显示\n     */\n    public static final int STATUS_NONE = 0;\n\n    /**\n     * 下拉状态 - 有更多。footer位置有progressbar进度框\n     */\n    public static final int STATUS_HAVE_MORE = 1;\n\n    /**\n     * 下拉状态 - 已经加载全部数据。footer位置显示文字\n     */\n    public static final int STATUS_LOADED_ALL = 2;\n\n    /**\n     * 当前状态, 默认为 STATUS_NONE\n     */\n    private int status = STATUS_NONE;\n\n    private int ITEM_VIEW_TYPE_FOOTER = 0x10002;\n\n    /**\n     * 正在加载更多中\n     */\n    private boolean isLoadingMore = false;\n\n    private RecyclerView mRecyclerView;\n    private RecyclerView.Adapter mAdapter;\n    private OnLoadMoreListener mOnLoadMoreListener;\n    private Drawable mLoadMoreProgressDrawable;\n\n    public LoadMoreAdapter(RecyclerView recyclerView,\n                           RecyclerView.Adapter adapter,\n                           OnLoadMoreListener onLoadMoreListener) {\n        // 不设置加载更多progressbar的drawable,使用默认的样式\n        this(recyclerView, adapter, onLoadMoreListener, null);\n    }\n\n    public LoadMoreAdapter(RecyclerView recyclerView,\n                           RecyclerView.Adapter adapter,\n                           OnLoadMoreListener onLoadMoreListener,\n                           Drawable loadMoreProgressDrawable) {\n        mRecyclerView = recyclerView;\n        mAdapter = adapter;\n        mOnLoadMoreListener = onLoadMoreListener;\n        mLoadMoreProgressDrawable = loadMoreProgressDrawable;\n        setScrollListener();\n    }\n\n    public RecyclerView.Adapter getSrcAdapter() {\n        return mAdapter;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        isLoadingMore = false;\n        this.status = status;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        if (position == mAdapter.getItemCount()) {\n            // 最后一个位置是FOOTER\n            return ITEM_VIEW_TYPE_FOOTER;\n        } else {\n            return mAdapter.getItemViewType(position);\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        // 原adapter数量上+1,多了个footer\n        return mAdapter.getItemCount() + 1;\n    }\n\n    public class LoadMoreViewHolder extends RecyclerView.ViewHolder {\n\n        public ProgressBar pb_footer_progress;\n        public TextView tv_footer_progress;\n\n        public LoadMoreViewHolder(View itemView) {\n            super(itemView);\n\n            pb_footer_progress = (ProgressBar) itemView.findViewById(R.id.pb_footer_progress);\n            tv_footer_progress = (TextView) itemView.findViewById(R.id.tv_footer_progress);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        if (viewType == ITEM_VIEW_TYPE_FOOTER) {\n            LayoutInflater inflater = LayoutInflater.from(parent.getContext());\n            View loadMore = inflater.inflate(R.layout.footer_progress, parent, false);\n            LoadMoreViewHolder holder = new LoadMoreViewHolder(loadMore);\n            return holder;\n        } else {\n            return mAdapter.onCreateViewHolder(parent, viewType);\n        }\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {\n        if (holder instanceof LoadMoreViewHolder) {\n            handleFooter((LoadMoreViewHolder) holder);\n        } else {\n            mAdapter.onBindViewHolder(holder, position);\n        }\n    }\n\n    /**\n     * 处理footer的view显示\n     */\n    private void handleFooter(final LoadMoreViewHolder holder) {\n        if (mLoadMoreProgressDrawable != null) {\n            // 设置自定义进度框样式\n            holder.pb_footer_progress.setIndeterminateDrawable(mLoadMoreProgressDrawable);\n        }\n\n        // 设置item占满屏幕宽度, 网格列表类型使用\n        RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();\n        if (layoutManager instanceof StaggeredGridLayoutManager) {\n            StaggeredGridLayoutManager.LayoutParams layoutParams =\n                    (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();\n            layoutParams.setFullSpan(true);\n        } else if (layoutManager instanceof GridLayoutManager) {\n            final GridLayoutManager manager = (GridLayoutManager) layoutManager;\n            manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {\n                @Override\n                public int getSpanSize(int position) {\n                    int spanSize = 1;\n                    if (getItemViewType(position) == ITEM_VIEW_TYPE_FOOTER) {\n                        spanSize = manager.getSpanCount();\n                    }\n                    return spanSize;\n                }\n            });\n        }\n\n        // 根据不同状态显示footer样式\n        switch (status) {\n            case STATUS_HAVE_MORE:\n                holder.itemView.setVisibility(View.VISIBLE);\n\n                holder.tv_footer_progress.setVisibility(View.GONE);\n                holder.pb_footer_progress.setVisibility(View.VISIBLE);\n                break;\n            case STATUS_LOADED_ALL:\n                holder.itemView.setVisibility(View.VISIBLE);\n\n                holder.tv_footer_progress.setVisibility(View.VISIBLE);\n                holder.pb_footer_progress.setVisibility(View.GONE);\n                break;\n            case STATUS_NONE:\n            default:\n                holder.itemView.setVisibility(View.GONE);\n                break;\n        }\n    }\n\n    /**\n     * 设置滚动监听, 判断当列表滚动到底部时, 触发加载更多回调\n     */\n    private void setScrollListener() {\n        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {\n            @Override\n            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {\n                RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();\n                if (layoutManager instanceof StaggeredGridLayoutManager) {\n                    StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;\n                    int pastVisibleItems = -1;\n                    int visibleItemCount = staggeredGridLayoutManager.getChildCount();\n                    int totalItemCount = staggeredGridLayoutManager.getItemCount();\n                    int[] firstVisibleItems = null;\n                    firstVisibleItems = staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);\n                    if (firstVisibleItems != null && firstVisibleItems.length > 0) {\n                        pastVisibleItems = firstVisibleItems[0];\n                    }\n\n                    if (visibleItemCount + pastVisibleItems >= totalItemCount) {\n                        triggerLoadMore();\n                    }\n                } else if (layoutManager instanceof LinearLayoutManager) {\n                    // GridLayoutManager 是 LinearLayoutManager 的子类, 也符合这个条件\n                    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;\n                    int visibleItemCount = linearLayoutManager.getChildCount();\n                    int totalItemCount = linearLayoutManager.getItemCount();\n                    int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();\n\n                    if (visibleItemCount + firstVisibleItemPosition >= totalItemCount) {\n                        triggerLoadMore();\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * 触发加载更多回调\n     */\n    private synchronized void triggerLoadMore() {\n        // 如果是正在加载更多中,不再重复触发\n        if (isLoadingMore) {\n            return;\n        }\n\n        // 如果状态不是STATUS_HAVE_MORE则不触发\n        if (status != STATUS_HAVE_MORE) {\n            return;\n        }\n\n        isLoadingMore = true;\n        mOnLoadMoreListener.onLoadMore();\n        onLoadMore();\n    }\n\n    protected void onLoadMore() {\n        // sub\n    }\n\n    public interface OnLoadMoreListener {\n        void onLoadMore();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/SettingRecyclerAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\n\nimport android.support.v7.widget.RecyclerView;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.SettingItem;\n\nimport java.util.List;\n\n/**\n * 设置选项列表适配器\n * <p>\n * Item通用样式为：左侧图标、中间文字、右侧文字、右侧图标。\n */\npublic class SettingRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {\n\n    private static final int ITEM_VIEW_TYPE_SETTING_ITEM = 0x10001;\n\n    protected List<SettingItem> datas;\n    protected AdapterView.OnItemClickListener mOnItemClickListener;\n\n    public SettingRecyclerAdapter(List<SettingItem> datas, AdapterView.OnItemClickListener listener) {\n        this.datas = datas;\n        mOnItemClickListener = listener;\n    }\n\n    @Override\n    public int getItemCount() {\n        return datas.size();\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return ITEM_VIEW_TYPE_SETTING_ITEM;\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n\n        public ImageView iv_left;\n        public TextView tv_mid;\n        public TextView tv_right;\n        public ImageView iv_right;\n\n        public ViewHolder(final View itemView) {\n            super(itemView);\n\n            iv_left = (ImageView) itemView.findViewById(R.id.iv_left);\n            tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n            tv_right = (TextView) itemView.findViewById(R.id.tv_right);\n            iv_right = (ImageView) itemView.findViewById(R.id.iv_right);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_setting, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {\n        ViewHolder settingViewHolder = (ViewHolder) holder;\n        holder.itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                if (mOnItemClickListener != null) {\n                    mOnItemClickListener.onItemClick(null, view, position, -1);\n                }\n            }\n        });\n        SettingItem data = datas.get(position);\n\n        settingViewHolder.iv_left.setImageResource(data.leftImgRes);\n        if (!TextUtils.isEmpty(data.rightText)) {\n            settingViewHolder.tv_right.setVisibility(View.VISIBLE);\n            settingViewHolder.tv_right.setText(data.rightText);\n        } else {\n            settingViewHolder.tv_right.setVisibility(View.GONE);\n        }\n        settingViewHolder.tv_mid.setText(data.midText);\n\n        if (data.rightImage != -1) {\n            settingViewHolder.iv_right.setVisibility(View.VISIBLE);\n            settingViewHolder.iv_right.setImageResource(data.rightImage);\n        } else {\n            settingViewHolder.iv_right.setVisibility(View.GONE);\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/base/BoreBaseActivity.java",
    "content": "package com.boredream.bdcodehelper.base;\n\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.utils.DialogUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\npublic class BoreBaseActivity extends AppCompatActivity {\n\n    protected String TAG;\n    private Dialog progressDialog;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        init();\n    }\n\n    private void init() {\n        TAG = getClass().getSimpleName();\n        progressDialog = DialogUtils.createProgressDialog(this);\n    }\n\n    /**\n     * 左侧有返回键的标题栏\n     * <p>如果在此基础上还要加其他内容,比如右侧有文字按钮,可以获取该方法返回值继续设置其他内容\n     *\n     * @param title 标题\n     */\n    protected TitleBuilder initBackTitle(String title) {\n        return new TitleBuilder(this)\n                .setTitleText(title)\n                .setLeftImage(R.mipmap.ic_back)\n                .setLeftOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        finish();\n                    }\n                });\n    }\n\n    /**\n     * 跳转页面,无extra简易型\n     *\n     * @param tarActivity 目标页面\n     */\n    public void intent2Activity(Class<? extends Activity> tarActivity) {\n        Intent intent = new Intent(this, tarActivity);\n        startActivity(intent);\n    }\n\n    public void showToast(String msg) {\n        ToastUtils.showToast(this, msg, Toast.LENGTH_SHORT);\n    }\n\n    public void showLog(String msg) {\n        Log.i(TAG, msg);\n    }\n\n    public void showProgressDialog() {\n        progressDialog.show();\n    }\n\n    public void dismissProgressDialog() {\n        progressDialog.dismiss();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/base/BoreBaseEntity.java",
    "content": "package com.boredream.bdcodehelper.base;\n\n\nimport com.boredream.bdcodehelper.entity.Pointer;\n\n/**\n * 数据实体基类\n * <p>\n * 之所以继承Pointer对象,是因为接口用法的限制,具体可以参考Bmob/LeanCloud/Parse的相关文档<br/>\n * 这样的接口可以让对象在提交创建和获取的时候都更加方便<br/>\n * 提交时只要添加Pointer的type和className等所需字段即可,获取时基本不用做任何额外处理\n */\npublic class BoreBaseEntity extends Pointer {\n\n    // 添加新数据时,返回为objectId + createdAt\n    // 更新数据时,返回为updateAt\n\n    private String createdAt;\n    private String updatedAt;\n\n    public String getCreatedAt() {\n        return createdAt;\n    }\n\n    public void setCreatedAt(String createdAt) {\n        this.createdAt = createdAt;\n    }\n\n    public String getUpdatedAt() {\n        return updatedAt;\n    }\n\n    public void setUpdatedAt(String updatedAt) {\n        this.updatedAt = updatedAt;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o instanceof BoreBaseEntity) {\n            BoreBaseEntity oEntity = (BoreBaseEntity) o;\n            return this.objectId.equals(oEntity.objectId);\n        }\n        return super.equals(o);\n    }\n\n    @Override\n    public String toString() {\n        return \"BaseEntity{\" +\n                \"objectId='\" + objectId + '\\'' +\n                \", createdAt='\" + createdAt + '\\'' +\n                \", updatedAt='\" + updatedAt + '\\'' +\n                '}';\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/db/AddressData.java",
    "content": "package com.boredream.bdcodehelper.db;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\n\nimport com.boredream.bdcodehelper.entity.city.CityModel;\nimport com.github.promeg.pinyinhelper.Pinyin;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\n\npublic class AddressData {\n    public static ArrayList<String> mProvinceDatas = new ArrayList<>();\n    public static HashMap<String, ArrayList<CityModel>> mCitisDatasMap = new HashMap<>();\n    public static ArrayList<CityModel> allCities = new ArrayList<>();\n    public static CityModel currentCity;\n\n    public static void init(final Context context) {\n        new Thread() {\n            @Override\n            public void run() {\n                // 初始化，只需要调用一次\n                AssetsDatabaseManager.initManager(context);\n                // 获取管理对象，因为数据库需要通过管理对象才能够获取\n                AssetsDatabaseManager adm = AssetsDatabaseManager.getManager();\n                // 通过管理对象获取数据库\n                SQLiteDatabase sql = adm.getDatabase(\"city\");\n\n                // city\n                Cursor cursorCity = sql.rawQuery(\"select *,* from T_City, T_Province where T_City.ProID = T_Province.ProSort\", null);\n                if (!cursorCity.moveToFirst()) {\n                    return;\n                }\n                do {\n                    String province = cursorCity.getString(cursorCity.getColumnIndex(\"ProName\"));\n\n                    CityModel city = new CityModel();\n                    city.province = province;\n                    city.id = cursorCity.getString(cursorCity.getColumnIndex(\"CitySort\"));\n                    city.name = cursorCity.getString(cursorCity.getColumnIndex(\"CityName\"));\n\n                    if(!city.name.endsWith(\"市\")) {\n                        continue;\n                    }\n\n                    city.name = city.name.substring(0, city.name.length() - 1);\n\n                    StringBuilder sbLetter = new StringBuilder();\n                    for(char c : city.name.toCharArray()) {\n                        String letter;\n                        if(c == '长') {\n                            letter = \"CHANG\";\n                        } else if(c == '重'){\n                            letter = \"CHONG\";\n                        } else if(c == '厦'){\n                            letter = \"XIA\";\n                        } else {\n                            letter = Pinyin.toPinyin(c);\n                        }\n                        sbLetter.append(letter);\n                    }\n                    city.letter = sbLetter.toString();\n\n                    allCities.add(city);\n\n                    if(!mProvinceDatas.contains(province)) {\n                        mProvinceDatas.add(province);\n                    }\n\n                    ArrayList<CityModel> cities = mCitisDatasMap.get(province);\n                    if(cities == null) {\n                        cities = new ArrayList<>();\n                        cities.add(city);\n                        mCitisDatasMap.put(province, cities);\n                    } else {\n                        cities.add(city);\n                    }\n\n                    // 默认城市\n                    if(city.name.equals(\"上海\")) {\n                        currentCity = city;\n                    }\n\n                } while (cursorCity.moveToNext());\n\n                Collections.sort(allCities, new Comparator<CityModel>() {\n                    @Override\n                    public int compare(CityModel cityModel, CityModel t1) {\n                        return cityModel.letter.compareTo(t1.letter);\n                    }\n                });\n            }\n        }.start();\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/db/AssetsDatabaseManager.java",
    "content": "package com.boredream.bdcodehelper.db;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.AssetManager;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * This is a Assets Database Manager\n * Use it, you can use a assets database file in you application\n * It will copy the database file to \"/data/data/[your application package name]/database\" when you first time you use it\n * Then you can get a SQLiteDatabase object by the assets database file\n *\n * How to use:\n * 1. Initialize AssetsDatabaseManager\n * 2. Get AssetsDatabaseManager\n * 3. Get a SQLiteDatabase object through database file\n * 4. Use this database object\n *\n * Using example:\n * AssetsDatabaseManager.initManager(getApplication()); // this method is only need call one time\n * AssetsDatabaseManager mg = AssetsDatabaseManager.getManager();   // get a AssetsDatabaseManager object\n * SQLiteDatabase db1 = mg.getDatabase(\"db1.db\");   // get SQLiteDatabase object, db1.db is a file in assets folder\n * db1.???  // every operate by you want\n * Of cause, you can use AssetsDatabaseManager.getManager().getDatabase(\"xx\") to get a database when you need use a database\n */\npublic class AssetsDatabaseManager {\n    private static String tag = \"AssetsDatabase\"; // for LogCat\n    private static String databasepath = \"/data/data/%s/database\"; // %s is packageName\n\n\n    // A mapping from assets database file to SQLiteDatabase object\n    private Map<String, SQLiteDatabase> databases = new HashMap<String, SQLiteDatabase>();\n\n    // Context of application\n    private Context context = null;\n\n    // Singleton Pattern\n    private static AssetsDatabaseManager mInstance = null;\n\n    /**\n     * Initialize AssetsDatabaseManager\n     * @param context, context of application\n     */\n    public static void initManager(Context context){\n        if(mInstance == null){\n            mInstance = new AssetsDatabaseManager(context);\n        }\n    }\n\n    /**\n     * Get a AssetsDatabaseManager object\n     * @return, if success return a AssetsDatabaseManager object, else return null\n     */\n    public static AssetsDatabaseManager getManager(){\n        return mInstance;\n    }\n\n    private AssetsDatabaseManager(Context context){\n        this.context = context;\n    }\n\n    /**\n     * Get a assets database, if this database is opened this method is only return a copy of the opened database\n     * @param dbfile, the assets file which will be opened for a database\n     * @return, if success it return a SQLiteDatabase object else return null\n     */\n    public SQLiteDatabase getDatabase(String dbfile) {\n        if(databases.get(dbfile) != null){\n            Log.i(tag, String.format(\"Return a database copy of %s\", dbfile));\n            return (SQLiteDatabase) databases.get(dbfile);\n        }\n        if(context==null)\n            return null;\n\n        Log.i(tag, String.format(\"Create database %s\", dbfile));\n        String spath = getDatabaseFilepath();\n        String sfile = getDatabaseFile(dbfile);\n\n        File file = new File(sfile);\n        SharedPreferences dbs = context.getSharedPreferences(AssetsDatabaseManager.class.toString(), 0);\n        boolean flag = dbs.getBoolean(dbfile, false); // Get Database file flag, if true means this database file was copied and valid\n        if(!flag || !file.exists()){\n            file = new File(spath);\n            if(!file.exists() && !file.mkdirs()){\n                Log.i(tag, \"Create \\\"\"+spath+\"\\\" fail!\");\n                return null;\n            }\n            if(!copyAssetsToFilesystem(dbfile, sfile)){\n                Log.i(tag, String.format(\"Copy %s to %s fail!\", dbfile, sfile));\n                return null;\n            }\n\n            dbs.edit().putBoolean(dbfile, true).commit();\n        }\n\n        SQLiteDatabase db = SQLiteDatabase.openDatabase(sfile, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);\n        if(db != null){\n            databases.put(dbfile, db);\n        }\n        return db;\n    }\n\n    private String getDatabaseFilepath(){\n        return String.format(databasepath, context.getApplicationInfo().packageName);\n    }\n\n    private String getDatabaseFile(String dbfile){\n        return getDatabaseFilepath()+\"/\"+dbfile;\n    }\n\n    private boolean copyAssetsToFilesystem(String assetsSrc, String des){\n        Log.i(tag, \"Copy \"+assetsSrc+\" to \"+des);\n        InputStream istream = null;\n        OutputStream ostream = null;\n        try{\n            AssetManager am = context.getAssets();\n            istream = am.open(assetsSrc);\n            ostream = new FileOutputStream(des);\n            byte[] buffer = new byte[1024];\n            int length;\n            while ((length = istream.read(buffer))>0){\n                ostream.write(buffer, 0, length);\n            }\n            istream.close();\n            ostream.close();\n        }\n        catch(Exception e){\n            e.printStackTrace();\n            try{\n                if(istream!=null)\n                    istream.close();\n                if(ostream!=null)\n                    ostream.close();\n            }\n            catch(Exception ee){\n                ee.printStackTrace();\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Close assets database\n     * @param dbfile, the assets file which will be closed soon\n     * @return, the status of this operating\n     */\n    public boolean closeDatabase(String dbfile){\n        if(databases.get(dbfile) != null){\n            SQLiteDatabase db = (SQLiteDatabase) databases.get(dbfile);\n            db.close();\n            databases.remove(dbfile);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Close all assets database\n     */\n    static public void closeAllDatabase(){\n        Log.i(tag, \"closeAllDatabase\");\n        if(mInstance != null){\n            for(int i=0; i<mInstance.databases.size(); ++i){\n                if(mInstance.databases.get(i)!=null){\n                    mInstance.databases.get(i).close();\n                }\n            }\n            mInstance.databases.clear();\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/AppUpdateInfo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class AppUpdateInfo extends BoreBaseEntity {\n    private int version;\n    private String versionName;\n    private String fileUrl;\n    private String updateInfo;\n\n    public int getVersion() {\n        return version;\n    }\n\n    public void setVersion(int version) {\n        this.version = version;\n    }\n\n    public String getVersionName() {\n        return versionName;\n    }\n\n    public void setVersionName(String versionName) {\n        this.versionName = versionName;\n    }\n\n    public String getFileUrl() {\n        return fileUrl;\n    }\n\n    public void setFileUrl(String fileUrl) {\n        this.fileUrl = fileUrl;\n    }\n\n    public String getUpdateInfo() {\n        return updateInfo;\n    }\n\n    public void setUpdateInfo(String updateInfo) {\n        this.updateInfo = updateInfo;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ErrorResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class ErrorResponse {\n\n    private int code;\n    private String error;\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public void setError(String error) {\n        this.error = error;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getError() {\n        return error;\n    }\n\n    @Override\n    public String toString() {\n        return \"ErrorResponse{\" +\n                \"code=\" + code +\n                \", error='\" + error + '\\'' +\n                '}';\n    }\n}\n\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FileUploadResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class FileUploadResponse {\n    private String filename;\n    private String group;\n    private String url;\n\n    public void setFilename(String filename) {\n        this.filename = filename;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getFilename() {\n        return filename;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if(o instanceof FileUploadResponse) {\n            return this.url.equals(((FileUploadResponse)o).url);\n        }\n        return super.equals(o);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FormItem.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport android.text.InputType;\n\npublic class FormItem {\n\n    public static final int TYPE_INPUT = 0;\n    public static final int TYPE_SELECT = 1;\n\n    /**\n     * 类型，0-输入，1-选择\n     */\n    public int type;\n\n    /**\n     * 左侧文字\n     */\n    public String leftText;\n\n    /**\n     * 中间文字，hint使用\n     */\n    public String midText;\n\n    /**\n     * 输入框类型\n     */\n    public int inputType;\n\n    /**\n     * 右侧图片id\n     */\n    public int rightImg;\n\n    public FormItem() {\n\n    }\n\n    public static FormItem getInputItem(String leftText, String hint) {\n        return getInputItem(leftText, hint, InputType.TYPE_CLASS_TEXT);\n    }\n\n    public static FormItem getInputItem(String leftText, String hint, int inputType) {\n        FormItem formItem = new FormItem();\n        formItem.type = TYPE_INPUT;\n        formItem.leftText = leftText;\n        formItem.midText = hint;\n        formItem.inputType = inputType;\n        return formItem;\n    }\n\n    public static FormItem getSelectItem(String leftText, int rightImg) {\n        FormItem formItem = new FormItem();\n        formItem.type = TYPE_SELECT;\n        formItem.leftText = leftText;\n        formItem.rightImg = rightImg;\n        return formItem;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ImageUrlInterface.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.io.Serializable;\n\npublic interface ImageUrlInterface extends Serializable {\n    String getImageUrl();\n    String getImageTitle();\n    String getImageLink();\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ListResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.util.ArrayList;\n\npublic class ListResponse<T> {\n    private ArrayList<T> results;\n\n    public ArrayList<T> getResults() {\n        return results;\n    }\n\n    public void setResults(ArrayList<T> results) {\n        this.results = results;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/PageIndex.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\n\nimport java.util.List;\n\n/**\n * 页数索引, 多页加载时使用\n */\npublic class PageIndex {\n\n    /**\n     * 起始页\n     */\n    private int startPage;\n\n    /**\n     * 请求加载的新页数\n     */\n    private int newPage;\n\n    /**\n     * 当前已加载的页数\n     */\n    private int currentPage;\n\n    /**\n     * 每页加载的数量\n     */\n    private int countPerPage;\n\n    public int getStartPage() {\n        return startPage;\n    }\n\n    /**\n     * 页数索引\n     *\n     * @param startPage 起始页, 通常是 0 或 1\n     */\n    public PageIndex(int startPage, int countPerPage) {\n        this.startPage = startPage;\n        this.countPerPage = countPerPage;\n        init();\n    }\n\n    /**\n     * 重置初始化\n     */\n    public void init() {\n        this.currentPage = startPage;\n    }\n\n    /**\n     * 新页数数据获取成功, 将当前页数更新未新页数\n     */\n    private void success() {\n        currentPage = newPage;\n    }\n\n    /**\n     * 起始页\n     *\n     * @return 起始页\n     */\n    public int toStartPage() {\n        newPage = startPage;\n        return newPage;\n    }\n\n    /**\n     * 下一页\n     *\n     * @return 当前页+1作为下一页\n     */\n    public int toNextPage() {\n        newPage = currentPage + 1;\n        return newPage;\n    }\n\n    /**\n     * 数据获取成功, 设置返回结果\n     *\n     * @param adapter\n     * @param currentList 当前已有数据\n     * @param newList     请求获取的新数据\n     * @param <T>\n     */\n    public <T> void setResponse(LoadMoreAdapter adapter, List<T> currentList, List<T> newList) {\n        // 更新当前页数\n        success();\n\n        // 如果当前页为起始页, 则清空数据\n        if (currentPage == startPage) {\n            currentList.clear();\n        }\n\n        if (newList == null) {\n            return;\n        }\n\n        // 添加数据\n        currentList.addAll(newList);\n\n        // 设置是否已加载完全部数据状态\n        adapter.setStatus(newList.size() == countPerPage\n                ? LoadMoreAdapter.STATUS_HAVE_MORE : LoadMoreAdapter.STATUS_LOADED_ALL);\n\n        // 更新UI\n        adapter.notifyDataSetChanged();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Pointer.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.google.gson.Gson;\n\nimport java.io.Serializable;\n\npublic class Pointer implements Serializable {\n    public static final String TYPE = \"Pointer\";\n\n    protected String __type;\n    protected String className;\n    protected String objectId;\n\n    public Pointer() {\n    }\n\n    public Pointer(String className, String objectId) {\n        this.__type = TYPE;\n        this.setClassName(className);\n        this.setObjectId(objectId);\n    }\n\n    public String get__type() {\n        return __type;\n    }\n\n    public void set__type(String __type) {\n        this.__type = __type;\n    }\n\n    public String getClassName() {\n        return this.className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n\n    public String getObjectId() {\n        return this.objectId;\n    }\n\n    public void setObjectId(String objectId) {\n        this.objectId = objectId;\n    }\n\n    /**\n     * 将Pointer转换为所需对象\n     *\n     * @param clazz 转换目标类型\n     * @return 转换后的对象, 转换失败时为null\n     */\n    public <T> T parseToObject(Class<T> clazz) {\n        T t = null;\n        Gson gson = new Gson();\n        try {\n            // 原Pointer对象转为json, 如果用include查询的话, Pointer中除了className还会包含目标对象的数据\n            String json = gson.toJson(this);\n            // 转为目标对象, 多余的className正好通过转换过滤掉\n\n            t = gson.fromJson(json, clazz);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return t;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Relation.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Relation implements Serializable {\n    private String __op = \"AddRelation\";\n    private List<Pointer> objects = new ArrayList();\n\n    public Relation(Pointer pointer) {\n        this.objects.add(pointer);\n    }\n\n    public Relation() {\n    }\n\n    public void add(Pointer pointer) {\n        this.objects.add(pointer);\n    }\n\n    public void remove(Pointer pointer) {\n        this.__op = \"RemoveRelation\";\n        this.objects.add(pointer);\n    }\n\n    public String get__op() {\n        return this.__op;\n    }\n\n    public List<Pointer> getObjects() {\n        return this.objects;\n    }\n\n    public void setObjects(List<Pointer> objects) {\n        this.objects = objects;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/RelationTo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class RelationTo {\n    public static final String OP_RELATEDTO = \"$relatedTo\";\n\n    private String key;\n    private Pointer object;\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public Pointer getObject() {\n        return object;\n    }\n\n    public void setObject(Pointer object) {\n        this.object = object;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/SettingItem.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\n/**\n * 更多item信息\n */\npublic class SettingItem {\n\n    /**\n     * 左侧图片\n     */\n    public int leftImgRes;\n\n    /**\n     * 中间文字\n     */\n    public String midText;\n\n    /**\n     * 右侧文字\n     */\n    public String rightText;\n\n    /**\n     * 右侧图片\n     */\n    public int rightImage;\n\n    public SettingItem() {\n\n    }\n\n    public SettingItem(int leftImgRes, String midText, String rightText, int rightImage) {\n        this.leftImgRes = leftImgRes;\n        this.midText = midText;\n        this.rightText = rightText;\n        this.rightImage = rightImage;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/UpdatePswRequest.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class UpdatePswRequest {\n    private String oldPassword;\n    private String newPassword;\n\n    public String getOldPassword() {\n        return oldPassword;\n    }\n\n    public void setOldPassword(String oldPassword) {\n        this.oldPassword = oldPassword;\n    }\n\n    public String getNewPassword() {\n        return newPassword;\n    }\n\n    public void setNewPassword(String newPassword) {\n        this.newPassword = newPassword;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Where.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.util.Map;\n\npublic class Where {\n    public static final String OP_INQUERY = \"$inQuery\";\n\n    private Map<String, String> where;\n    private String className;\n\n    public Map<String, String> getWhere() {\n        return where;\n    }\n\n    public void setWhere(Map<String, String> where) {\n        this.where = where;\n    }\n\n    public String getClassName() {\n        return className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/city/BaseAddressModel.java",
    "content": "package com.boredream.bdcodehelper.entity.city;\n\nimport java.io.Serializable;\n\npublic class BaseAddressModel implements Serializable {\n    public String id;\n    public String name;\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/city/CityModel.java",
    "content": "package com.boredream.bdcodehelper.entity.city;\n\npublic class CityModel extends BaseAddressModel {\n\tpublic String province;\n\tpublic String letter;\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif(o instanceof CityModel) {\n\t\t\treturn ((CityModel)o).id.equals(this.id);\n\t\t}\n\t\treturn super.equals(o);\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/fragment/FragmentController.java",
    "content": "package com.boredream.bdcodehelper.fragment;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v7.app.AppCompatActivity;\n\nimport java.util.ArrayList;\n\n/**\n * fragment切换控制器, 初始化时直接add全部fragment, 然后利用show和hide进行切换控制\n */\npublic class FragmentController {\n\n    private int containerId;\n    private FragmentManager fm;\n    private ArrayList<Fragment> fragments;\n\n    public FragmentController(AppCompatActivity activity, int containerId, ArrayList<Fragment> fragments) {\n        this.containerId = containerId;\n        this.fragments = fragments;\n        this.fm = activity.getSupportFragmentManager();\n        initFragment();\n    }\n\n    public void initFragment() {\n        FragmentTransaction ft = fm.beginTransaction();\n        for (int i = 0; i < fragments.size(); i++) {\n            ft.add(containerId, fragments.get(i), String.valueOf(i));\n        }\n        ft.commit();\n    }\n\n    public void showFragment(int position) {\n        hideFragments();\n        Fragment fragment = fragments.get(position);\n        FragmentTransaction ft = fm.beginTransaction();\n        ft.show(fragment);\n        ft.commit();\n    }\n\n    public void hideFragments() {\n        FragmentTransaction ft = fm.beginTransaction();\n        for (Fragment fragment : fragments) {\n            if (fragment != null) {\n                ft.hide(fragment);\n            }\n        }\n        ft.commit();\n    }\n\n    public Fragment getFragment(int position) {\n        return fragments.get(position);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/ErrorConstants.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ErrorConstants {\n    public static Map<Integer, String> errors;\n\n    static {\n        errors = new HashMap<>();\n        errors.put(9001, \"Application Id为空，请初始化.\");\n        errors.put(9002, \"解析返回数据出错\");\n        errors.put(9003, \"上传文件出错\");\n        errors.put(9004, \"文件上传失败\");\n        errors.put(9005, \"批量操作只支持最多50条\");\n        errors.put(9006, \"objectId为空\");\n        errors.put(9007, \"文件大小超过10M\");\n        errors.put(9008, \"上传文件不存在\");\n        errors.put(9009, \"没有缓存数据\");\n        errors.put(9010, \"网络超时\");\n        errors.put(9011, \"BmobUser类不支持批量操作\");\n        errors.put(9012, \"上下文为空\");\n        errors.put(9013, \"BmobObject（数据表名称）格式不正确\");\n        errors.put(9014, \"第三方账号授权失败\");\n        errors.put(9015, \"其他错误均返回此code\");\n        errors.put(9016, \"无网络连接，请检查您的手机网络.\");\n        errors.put(9017, \"与第三方登录有关的错误，具体请看对应的错误描述\");\n        errors.put(9018, \"参数不能为空\");\n        errors.put(9019, \"格式不正确：手机号码、邮箱地址、验证码\");\n\n        errors.put(401, \"用户登陆信息失效\");\n        errors.put(500, \"服务器忙，请稍后再试\");\n\n        errors.put(101, \"用户名或密码不正确\");\n        errors.put(102, \"格式不正确\");\n        errors.put(103, \"查询单个对象或更新对象时必须提供objectId 或 非法的 class 名称，class 名称是大小写敏感的，并且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线.\");\n        errors.put(104, \"关联的class名称不存在\");\n        errors.put(105, \"字段名是大小写敏感的，且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线 或 字段名是\");\n        errors.put(106, \"不是一个正确的指针类型\");\n        errors.put(107, \"数据格式不正确\");\n        errors.put(108, \"用户名和密码是必需的\");\n        errors.put(109, \"登录信息是必需的，如邮箱和密码时缺少其中一个提示此信息\");\n        errors.put(111, \"传入的字段值与字段类型不匹配\");\n        errors.put(112, \"请求的值必须是数组\");\n        errors.put(113, \"请求数组中每个元素应该是一个像这样子的json对象\");\n        errors.put(114, \"请求数组大于50\");\n        errors.put(117, \"纬度范围在[-90, 90] 或 经度范围在[-180, 180]\");\n        errors.put(120, \"要使用此功能，请在\");\n        errors.put(131, \"不正确的deviceToken\");\n        errors.put(132, \"不正确的installationId\");\n        errors.put(133, \"不正确的deviceType\");\n        errors.put(134, \"deviceToken已经存在\");\n        errors.put(135, \"installationId已经存在\");\n        errors.put(136, \"只读属性不能修改 或 android设备不需要设置deviceToken\");\n        errors.put(138, \"表是只读的\");\n        errors.put(139, \"角色名称是大小写敏感的，并且必须以英文字母开头，有效的字符仅限在英文字母、数字、空格、横线以及下划线。\");\n        errors.put(141, \"缺失推送需要的data参数\");\n        errors.put(142, \"时间格式应该如下： 2013-12-04 00:51:13\");\n        errors.put(143, \"必须是一个数字\");\n        errors.put(144, \"不能是之前的时间\");\n        errors.put(145, \"文件大小错误\");\n        errors.put(146, \"文件名错误\");\n        errors.put(147, \"文件分页上传偏移量错误\");\n        errors.put(148, \"文件上下文错误\");\n        errors.put(149, \"空文件\");\n        errors.put(150, \"文件上传错误\");\n        errors.put(151, \"文件删除错误\");\n        errors.put(160, \"图片错误\");\n        errors.put(161, \"图片模式错误\");\n        errors.put(162, \"图片宽度错误\");\n        errors.put(163, \"图片高度错误\");\n        errors.put(164, \"图片长边错误\");\n        errors.put(165, \"图片短边错误\");\n        errors.put(201, \"缺失数据\");\n        errors.put(202, \"用户名已经存在\");\n        errors.put(203, \"邮箱已经存在\");\n        errors.put(204, \"必须提供一个邮箱地址\");\n        errors.put(205, \"没有找到此邮件的用户\");\n        errors.put(206, \"登录用户才能修改自己的信息。RestAPI的Http Header中没有提供sessionToken的正确值，不能修改或删除用户\");\n        errors.put(207, \"验证码错误\");\n        errors.put(208, \"authData不正确\");\n        errors.put(209, \"该手机号码已经存在\");\n        errors.put(210, \"密码不正确\");\n        errors.put(211, \"找不到用户\");\n        errors.put(301, \"验证错误详细提示，如邮箱格式不正确\");\n        errors.put(302, \"Bmob后台设置了应用设置值， 如'不允许SDK创建表 '\");\n        errors.put(310, \"云端逻辑运行错误的详细信息\");\n        errors.put(311, \"云端逻辑名称是大小写敏感的，且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线。\");\n        errors.put(401, \"唯一键不能存在重复的值\");\n        errors.put(402, \"查询的wher语句长度大于具体多少个字节\");\n        errors.put(601, \"不正确的BQL查询语句\");\n        errors.put(1002, \"该应用能创建的表数已达到限制\");\n        errors.put(1003, \"该表的行数已达到限制\");\n        errors.put(1004, \"该表的列数已达到限制\");\n        errors.put(1005, \"每月api请求数量已达到限制\");\n        errors.put(1006, \"该应用能创建定时任务数已达到限制\");\n        errors.put(1007, \"该应用能创建云端逻辑数已达到限制\");\n        errors.put(1500, \"你上传的文件大小已超出限制\");\n\n        errors.put(10010, \"该手机号发送短信达到限制(对于一个应用来说，一天给同一手机号发送短信不能超过10条，一小时给同一手机号发送短信不能超过5条，一分钟给同一手机号发送短信不能超过1条)\");\n        errors.put(10011, \"该账户无可用的发送短信条数\");\n        errors.put(10012, \"身份信息必须审核通过才能使用该功能\");\n        errors.put(10013, \"非法短信内容\");\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/GlideCircleTransform.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapShader;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\n\nimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;\nimport com.bumptech.glide.load.resource.bitmap.BitmapTransformation;\n\npublic class GlideCircleTransform extends BitmapTransformation {\n    public GlideCircleTransform(Context context) {\n        super(context);\n    }\n\n    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {\n        return circleCrop(pool, toTransform);\n    }\n\n    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {\n        if (source == null) return null;\n        int size = Math.min(source.getWidth(), source.getHeight());\n        int x = (source.getWidth() - size) / 2;\n        int y = (source.getHeight() - size) / 2;\n        // TODO this could be acquired from the pool too\n        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);\n        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);\n        if (result == null) {\n            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);\n        }\n        Canvas canvas = new Canvas(result);\n        Paint paint = new Paint();\n        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));\n        paint.setAntiAlias(true);\n        float r = size / 2f;\n        canvas.drawCircle(r, r, r, paint);\n        return result;\n    }\n\n    @Override\n    public String getId() {\n        return getClass().getName();\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/MultiPageRequest.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport rx.Observable;\n\npublic abstract class MultiPageRequest<T> {\n\n    public abstract Observable<T> request(int page);\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/ObservableDecorator.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\nimport rx.android.schedulers.AndroidSchedulers;\nimport rx.schedulers.Schedulers;\n\n/**\n * 观察者装饰器\n */\npublic class ObservableDecorator {\n\n    public static <T> Observable<T> decorate(Observable<T> observable) {\n        return observable\n                .subscribeOn(Schedulers.newThread())\n                .observeOn(AndroidSchedulers.mainThread())\n                .delay(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread()); // FIXME 模拟延迟,用于观察加载框等效果\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/RoundedCornersTransformation.java",
    "content": "package com.boredream.bdcodehelper.net;\n\n/**\n * Copyright (C) 2015 Wasabeef\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapShader;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.Transformation;\nimport com.bumptech.glide.load.engine.Resource;\nimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;\nimport com.bumptech.glide.load.resource.bitmap.BitmapResource;\n\npublic class RoundedCornersTransformation implements Transformation<Bitmap> {\n\n  public enum CornerType {\n    ALL,\n    TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,\n    TOP, BOTTOM, LEFT, RIGHT,\n    OTHER_TOP_LEFT, OTHER_TOP_RIGHT, OTHER_BOTTOM_LEFT, OTHER_BOTTOM_RIGHT,\n    DIAGONAL_FROM_TOP_LEFT, DIAGONAL_FROM_TOP_RIGHT\n  }\n\n  private BitmapPool mBitmapPool;\n  private int mRadius;\n  private int mDiameter;\n  private int mMargin;\n  private CornerType mCornerType;\n\n  public RoundedCornersTransformation(Context context, int radius, int margin) {\n    this(context, radius, margin, CornerType.ALL);\n  }\n\n  public RoundedCornersTransformation(BitmapPool pool, int radius, int margin) {\n    this(pool, radius, margin, CornerType.ALL);\n  }\n\n  public RoundedCornersTransformation(Context context, int radius, int margin,\n      CornerType cornerType) {\n    this(Glide.get(context).getBitmapPool(), radius, margin, cornerType);\n  }\n\n  public RoundedCornersTransformation(BitmapPool pool, int radius, int margin,\n      CornerType cornerType) {\n    mBitmapPool = pool;\n    mRadius = radius;\n    mDiameter = mRadius * 2;\n    mMargin = margin;\n    mCornerType = cornerType;\n  }\n\n  @Override\n  public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {\n    Bitmap source = resource.get();\n\n    int width = source.getWidth();\n    int height = source.getHeight();\n\n    Bitmap bitmap = mBitmapPool.get(width, height, Bitmap.Config.ARGB_8888);\n    if (bitmap == null) {\n      bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n    }\n\n    Canvas canvas = new Canvas(bitmap);\n    Paint paint = new Paint();\n    paint.setAntiAlias(true);\n    paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));\n    drawRoundRect(canvas, paint, width, height);\n    return BitmapResource.obtain(bitmap, mBitmapPool);\n  }\n\n  private void drawRoundRect(Canvas canvas, Paint paint, float width, float height) {\n    float right = width - mMargin;\n    float bottom = height - mMargin;\n\n    switch (mCornerType) {\n      case ALL:\n        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);\n        break;\n      case TOP_LEFT:\n        drawTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case TOP_RIGHT:\n        drawTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM_LEFT:\n        drawBottomLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM_RIGHT:\n        drawBottomRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case TOP:\n        drawTopRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM:\n        drawBottomRoundRect(canvas, paint, right, bottom);\n        break;\n      case LEFT:\n        drawLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case RIGHT:\n        drawRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_TOP_LEFT:\n        drawOtherTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_TOP_RIGHT:\n        drawOtherTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_BOTTOM_LEFT:\n        drawOtherBottomLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_BOTTOM_RIGHT:\n        drawOtherBottomRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case DIAGONAL_FROM_TOP_LEFT:\n        drawDiagonalFromTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case DIAGONAL_FROM_TOP_RIGHT:\n        drawDiagonalFromTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      default:\n        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);\n        break;\n    }\n  }\n\n  private void drawTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, mMargin + mRadius, bottom), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n    canvas.drawRect(new RectF(right - mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom - mRadius), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawBottomRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n    canvas.drawRect(new RectF(right - mRadius, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawTopRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawBottomRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n  }\n\n  private void drawOtherTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);\n  }\n\n  private void drawOtherTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawOtherBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mRadius, bottom), paint);\n  }\n\n  private void drawOtherBottomRightRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawDiagonalFromTopLeftRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),\n        mRadius, mRadius, paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mDiameter, bottom), paint);\n    canvas.drawRect(new RectF(mMargin + mDiameter, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawDiagonalFromTopRightRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,\n        mRadius, paint);\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  @Override public String getId() {\n    return \"RoundedTransformation(radius=\" + mRadius + \", margin=\" + mMargin + \", diameter=\"\n        + mDiameter + \", cornerType=\" + mCornerType.name() + \")\";\n  }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/FormItemsPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.FormItem;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class FormItemsPresent {\n\n    public interface OnSelectItemClickListener {\n        void onSelectItemClick(String leftText);\n    }\n\n    private Context context;\n    private LinearLayout ll_container;\n    private List<FormItem> items;\n\n    public FormItemsPresent(LinearLayout ll_container) {\n        this.context = ll_container.getContext();\n        this.ll_container = ll_container;\n    }\n\n    public void load(List<FormItem> items, Integer[] emptyIndexs,\n                     final OnSelectItemClickListener listener) {\n        this.items = items;\n        List<Integer> emptyIndexList = Arrays.asList(emptyIndexs);\n\n        for (int i = 0; i < items.size(); i++) {\n            final FormItem formItem = items.get(i);\n\n            // item\n            View itemView;\n            if (formItem.type == FormItem.TYPE_INPUT) {\n                // input\n                itemView = View.inflate(context, R.layout.formitem_input, null);\n                EditText tv_mid = (EditText) itemView.findViewById(R.id.tv_mid);\n                tv_mid.setInputType(formItem.inputType);\n                tv_mid.setHint(formItem.midText);\n            } else {\n                // select\n                itemView = View.inflate(context, R.layout.formitem_select, null);\n\n                ImageView iv_right = (ImageView) itemView.findViewById(R.id.iv_right);\n                if (formItem.rightImg != -1) {\n                    iv_right.setImageResource(formItem.rightImg);\n                }\n\n                itemView.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        if (listener != null) {\n                            listener.onSelectItemClick(formItem.leftText);\n                        }\n                    }\n                });\n            }\n            TextView tv_left = (TextView) itemView.findViewById(R.id.tv_left);\n            tv_left.setText(formItem.leftText);\n            itemView.setTag(formItem.leftText);\n            ll_container.addView(itemView);\n\n            // divider\n            View dividerView;\n            if (emptyIndexList.contains(i)) {\n                dividerView = View.inflate(context, R.layout.include_group_divider, null);\n            } else {\n                dividerView = new View(context);\n                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(\n                        LinearLayout.LayoutParams.MATCH_PARENT, 1);\n                dividerView.setLayoutParams(params);\n                dividerView.setBackgroundResource(R.color.divider_gray);\n            }\n            ll_container.addView(dividerView);\n        }\n    }\n\n    public ViewGroup getItemView(String leftText) {\n        ViewGroup itemView = (ViewGroup) ll_container.findViewWithTag(leftText);\n        return itemView;\n    }\n\n    public String getString(String leftText) {\n        ViewGroup itemView = getItemView(leftText);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        return tv_mid.getText().toString().trim();\n    }\n\n    public LinearLayout showMidContainer(String leftText) {\n        ViewGroup itemView = getItemView(leftText);\n        LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        ll_mid_container.setVisibility(View.VISIBLE);\n        tv_mid.setVisibility(View.GONE);\n        return ll_mid_container;\n    }\n\n    public TextView showMidText(String leftText, String midText) {\n        ViewGroup itemView = getItemView(leftText);\n        LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        ll_mid_container.setVisibility(View.GONE);\n        tv_mid.setVisibility(View.VISIBLE);\n        tv_mid.setText(midText);\n        return tv_mid;\n    }\n\n    public boolean validate() {\n        for (FormItem item : items) {\n            ViewGroup itemView = getItemView(item.leftText);\n            if (item.type == FormItem.TYPE_INPUT) {\n                // input\n                EditText tv_mid = (EditText) itemView.findViewById(R.id.tv_mid);\n                if (TextUtils.isEmpty(tv_mid.getText().toString().trim())) {\n                    ToastUtils.showToast(context, tv_mid.getHint());\n                    return false;\n                }\n            } else {\n                // select\n                TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n                LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n                if (tv_mid.getVisibility() == View.VISIBLE) {\n                    if (TextUtils.isEmpty(tv_mid.getText().toString().trim())) {\n                        ToastUtils.showToast(context, \"请选择\" + item.leftText);\n                        return false;\n                    }\n                } else {\n                    if (ll_mid_container.getChildCount() == 0) {\n                        ToastUtils.showToast(context, \"请选择\" + item.leftText);\n                        return false;\n                    }\n                }\n            }\n        }\n        return true;\n\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/GroupEtEmptyCheckPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.widget.EditText;\n\npublic class GroupEtEmptyCheckPresent {\n\n    private EditText[] ets;\n\n    public interface OnEtEmptyListener {\n        void onEtEmpty(boolean hasOneEmpty);\n    }\n\n    public GroupEtEmptyCheckPresent(EditText... ets) {\n        this.ets = ets;\n    }\n\n    public void check(final OnEtEmptyListener listener) {\n        for(EditText et : ets) {\n            et.addTextChangedListener(new TextWatcher() {\n                @Override\n                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {\n\n                }\n\n                @Override\n                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {\n                    checkAllEt(listener, ets);\n                }\n\n                @Override\n                public void afterTextChanged(Editable editable) {\n\n                }\n            });\n        }\n    }\n\n    private void checkAllEt(OnEtEmptyListener listener, EditText[] ets) {\n        boolean hasEmpty = false;\n\n        for(EditText et : ets) {\n            String s = et.getText().toString().trim();\n            if(TextUtils.isEmpty(s)) {\n                hasEmpty = true;\n                break;\n            }\n         }\n\n        listener.onEtEmpty(hasEmpty);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/ImageBannerPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.content.Context;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.CountDownTimer;\nimport android.support.v4.view.ViewPager;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.BannerPagerAdapter;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\n\nimport java.util.ArrayList;\n\npublic class ImageBannerPresent {\n\n    private static final int AUTO_SCROLL_GAP_TIME = 4000;\n    private static final int STATE_STOP = 0;\n    private static final int STATE_AUTO_SCROLLING = 1;\n    private int currentState;\n\n    private Context context;\n    private final CountDownTimer countDownTimer;\n\n    private ArrayList<? extends ImageUrlInterface> images;\n    private ViewPager vp_banner;\n\n    private RadioGroup rg_indicator;\n    private BannerPagerAdapter adapter;\n\n    public ImageBannerPresent(Context context, View include_banner_with_indicator) {\n        this.context = context;\n\n        vp_banner = (ViewPager) include_banner_with_indicator.findViewById(R.id.vp_banner);\n        rg_indicator = (RadioGroup) include_banner_with_indicator.findViewById(R.id.rg_indicator);\n\n        vp_banner.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\n            @Override\n            public void onPageScrollStateChanged(int state) {\n                // FIXME\n//                if (state == ViewPager.SCROLL_STATE_DRAGGING) {\n//                    stopAutoScroll();\n//                } else {\n//                    startAutoScroll();\n//                }\n            }\n        });\n\n        countDownTimer = new CountDownTimer(\n                Long.MAX_VALUE, AUTO_SCROLL_GAP_TIME) {\n            @Override\n            public void onTick(long l) {\n                vp_banner.setCurrentItem(vp_banner.getCurrentItem() + 1);\n            }\n\n            @Override\n            public void onFinish() {\n\n            }\n        };\n    }\n\n    public void load(ArrayList<? extends ImageUrlInterface> images) {\n        this.images = images;\n\n        adapter = new BannerPagerAdapter(context, images);\n        vp_banner.setAdapter(adapter);\n\n        setIndicator();\n        startAutoScroll();\n    }\n\n    public void startAutoScroll() {\n        if (currentState == STATE_AUTO_SCROLLING) {\n            return;\n        }\n\n        currentState = STATE_AUTO_SCROLLING;\n        countDownTimer.start();\n    }\n\n    public void stopAutoScroll() {\n        currentState = STATE_STOP;\n        countDownTimer.cancel();\n    }\n\n    private void setIndicator() {\n        if (images.size() <= 1) {\n            rg_indicator.setVisibility(View.GONE);\n            return;\n        }\n\n        rg_indicator.setVisibility(View.VISIBLE);\n\n        vp_banner.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n            @Override\n            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {\n\n            }\n\n            @Override\n            public void onPageSelected(int position) {\n                if (rg_indicator.getChildCount() > 1) {\n                    ((RadioButton) rg_indicator.getChildAt(position % images.size())).setChecked(true);\n                }\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int state) {\n\n            }\n        });\n\n        rg_indicator.removeAllViews();\n        for (int i = 0; i < images.size(); i++) {\n            RadioButton rb = new RadioButton(context);\n            RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(\n                    DisplayUtils.dp2px(context, 8), DisplayUtils.dp2px(context, 8));\n            if (i > 0) {\n                params.setMargins(DisplayUtils.dp2px(context, 8), 0, 0, 0);\n            }\n            rb.setLayoutParams(params);\n            rb.setButtonDrawable(new ColorDrawable());\n            rb.setBackgroundResource(R.drawable.shape_oval_primary2white_sel);\n            rb.setOnTouchListener(new View.OnTouchListener() {\n                @Override\n                public boolean onTouch(View view, MotionEvent motionEvent) {\n                    // do nothing\n                    return true;\n                }\n            });\n            rg_indicator.addView(rb);\n        }\n\n        ((RadioButton) rg_indicator.getChildAt(0)).setChecked(true);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/ImageBrowserPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.app.Activity;\nimport android.support.v4.view.ViewPager;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.adapter.ImageBrowserAdapter;\n\nimport java.util.ArrayList;\n\npublic class ImageBrowserPresent {\n    private Activity activity;\n    private ViewPager vp_image_brower;\n    private TextView tv_image_index;\n\n    private int position;\n    private ImageBrowserAdapter adapter;\n    private ArrayList<String> images;\n\n    public ImageBrowserPresent(Activity activity, ImageBrowserAdapter adapter,\n                               ViewPager vp_image_brower, TextView tv_image_index) {\n        this.activity = activity;\n        this.adapter = adapter;\n        this.vp_image_brower = vp_image_brower;\n        this.tv_image_index = tv_image_index;\n    }\n\n    public void init() {\n        initData();\n        setData();\n    }\n\n    private void initData() {\n        images = (ArrayList<String>) activity.getIntent().getSerializableExtra(\"images\");\n        position = activity.getIntent().getIntExtra(\"position\", 0);\n    }\n\n    private void setData() {\n        vp_image_brower.setAdapter(adapter);\n\n        final int size = images.size();\n        int initPosition = position;\n\n        if (size > 1) {\n            tv_image_index.setVisibility(View.VISIBLE);\n            tv_image_index.setText((position + 1) + \"/\" + size);\n        } else {\n            tv_image_index.setVisibility(View.GONE);\n        }\n\n        vp_image_brower.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n\n            @Override\n            public void onPageSelected(int arg0) {\n                int index = arg0 % size;\n                tv_image_index.setText((index + 1) + \"/\" + size);\n            }\n\n            @Override\n            public void onPageScrolled(int arg0, float arg1, int arg2) {\n\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int arg0) {\n\n            }\n        });\n\n        vp_image_brower.setCurrentItem(initPosition);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/MultiPageLoadPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.app.Activity;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.View;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.entity.PageIndex;\nimport com.boredream.bdcodehelper.net.MultiPageRequest;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\n\nimport java.util.ArrayList;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\n\npublic class MultiPageLoadPresent {\n\n    private Activity activity;\n    private LoadMoreAdapter loadMoreAdapter;\n\n    private SwipeRefreshLayout srl;\n    private RecyclerView rv;\n    private RecyclerView.ItemDecoration itemDecoration;\n\n    public RecyclerView getRv() {\n        return rv;\n    }\n\n    public MultiPageLoadPresent(Activity activity, View include_refresh_list, PageIndex pageIndex) {\n        this.activity = activity;\n        this.srl = (SwipeRefreshLayout) include_refresh_list;\n        this.pageIndex = pageIndex;\n        initView();\n    }\n\n    private void initView() {\n        srl.setColorSchemeColors(activity.getResources().getColor(R.color.colorPrimary));\n        rv = (RecyclerView) srl.findViewById(R.id.rv);\n\n        LinearLayoutManager layoutManager = new LinearLayoutManager(\n                activity, StaggeredGridLayoutManager.VERTICAL, false);\n        rv.setLayoutManager(layoutManager);\n        itemDecoration = new DividerItemDecoration(activity);\n        rv.addItemDecoration(itemDecoration);\n    }\n\n    public void setItemDecoration(RecyclerView.ItemDecoration itemDecoration) {\n        rv.removeItemDecoration(this.itemDecoration);\n        this.itemDecoration = itemDecoration;\n        if (this.itemDecoration != null) {\n            rv.addItemDecoration(this.itemDecoration);\n        }\n    }\n\n    private ArrayList datas;\n    private PageIndex pageIndex;\n    private MultiPageRequest request;\n    private Subscriber subscriber;\n\n    public void setDatas(ArrayList datas) {\n        this.datas = datas;\n        rv.post(new Runnable() {\n            @Override\n            public void run() {\n                loadMoreAdapter.notifyDataSetChanged();\n            }\n        });\n    }\n\n    public <T> Subscription load(RecyclerView.Adapter adapter,\n                                 ArrayList datas,\n                                 MultiPageRequest<T> request,\n                                 Subscriber<T> subscriber) {\n        this.datas = datas;\n        this.request = request;\n        this.subscriber = subscriber;\n\n        loadMoreAdapter = new LoadMoreAdapter(rv, adapter,\n                new LoadMoreAdapter.OnLoadMoreListener() {\n                    @Override\n                    public void onLoadMore() {\n                        // 列表拉到底部时,加载下一页\n                        loadData(pageIndex.toNextPage());\n                    }\n                });\n        rv.setAdapter(loadMoreAdapter);\n        srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {\n            @Override\n            public void onRefresh() {\n                // 下拉刷新时,重新加载起始页\n                loadData(pageIndex.toStartPage());\n            }\n        });\n\n        return loadData(this.pageIndex.toStartPage());\n    }\n\n    public void setStatus(int status) {\n        if(loadMoreAdapter != null) {\n            loadMoreAdapter.setStatus(status);\n        }\n    }\n\n    public void notifyDataSetChanged() {\n        if(loadMoreAdapter != null) {\n            loadMoreAdapter.notifyDataSetChanged();\n        }\n    }\n\n    public void initPage() {\n        pageIndex.init();\n    }\n\n    public boolean isRefreshing() {\n        return srl.isRefreshing();\n    }\n\n    public void setRefreshing(final boolean refreshing) {\n        srl.post(new Runnable() {\n            @Override\n            public void run() {\n                srl.setRefreshing(refreshing);\n            }\n        });\n    }\n\n    /**\n     * 加载列表\n     *\n     * @param page 页数\n     */\n    private Subscription loadData(final int page) {\n        Observable observable = this.request.request(page);\n        return ObservableDecorator.decorate(observable).subscribe(\n                new Subscriber<ListResponse>() {\n                    @Override\n                    public void onNext(ListResponse response) {\n                        if (subscriber != null) {\n                            subscriber.onNext(response);\n                        }\n                        setRefreshing(false);\n\n                        // 加载成功后更新数据\n                        pageIndex.setResponse(loadMoreAdapter, datas, response.getResults());\n                    }\n\n                    @Override\n                    public void onCompleted() {\n                        if (subscriber != null) {\n                            subscriber.onCompleted();\n                        }\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        if (subscriber != null) {\n                            subscriber.onError(throwable);\n                        }\n                        setRefreshing(false);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ActivityUtils.java",
    "content": "/*\n * Copyright 2016, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.utils;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\n\n/**\n * This provides methods to help Activities load their UI.\n */\npublic class ActivityUtils {\n\n    /**\n     * The {@code fragment} is added to the container view with id {@code frameId}. The operation is\n     * performed by the {@code fragmentManager}.\n     */\n    public static void addFragmentToActivity(FragmentManager fragmentManager,\n                                             Fragment fragment, int frameId) {\n        FragmentTransaction transaction = fragmentManager.beginTransaction();\n        transaction.add(frameId, fragment);\n        transaction.commit();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/AppUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.telephony.TelephonyManager;\nimport android.util.Log;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\n\nimport java.io.File;\n\npublic class AppUtils {\n\n    /**\n     * 获取版本名称\n     */\n    public static String getAppVersionName(Context context) {\n        String versionName = \"\";\n        try {\n            // ---get the package info---\n            PackageManager pm = context.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);\n            versionName = pi.versionName;\n            if (versionName == null || versionName.length() <= 0) {\n                return \"\";\n            }\n        } catch (Exception e) {\n            Log.e(\"VersionInfo\", \"Exception\", e);\n        }\n        return versionName;\n    }\n\n    /**\n     * 获取版本号\n     */\n    public static int getAppVersionCode(Context context) {\n        int versioncode = -1;\n        try {\n            // ---get the package info---\n            PackageManager pm = context.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);\n            versioncode = pi.versionCode;\n        } catch (Exception e) {\n            Log.e(\"VersionInfo\", \"Exception\", e);\n        }\n        return versioncode;\n    }\n\n    public static String getIMEI(Context context) {\n        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);\n        return tm.getDeviceId();\n    }\n\n    /**\n     * 显示软键盘\n     */\n    public static void openSoftInput(EditText et) {\n        InputMethodManager inputMethodManager = (InputMethodManager) et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.showSoftInput(et, InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    /**\n     * 隐藏软键盘\n     */\n    public static void hideSoftInput(EditText et) {\n        InputMethodManager inputMethodManager = (InputMethodManager) et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.hideSoftInputFromWindow(et.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    /**\n     * 获取SD卡路径\n     *\n     * @return 如果sd卡不存在则返回null\n     */\n    public static File getSDPath() {\n        File sdDir = null;\n        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);   //判断sd卡是否存在\n        if (sdCardExist) {\n            sdDir = Environment.getExternalStorageDirectory();//获取跟目录\n        }\n        return sdDir;\n    }\n\n    /**\n     * 安装文件\n     *\n     * @param data\n     */\n    public static void promptInstall(Context context, Uri data) {\n        Intent promptInstall = new Intent(Intent.ACTION_VIEW)\n                .setDataAndType(data, \"application/vnd.android.package-archive\");\n        // FLAG_ACTIVITY_NEW_TASK 可以保证安装成功时可以正常打开 app\n        promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(promptInstall);\n    }\n\n    public static void copy2clipboard(Context context, String text){\n        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);\n        ClipData clip = ClipData.newPlainText(\"clip\", text);\n        cm.setPrimaryClip(clip);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DateUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.text.TextUtils;\nimport android.text.format.DateFormat;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * 日期时间工具类\n */\npublic class DateUtils {\n\n    public static final long ONE_SECOND_MILLIONS = 1000;\n    public static final long ONE_MINUTE_MILLIONS = 60 * ONE_SECOND_MILLIONS;\n    public static final long ONE_HOUR_MILLIONS = 60 * ONE_MINUTE_MILLIONS;\n    public static final long ONE_DAY_MILLIONS = 24 * ONE_HOUR_MILLIONS;\n    public static final int DAY_OF_YEAR = 365;\n\n    // 日期格式为 2016-02-03 17:04:58\n    public static final String PATTERN_DATE = \"yyyy年MM月dd日\";\n    public static final String PATTERN_TIME = \"HH:mm:ss\";\n    public static final String PATTERN_SPLIT = \" \";\n    public static final String PATTERN = PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME;\n\n    public static String getShortTime(String dateStr) {\n        String str;\n\n        Date date = str2date(dateStr);\n        Date curDate = new Date();\n\n        long durTime = curDate.getTime() - date.getTime();\n        int dayDiff = calculateDayDiff(date, curDate);\n\n        if (durTime <= 10 * ONE_MINUTE_MILLIONS) {\n            str = \"刚刚\";\n        } else if (durTime < ONE_HOUR_MILLIONS) {\n            str = durTime / ONE_MINUTE_MILLIONS + \"分钟前\";\n        } else if (dayDiff == 0) {\n            str = durTime / ONE_HOUR_MILLIONS + \"小时前\";\n        } else if (dayDiff == -1) {\n            str = \"昨天\" + DateFormat.format(\"HH:mm\", date);\n        } else if (isSameYear(date, curDate) && dayDiff < -1) {\n            str = DateFormat.format(\"MM-dd\", date).toString();\n        } else {\n            str = DateFormat.format(\"yyyy-MM\", date).toString();\n        }\n\n        return str;\n    }\n\n    /**\n     * 获取日期 PATTERN_DATE 部分\n     */\n    public static String getDate(String date) {\n        if (TextUtils.isEmpty(date) || !date.contains(PATTERN_SPLIT)) {\n            return \"\";\n        }\n        return date.split(PATTERN_SPLIT)[0];\n    }\n\n    /**\n     * 原有日期上累加月\n     *\n     * @return 累加后的日期 PATTERN_DATE 部分\n     */\n    public static String addMonth(String date, int moonCount) {\n        //如果date为空 就用当前时间\n        if (TextUtils.isEmpty(date)) {\n            SimpleDateFormat df = new SimpleDateFormat(PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME);\n            date = df.format(new Date());\n        }\n        Calendar calendar = str2calendar(date);\n        calendar.add(Calendar.MONTH, moonCount);\n        return getDate(calendar2str(calendar));\n    }\n\n    /**\n     * 计算天数差\n     */\n    public static int calculateDayDiff(Date targetTime, Date compareTime) {\n        boolean sameYear = isSameYear(targetTime, compareTime);\n        if (sameYear) {\n            return calculateDayDiffOfSameYear(targetTime, compareTime);\n        } else {\n            int dayDiff = 0;\n\n            // 累计年数差的整年天数\n            int yearDiff = calculateYearDiff(targetTime, compareTime);\n            dayDiff += yearDiff * DAY_OF_YEAR;\n\n            // 累计同一年内的天数\n            dayDiff += calculateDayDiffOfSameYear(targetTime, compareTime);\n\n            return dayDiff;\n        }\n    }\n\n    /**\n     * 计算同一年内的天数差\n     */\n    public static int calculateDayDiffOfSameYear(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return 0;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarDayOfYear = tarCalendar.get(Calendar.DAY_OF_YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comDayOfYear = compareCalendar.get(Calendar.DAY_OF_YEAR);\n\n        return tarDayOfYear - comDayOfYear;\n    }\n\n    /**\n     * 计算年数差\n     */\n    public static int calculateYearDiff(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return 0;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n\n        return tarYear - comYear;\n    }\n\n    /**\n     * 计算月数差\n     *\n     * @param targetTime\n     * @param compareTime\n     * @return\n     */\n    public static int calculateMonthDiff(String targetTime, String compareTime) {\n        return calculateMonthDiff(str2date(targetTime, PATTERN_DATE),\n                str2date(compareTime, PATTERN_DATE));\n    }\n\n    /**\n     * 计算月数差\n     *\n     * @param targetTime\n     * @param compareTime\n     * @return\n     */\n    public static int calculateMonthDiff(Date targetTime, Date compareTime) {\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n        int tarMonth = tarCalendar.get(Calendar.MONTH);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n        int comMonth = compareCalendar.get(Calendar.MONTH);\n        return ((tarYear - comYear) * 12 + tarMonth - comMonth);\n\n    }\n\n    /**\n     * 是否为同一年\n     */\n    public static boolean isSameYear(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return false;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n\n        return tarYear == comYear;\n    }\n\n    public static Date str2date(String str, String format) {\n        Date date = null;\n        try {\n            if (str != null) {\n                SimpleDateFormat sdf = new SimpleDateFormat(format);\n                date = sdf.parse(str);\n            }\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        return date;\n    }\n\n    public static Date str2date(String str) {\n        return str2date(str, PATTERN);\n    }\n\n    public static String date2str(Date date) {\n        return date2str(date, PATTERN);\n    }\n\n    public static String date2str(Date date, String format) {\n        SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.CHINA);\n        return sdf.format(date);\n    }\n\n    public static Calendar str2calendar(String str) {\n        Calendar calendar = null;\n        Date date = str2date(str);\n        if (date != null) {\n            calendar = Calendar.getInstance();\n            calendar.setTime(date);\n        }\n        return calendar;\n    }\n\n\n    public static Calendar str2calendar(String str, String format) {\n        Calendar calendar = null;\n        Date date = str2date(str, format);\n        if (date != null) {\n            calendar = Calendar.getInstance();\n            calendar.setTime(date);\n        }\n        return calendar;\n    }\n\n    public static String calendar2str(Calendar calendar) {\n        return date2str(calendar.getTime());\n    }\n\n    public static String calendar2str(Calendar calendar, String format) {\n        return date2str(calendar.getTime(), format);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DialogUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.support.v7.app.AlertDialog;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 对话框工具类, 提供常用对话框显示, 使用support.v7包内的AlertDialog样式\n */\npublic class DialogUtils {\n\n    public static Dialog createProgressDialog(Context context) {\n        return createProgressDialog(context, true);\n    }\n\n    public static Dialog createProgressDialog(Context context, boolean needCancle) {\n        ProgressDialog dialog = new ProgressDialog(context);\n        dialog.setMessage(\"Loading ...\");\n        dialog.setCancelable(needCancle);\n        dialog.setCanceledOnTouchOutside(false);\n        return dialog;\n    }\n\n    public static Dialog showCommonDialog(Context context, String message,\n                                          DialogInterface.OnClickListener listener) {\n        return new AlertDialog.Builder(context)\n                .setMessage(message)\n                .setPositiveButton(context.getString(R.string.dialog_positive), listener)\n                .setNegativeButton(context.getString(R.string.dialog_negative), null)\n                .show();\n    }\n\n    public static Dialog showConfirmDialog(Context context, String message,\n                                           DialogInterface.OnClickListener listener) {\n        return new AlertDialog.Builder(context)\n                .setMessage(message)\n                .setPositiveButton(context.getString(R.string.dialog_positive), listener)\n                .show();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DisplayUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.util.DisplayMetrics;\n\npublic class DisplayUtils {\n\t/**\n\t * 将px值转换为dp值\n\t */\n\tpublic static int px2dp(Context context, float pxValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().density;\n\t\treturn (int) (pxValue / scale + 0.5f);\n\t}\n\n\t/**\n\t * 将dp值转换为px值\n\t */\n\tpublic static int dp2px(Context context, float dpValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().density;\n\t\treturn (int) (dpValue * scale + 0.5f);\n\t}\n\n\t/**\n\t * 将px值转换为sp值\n\t */\n\tpublic static int px2sp(Context context, float pxValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().scaledDensity;\n\t\treturn (int) (pxValue / scale + 0.5f);\n\t}\n\n\t/**\n\t * 将sp值转换为px值\n\t */\n\tpublic static int sp2px(Context context, float dpValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().scaledDensity;\n\t\treturn (int) (dpValue * scale + 0.5f);\n\t}\n\n\t/**\n\t * 获取屏幕宽度\n\t */\n\tpublic static int getScreenWidthPixels(Activity context) {\n\t\tDisplayMetrics metric = new DisplayMetrics();\n\t\tcontext.getWindowManager().getDefaultDisplay().getMetrics(metric);\n\t\treturn metric.widthPixels;\n\t}\n\n\t/**\n\t * 获取屏幕高度\n\t */\n\tpublic static int getScreenHeightPixels(Activity context) {\n\t\tDisplayMetrics metric = new DisplayMetrics();\n\t\tcontext.getWindowManager().getDefaultDisplay().getMetrics(metric);\n\t\treturn metric.heightPixels;\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ErrorInfoUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.text.TextUtils;\n\nimport com.boredream.bdcodehelper.entity.ErrorResponse;\nimport com.boredream.bdcodehelper.net.ErrorConstants;\nimport com.google.gson.Gson;\nimport com.squareup.okhttp.MediaType;\nimport com.squareup.okhttp.ResponseBody;\n\nimport java.net.UnknownHostException;\n\nimport retrofit.HttpException;\n\npublic class ErrorInfoUtils {\n\n    /**\n     * 解析服务器错误信息\n     */\n    public static String parseHttpErrorInfo(Throwable throwable) {\n        String errorInfo = throwable.getMessage();\n\n        if (throwable instanceof HttpException) {\n            // 如果是Retrofit的Http错误,则转换类型,获取信息\n            HttpException exception = (HttpException) throwable;\n            ResponseBody responseBody = exception.response().errorBody();\n            MediaType type = responseBody.contentType();\n\n            // 如果是application/json类型数据,则解析返回内容\n            if (type.type().equals(\"application\") && type.subtype().equals(\"json\")) {\n                try {\n                    // 这里的返回内容是Bmob/AVOS/Parse等RestFul API文档中的错误代码和错误信息对象\n                    ErrorResponse errorResponse = new Gson().fromJson(\n                            responseBody.string(), ErrorResponse.class);\n\n                    errorInfo = getLocalErrorInfo(errorResponse);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        } else {\n            if (throwable instanceof UnknownHostException) {\n                errorInfo = \"无法连接到服务器\";\n            }\n        }\n\n        return errorInfo;\n    }\n\n    /**\n     * 获取本地预设错误信息\n     */\n    private static String getLocalErrorInfo(ErrorResponse error) {\n        String s = ErrorConstants.errors.get(error.getCode());\n        if (TextUtils.isEmpty(s)) {\n            return error.getError();\n        } else {\n            return s;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ImageUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.provider.DocumentsContract;\nimport android.provider.MediaStore;\nimport android.support.v7.app.AlertDialog;\n\n/**\n * 图片工具类\n */\npublic class ImageUtils {\n\n    /**\n     * 拍照\n     */\n    public static final int REQUEST_CODE_FROM_CAMERA = 1 << 10;\n\n    /**\n     * 相册\n     */\n    public static final int REQUEST_CODE_FROM_ALBUM = 1 << 12;\n\n    /**\n     * 裁剪\n     */\n    public static final int REQUEST_CODE_CROP_IMAGE = 1 << 14;\n\n    /**\n     * 存放拍照图片的uri地址\n     */\n    public static Uri imageUriFromCamera;\n\n    /**\n     * 存放裁剪图片的uri地址\n     */\n    public static Uri cropImageUri;\n\n    /**\n     * 显示获取照片不同方式对话框\n     */\n    public static void showImagePickDialog(final Activity activity) {\n        showImagePickDialog(activity, 0);\n    }\n\n    /**\n     * 显示获取照片不同方式对话框\n     */\n    public static void showImagePickDialog(final Activity activity, final int addRequest) {\n        String title = \"选择获取图片方式\";\n        String[] items = new String[]{\"拍照\", \"相册\"};\n        new AlertDialog.Builder(activity)\n                .setTitle(title)\n                .setItems(items, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                        switch (which) {\n                            case 0:\n                                pickImageFromCamera(activity, addRequest);\n                                break;\n                            case 1:\n                                pickImageFromAlbum(activity, addRequest);\n                                break;\n                            default:\n                                break;\n                        }\n                    }\n                })\n                .setNegativeButton(\"取消\", null)\n                .show();\n    }\n\n    /**\n     * 打开相机拍照获取图片\n     */\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public static void pickImageFromCamera(final Activity activity, int addRequest) {\n        // 先生成一个uri地址用于存放拍照获取的图片\n        imageUriFromCamera = createImageUri(activity);\n\n        Intent intent = new Intent();\n        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUriFromCamera);\n        activity.startActivityForResult(intent, REQUEST_CODE_FROM_CAMERA + addRequest);\n    }\n\n    /**\n     * 打开相机拍照获取图片\n     */\n    public static void pickImageFromCamera(final Activity activity) {\n        pickImageFromCamera(activity, 0);\n    }\n\n    /**\n     * 打开本地相册选取图片\n     */\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public static void pickImageFromAlbum(final Activity activity, int addRequest) {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_GET_CONTENT);\n        intent.setType(\"image/*\");\n        activity.startActivityForResult(intent, REQUEST_CODE_FROM_ALBUM + addRequest);\n    }\n\n    /**\n     * 打开本地相册选取图片\n     */\n    public static void pickImageFromAlbum(final Activity activity) {\n        pickImageFromAlbum(activity, 0);\n    }\n\n    /**\n     * 图片裁剪\n     */\n    public static void cropImage(Activity activity, Uri srcUri) {\n        cropImageUri = createImageUri(activity);\n\n        Intent intent = new Intent(\"com.android.camera.action.CROP\");\n        intent.setDataAndType(srcUri, \"image/*\");\n        intent.putExtra(\"crop\", \"true\");\n\n        ////////////////////////////////////////////////////////////////\n        // 1.宽高和比例都不设置时,裁剪框可以自行调整(比例和大小都可以随意调整)\n        ////////////////////////////////////////////////////////////////\n        // 2.只设置裁剪框宽高比(aspect)后,裁剪框比例固定不可调整,只能调整大小\n        /////////////////////////////////\n        // 3.裁剪后生成图片宽高(output)的设置和裁剪框无关,只决定最终生成图片大小\n        ////////////////////////////////////////////////////////////////\n        // 4.裁剪框宽高比例(aspect)可以和裁剪后生成图片比例(output)不同,此时,\n        //\t会以裁剪框的宽为准,按照裁剪宽高比例生成一个图片,该图和框选部分可能不同,\n        //  不同的情况可能是截取框选的一部分,也可能超出框选部分,向下延伸补足\n        ////////////////////////////////////////////////////////////////\n\n        // aspectX aspectY 是裁剪框宽高的比例\n        intent.putExtra(\"aspectX\", 1);\n        intent.putExtra(\"aspectY\", 1);\n        // outputX outputY 是裁剪后生成图片的宽高\n//\t\tintent.putExtra(\"outputX\", 300);\n//\t\tintent.putExtra(\"outputY\", 100);\n\n        // return-data为true时,会直接返回bitmap数据,但是大图裁剪时会出现OOM,推荐下面为false时的方式\n        // return-data为false时,不会返回bitmap,但需要指定一个MediaStore.EXTRA_OUTPUT保存图片uri\n        intent.putExtra(\"return-data\", false);\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);\n\n        activity.startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE);\n    }\n\n    /**\n     * 创建一条图片uri,用于保存拍照后的照片\n     */\n    private static Uri createImageUri(Context context) {\n        String name = \"boreImg\" + System.currentTimeMillis();\n        ContentValues values = new ContentValues();\n        values.put(MediaStore.Images.Media.TITLE, name);\n        values.put(MediaStore.Images.Media.DISPLAY_NAME, name + \".jpeg\");\n        values.put(MediaStore.Images.Media.MIME_TYPE, \"image/jpeg\");\n        Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);\n        return uri;\n    }\n\n    /**\n     * 删除一条图片\n     */\n    public static void deleteImageUri(Context context, Uri uri) {\n        context.getContentResolver().delete(imageUriFromCamera, null, null);\n    }\n\n    /**\n     * 用第三方应用app打开图片\n     */\n    public static void openImageByOtherApp(Context context, Uri imageUri) {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_VIEW);\n        intent.setDataAndType(imageUri, \"image/*\");\n        context.startActivity(intent);\n    }\n\n    /**\n     * 根据Uri获取图片绝对路径，解决Android4.4以上版本Uri转换\n     */\n    public static String getImageAbsolutePath19(Context context, Uri imageUri) {\n        if (context == null || imageUri == null)\n            return null;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT\n                && DocumentsContract.isDocumentUri(context, imageUri)) {\n            if (isExternalStorageDocument(imageUri)) {\n                String docId = DocumentsContract.getDocumentId(imageUri);\n                String[] split = docId.split(\":\");\n                String type = split[0];\n                if (\"primary\".equalsIgnoreCase(type)) {\n                    return Environment.getExternalStorageDirectory() + \"/\" + split[1];\n                }\n            } else if (isDownloadsDocument(imageUri)) {\n                String id = DocumentsContract.getDocumentId(imageUri);\n                Uri contentUri = ContentUris.withAppendedId(Uri.parse(\"content://downloads/public_downloads\"), Long.valueOf(id));\n                return getDataColumn(context, contentUri, null, null);\n            } else if (isMediaDocument(imageUri)) {\n                String docId = DocumentsContract.getDocumentId(imageUri);\n                String[] split = docId.split(\":\");\n                String type = split[0];\n                Uri contentUri = null;\n                if (\"image\".equals(type)) {\n                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;\n                } else if (\"video\".equals(type)) {\n                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;\n                } else if (\"audio\".equals(type)) {\n                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;\n                }\n                String selection = MediaStore.Images.Media._ID + \"=?\";\n                String[] selectionArgs = new String[]{split[1]};\n                return getDataColumn(context, contentUri, selection, selectionArgs);\n            }\n        }\n\n        // MediaStore (and general)\n        if (\"content\".equalsIgnoreCase(imageUri.getScheme())) {\n            // Return the remote address\n            if (isGooglePhotosUri(imageUri))\n                return imageUri.getLastPathSegment();\n            return getDataColumn(context, imageUri, null, null);\n        }\n        // File\n        else if (\"file\".equalsIgnoreCase(imageUri.getScheme())) {\n            return imageUri.getPath();\n        }\n        return null;\n    }\n\n    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {\n        Cursor cursor = null;\n        String column = MediaStore.Images.Media.DATA;\n        String[] projection = {column};\n        try {\n            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);\n            if (cursor != null && cursor.moveToFirst()) {\n                int index = cursor.getColumnIndexOrThrow(column);\n                return cursor.getString(index);\n            }\n        } finally {\n            if (cursor != null)\n                cursor.close();\n        }\n        return null;\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is ExternalStorageProvider.\n     */\n    private static boolean isExternalStorageDocument(Uri uri) {\n        return \"com.android.externalstorage.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is DownloadsProvider.\n     */\n    private static boolean isDownloadsDocument(Uri uri) {\n        return \"com.android.providers.downloads.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is MediaProvider.\n     */\n    private static boolean isMediaDocument(Uri uri) {\n        return \"com.android.providers.media.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is Google Photos.\n     */\n    private static boolean isGooglePhotosUri(Uri uri) {\n        return \"com.google.android.apps.photos.content\".equals(uri.getAuthority());\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/LogUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.util.Log;\n\npublic class LogUtils {\n\n    public static void showLog(String log) {\n        showLog(\"DDD\", log);\n    }\n\n    public static void showLog(String tag, String log) {\n        Log.i(tag, log);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/NetUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\n\npublic class NetUtils {\n\n    private NetUtils() {\n        /* cannot be instantiated */\n        throw new UnsupportedOperationException(\"cannot be instantiated\");\n    }\n\n    /**\n     * 判断网络是否连接\n     */\n    public static boolean isConnected(Context context) {\n        ConnectivityManager cm = (ConnectivityManager)\n                context.getSystemService(Context.CONNECTIVITY_SERVICE);\n\n        if (null == cm) {\n            return false;\n        }\n\n        NetworkInfo info = cm.getActiveNetworkInfo();\n        if (null != info && info.isConnected()) {\n            if (info.getState() == NetworkInfo.State.CONNECTED) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 判断是否是wifi连接\n     */\n    public static boolean isWifi(Context context) {\n        ConnectivityManager cm = (ConnectivityManager)\n                context.getSystemService(Context.CONNECTIVITY_SERVICE);\n\n        if (null == cm) {\n            return false;\n        }\n\n        NetworkInfo info = cm.getActiveNetworkInfo();\n        if (null != info) {\n            if (info.getType() == ConnectivityManager.TYPE_WIFI) {\n                return true;\n            }\n        }\n        return false;\n\n    }\n\n    /**\n     * 打开网络设置界面\n     */\n    public static void openSetting(Activity activity, int requestCode) {\n        Intent intent = new Intent(\"/\");\n        ComponentName cm = new ComponentName(\"com.android.settings\",\n                \"com.android.settings.WirelessSettings\");\n        intent.setComponent(cm);\n        intent.setAction(Intent.ACTION_VIEW);\n        activity.startActivityForResult(intent, requestCode);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/StringUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.Context;\nimport android.text.TextPaint;\nimport android.text.style.ClickableSpan;\nimport android.view.View;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.text.DecimalFormat;\n\npublic class StringUtils {\n\n    public static boolean isEmpty(CharSequence str) {\n        return str == null || str.length() == 0;\n    }\n\n    public static String getMoney(float cost) {\n        DecimalFormat decimalFormat = new DecimalFormat(\"0.00\");\n        return \"￥\" + decimalFormat.format(cost);\n    }\n\n    public static class PrimaryClickableSpan extends ClickableSpan {\n\n        private Context context;\n\n        public PrimaryClickableSpan(Context context) {\n            this.context = context;\n        }\n\n        @Override\n        public void onClick(View widget) {\n            // do nothing\n        }\n\n        @Override\n        public void updateDrawState(TextPaint ds) {\n            ds.setColor(context.getResources().getColor(R.color.colorPrimary));\n            ds.setUnderlineText(false);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/TitleBuilder.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 标题栏构造器,使用方法 new TitleBuilder().setMethod().setMethod()......\n * <p/>\n * 统一格式为标题文字,左右各自是文字/图片按钮\n * 按钮都默认不显示,只有在你调用setLeftText时才会显示左侧按钮文字,图片同理\n * 图片或文字的点击事件都用Left/RightOnClickListener\n */\npublic class TitleBuilder {\n\n    private View rootView;\n    private TextView tvTitle;\n    private ImageView ivLeft;\n    private ImageView ivRight;\n    private TextView tvLeft;\n    private TextView tvRight;\n\n    public View getRootView() {\n        return rootView;\n    }\n\n    public TextView getTvTitle() {\n        return tvTitle;\n    }\n\n    public ImageView getIvLeft() {\n        return ivLeft;\n    }\n\n    public ImageView getIvRight() {\n        return ivRight;\n    }\n\n    public TextView getTvLeft() {\n        return tvLeft;\n    }\n\n    public TextView getTvRight() {\n        return tvRight;\n    }\n\n    /**\n     * Activity中使用这个构造方法\n     */\n    public TitleBuilder(Activity context) {\n        rootView = context.findViewById(R.id.rl_titlebar);\n        if (rootView == null) {\n            return;\n        }\n        tvTitle = (TextView) rootView.findViewById(R.id.titlebar_tv);\n        ivLeft = (ImageView) rootView.findViewById(R.id.titlebar_iv_left);\n        ivRight = (ImageView) rootView.findViewById(R.id.titlebar_iv_right);\n        tvLeft = (TextView) rootView.findViewById(R.id.titlebar_tv_left);\n        tvRight = (TextView) rootView.findViewById(R.id.titlebar_tv_right);\n    }\n\n    /**\n     * Fragment中使用这个构造方法\n     */\n    public TitleBuilder(View context) {\n        rootView = context.findViewById(R.id.rl_titlebar);\n        if (rootView == null) {\n            return;\n        }\n        tvTitle = (TextView) rootView.findViewById(R.id.titlebar_tv);\n        ivLeft = (ImageView) rootView.findViewById(R.id.titlebar_iv_left);\n        ivRight = (ImageView) rootView.findViewById(R.id.titlebar_iv_right);\n        tvLeft = (TextView) rootView.findViewById(R.id.titlebar_tv_left);\n        tvRight = (TextView) rootView.findViewById(R.id.titlebar_tv_right);\n    }\n\n    // title\n    public TitleBuilder setTitleBgRes(int resid) {\n        rootView.setBackgroundResource(resid);\n        return this;\n    }\n\n    public TitleBuilder setTitleText(String text) {\n        tvTitle.setVisibility(TextUtils.isEmpty(text) ? View.GONE\n                : View.VISIBLE);\n        tvTitle.setText(text);\n        return this;\n    }\n\n    // left\n    public TitleBuilder setLeftImage(int resId) {\n        ivLeft.setVisibility(resId > 0 ? View.VISIBLE : View.GONE);\n        ivLeft.setImageResource(resId);\n        return this;\n    }\n\n    public TitleBuilder setLeftText(String text) {\n        tvLeft.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);\n        tvLeft.setText(text);\n        return this;\n    }\n\n    public TitleBuilder setLeftOnClickListener(OnClickListener listener) {\n        if (ivLeft.getVisibility() == View.VISIBLE) {\n            ivLeft.setOnClickListener(listener);\n        } else if (tvLeft.getVisibility() == View.VISIBLE) {\n            tvLeft.setOnClickListener(listener);\n        }\n        return this;\n    }\n\n    // right\n    public TitleBuilder setRightImage(int resId) {\n        ivRight.setVisibility(resId > 0 ? View.VISIBLE : View.GONE);\n        ivRight.setImageResource(resId);\n        return this;\n    }\n\n    public TitleBuilder setRightText(String text) {\n        tvRight.setVisibility(TextUtils.isEmpty(text) ? View.GONE\n                : View.VISIBLE);\n        tvRight.setText(text);\n        return this;\n    }\n\n    public TitleBuilder setRightTextColor(Context context, int resId) {\n        tvRight.setTextColor(context.getResources().getColor(resId));\n        return this;\n    }\n\n    public TitleBuilder setTitleTextColor(Context context, int resId) {\n        tvTitle.setTextColor(context.getResources().getColor(resId));\n        return this;\n    }\n\n\n    public TitleBuilder setRightOnClickListener(OnClickListener listener) {\n        if (ivRight.getVisibility() == View.VISIBLE) {\n            ivRight.setOnClickListener(listener);\n        } else if (tvRight.getVisibility() == View.VISIBLE) {\n            tvRight.setOnClickListener(listener);\n        }\n        return this;\n    }\n\n    public View build() {\n        return rootView;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ToastUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\npublic class ToastUtils {\n\n    private static Toast mToast;\n\n    /**\n     * 非阻塞试显示Toast,防止出现连续点击Toast时的显示问题\n     */\n    public static void showToast(Context context, CharSequence text, int duration) {\n        if (mToast == null) {\n            mToast = Toast.makeText(context, text, duration);\n        } else {\n            mToast.setText(text);\n            mToast.setDuration(duration);\n        }\n        mToast.show();\n    }\n\n    public static void showToast(Context context, CharSequence text) {\n        showToast(context, text, Toast.LENGTH_SHORT);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ViewUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\npublic class ViewUtils {\n\n//    public static void setIndicator(Context context, final int size,\n//                                    final ViewPager vp_banner, final RadioGroup rg_indicator) {\n//        // 无图片和只有一张时不要indicator\n//        if (size <= 1) {\n//            rg_indicator.setVisibility(View.GONE);\n//            return;\n//        }\n//        rg_indicator.setVisibility(View.VISIBLE);\n//\n//        vp_banner.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\n//\n//            @Override\n//            public void onPageSelected(int position) {\n//                // ViewPager和RadioGroup联动\n//                if (rg_indicator.getChildCount() > 1) {\n//                    ((RadioButton) rg_indicator.getChildAt(position % size)).setChecked(true);\n//                }\n//            }\n//        });\n//\n//        // 根据图片数量添加RadioButton\n//        rg_indicator.removeAllViews();\n//        for (int i = 0; i < size; i++) {\n//            RadioButton rb = new RadioButton(context);\n//            // TODO 圆形大小\n//            RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(\n//                    DisplayUtils.dp2px(context, 8), DisplayUtils.dp2px(context, 8));\n//            if (i > 0) {\n//                params.setMargins(DisplayUtils.dp2px(context, 8), 0, 0, 0);\n//            }\n//            rb.setLayoutParams(params);\n//            rb.setButtonDrawable(new ColorDrawable());\n//            rb.setBackgroundResource(R.drawable.shape_oval_yellow_stroke2solid_sel);\n//            rb.setOnTouchListener(new View.OnTouchListener() {\n//                @Override\n//                public boolean onTouch(View view, MotionEvent motionEvent) {\n//                    // 圆不可点击选择\n//                    return true;\n//                }\n//            });\n//            rg_indicator.addView(rb);\n//        }\n//\n//        // 默认选中第一个\n//        if (rg_indicator.getChildCount() > 0) {\n//            ((RadioButton) rg_indicator.getChildAt(0)).setChecked(true);\n//        }\n//    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/AddressWheelDialog.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.view.View;\nimport android.widget.Button;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.db.AddressData;\nimport com.boredream.bdcodehelper.entity.city.CityModel;\nimport com.boredream.bdcodehelper.view.wheel.OnWheelChangedListener;\nimport com.boredream.bdcodehelper.view.wheel.WheelView;\nimport com.boredream.bdcodehelper.view.wheel.adapters.ArrayWheelAdapter;\n\nimport java.util.ArrayList;\n\npublic class AddressWheelDialog extends Dialog implements OnWheelChangedListener {\n\n    private String mCurrentProvice;\n    private CityModel mCurrentCity;\n\n    private WheelView mViewProvince;\n    private WheelView mViewCity;\n    private Button mBtnConfirm;\n\n    public AddressWheelDialog(Context context) {\n        super(context);\n\n        initViews();\n        initData();\n    }\n\n    private void initViews() {\n        setContentView(R.layout.wheel_dialog_address);\n\n        mViewProvince = (WheelView) findViewById(R.id.id_province);\n        mViewCity = (WheelView) findViewById(R.id.id_city);\n        mBtnConfirm = (Button) findViewById(R.id.btn_confirm);\n\n        mViewProvince.addChangingListener(this);\n        mViewCity.addChangingListener(this);\n        mBtnConfirm.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                if(onAddressSelectListener != null) {\n                    CityModel address = new CityModel();\n                    onAddressSelectListener.onAddressSelected(address);\n                }\n            }\n        });\n    }\n\n    private void initData() {\n        mViewProvince.setViewAdapter(new ArrayWheelAdapter<>(getContext(), AddressData.mProvinceDatas));\n        mViewProvince.setVisibleItems(7);\n        mViewCity.setVisibleItems(7);\n        updateCities();\n    }\n\n    @Override\n    public void onChanged(WheelView wheel, int oldValue, int newValue) {\n        if (wheel == mViewProvince) {\n            updateCities();\n        }\n    }\n\n    private void updateCities() {\n        int pCurrent = mViewProvince.getCurrentItem();\n        mCurrentProvice = AddressData.mProvinceDatas.get(pCurrent);\n        ArrayList<CityModel> cities = AddressData.mCitisDatasMap.get(mCurrentProvice);\n        if (cities == null) {\n            cities = new ArrayList<>();\n        }\n        mViewCity.setViewAdapter(new ArrayWheelAdapter<>(getContext(), cities));\n        mViewCity.setCurrentItem(0);\n    }\n\n    private OnAddressSelectListener onAddressSelectListener;\n\n    public void setOnAddressSelectListener(OnAddressSelectListener onAddressSelectListener) {\n        this.onAddressSelectListener = onAddressSelectListener;\n    }\n\n    public interface OnAddressSelectListener {\n        void onAddressSelected(CityModel address);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/BottomTabRadioButton.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.widget.RadioButton;\n\nimport com.boredream.bdcodehelper.R;\n\npublic class BottomTabRadioButton extends RadioButton {\n\n    /**\n     * 提示模式 - 无提示\n     */\n    private static final int MODE_NONE = 0;\n\n    /**\n     * 提示模式 - 红点提示\n     */\n    private static final int MODE_POINT = 1;\n\n    /**\n     * 提示模式 - 数字提示\n     */\n    private static final int MODE_NUM = 2;\n\n    /**\n     * 默认红点默认半径\n     */\n    private static final float DEFAULT_POINT_RADIUS = 4; //dp\n\n    /**\n     * 默认数字圆圈半径\n     */\n    private static final float DEFAULT_NUM_RADIUS = 8; //dp\n\n    /**\n     * 默认数字文字大小\n     */\n    private static final float DEFAULT_NUM_SIZE = 10; //sp\n\n    private Paint hintPaint;\n    private Paint textPaint;\n    private Rect textRect = new Rect();\n\n    /**\n     * 提示模式\n     */\n    private int hint_mode;\n\n    /**\n     * 圆填充色\n     */\n    private int hint_color;\n\n    /**\n     * 据顶部距离\n     */\n    private int hint_toppadding;\n\n    /**\n     * 据右侧距离\n     */\n    private int hint_rightpadding;\n\n    /**\n     * 圆点半径\n     */\n    private int point_radius;\n\n    /**\n     * 数字\n     */\n    private int num;\n\n    /**\n     * 数字圆圈半径\n     */\n    private int num_radius;\n\n    /**\n     * 数字文字大小\n     */\n    private int num_size;\n\n    /**\n     * 数字文字颜色\n     */\n    private int num_color;\n\n    public int getHint_mode() {\n        return hint_mode;\n    }\n\n    public void setHint_mode(int hint_mode) {\n        this.hint_mode = hint_mode;\n        invalidate();\n    }\n\n    public int getHint_color() {\n        return hint_color;\n    }\n\n    public void setHint_color(int hint_color) {\n        this.hint_color = hint_color;\n        invalidate();\n    }\n\n    public int getHint_toppadding() {\n        return hint_toppadding;\n    }\n\n    public void setHint_toppadding(int hint_toppadding) {\n        this.hint_toppadding = hint_toppadding;\n        invalidate();\n    }\n\n    public int getHint_rightpadding() {\n        return hint_rightpadding;\n    }\n\n    public void setHint_rightpadding(int hint_rightpadding) {\n        this.hint_rightpadding = hint_rightpadding;\n        invalidate();\n    }\n\n    public int getPoint_radius() {\n        return point_radius;\n    }\n\n    public void setPoint_radius(int point_radius) {\n        this.point_radius = point_radius;\n        invalidate();\n    }\n\n    public int getNum() {\n        return num;\n    }\n\n    public void setNum(int num) {\n        this.num = num;\n        invalidate();\n    }\n\n    public int getNum_radius() {\n        return num_radius;\n    }\n\n    public void setNum_radius(int num_radius) {\n        this.num_radius = num_radius;\n        invalidate();\n    }\n\n    public int getNum_size() {\n        return num_size;\n    }\n\n    public void setNum_size(int num_size) {\n        this.num_size = num_size;\n        invalidate();\n    }\n\n    public int getNum_color() {\n        return num_color;\n    }\n\n    public void setNum_color(int num_color) {\n        this.num_color = num_color;\n        invalidate();\n    }\n\n    public BottomTabRadioButton(Context context) {\n        super(context);\n    }\n\n    public BottomTabRadioButton(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView(attrs);\n    }\n\n    public BottomTabRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView(attrs);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public BottomTabRadioButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        initView(attrs);\n    }\n\n    private void initView(AttributeSet attrs) {\n        Context context = getContext();\n        DisplayMetrics metrics = context.getResources().getDisplayMetrics();\n\n        // 根据attrs获取属性\n        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BottomTabRadioButton);\n\n        hint_mode = ta.getInt(R.styleable.BottomTabRadioButton_hint_mode,\n                MODE_NONE);\n        hint_color = ta.getColor(R.styleable.BottomTabRadioButton_hint_color,\n                Color.RED);\n\n        hint_toppadding = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_hint_toppadding,\n                0);\n        hint_rightpadding = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_hint_rightpadding,\n                0);\n\n        float defaultPointRadius = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_POINT_RADIUS, metrics);\n        point_radius = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_point_radius,\n                (int) (defaultPointRadius + 0.5f));\n\n        num = ta.getInt(R.styleable.BottomTabRadioButton_num,\n                -1);\n        float defaultNumRadius = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_NUM_RADIUS, metrics);\n        num_radius = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_radius,\n                (int) (defaultNumRadius + 0.5f));\n        float defaultNumSize = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_SP, DEFAULT_NUM_SIZE, metrics);\n        num_size = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_size,\n                (int) (defaultNumSize + 0.5f));\n        num_color = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_color,\n                Color.WHITE);\n\n        ta.recycle();\n\n        // 初始化背景圆画笔\n        hintPaint = new Paint();\n        hintPaint.setAntiAlias(true);\n        hintPaint.setStyle(Paint.Style.FILL);\n        hintPaint.setColor(hint_color);\n\n        // 初始化数字文字画笔\n        textPaint = new Paint();\n        textPaint.setAntiAlias(true);\n        textPaint.setColor(num_color);\n        textPaint.setTextSize(num_size);\n        textPaint.setFakeBoldText(true);\n        textPaint.setTextAlign(Paint.Align.CENTER);\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        if (hint_mode == MODE_POINT) { // 如果是圆点模式\n            // 直接画一个圆点\n            float width = getWidth();\n            float centerX = width - hint_rightpadding - point_radius;\n            float centerY = hint_toppadding + point_radius;\n\n            canvas.drawCircle(centerX, centerY, point_radius, hintPaint);\n        } else if (hint_mode == MODE_NUM) { // 如果是数字模式\n            // 1.画一个背景圆\n            float width = getWidth();\n            float centerX = width - hint_rightpadding - num_radius;\n            float centerY = hint_toppadding + num_radius;\n\n            canvas.drawCircle(centerX, centerY, num_radius, hintPaint);\n\n            // 2.画数字\n            if (num >= 0) {\n                String numStr = String.valueOf(num);\n\n                if (num >= 100) {\n                    // 如果超过100使用\"...\"\n                    numStr = \"...\";\n                }\n                textPaint.getTextBounds(numStr, 0, numStr.length(), textRect);\n                float textCenterY = centerY + textRect.bottom - textRect.top / 2;\n                canvas.drawText(numStr, centerX, textCenterY, textPaint);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/CheckableLinearLayout.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.Checkable;\nimport android.widget.LinearLayout;\n\n/**\n * This is a simple wrapper for {@link LinearLayout} that implements the {@link Checkable}\n * interface by keeping an internal 'checked' state flag.\n * <p>\n * This can be used as the root view for a custom list item layout for\n * {@link android.widget.AbsListView} elements with a\n * {@link android.widget.AbsListView#setChoiceMode(int) choiceMode} set.\n */\npublic class CheckableLinearLayout extends LinearLayout implements Checkable {\n    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};\n\n    private boolean mChecked = false;\n\n    public CheckableLinearLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public boolean isChecked() {\n        return mChecked;\n    }\n\n    public void setChecked(boolean b) {\n        if (b != mChecked) {\n            mChecked = b;\n            refreshDrawableState();\n        }\n    }\n\n    public void toggle() {\n        setChecked(!mChecked);\n    }\n\n    @Override\n    public int[] onCreateDrawableState(int extraSpace) {\n        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);\n        if (isChecked()) {\n            mergeDrawableStates(drawableState, CHECKED_STATE_SET);\n        }\n        return drawableState;\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DividerItemDecoration.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class DividerItemDecoration extends RecyclerView.ItemDecoration {\n\n    private static final int[] ATTRS = new int[]{\n            android.R.attr.listDivider\n    };\n\n    private List<Integer> ignorePositionList;\n\n    private Drawable mDivider;\n\n    public DividerItemDecoration(Context context) {\n        final TypedArray a = context.obtainStyledAttributes(ATTRS);\n        mDivider = a.getDrawable(0);\n        a.recycle();\n    }\n\n    /**\n     * 忽略分割线的position,即该位置不添加\n     */\n    public void setIgnorePositions(Integer[] ignorePositions) {\n        ignorePositionList = Arrays.asList(ignorePositions);\n    }\n\n    @Override\n    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {\n        drawVertical(c, parent);\n    }\n\n    public void drawVertical(Canvas c, RecyclerView parent) {\n        final int left = parent.getPaddingLeft();\n        final int right = parent.getWidth() - parent.getPaddingRight();\n\n        final int childCount = parent.getChildCount();\n        for (int i = 0; i < childCount; i++) {\n            if (ignorePositionList != null && ignorePositionList.contains(i)) {\n                continue;\n            }\n\n            final View child = parent.getChildAt(i);\n            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child\n                    .getLayoutParams();\n            final int top = child.getBottom() + params.bottomMargin +\n                    Math.round(ViewCompat.getTranslationY(child));\n//            final int bottom = top + mDivider.getIntrinsicHeight();\n            final int bottom = top + 1;\n            mDivider.setBounds(left, top, right, bottom);\n            mDivider.draw(c);\n        }\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n//        outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());\n        outRect.set(0, 0, 0, 1);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DrawableRadioButton.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.widget.RadioButton;\n\nimport com.boredream.bdcodehelper.R;\n\n\npublic class DrawableRadioButton extends RadioButton {\n\n    private int widthPx;\n    private int heightPx;\n\n    public DrawableRadioButton(Context context) {\n        super(context);\n    }\n\n    public DrawableRadioButton(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        initView(context, attrs);\n    }\n\n    public DrawableRadioButton(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        initView(context, attrs);\n    }\n\n    private void initView(Context context, AttributeSet attrs) {\n        TypedArray ta = context.obtainStyledAttributes(attrs,\n                R.styleable.DrawableTextView);\n\n        widthPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableWidth, -1);\n        heightPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableHeight, -1);\n\n        // 左右上下四个图片\n        Drawable[] drawables = getCompoundDrawables();\n\n        setDrawables(drawables);\n\n        ta.recycle();\n    }\n\n    /**\n     * 左上右下四个图片,只会取一个方向图片使用\n     */\n    public void setDrawables(Drawable[] drawables) {\n        // 左右上下四个图片\n        Drawable drawable = null;\n        // 如果其中一个方向有图片,获取之\n        for (int i = 0; i < drawables.length; i++) {\n            if (drawables[i] != null) {\n                drawable = drawables[i];\n                break;\n            }\n        }\n\n        // 设置宽高\n        if (drawable != null && widthPx != -1 && heightPx != -1) {\n            drawable.setBounds(0, 0, widthPx, heightPx);\n        }\n\n        // 将图片放回到TextView中\n        setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DrawableTextView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n\npublic class DrawableTextView extends TextView {\n\n    private final int widthPx;\n    private final int heightPx;\n\n    public DrawableTextView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        TypedArray ta = context.obtainStyledAttributes(attrs,\n                R.styleable.DrawableTextView);\n\n        widthPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableWidth, -1);\n        heightPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableHeight, -1);\n\n        // 左右上下四个图片\n        Drawable[] drawables = getCompoundDrawables();\n\n        setDrawables(drawables);\n\n        ta.recycle();\n    }\n\n    /**\n     * 左上右下四个图片,只会取一个方向图片使用\n     */\n    public void setDrawables(Drawable[] drawables) {\n        // 左右上下四个图片\n        Drawable drawable = null;\n        // 如果其中一个方向有图片,获取之\n        for (int i = 0; i < drawables.length; i++) {\n            if (drawables[i] != null) {\n                drawable = drawables[i];\n                break;\n            }\n        }\n\n        // 设置宽高\n        if (drawable != null && widthPx != -1 && heightPx != -1) {\n            drawable.setBounds(0, 0, widthPx, heightPx);\n        }\n\n        // 将图片放回到TextView中\n        setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);\n    }\n\n    public DrawableTextView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public DrawableTextView(Context context) {\n        this(context, null);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DropDownMenu.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.animation.AnimationUtils;\nimport android.widget.FrameLayout;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.util.List;\n\npublic class DropDownMenu extends LinearLayout {\n\n    //顶部菜单布局\n    private LinearLayout tabMenuView;\n    //底部容器，包含popupMenuViews，maskView\n    private FrameLayout containerView;\n    //弹出菜单父布局\n    private FrameLayout popupMenuViews;\n    //遮罩半透明View，点击可关闭DropDownMenu\n    private View maskView;\n    //tabMenuView里面选中的tab位置，-1表示未选中\n    private int current_tab_position = -1;\n\n    //分割线颜色\n    private int dividerColor = getResources().getColor(R.color.divider_gray);\n    //tab选中颜色\n    private int textSelectedColor = getResources().getColor(R.color.colorPrimary);\n    //tab未选中颜色\n    private int textUnselectedColor = getResources().getColor(R.color.txt_black);\n    //遮罩颜色\n    private int maskColor = 0x88888888;\n    //tab字体大小\n    private int menuTextSize = 12;\n\n    //tab选中图标\n    private int menuSelectedIcon;\n    //tab未选中图标\n    private int menuUnselectedIcon;\n\n\n    public DropDownMenu(Context context) {\n        super(context, null);\n    }\n\n    public DropDownMenu(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    @TargetApi(Build.VERSION_CODES.HONEYCOMB)\n    public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        setOrientation(VERTICAL);\n\n        //为DropDownMenu添加自定义属性\n        int menuBackgroundColor = 0xffffffff;\n        int underlineColor = 0xffcccccc;\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DropDownMenu);\n        underlineColor = a.getColor(R.styleable.DropDownMenu_ddunderlineColor, underlineColor);\n        dividerColor = a.getColor(R.styleable.DropDownMenu_dddividerColor, dividerColor);\n        textSelectedColor = a.getColor(R.styleable.DropDownMenu_ddtextSelectedColor, textSelectedColor);\n        textUnselectedColor = a.getColor(R.styleable.DropDownMenu_ddtextUnselectedColor, textUnselectedColor);\n        menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_ddmenuBackgroundColor, menuBackgroundColor);\n        maskColor = a.getColor(R.styleable.DropDownMenu_ddmaskColor, maskColor);\n        menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_ddmenuTextSize, menuTextSize);\n        menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuSelectedIcon, menuSelectedIcon);\n        menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuUnselectedIcon, menuUnselectedIcon);\n        a.recycle();\n\n        //初始化tabMenuView并添加到tabMenuView\n        tabMenuView = new LinearLayout(context);\n        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n        tabMenuView.setOrientation(HORIZONTAL);\n        tabMenuView.setBackgroundColor(menuBackgroundColor);\n        tabMenuView.setLayoutParams(params);\n        addView(tabMenuView, 0);\n\n        //为tabMenuView添加下划线\n        View underLine = new View(getContext());\n        underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpTpPx(1.0f)));\n        underLine.setBackgroundColor(underlineColor);\n        addView(underLine, 1);\n\n        //初始化containerView并将其添加到DropDownMenu\n        containerView = new FrameLayout(context);\n        containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));\n        addView(containerView, 2);\n\n    }\n\n    /**\n     * 初始化DropDownMenu\n     *\n     * @param tabTexts\n     * @param popupViews\n     * @param contentView\n     */\n    public void setDropDownMenu(List<String> tabTexts, List<View> popupViews, View contentView) {\n        if (tabTexts.size() != popupViews.size()) {\n            throw new IllegalArgumentException(\"params not match, tabTexts.size() should be equal popupViews.size()\");\n        }\n\n        for (int i = 0; i < tabTexts.size(); i++) {\n            addTab(tabTexts, i);\n        }\n\n        containerView.addView(contentView, 0);\n\n        maskView = new View(getContext());\n        maskView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));\n        maskView.setBackgroundColor(maskColor);\n        maskView.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                closeMenu();\n            }\n        });\n        containerView.addView(maskView, 1);\n        maskView.setVisibility(GONE);\n\n        popupMenuViews = new FrameLayout(getContext());\n        popupMenuViews.setVisibility(GONE);\n        containerView.addView(popupMenuViews, 2);\n\n        for (int i = 0; i < popupViews.size(); i++) {\n            popupViews.get(i).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n            popupMenuViews.addView(popupViews.get(i), i);\n        }\n\n    }\n\n    private void addTab(List<String> tabTexts, int i) {\n        final TextView tab = new TextView(getContext());\n        tab.setSingleLine();\n        tab.setEllipsize(TextUtils.TruncateAt.END);\n        tab.setGravity(Gravity.CENTER);\n        tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, menuTextSize);\n        tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));\n        tab.setTextColor(textUnselectedColor);\n        tab.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(menuUnselectedIcon), null);\n        tab.setText(tabTexts.get(i));\n        tab.setPadding(dpTpPx(48), dpTpPx(8), dpTpPx(48), dpTpPx(8));\n        //添加点击事件\n        tab.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                switchMenu(tab);\n            }\n        });\n        tabMenuView.addView(tab);\n        //添加分割线\n        if (i < tabTexts.size() - 1) {\n            View view = new View(getContext());\n            LayoutParams params = new LayoutParams(\n                    dpTpPx(0.5f), ViewGroup.LayoutParams.MATCH_PARENT);\n            params.setMargins(0, dpTpPx(4), 0, dpTpPx(4));\n            view.setLayoutParams(params);\n            view.setBackgroundColor(dividerColor);\n            tabMenuView.addView(view);\n        }\n    }\n\n    /**\n     * 改变tab文字\n     *\n     * @param text\n     */\n    public void setTabText(String text) {\n        if (current_tab_position != -1) {\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setText(text);\n        }\n    }\n\n    public void setTabClickable(boolean clickable) {\n        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {\n            tabMenuView.getChildAt(i).setClickable(clickable);\n        }\n    }\n\n    /**\n     * 关闭菜单\n     */\n    public void closeMenu() {\n        if (current_tab_position != -1) {\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setTextColor(textUnselectedColor);\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                    getResources().getDrawable(menuUnselectedIcon), null);\n            popupMenuViews.setVisibility(View.GONE);\n            popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_out));\n            maskView.setVisibility(GONE);\n            maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_out));\n            current_tab_position = -1;\n        }\n\n    }\n\n    /**\n     * DropDownMenu是否处于可见状态\n     *\n     * @return\n     */\n    public boolean isShowing() {\n        return current_tab_position != -1;\n    }\n\n    /**\n     * 切换菜单\n     *\n     * @param target\n     */\n    private void switchMenu(View target) {\n        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {\n            if (target == tabMenuView.getChildAt(i)) {\n                if (current_tab_position == i) {\n                    closeMenu();\n                } else {\n                    if (current_tab_position == -1) {\n                        popupMenuViews.setVisibility(View.VISIBLE);\n                        popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_in));\n                        maskView.setVisibility(VISIBLE);\n                        maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_in));\n                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);\n                    } else {\n                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);\n                    }\n                    current_tab_position = i;\n                    ((TextView) tabMenuView.getChildAt(i)).setTextColor(textSelectedColor);\n                    ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                            getResources().getDrawable(menuSelectedIcon), null);\n                }\n            } else {\n                ((TextView) tabMenuView.getChildAt(i)).setTextColor(textUnselectedColor);\n                ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                        getResources().getDrawable(menuUnselectedIcon), null);\n                popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);\n            }\n        }\n    }\n\n    public int dpTpPx(float value) {\n        DisplayMetrics dm = getResources().getDisplayMetrics();\n        return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm) + 0.5);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/EmptyItemDecoration.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.graphics.Rect;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npublic class EmptyItemDecoration extends RecyclerView.ItemDecoration {\n\n    /**\n     * decoration添加的位置,为空时所有item都添加\n     */\n    private List<Integer> dividerPositionList;\n    private int height;\n\n    public EmptyItemDecoration(int height) {\n        this.height = height;\n    }\n\n    public EmptyItemDecoration(Integer[] dividerPositions, int height) {\n        this.dividerPositionList = Arrays.asList(dividerPositions);\n        this.height = height;\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n        int position = parent.getChildAdapterPosition(view);\n        if (dividerPositionList == null || dividerPositionList.contains(position)) {\n            outRect.set(0, 0, 0, height);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/GridSpacingDecorator.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.graphics.Rect;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\npublic class GridSpacingDecorator extends RecyclerView.ItemDecoration {\n\n    private int space;\n\n    public GridSpacingDecorator(int space) {\n        this.space = space;\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n        outRect.left = space / 2;\n        outRect.right = space / 2;\n        outRect.bottom = space;\n        if (parent.getChildAdapterPosition(view) <= 1) {\n            outRect.top = space;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/PinnedSectionListView.java",
    "content": "package com.boredream.bdcodehelper.view;\n/*\n * Copyright (C) 2013 Sergej Shafarenka, halfbit.de\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file kt in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.database.DataSetObserver;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.PointF;\nimport android.graphics.Rect;\nimport android.graphics.drawable.GradientDrawable;\nimport android.graphics.drawable.GradientDrawable.Orientation;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.SoundEffectConstants;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.widget.AbsListView;\nimport android.widget.HeaderViewListAdapter;\nimport android.widget.ListAdapter;\nimport android.widget.ListView;\nimport android.widget.SectionIndexer;\n\nimport com.boredream.bdcodehelper.BuildConfig;\n\n/**\n * ListView, which is capable to pin section views at its top while the rest is still scrolled.\n */\npublic class PinnedSectionListView extends ListView {\n\n\n    //-- inner classes\n\n\t/** List adapter to be implemented for being used with PinnedSectionListView adapter. */\n\tpublic static interface PinnedSectionListAdapter extends ListAdapter {\n\t\t/** This method shall return 'true' if views of given type has to be pinned. */\n\t\tboolean isItemViewTypePinned(int viewType);\n\t}\n\n\t/** Wrapper class for pinned section view and its position in the list. */\n\tstatic class PinnedSection {\n\t\tpublic View view;\n\t\tpublic int position;\n\t\tpublic long id;\n\t}\n\n\t//-- class fields\n\n    // fields used for handling touch events\n    private final Rect mTouchRect = new Rect();\n    private final PointF mTouchPoint = new PointF();\n    private int mTouchSlop;\n    private View mTouchTarget;\n    private MotionEvent mDownEvent;\n\n    // fields used for drawing shadow under a pinned section\n    private GradientDrawable mShadowDrawable;\n    private int mSectionsDistanceY;\n    private int mShadowHeight;\n\n    /** Delegating listener, can be null. */\n    OnScrollListener mDelegateOnScrollListener;\n\n    /** Shadow for being recycled, can be null. */\n    PinnedSection mRecycleSection;\n\n    /** shadow instance with a pinned view, can be null. */\n    PinnedSection mPinnedSection;\n\n    /** Pinned view Y-translation. We use it to stick pinned view to the next section. */\n    int mTranslateY;\n\n\t/** Scroll listener which does the magic */\n\tprivate final OnScrollListener mOnScrollListener = new OnScrollListener() {\n\n\t\t// boredream-view which need to hide\n\t\tprivate View hideView;\n\n\t\t@Override public void onScrollStateChanged(AbsListView view, int scrollState) {\n\t\t\tif (mDelegateOnScrollListener != null) { // delegate\n\t\t\t\tmDelegateOnScrollListener.onScrollStateChanged(view, scrollState);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {\n\n            if (mDelegateOnScrollListener != null) { // delegate\n                mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);\n            }\n\n            // get expected adapter or fail fast\n            ListAdapter adapter = getAdapter();\n            if (adapter == null || visibleItemCount == 0) return; // nothing to do\n\n            final boolean isFirstVisibleItemSection =\n                    isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem));\n\n            if (isFirstVisibleItemSection) {\n                View sectionView = getChildAt(0);\n                if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow\n                    destroyPinnedShadow();\n                \t// boredream-re show pinned item of list\n                \tif(hideView != null && hideView.getVisibility() == View.INVISIBLE) {\n                \t\thideView.setVisibility(View.VISIBLE);\n                \t}\n                } else { // section doesn't stick to the top, make sure we have a pinned shadow\n                    ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount);\n                    \n                    // boredream-hide pinned item of list\n                    if(mPinnedSection != null\n                    \t\t&& firstVisibleItem == mPinnedSection.position\n                    \t\t&& sectionView.getTop() < 0) {\n                    \thideView = sectionView;\n                    \tsectionView.setVisibility(View.INVISIBLE);\n                    }\n                }\n            } else { // section is not at the first visible position\n            \t// boredream-re show pinned item of list\n            \tif(hideView != null && hideView.getVisibility() == View.INVISIBLE) {\n            \t\thideView.setVisibility(View.VISIBLE);\n            \t}\n            \t\n                int sectionPosition = findCurrentSectionPosition(firstVisibleItem);\n                if (sectionPosition > -1) { // we have section position\n                    ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount);\n                } else { // there is no section for the first visible item, destroy shadow\n                    destroyPinnedShadow();\n                }\n            }\n\t\t};\n\n\t};\n\n\t/** Default change observer. */\n    private final DataSetObserver mDataSetObserver = new DataSetObserver() {\n        @Override public void onChanged() {\n            recreatePinnedShadow();\n        };\n        @Override public void onInvalidated() {\n            recreatePinnedShadow();\n        }\n    };\n\n\t//-- constructors\n\n    public PinnedSectionListView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView();\n    }\n\n    public PinnedSectionListView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        initView();\n    }\n\n    private void initView() {\n        setOnScrollListener(mOnScrollListener);\n        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();\n        initShadow(true);\n    }\n\n    //-- public API methods\n\n    public void setShadowVisible(boolean visible) {\n        initShadow(visible);\n        if (mPinnedSection != null) {\n            View v = mPinnedSection.view;\n            invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight);\n        }\n    }\n\n    //-- pinned section drawing methods\n\n    public void initShadow(boolean visible) {\n        if (visible) {\n            if (mShadowDrawable == null) {\n                mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM,\n                        new int[] { Color.parseColor(\"#ffa0a0a0\"), Color.parseColor(\"#50a0a0a0\"), Color.parseColor(\"#00a0a0a0\")});\n                mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density);\n            }\n        } else {\n            if (mShadowDrawable != null) {\n                mShadowDrawable = null;\n                mShadowHeight = 0;\n            }\n        }\n    }\n\n\t/** Create shadow wrapper with a pinned view for a view at given position */\n\tvoid createPinnedShadow(int position) {\n\n\t\t// try to recycle shadow\n\t\tPinnedSection pinnedShadow = mRecycleSection;\n\t\tmRecycleSection = null;\n\n\t\t// create new shadow, if needed\n\t\tif (pinnedShadow == null) pinnedShadow = new PinnedSection();\n\t\t// request new view using recycled view, if such\n\t\tView pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedSectionListView.this);\n\n\t\t// read layout parameters\n\t\tLayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams();\n\t\tif (layoutParams == null) {\n//\t\t    layoutParams = (LayoutParams) generateDefaultLayoutParams();\n\t\t\t// boredream-fix bug\n\t\t\tlayoutParams = (LayoutParams) new LayoutParams(\n\t                LayoutParams.MATCH_PARENT,\n\t                LayoutParams.WRAP_CONTENT, 0);\n\t\t    pinnedView.setLayoutParams(layoutParams);\n\t\t}\n\n\t\tint heightMode = MeasureSpec.getMode(layoutParams.height);\n\t\tint heightSize = MeasureSpec.getSize(layoutParams.height);\n\n\t\tif (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY;\n\n\t\tint maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom();\n\t\tif (heightSize > maxHeight) heightSize = maxHeight;\n\n\t\t// measure & layout\n\t\tint ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY);\n\t\tint hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode);\n\t\tpinnedView.measure(ws, hs);\n\t\tpinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight());\n\t\tmTranslateY = 0;\n\n\t\t// initialize pinned shadow\n\t\tpinnedShadow.view = pinnedView;\n\t\tpinnedShadow.position = position;\n\t\tpinnedShadow.id = getAdapter().getItemId(position);\n\n\t\t// store pinned shadow\n\t\tmPinnedSection = pinnedShadow;\n\t}\n\n\t/** Destroy shadow wrapper for currently pinned view */\n\tvoid destroyPinnedShadow() {\n\t    if (mPinnedSection != null) {\n\t        // keep shadow for being recycled later\n\t        mRecycleSection = mPinnedSection;\n\t        mPinnedSection = null;\n\t    }\n\t}\n\n\t/** Makes sure we have an actual pinned shadow for given position. */\n    void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) {\n        if (visibleItemCount < 2) { // no need for creating shadow at all, we have a single visible item\n            destroyPinnedShadow();\n            return;\n        }\n\n        if (mPinnedSection != null\n                && mPinnedSection.position != sectionPosition) { // invalidate shadow, if required\n            destroyPinnedShadow();\n        }\n\n        if (mPinnedSection == null) { // create shadow, if empty\n            createPinnedShadow(sectionPosition);\n        }\n\n        // align shadow according to next section position, if needed\n        int nextPosition = sectionPosition + 1;\n        if (nextPosition < getCount()) {\n            int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition,\n                    visibleItemCount - (nextPosition - firstVisibleItem));\n            if (nextSectionPosition > -1) {\n                View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem);\n                final int bottom = mPinnedSection.view.getBottom() + getPaddingTop();\n                mSectionsDistanceY = nextSectionView.getTop() - bottom;\n                if (mSectionsDistanceY < 0) {\n                    // next section overlaps pinned shadow, move it up\n                    mTranslateY = mSectionsDistanceY;\n                } else {\n                    // next section does not overlap with pinned, stick to top\n                    mTranslateY = 0;\n                }\n            } else {\n                // no other sections are visible, stick to top\n                mTranslateY = 0;\n                mSectionsDistanceY = Integer.MAX_VALUE;\n            }\n        }\n\n    }\n\n\tint findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) {\n\t\tListAdapter adapter = getAdapter();\n\n        int adapterDataCount = adapter.getCount();\n        if (getLastVisiblePosition() >= adapterDataCount) return -1; // dataset has changed, no candidate\n\n        if (firstVisibleItem+visibleItemCount >= adapterDataCount){//added to prevent index Outofbound (in case)\n            visibleItemCount = adapterDataCount-firstVisibleItem;\n        }\n\n\t\tfor (int childIndex = 0; childIndex < visibleItemCount; childIndex++) {\n\t\t\tint position = firstVisibleItem + childIndex;\n\t\t\tint viewType = adapter.getItemViewType(position);\n\t\t\tif (isItemViewTypePinned(adapter, viewType)) return position;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tint findCurrentSectionPosition(int fromPosition) {\n\t\tListAdapter adapter = getAdapter();\n\n\t\tif (fromPosition >= adapter.getCount()) return -1; // dataset has changed, no candidate\n\t\t\n\t\tif (adapter instanceof SectionIndexer) {\n\t\t\t// try fast way by asking section indexer\n\t\t\tSectionIndexer indexer = (SectionIndexer) adapter;\n\t\t\tint sectionPosition = indexer.getSectionForPosition(fromPosition);\n\t\t\tint itemPosition = indexer.getPositionForSection(sectionPosition);\n\t\t\tint typeView = adapter.getItemViewType(itemPosition);\n\t\t\tif (isItemViewTypePinned(adapter, typeView)) {\n\t\t\t\treturn itemPosition;\n\t\t\t} // else, no luck\n\t\t}\n\n\t\t// try slow way by looking through to the next section item above\n\t\tfor (int position=fromPosition; position>=0; position--) {\n\t\t\tint viewType = adapter.getItemViewType(position);\n\t\t\tif (isItemViewTypePinned(adapter, viewType)) return position;\n\t\t}\n\t\treturn -1; // no candidate found\n\t}\n\n\tvoid recreatePinnedShadow() {\n\t    destroyPinnedShadow();\n        ListAdapter adapter = getAdapter();\n        if (adapter != null && adapter.getCount() > 0) {\n            int firstVisiblePosition = getFirstVisiblePosition();\n            int sectionPosition = findCurrentSectionPosition(firstVisiblePosition);\n            if (sectionPosition == -1) return; // no views to pin, exit\n            ensureShadowForPosition(sectionPosition,\n                    firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition);\n        }\n\t}\n\n\t@Override\n\tpublic void setOnScrollListener(OnScrollListener listener) {\n\t\tif (listener == mOnScrollListener) {\n\t\t\tsuper.setOnScrollListener(listener);\n\t\t} else {\n\t\t\tmDelegateOnScrollListener = listener;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onRestoreInstanceState(Parcelable state) {\n\t\tsuper.onRestoreInstanceState(state);\n\t\tpost(new Runnable() {\n\t\t\t@Override public void run() { // restore pinned view after configuration change\n\t\t\t    recreatePinnedShadow();\n\t\t\t}\n\t\t});\n\t}\n\n\t@Override\n\tpublic void setAdapter(ListAdapter adapter) {\n\n\t    // assert adapter in debug mode\n\t\tif (BuildConfig.DEBUG && adapter != null) {\n\t\t\tif (!(adapter instanceof PinnedSectionListAdapter))\n\t\t\t\tthrow new IllegalArgumentException(\"Does your adapter implement PinnedSectionListAdapter?\");\n\t\t\tif (adapter.getViewTypeCount() < 2)\n\t\t\t\tthrow new IllegalArgumentException(\"Does your adapter handle at least two types\" +\n\t\t\t\t\t\t\" of views in getViewTypeCount() method: items and sections?\");\n\t\t}\n\n\t\t// unregister observer at old adapter and register on new one\n\t\tListAdapter oldAdapter = getAdapter();\n\t\tif (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver);\n\t\tif (adapter != null) adapter.registerDataSetObserver(mDataSetObserver);\n\n\t\t// destroy pinned shadow, if new adapter is not same as old one\n\t\tif (oldAdapter != adapter) destroyPinnedShadow();\n\n\t\tsuper.setAdapter(adapter);\n\t}\n\n\t@Override\n\tprotected void onLayout(boolean changed, int l, int t, int r, int b) {\n\t    super.onLayout(changed, l, t, r, b);\n        if (mPinnedSection != null) {\n            int parentWidth = r - l - getPaddingLeft() - getPaddingRight();\n            int shadowWidth = mPinnedSection.view.getWidth();\n            if (parentWidth != shadowWidth) {\n                recreatePinnedShadow();\n            }\n        }\n\t}\n\n\t@Override\n\tprotected void dispatchDraw(Canvas canvas) {\n\t\tsuper.dispatchDraw(canvas);\n\n\t\tif (mPinnedSection != null) {\n\n\t\t\t// prepare variables\n\t\t\tint pLeft = getListPaddingLeft();\n\t\t\tint pTop = getListPaddingTop();\n\t\t\tView view = mPinnedSection.view;\n\n\t\t\t// draw child\n\t\t\tcanvas.save();\n\n\t\t\tint clipHeight = view.getHeight() +\n\t\t\t        (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY));\n\t\t\tcanvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);\n\n\t\t\tcanvas.translate(pLeft, pTop + mTranslateY);\n\t\t\tdrawChild(canvas, mPinnedSection.view, getDrawingTime());\n\n\t\t\tif (mShadowDrawable != null && mSectionsDistanceY > 0) {\n\t\t\t    mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),\n\t\t\t            mPinnedSection.view.getBottom(),\n\t\t\t            mPinnedSection.view.getRight(),\n\t\t\t            mPinnedSection.view.getBottom() + mShadowHeight);\n\t\t\t    mShadowDrawable.draw(canvas);\n\t\t\t}\n\n\t\t\tcanvas.restore();\n\t\t}\n\t}\n\n\t//-- touch handling methods\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent ev) {\n\n        final float x = ev.getX();\n        final float y = ev.getY();\n        final int action = ev.getAction();\n\n        if (action == MotionEvent.ACTION_DOWN\n                && mTouchTarget == null\n                && mPinnedSection != null\n                && isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target\n\n            // user touched pinned view\n            mTouchTarget = mPinnedSection.view;\n            mTouchPoint.x = x;\n            mTouchPoint.y = y;\n\n            // copy down event for eventually be used later\n            mDownEvent = MotionEvent.obtain(ev);\n        }\n\n        if (mTouchTarget != null) {\n            if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view\n                mTouchTarget.dispatchTouchEvent(ev);\n            }\n\n            if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view\n                super.dispatchTouchEvent(ev);\n                performPinnedItemClick();\n                clearTouchTarget();\n\n            } else if (action == MotionEvent.ACTION_CANCEL) { // cancel\n                clearTouchTarget();\n\n            } else if (action == MotionEvent.ACTION_MOVE) {\n                if (Math.abs(y - mTouchPoint.y) > mTouchSlop) {\n\n                    // cancel sequence on touch target\n                    MotionEvent event = MotionEvent.obtain(ev);\n                    event.setAction(MotionEvent.ACTION_CANCEL);\n                    mTouchTarget.dispatchTouchEvent(event);\n                    event.recycle();\n\n                    // provide correct sequence to super class for further handling\n                    super.dispatchTouchEvent(mDownEvent);\n                    super.dispatchTouchEvent(ev);\n                    clearTouchTarget();\n\n                }\n            }\n\n            return true;\n        }\n\n        // call super if this was not our pinned view\n        return super.dispatchTouchEvent(ev);\n    }\n\n    private boolean isPinnedViewTouched(View view, float x, float y) {\n        view.getHitRect(mTouchRect);\n\n        // by taping top or bottom padding, the list performs on click on a border item.\n        // we don't add top padding here to keep behavior consistent.\n        mTouchRect.top += mTranslateY;\n\n        mTouchRect.bottom += mTranslateY + getPaddingTop();\n        mTouchRect.left += getPaddingLeft();\n        mTouchRect.right -= getPaddingRight();\n        return mTouchRect.contains((int)x, (int)y);\n    }\n\n    private void clearTouchTarget() {\n        mTouchTarget = null;\n        if (mDownEvent != null) {\n            mDownEvent.recycle();\n            mDownEvent = null;\n        }\n    }\n\n    private boolean performPinnedItemClick() {\n        if (mPinnedSection == null) return false;\n\n        OnItemClickListener listener = getOnItemClickListener();\n        if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) {\n            View view =  mPinnedSection.view;\n            playSoundEffect(SoundEffectConstants.CLICK);\n            if (view != null) {\n                view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);\n            }\n            listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id);\n            return true;\n        }\n        return false;\n    }\n\n    public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) {\n        if (adapter instanceof HeaderViewListAdapter) {\n            adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();\n        }\n        return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/PositionBar.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n@SuppressLint(\"ClickableViewAccessibility\")\npublic class PositionBar extends LinearLayout {\n\n\tprivate String[] mItems = { \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\",\n\t\t\t\"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\",\n\t\t\t\"V\", \"W\", \"X\", \"Y\", \"Z\" };\n\n\tprivate OnPositionChangedListener listener;\n\n\tpublic void setOnPositionChangedListener(OnPositionChangedListener listener) {\n\t\tthis.listener = listener;\n\t}\n\n\tpublic PositionBar(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t\t\n\t\tsetOrientation(VERTICAL);\n\t\tsetBackgroundResource(R.drawable.cirrect_5a_primary_solid);\n\t}\n\t\n\tpublic void setItems(String[] items) {\n\t\tmItems = items;\n\t\tfor (CharSequence s : mItems) {\n\t\t\tTextView t = new TextView(getContext());\n\t\t\tt.setText(s);\n\t\t\tt.setTextSize(10);\n\t\t\tLayoutParams params = new LayoutParams(\n\t\t\t\t\tViewGroup.LayoutParams.WRAP_CONTENT, 0);\n\t\t\tparams.weight = 1;\n\t\t\tt.setLayoutParams(params);\n\t\t\tt.setTextColor(getResources().getColor(R.color.txt_black));\n\t\t\taddView(t);\n\t\t}\n\t}\n\n\tpublic String[] getItems() {\n\t\treturn mItems;\n\t}\n\n\tpublic PositionBar(Context context) {\n\t\tthis(context, null);\n\t}\n\n\t@Override\n\tpublic boolean onTouchEvent(MotionEvent ev) {\n\t\tfinal int action = ev.getAction();\n\t\tTextView child = null;\n\n\t\tswitch (action & MotionEvent.ACTION_MASK) {\n\t\tcase MotionEvent.ACTION_DOWN:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_10a_primary_solid);\n\t\t\tchild = findChildByLocation(ev.getX(), ev.getY());\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(child==null?\"\":child.getText().toString());\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MotionEvent.ACTION_MOVE:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_10a_primary_solid);\n\t\t\tchild = findChildByLocation(ev.getX(), ev.getY());\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(child==null?\"\":child.getText().toString());\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MotionEvent.ACTION_UP:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_5a_primary_solid);\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(\"\");\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate TextView findChildByLocation(float x, float y) {\n\t\tTextView child = null;\n\t\tint mContentTop = getChildAt(0).getTop();\n\t\tint mContentBottom = getChildAt(getChildCount() - 1).getBottom();\n\t\tint defSize = (mContentBottom - mContentTop) / mItems.length;\n\n\t\tint index = (int) ((y - mContentTop) / defSize);\n\t\tif (index >= 0 && index < mItems.length\n\t\t\t\t&& x >= 0 && x <= getWidth()) {\n\t\t\tchild = (TextView) getChildAt(index);\n\t\t}\n\t\treturn child;\n\t}\n\n\tpublic interface OnPositionChangedListener {\n\t\tvoid onPositionSelected(String key);\n\t}\n\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightGridView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.GridView;\n\npublic class WrapHeightGridView extends GridView {\n\n    public WrapHeightGridView(Context context) {\n        super(context);\n    }\n\n    public WrapHeightGridView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public WrapHeightGridView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int heightSpec = MeasureSpec.makeMeasureSpec(\n                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);\n\n        super.onMeasure(widthMeasureSpec, heightSpec);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightLinearLayoutManager.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * 用作wrap_content的RecyclerView\n */\npublic class WrapHeightLinearLayoutManager extends LinearLayoutManager {\n\n    public WrapHeightLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {\n        super(context, orientation, reverseLayout);\n    }\n\n    private int[] mMeasuredDimension = new int[2];\n\n    @Override\n    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,\n                          int widthSpec, int heightSpec) {\n        final int widthMode = View.MeasureSpec.getMode(widthSpec);\n        final int heightMode = View.MeasureSpec.getMode(heightSpec);\n        final int widthSize = View.MeasureSpec.getSize(widthSpec);\n        final int heightSize = View.MeasureSpec.getSize(heightSpec);\n        int width = 0;\n        int height = 0;\n        for (int i = 0; i < getItemCount(); i++) {\n            measureScrapChild(recycler, i,\n                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),\n                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),\n                    mMeasuredDimension);\n\n            if (getOrientation() == HORIZONTAL) {\n                width = width + mMeasuredDimension[0];\n                if (i == 0) {\n                    height = mMeasuredDimension[1];\n                }\n            } else {\n                height = height + mMeasuredDimension[1];\n                if (i == 0) {\n                    width = mMeasuredDimension[0];\n                }\n            }\n        }\n        switch (widthMode) {\n            case View.MeasureSpec.EXACTLY:\n                width = widthSize;\n            case View.MeasureSpec.AT_MOST:\n            case View.MeasureSpec.UNSPECIFIED:\n        }\n\n        switch (heightMode) {\n            case View.MeasureSpec.EXACTLY:\n                height = heightSize;\n            case View.MeasureSpec.AT_MOST:\n            case View.MeasureSpec.UNSPECIFIED:\n        }\n\n        setMeasuredDimension(width, height);\n    }\n\n    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,\n                                   int heightSpec, int[] measuredDimension) {\n        View view = recycler.getViewForPosition(position);\n        if (view != null) {\n            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();\n            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,\n                    getPaddingLeft() + getPaddingRight(), p.width);\n            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,\n                    getPaddingTop() + getPaddingBottom(), p.height);\n            view.measure(childWidthSpec, childHeightSpec);\n            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;\n            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;\n            recycler.recycleView(view);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightListView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.ListView;\n\npublic class WrapHeightListView extends ListView {\n\n    public WrapHeightListView(Context context) {\n        super(context);\n    }\n\n    public WrapHeightListView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public WrapHeightListView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int heightSpec = MeasureSpec.makeMeasureSpec(\n                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);\n\n        super.onMeasure(widthMeasureSpec, heightSpec);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/ItemsRange.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Range for visible items.\n */\npublic class ItemsRange {\n\t// First item number\n\tprivate int first;\n\t\n\t// Items count\n\tprivate int count;\n\n\t/**\n\t * Default constructor. Creates an empty range\n\t */\n    public ItemsRange() {\n        this(0, 0);\n    }\n    \n\t/**\n\t * Constructor\n\t * @param first the number of first item\n\t * @param count the count of items\n\t */\n\tpublic ItemsRange(int first, int count) {\n\t\tthis.first = first;\n\t\tthis.count = count;\n\t}\n\t\n\t/**\n\t * Gets number of  first item\n\t * @return the number of the first item\n\t */\n\tpublic int getFirst() {\n\t\treturn first;\n\t}\n\t\n\t/**\n\t * Gets number of last item\n\t * @return the number of last item\n\t */\n\tpublic int getLast() {\n\t\treturn getFirst() + getCount() - 1;\n\t}\n\t\n\t/**\n\t * Get items count\n\t * @return the count of items\n\t */\n\tpublic int getCount() {\n\t\treturn count;\n\t}\n\t\n\t/**\n\t * Tests whether item is contained by range\n\t * @param index the item number\n\t * @return true if item is contained\n\t */\n\tpublic boolean contains(int index) {\n\t\treturn index >= getFirst() && index <= getLast();\n\t}\n}"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelChangedListener.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel changed listener interface.\n * <p>The onChanged() method is called whenever current wheel positions is changed:\n * <li> New Wheel position is set\n * <li> Wheel view is scrolled\n */\npublic interface OnWheelChangedListener {\n\t/**\n\t * Callback method to be invoked when current item changed\n\t * @param wheel the wheel view whose state has changed\n\t * @param oldValue the old value of current item\n\t * @param newValue the new value of current item\n\t */\n\tvoid onChanged(WheelView wheel, int oldValue, int newValue);\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelClickedListener.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel clicked listener interface.\n * <p>The onItemClicked() method is called whenever a wheel item is clicked\n * <li> New Wheel position is set\n * <li> Wheel view is scrolled\n */\npublic interface OnWheelClickedListener {\n    /**\n     * Callback method to be invoked when current item clicked\n     * @param wheel the wheel view\n     * @param itemIndex the index of clicked item\n     */\n    void onItemClicked(WheelView wheel, int itemIndex);\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelScrollListener.java",
    "content": "/*\n *  Copyright 2010 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel scrolled listener interface.\n */\npublic interface OnWheelScrollListener {\n\t/**\n\t * Callback method to be invoked when scrolling started.\n\t * @param wheel the wheel view whose state has changed.\n\t */\n\tvoid onScrollingStarted(WheelView wheel);\n\t\n\t/**\n\t * Callback method to be invoked when scrolling ended.\n\t * @param wheel the wheel view whose state has changed.\n\t */\n\tvoid onScrollingFinished(WheelView wheel);\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelAdapter.java",
    "content": "/*\n *  Copyright 2010 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel adapter interface\n * \n * @deprecated Use WheelViewAdapter\n */\npublic interface WheelAdapter {\n\t/**\n\t * Gets items count\n\t * @return the count of wheel items\n\t */\n\tpublic int getItemsCount();\n\t\n\t/**\n\t * Gets a wheel item by index.\n\t * \n\t * @param index the item index\n\t * @return the wheel item text or null\n\t */\n\tpublic String getItem(int index);\n\t\n\t/**\n\t * Gets maximum item length. It is used to determine the wheel width. \n\t * If -1 is returned there will be used the default wheel width.\n\t * \n\t * @return the maximum item length or -1\n\t */\n\tpublic int getMaximumLength();\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelRecycle.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.view.View;\nimport android.widget.LinearLayout;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Recycle stores wheel items to reuse. \n */\npublic class WheelRecycle {\n\t// Cached items\n\tprivate List<View> items;\n\t\n\t// Cached empty items\n\tprivate List<View> emptyItems;\n\t\n\t// Wheel view\n\tprivate WheelView wheel;\n\t\n\t/**\n\t * Constructor\n\t * @param wheel the wheel view\n\t */\n\tpublic WheelRecycle(WheelView wheel) {\n\t\tthis.wheel = wheel;\n\t}\n\n\t/**\n\t * Recycles items from specified layout.\n\t * There are saved only items not included to specified range.\n\t * All the cached items are removed from original layout.\n\t * \n\t * @param layout the layout containing items to be cached\n\t * @param firstItem the number of first item in layout\n\t * @param range the range of current wheel items \n\t * @return the new value of first item number\n\t */\n\tpublic int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) {\n\t\tint index = firstItem;\n\t\tfor (int i = 0; i < layout.getChildCount();) {\n\t\t\tif (!range.contains(index)) {\n\t\t\t\trecycleView(layout.getChildAt(i), index);\n\t\t\t\tlayout.removeViewAt(i);\n\t\t\t\tif (i == 0) { // first item\n\t\t\t\t\tfirstItem++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ti++; // go to next item\n\t\t\t}\n\t\t\tindex++;\n\t\t}\n\t\treturn firstItem;\n\t}\n\t\n\t/**\n\t * Gets item view\n\t * @return the cached view\n\t */\n\tpublic View getItem() {\n\t\treturn getCachedView(items);\n\t}\n\n\t/**\n\t * Gets empty item view\n\t * @return the cached empty view\n\t */\n\tpublic View getEmptyItem() {\n\t\treturn getCachedView(emptyItems);\n\t}\n\t\n\t/**\n\t * Clears all views \n\t */\n\tpublic void clearAll() {\n\t\tif (items != null) {\n\t\t\titems.clear();\n\t\t}\n\t\tif (emptyItems != null) {\n\t\t\temptyItems.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Adds view to specified cache. Creates a cache list if it is null.\n\t * @param view the view to be cached\n\t * @param cache the cache list\n\t * @return the cache list\n\t */\n\tprivate List<View> addView(View view, List<View> cache) {\n\t\tif (cache == null) {\n\t\t\tcache = new LinkedList<View>();\n\t\t}\n\t\t\n\t\tcache.add(view);\n\t\treturn cache;\n\t}\n\n\t/**\n\t * Adds view to cache. Determines view type (item view or empty one) by index.\n\t * @param view the view to be cached\n\t * @param index the index of view\n\t */\n\tprivate void recycleView(View view, int index) {\n\t\tint count = wheel.getViewAdapter().getItemsCount();\n\n\t\tif ((index < 0 || index >= count) && !wheel.isCyclic()) {\n\t\t\t// empty view\n\t\t\temptyItems = addView(view, emptyItems);\n\t\t} else {\n\t\t\twhile (index < 0) {\n\t\t\t\tindex = count + index;\n\t\t\t}\n\t\t\tindex %= count;\n\t\t\titems = addView(view, items);\n\t\t}\n\t}\n\t\n\t/**\n\t * Gets view from specified cache.\n\t * @param cache the cache\n\t * @return the first view from cache.\n\t */\n\tprivate View getCachedView(List<View> cache) {\n\t\tif (cache != null && cache.size() > 0) {\n\t\t\tView view = cache.get(0);\n\t\t\tcache.remove(0);\n\t\t\treturn view;\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelScroller.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\nimport android.view.GestureDetector.SimpleOnGestureListener;\nimport android.view.animation.Interpolator;\nimport android.widget.Scroller;\n\n/**\n * Scroller class handles scrolling events and updates the \n */\npublic class WheelScroller {\n    /**\n     * Scrolling listener interface\n     */\n    public interface ScrollingListener {\n        /**\n         * Scrolling callback called when scrolling is performed.\n         * @param distance the distance to scroll\n         */\n        void onScroll(int distance);\n\n        /**\n         * Starting callback called when scrolling is started\n         */\n        void onStarted();\n        \n        /**\n         * Finishing callback called after justifying\n         */\n        void onFinished();\n        \n        /**\n         * Justifying callback called to justify a view when scrolling is ended\n         */\n        void onJustify();\n    }\n    \n    /** Scrolling duration */\n    private static final int SCROLLING_DURATION = 400;\n\n    /** Minimum delta for scrolling */\n    public static final int MIN_DELTA_FOR_SCROLLING = 1;\n\n    // Listener\n    private ScrollingListener listener;\n    \n    // Context\n    private Context context;\n    \n    // Scrolling\n    private GestureDetector gestureDetector;\n    private Scroller scroller;\n    private int lastScrollY;\n    private float lastTouchedY;\n    private boolean isScrollingPerformed;\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param listener the scrolling listener\n     */\n    public WheelScroller(Context context, ScrollingListener listener) {\n        gestureDetector = new GestureDetector(context, gestureListener);\n        gestureDetector.setIsLongpressEnabled(false);\n        \n        scroller = new Scroller(context);\n\n        this.listener = listener;\n        this.context = context;\n    }\n    \n    /**\n     * Set the the specified scrolling interpolator\n     * @param interpolator the interpolator\n     */\n    public void setInterpolator(Interpolator interpolator) {\n        scroller.forceFinished(true);\n        scroller = new Scroller(context, interpolator);\n    }\n    \n    /**\n     * Scroll the wheel\n     * @param distance the scrolling distance\n     * @param time the scrolling duration\n     */\n    public void scroll(int distance, int time) {\n        scroller.forceFinished(true);\n\n        lastScrollY = 0;\n        \n        scroller.startScroll(0, 0, 0, distance, time != 0 ? time : SCROLLING_DURATION);\n        setNextMessage(MESSAGE_SCROLL);\n        \n        startScrolling();\n    }\n   \n    /**\n     * Stops scrolling\n     */\n    public void stopScrolling() {\n        scroller.forceFinished(true);\n    }\n    \n    /**\n     * Handles Touch event \n     * @param event the motion event\n     * @return\n     */\n    public boolean onTouchEvent(MotionEvent event) {\n        switch (event.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n                lastTouchedY = event.getY();\n                scroller.forceFinished(true);\n                clearMessages();\n                break;\n    \n            case MotionEvent.ACTION_MOVE:\n                // perform scrolling\n                int distanceY = (int)(event.getY() - lastTouchedY);\n                if (distanceY != 0) {\n                    startScrolling();\n                    listener.onScroll(distanceY);\n                    lastTouchedY = event.getY();\n                }\n                break;\n        }\n        \n        if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {\n            justify();\n        }\n\n        return true;\n    }\n    \n    // gesture listener\n    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {\n        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {\n            // Do scrolling in onTouchEvent() since onScroll() are not call immediately\n            //  when user touch and move the wheel\n            return true;\n        }\n        \n        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {\n            lastScrollY = 0;\n            final int maxY = 0x7FFFFFFF;\n            final int minY = -maxY;\n            scroller.fling(0, lastScrollY, 0, (int) -velocityY, 0, 0, minY, maxY);\n            setNextMessage(MESSAGE_SCROLL);\n            return true;\n        }\n    };\n\n    // Messages\n    private final int MESSAGE_SCROLL = 0;\n    private final int MESSAGE_JUSTIFY = 1;\n    \n    /**\n     * Set next message to queue. Clears queue before.\n     * \n     * @param message the message to set\n     */\n    private void setNextMessage(int message) {\n        clearMessages();\n        animationHandler.sendEmptyMessage(message);\n    }\n\n    /**\n     * Clears messages from queue\n     */\n    private void clearMessages() {\n        animationHandler.removeMessages(MESSAGE_SCROLL);\n        animationHandler.removeMessages(MESSAGE_JUSTIFY);\n    }\n    \n    // animation handler\n    private Handler animationHandler = new Handler() {\n        public void handleMessage(Message msg) {\n            scroller.computeScrollOffset();\n            int currY = scroller.getCurrY();\n            int delta = lastScrollY - currY;\n            lastScrollY = currY;\n            if (delta != 0) {\n                listener.onScroll(delta);\n            }\n            \n            // scrolling is not finished when it comes to final Y\n            // so, finish it manually \n            if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {\n                currY = scroller.getFinalY();\n                scroller.forceFinished(true);\n            }\n            if (!scroller.isFinished()) {\n                animationHandler.sendEmptyMessage(msg.what);\n            } else if (msg.what == MESSAGE_SCROLL) {\n                justify();\n            } else {\n                finishScrolling();\n            }\n        }\n    };\n    \n    /**\n     * Justifies wheel\n     */\n    private void justify() {\n        listener.onJustify();\n        setNextMessage(MESSAGE_JUSTIFY);\n    }\n\n    /**\n     * Starts scrolling\n     */\n    private void startScrolling() {\n        if (!isScrollingPerformed) {\n            isScrollingPerformed = true;\n            listener.onStarted();\n        }\n    }\n\n    /**\n     * Finishes scrolling\n     */\n    void finishScrolling() {\n        if (isScrollingPerformed) {\n            listener.onFinished();\n            isScrollingPerformed = false;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelView.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n * \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.content.Context;\nimport android.database.DataSetObserver;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.GradientDrawable;\nimport android.graphics.drawable.GradientDrawable.Orientation;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup.LayoutParams;\nimport android.view.animation.Interpolator;\nimport android.widget.LinearLayout;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.view.wheel.adapters.WheelViewAdapter;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Numeric wheel view.\n * \n * @author Yuri Kanivets\n */\npublic class WheelView extends View {\n\n\t/** Top and bottom shadows colors */\n\t/*/ Modified by wulianghuan 2014-11-25\n\tprivate int[] SHADOWS_COLORS = new int[] { 0xFF111111,\n\t\t\t0x00AAAAAA, 0x00AAAAAA };\n\t//*/\n\tprivate int[] SHADOWS_COLORS = new int[] { 0xefE9E9E9,\n\t\t\t0xcfE9E9E9, 0x3fE9E9E9 };\n\n\t/** Top and bottom items offset (to hide that) */\n\tprivate static final int ITEM_OFFSET_PERCENT = 0;\n\n\t/** Left and right padding value */\n\tprivate static final int PADDING = 10;\n\n\t/** Default count of visible items */\n\tprivate static final int DEF_VISIBLE_ITEMS = 5;\n\n\t// Wheel Values\n\tprivate int currentItem = 0;\n\n\t// Count of visible items\n\tprivate int visibleItems = DEF_VISIBLE_ITEMS;\n\n\t// Item height\n\tprivate int itemHeight = 0;\n\n\t// Center Line\n\tprivate Drawable centerDrawable;\n\n\t// Wheel drawables\n\tprivate int wheelBackground = R.drawable.wheel_bg;\n\tprivate int wheelForeground = R.drawable.wheel_val;\n\n\t// Shadows drawables\n\tprivate GradientDrawable topShadow;\n\tprivate GradientDrawable bottomShadow;\n\n\t// Draw Shadows\n\tprivate boolean drawShadows = true;\n\n\t// Scrolling\n\tprivate WheelScroller scroller;\n\tprivate boolean isScrollingPerformed;\n\tprivate int scrollingOffset;\n\n\t// Cyclic\n\tboolean isCyclic = false;\n\n\t// Items layout\n\tprivate LinearLayout itemsLayout;\n\n\t// The number of first item in layout\n\tprivate int firstItem;\n\n\t// View adapter\n\tprivate WheelViewAdapter viewAdapter;\n\n\t// Recycle\n\tprivate WheelRecycle recycle = new WheelRecycle(this);\n\n\t// Listeners\n\tprivate List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();\n\tprivate List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();\n\tprivate List<OnWheelClickedListener> clickingListeners = new LinkedList<OnWheelClickedListener>();\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context, AttributeSet attrs, int defStyle) {\n\t\tsuper(context, attrs, defStyle);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context) {\n\t\tsuper(context);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Initializes class data\n\t * @param context the context\n\t */\n\tprivate void initData(Context context) {\n\t\tscroller = new WheelScroller(getContext(), scrollingListener);\n\t}\n\n\t// Scrolling listener\n\tWheelScroller.ScrollingListener scrollingListener = new WheelScroller.ScrollingListener() {\n\t\t@Override\n\t\tpublic void onStarted() {\n\t\t\tisScrollingPerformed = true;\n\t\t\tnotifyScrollingListenersAboutStart();\n\t\t}\n\n\t\t@Override\n\t\tpublic void onScroll(int distance) {\n\t\t\tdoScroll(distance);\n\n\t\t\tint height = getHeight();\n\t\t\tif (scrollingOffset > height) {\n\t\t\t\tscrollingOffset = height;\n\t\t\t\tscroller.stopScrolling();\n\t\t\t} else if (scrollingOffset < -height) {\n\t\t\t\tscrollingOffset = -height;\n\t\t\t\tscroller.stopScrolling();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void onFinished() {\n\t\t\tif (isScrollingPerformed) {\n\t\t\t\tnotifyScrollingListenersAboutEnd();\n\t\t\t\tisScrollingPerformed = false;\n\t\t\t}\n\n\t\t\tscrollingOffset = 0;\n\t\t\tinvalidate();\n\t\t}\n\n\t\t@Override\n\t\tpublic void onJustify() {\n\t\t\tif (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) {\n\t\t\t\tscroller.scroll(scrollingOffset, 0);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Set the the specified scrolling interpolator\n\t * @param interpolator the interpolator\n\t */\n\tpublic void setInterpolator(Interpolator interpolator) {\n\t\tscroller.setInterpolator(interpolator);\n\t}\n\n\t/**\n\t * Gets count of visible items\n\t * \n\t * @return the count of visible items\n\t */\n\tpublic int getVisibleItems() {\n\t\treturn visibleItems;\n\t}\n\n\t/**\n\t * Sets the desired count of visible items.\n\t * Actual amount of visible items depends on wheel layout parameters.\n\t * To apply changes and rebuild view call measure().\n\t * \n\t * @param count the desired count for visible items\n\t */\n\tpublic void setVisibleItems(int count) {\n\t\tvisibleItems = count;\n\t}\n\n\t/**\n\t * Gets view adapter\n\t * @return the view adapter\n\t */\n\tpublic WheelViewAdapter getViewAdapter() {\n\t\treturn viewAdapter;\n\t}\n\n\t// Adapter listener\n\tprivate DataSetObserver dataObserver = new DataSetObserver() {\n\t\t@Override\n\t\tpublic void onChanged() {\n\t\t\tinvalidateWheel(false);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onInvalidated() {\n\t\t\tinvalidateWheel(true);\n\t\t}\n\t};\n\n\t/**\n\t * Sets view adapter. Usually new adapters contain different views, so\n\t * it needs to rebuild view by calling measure().\n\t * \n\t * @param viewAdapter the view adapter\n\t */\n\tpublic void setViewAdapter(WheelViewAdapter viewAdapter) {\n\t\tif (this.viewAdapter != null) {\n\t\t\tthis.viewAdapter.unregisterDataSetObserver(dataObserver);\n\t\t}\n\t\tthis.viewAdapter = viewAdapter;\n\t\tif (this.viewAdapter != null) {\n\t\t\tthis.viewAdapter.registerDataSetObserver(dataObserver);\n\t\t}\n\n\t\tinvalidateWheel(true);\n\t}\n\n\t/**\n\t * Adds wheel changing listener\n\t * @param listener the listener\n\t */\n\tpublic void addChangingListener(OnWheelChangedListener listener) {\n\t\tchangingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel changing listener\n\t * @param listener the listener\n\t */\n\tpublic void removeChangingListener(OnWheelChangedListener listener) {\n\t\tchangingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies changing listeners\n\t * @param oldValue the old wheel value\n\t * @param newValue the new wheel value\n\t */\n\tprotected void notifyChangingListeners(int oldValue, int newValue) {\n\t\tfor (OnWheelChangedListener listener : changingListeners) {\n\t\t\tlistener.onChanged(this, oldValue, newValue);\n\t\t}\n\t}\n\n\t/**\n\t * Adds wheel scrolling listener\n\t * @param listener the listener\n\t */\n\tpublic void addScrollingListener(OnWheelScrollListener listener) {\n\t\tscrollingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel scrolling listener\n\t * @param listener the listener\n\t */\n\tpublic void removeScrollingListener(OnWheelScrollListener listener) {\n\t\tscrollingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies listeners about starting scrolling\n\t */\n\tprotected void notifyScrollingListenersAboutStart() {\n\t\tfor (OnWheelScrollListener listener : scrollingListeners) {\n\t\t\tlistener.onScrollingStarted(this);\n\t\t}\n\t}\n\n\t/**\n\t * Notifies listeners about ending scrolling\n\t */\n\tprotected void notifyScrollingListenersAboutEnd() {\n\t\tfor (OnWheelScrollListener listener : scrollingListeners) {\n\t\t\tlistener.onScrollingFinished(this);\n\t\t}\n\t}\n\n\t/**\n\t * Adds wheel clicking listener\n\t * @param listener the listener\n\t */\n\tpublic void addClickingListener(OnWheelClickedListener listener) {\n\t\tclickingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel clicking listener\n\t * @param listener the listener\n\t */\n\tpublic void removeClickingListener(OnWheelClickedListener listener) {\n\t\tclickingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies listeners about clicking\n\t */\n\tprotected void notifyClickListenersAboutClick(int item) {\n\t\tfor (OnWheelClickedListener listener : clickingListeners) {\n\t\t\tlistener.onItemClicked(this, item);\n\t\t}\n\t}\n\n\t/**\n\t * Gets current value\n\t * \n\t * @return the current value\n\t */\n\tpublic int getCurrentItem() {\n\t\treturn currentItem;\n\t}\n\n\t/**\n\t * Sets the current item. Does nothing when index is wrong.\n\t * \n\t * @param index the item index\n\t * @param animated the animation flag\n\t */\n\tpublic void setCurrentItem(int index, boolean animated) {\n\t\tif (viewAdapter == null || viewAdapter.getItemsCount() == 0) {\n\t\t\treturn; // throw?\n\t\t}\n\n\t\tint itemCount = viewAdapter.getItemsCount();\n\t\tif (index < 0 || index >= itemCount) {\n\t\t\tif (isCyclic) {\n\t\t\t\twhile (index < 0) {\n\t\t\t\t\tindex += itemCount;\n\t\t\t\t}\n\t\t\t\tindex %= itemCount;\n\t\t\t} else{\n\t\t\t\treturn; // throw?\n\t\t\t}\n\t\t}\n\t\tif (index != currentItem) {\n\t\t\tif (animated) {\n\t\t\t\tint itemsToScroll = index - currentItem;\n\t\t\t\tif (isCyclic) {\n\t\t\t\t\tint scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem);\n\t\t\t\t\tif (scroll < Math.abs(itemsToScroll)) {\n\t\t\t\t\t\titemsToScroll = itemsToScroll < 0 ? scroll : -scroll;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscroll(itemsToScroll, 0);\n\t\t\t} else {\n\t\t\t\tscrollingOffset = 0;\n\n\t\t\t\tint old = currentItem;\n\t\t\t\tcurrentItem = index;\n\n\t\t\t\tnotifyChangingListeners(old, currentItem);\n\n\t\t\t\tinvalidate();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Sets the current item w/o animation. Does nothing when index is wrong.\n\t * \n\t * @param index the item index\n\t */\n\tpublic void setCurrentItem(int index) {\n\t\tsetCurrentItem(index, false);\n\t}\n\n\t/**\n\t * Tests if wheel is cyclic. That means before the 1st item there is shown the last one\n\t * @return true if wheel is cyclic\n\t */\n\tpublic boolean isCyclic() {\n\t\treturn isCyclic;\n\t}\n\n\t/**\n\t * Set wheel cyclic flag\n\t * @param isCyclic the flag to set\n\t */\n\tpublic void setCyclic(boolean isCyclic) {\n\t\tthis.isCyclic = isCyclic;\n\t\tinvalidateWheel(false);\n\t}\n\n\t/**\n\t * Determine whether shadows are drawn\n\t * @return true is shadows are drawn\n\t */\n\tpublic boolean drawShadows() {\n\t\treturn drawShadows;\n\t}\n\n\t/**\n\t * Set whether shadows should be drawn\n\t * @param drawShadows flag as true or false\n\t */\n\tpublic void setDrawShadows(boolean drawShadows) {\n\t\tthis.drawShadows = drawShadows;\n\t}\n\n\t/**\n\t * Set the shadow gradient color\n\t * @param start\n\t * @param middle\n\t * @param end\n\t */\n\tpublic void setShadowColor(int start, int middle, int end) {\n\t\tSHADOWS_COLORS = new int[] {start, middle, end};\n\t}\n\n\t/**\n\t * Sets the drawable for the wheel background\n\t * @param resource\n\t */\n\tpublic void setWheelBackground(int resource) {\n\t\twheelBackground = resource;\n\t\tsetBackgroundResource(wheelBackground);\n\t}\n\n\t/**\n\t * Sets the drawable for the wheel foreground\n\t * @param resource\n\t */\n\tpublic void setWheelForeground(int resource) {\n\t\twheelForeground = resource;\n\t\tcenterDrawable = getContext().getResources().getDrawable(wheelForeground);\n\t}\n\n\t/**\n\t * Invalidates wheel\n\t * @param clearCaches if true then cached views will be clear\n\t */\n\tpublic void invalidateWheel(boolean clearCaches) {\n\t\tif (clearCaches) {\n\t\t\trecycle.clearAll();\n\t\t\tif (itemsLayout != null) {\n\t\t\t\titemsLayout.removeAllViews();\n\t\t\t}\n\t\t\tscrollingOffset = 0;\n\t\t} else if (itemsLayout != null) {\n\t\t\t// cache all items\n\t\t\trecycle.recycleItems(itemsLayout, firstItem, new ItemsRange());\n\t\t}\n\n\t\tinvalidate();\n\t}\n\n\t/**\n\t * Initializes resources\n\t */\n\tprivate void initResourcesIfNecessary() {\n\t\tif (centerDrawable == null) {\n\t\t\tcenterDrawable = getContext().getResources().getDrawable(wheelForeground);\n\t\t}\n\n\t\tif (topShadow == null) {\n\t\t\ttopShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);\n\t\t}\n\n\t\tif (bottomShadow == null) {\n\t\t\tbottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);\n\t\t}\n\n\t\tsetBackgroundResource(wheelBackground);\n\t}\n\n\t/**\n\t * Calculates desired height for layout\n\t * \n\t * @param layout\n\t *            the source layout\n\t * @return the desired layout height\n\t */\n\tprivate int getDesiredHeight(LinearLayout layout) {\n\t\tif (layout != null && layout.getChildAt(0) != null) {\n\t\t\titemHeight = layout.getChildAt(0).getMeasuredHeight();\n\t\t}\n\n\t\tint desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50;\n\n\t\treturn Math.max(desired, getSuggestedMinimumHeight());\n\t}\n\n\t/**\n\t * Returns height of wheel item\n\t * @return the item height\n\t */\n\tprivate int getItemHeight() {\n\t\tif (itemHeight != 0) {\n\t\t\treturn itemHeight;\n\t\t}\n\n\t\tif (itemsLayout != null && itemsLayout.getChildAt(0) != null) {\n\t\t\titemHeight = itemsLayout.getChildAt(0).getHeight();\n\t\t\treturn itemHeight;\n\t\t}\n\n\t\treturn getHeight() / visibleItems;\n\t}\n\n\t/**\n\t * Calculates control width and creates text layouts\n\t * @param widthSize the input layout width\n\t * @param mode the layout mode\n\t * @return the calculated control width\n\t */\n\tprivate int calculateLayoutWidth(int widthSize, int mode) {\n\t\tinitResourcesIfNecessary();\n\n\t\t// TODO: make it static\n\t\titemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));\n\t\titemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED),\n\t\t\t\tMeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));\n\t\tint width = itemsLayout.getMeasuredWidth();\n\n\t\tif (mode == MeasureSpec.EXACTLY) {\n\t\t\twidth = widthSize;\n\t\t} else {\n\t\t\twidth += 2 * PADDING;\n\n\t\t\t// Check against our minimum width\n\t\t\twidth = Math.max(width, getSuggestedMinimumWidth());\n\n\t\t\tif (mode == MeasureSpec.AT_MOST && widthSize < width) {\n\t\t\t\twidth = widthSize;\n\t\t\t}\n\t\t}\n\n\t\titemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY),\n\t\t\t\tMeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));\n\n\t\treturn width;\n\t}\n\n\t@Override\n\tprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\t\tint widthMode = MeasureSpec.getMode(widthMeasureSpec);\n\t\tint heightMode = MeasureSpec.getMode(heightMeasureSpec);\n\t\tint widthSize = MeasureSpec.getSize(widthMeasureSpec);\n\t\tint heightSize = MeasureSpec.getSize(heightMeasureSpec);\n\n\t\tbuildViewForMeasuring();\n\n\t\tint width = calculateLayoutWidth(widthSize, widthMode);\n\n\t\tint height;\n\t\tif (heightMode == MeasureSpec.EXACTLY) {\n\t\t\theight = heightSize;\n\t\t} else {\n\t\t\theight = getDesiredHeight(itemsLayout);\n\n\t\t\tif (heightMode == MeasureSpec.AT_MOST) {\n\t\t\t\theight = Math.min(height, heightSize);\n\t\t\t}\n\t\t}\n\n\t\tsetMeasuredDimension(width, height);\n\t}\n\n\t@Override\n\tprotected void onLayout(boolean changed, int l, int t, int r, int b) {\n\t\tlayout(r - l, b - t);\n\t}\n\n\t/**\n\t * Sets layouts width and height\n\t * @param width the layout width\n\t * @param height the layout height\n\t */\n\tprivate void layout(int width, int height) {\n\t\tint itemsWidth = width - 2 * PADDING;\n\n\t\titemsLayout.layout(0, 0, itemsWidth, height);\n\t}\n\n\t@Override\n\tprotected void onDraw(Canvas canvas) {\n\t\tsuper.onDraw(canvas);\n\n\t\tif (viewAdapter != null && viewAdapter.getItemsCount() > 0) {\n\t\t\tupdateView();\n\n\t\t\tdrawItems(canvas);\n\t\t\tdrawCenterRect(canvas);\n\t\t}\n\n\t\tif (drawShadows) drawShadows(canvas);\n\t}\n\n\t/**\n\t * Draws shadows on top and bottom of control\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawShadows(Canvas canvas) {\n\t\t/*/ Modified by wulianghuan 2014-11-25\n\t\tint height = (int)(1.5 * getItemHeight());\n\t\t//*/\n\t\tint height = (int)(3 * getItemHeight());\n\t\t//*/\n\t\ttopShadow.setBounds(0, 0, getWidth(), height);\n\t\ttopShadow.draw(canvas);\n\n\t\tbottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());\n\t\tbottomShadow.draw(canvas);\n\t}\n\n\t/**\n\t * Draws items\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawItems(Canvas canvas) {\n\t\tcanvas.save();\n\n\t\tint top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2;\n\t\tcanvas.translate(PADDING, - top + scrollingOffset);\n\n\t\titemsLayout.draw(canvas);\n\n\t\tcanvas.restore();\n\t}\n\n\t/**\n\t * Draws rect for current value\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawCenterRect(Canvas canvas) {\n\t\tint center = getHeight() / 2;\n\t\tint offset = (int) (getItemHeight() / 2 * 1.2);\n\t\t/*/ Remarked by wulianghuan 2014-11-27  使用自己的画线，而不是描边\n\t\tRect rect = new Rect(left, top, right, bottom)\n\t\tcenterDrawable.setBounds(bounds)\n\t\tcenterDrawable.setBounds(0, center - offset, getWidth(), center + offset);\n\t\tcenterDrawable.draw(canvas);\n\t\t//*/\n\t\tPaint paint = new Paint();\n\t\tpaint.setColor(getResources().getColor(R.color.province_line_border));\n\t\t// 设置线宽\n\t\tpaint.setStrokeWidth((float) 3);\n\t\t// 绘制上边直线\n\t\tcanvas.drawLine(0, center - offset, getWidth(), center - offset, paint);\n\t\t// 绘制下边直线\n\t\tcanvas.drawLine(0, center + offset, getWidth(), center + offset, paint);\n\t\t//*/\n\t}\n\n\t@Override\n\tpublic boolean onTouchEvent(MotionEvent event) {\n\t\tif (!isEnabled() || getViewAdapter() == null) {\n\t\t\treturn true;\n\t\t}\n\n\t\tswitch (event.getAction()) {\n\t\t\tcase MotionEvent.ACTION_MOVE:\n\t\t\t\tif (getParent() != null) {\n\t\t\t\t\tgetParent().requestDisallowInterceptTouchEvent(true);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase MotionEvent.ACTION_UP:\n\t\t\t\tif (!isScrollingPerformed) {\n\t\t\t\t\tint distance = (int) event.getY() - getHeight() / 2;\n\t\t\t\t\tif (distance > 0) {\n\t\t\t\t\t\tdistance += getItemHeight() / 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdistance -= getItemHeight() / 2;\n\t\t\t\t\t}\n\t\t\t\t\tint items = distance / getItemHeight();\n\t\t\t\t\tif (items != 0 && isValidItemIndex(currentItem + items)) {\n\t\t\t\t\t\tnotifyClickListenersAboutClick(currentItem + items);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn scroller.onTouchEvent(event);\n\t}\n\n\t/**\n\t * Scrolls the wheel\n\t * @param delta the scrolling value\n\t */\n\tprivate void doScroll(int delta) {\n\t\tscrollingOffset += delta;\n\n\t\tint itemHeight = getItemHeight();\n\t\tint count = scrollingOffset / itemHeight;\n\n\t\tint pos = currentItem - count;\n\t\tint itemCount = viewAdapter.getItemsCount();\n\n\t\tint fixPos = scrollingOffset % itemHeight;\n\t\tif (Math.abs(fixPos) <= itemHeight / 2) {\n\t\t\tfixPos = 0;\n\t\t}\n\t\tif (isCyclic && itemCount > 0) {\n\t\t\tif (fixPos > 0) {\n\t\t\t\tpos--;\n\t\t\t\tcount++;\n\t\t\t} else if (fixPos < 0) {\n\t\t\t\tpos++;\n\t\t\t\tcount--;\n\t\t\t}\n\t\t\t// fix position by rotating\n\t\t\twhile (pos < 0) {\n\t\t\t\tpos += itemCount;\n\t\t\t}\n\t\t\tpos %= itemCount;\n\t\t} else {\n\t\t\t//\n\t\t\tif (pos < 0) {\n\t\t\t\tcount = currentItem;\n\t\t\t\tpos = 0;\n\t\t\t} else if (pos >= itemCount) {\n\t\t\t\tcount = currentItem - itemCount + 1;\n\t\t\t\tpos = itemCount - 1;\n\t\t\t} else if (pos > 0 && fixPos > 0) {\n\t\t\t\tpos--;\n\t\t\t\tcount++;\n\t\t\t} else if (pos < itemCount - 1 && fixPos < 0) {\n\t\t\t\tpos++;\n\t\t\t\tcount--;\n\t\t\t}\n\t\t}\n\n\t\tint offset = scrollingOffset;\n\t\tif (pos != currentItem) {\n\t\t\tsetCurrentItem(pos, false);\n\t\t} else {\n\t\t\tinvalidate();\n\t\t}\n\n\t\t// update offset\n\t\tscrollingOffset = offset - count * itemHeight;\n\t\tif (scrollingOffset > getHeight()) {\n\t\t\tscrollingOffset = scrollingOffset % getHeight() + getHeight();\n\t\t}\n\t}\n\n\t/**\n\t * Scroll the wheel\n\t * @param itemsToScroll items to scroll\n\t * @param time scrolling duration\n\t */\n\tpublic void scroll(int itemsToScroll, int time) {\n\t\tint distance = itemsToScroll * getItemHeight() - scrollingOffset;\n\t\tscroller.scroll(distance, time);\n\t}\n\n\t/**\n\t * Calculates range for wheel items\n\t * @return the items range\n\t */\n\tprivate ItemsRange getItemsRange() {\n\t\tif (getItemHeight() == 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tint first = currentItem;\n\t\tint count = 1;\n\n\t\twhile (count * getItemHeight() < getHeight()) {\n\t\t\tfirst--;\n\t\t\tcount += 2; // top + bottom items\n\t\t}\n\n\t\tif (scrollingOffset != 0) {\n\t\t\tif (scrollingOffset > 0) {\n\t\t\t\tfirst--;\n\t\t\t}\n\t\t\tcount++;\n\n\t\t\t// process empty items above the first or below the second\n\t\t\tint emptyItems = scrollingOffset / getItemHeight();\n\t\t\tfirst -= emptyItems;\n\t\t\tcount += Math.asin(emptyItems);\n\t\t}\n\t\treturn new ItemsRange(first, count);\n\t}\n\n\t/**\n\t * Rebuilds wheel items if necessary. Caches all unused items.\n\t * \n\t * @return true if items are rebuilt\n\t */\n\tprivate boolean rebuildItems() {\n\t\tboolean updated = false;\n\t\tItemsRange range = getItemsRange();\n\t\tif (itemsLayout != null) {\n\t\t\tint first = recycle.recycleItems(itemsLayout, firstItem, range);\n\t\t\tupdated = firstItem != first;\n\t\t\tfirstItem = first;\n\t\t} else {\n\t\t\tcreateItemsLayout();\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (!updated) {\n\t\t\tupdated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount();\n\t\t}\n\n\t\tif (firstItem > range.getFirst() && firstItem <= range.getLast()) {\n\t\t\tfor (int i = firstItem - 1; i >= range.getFirst(); i--) {\n\t\t\t\tif (!addViewItem(i, true)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfirstItem = i;\n\t\t\t}\n\t\t} else {\n\t\t\tfirstItem = range.getFirst();\n\t\t}\n\n\t\tint first = firstItem;\n\t\tfor (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) {\n\t\t\tif (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) {\n\t\t\t\tfirst++;\n\t\t\t}\n\t\t}\n\t\tfirstItem = first;\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Updates view. Rebuilds items and label if necessary, recalculate items sizes.\n\t */\n\tprivate void updateView() {\n\t\tif (rebuildItems()) {\n\t\t\tcalculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);\n\t\t\tlayout(getWidth(), getHeight());\n\t\t}\n\t}\n\n\t/**\n\t * Creates item layouts if necessary\n\t */\n\tprivate void createItemsLayout() {\n\t\tif (itemsLayout == null) {\n\t\t\titemsLayout = new LinearLayout(getContext());\n\t\t\titemsLayout.setOrientation(LinearLayout.VERTICAL);\n\t\t}\n\t}\n\n\t/**\n\t * Builds view for measuring\n\t */\n\tprivate void buildViewForMeasuring() {\n\t\t// clear all items\n\t\tif (itemsLayout != null) {\n\t\t\trecycle.recycleItems(itemsLayout, firstItem, new ItemsRange());\n\t\t} else {\n\t\t\tcreateItemsLayout();\n\t\t}\n\n\t\t// add views\n\t\tint addItems = visibleItems / 2;\n\t\tfor (int i = currentItem + addItems; i >= currentItem - addItems; i--) {\n\t\t\tif (addViewItem(i, true)) {\n\t\t\t\tfirstItem = i;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Adds view for item to items layout\n\t * @param index the item index\n\t * @param first the flag indicates if view should be first\n\t * @return true if corresponding item exists and is added\n\t */\n\tprivate boolean addViewItem(int index, boolean first) {\n\t\tView view = getItemView(index);\n\t\tif (view != null) {\n\t\t\tif (first) {\n\t\t\t\titemsLayout.addView(view, 0);\n\t\t\t} else {\n\t\t\t\titemsLayout.addView(view);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks whether intem index is valid\n\t * @param index the item index\n\t * @return true if item index is not out of bounds or the wheel is cyclic\n\t */\n\tprivate boolean isValidItemIndex(int index) {\n\t\treturn viewAdapter != null && viewAdapter.getItemsCount() > 0 &&\n\t\t\t\t(isCyclic || index >= 0 && index < viewAdapter.getItemsCount());\n\t}\n\n\t/**\n\t * Returns view for specified item\n\t * @param index the item index\n\t * @return item view or empty view if index is out of bounds\n\t */\n\tprivate View getItemView(int index) {\n\t\tif (viewAdapter == null || viewAdapter.getItemsCount() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tint count = viewAdapter.getItemsCount();\n\t\tif (!isValidItemIndex(index)) {\n\t\t\treturn viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout);\n\t\t} else {\n\t\t\twhile (index < 0) {\n\t\t\t\tindex = count + index;\n\t\t\t}\n\t\t}\n\n\t\tindex %= count;\n\t\treturn viewAdapter.getItem(index, recycle.getItem(), itemsLayout);\n\t}\n\n\t/**\n\t * Stops scrolling\n\t */\n\tpublic void stopScrolling() {\n\t\tscroller.stopScrolling();\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AbstractWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.database.DataSetObserver;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Abstract Wheel adapter.\n */\npublic abstract class AbstractWheelAdapter implements WheelViewAdapter {\n    // Observers\n    private List<DataSetObserver> datasetObservers;\n    \n    @Override\n    public View getEmptyItem(View convertView, ViewGroup parent) {\n        return null;\n    }\n\n    @Override\n    public void registerDataSetObserver(DataSetObserver observer) {\n        if (datasetObservers == null) {\n            datasetObservers = new LinkedList<DataSetObserver>();\n        }\n        datasetObservers.add(observer);\n    }\n\n    @Override\n    public void unregisterDataSetObserver(DataSetObserver observer) {\n        if (datasetObservers != null) {\n            datasetObservers.remove(observer);\n        }\n    }\n    \n    /**\n     * Notifies observers about data changing\n     */\n    protected void notifyDataChangedEvent() {\n        if (datasetObservers != null) {\n            for (DataSetObserver observer : datasetObservers) {\n                observer.onChanged();\n            }\n        }\n    }\n    \n    /**\n     * Notifies observers about invalidating data\n     */\n    protected void notifyDataInvalidatedEvent() {\n        if (datasetObservers != null) {\n            for (DataSetObserver observer : datasetObservers) {\n                observer.onInvalidated();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AbstractWheelTextAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\n/**\n * Abstract wheel adapter provides common functionality for adapters.\n */\npublic abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {\n    \n    /** Text view resource. Used as a default view for adapter. */\n    public static final int TEXT_VIEW_ITEM_RESOURCE = -1;\n    \n    /** No resource constant. */\n    protected static final int NO_RESOURCE = 0;\n    \n    /** Default text color */\n    public static final int DEFAULT_TEXT_COLOR = 0xFF585858;\n    \n    /** Default text color */\n    public static final int LABEL_COLOR = 0xFF700070;\n    \n    /** Default text size */\n    public static final int DEFAULT_TEXT_SIZE = 18;\n    \n    // Text settings\n    private int textColor = DEFAULT_TEXT_COLOR;\n    private int textSize = DEFAULT_TEXT_SIZE;\n    \n    // Current context\n    protected Context context;\n    // Layout inflater\n    protected LayoutInflater inflater;\n    \n    // Items resources\n    protected int itemResourceId;\n    protected int itemTextResourceId;\n    \n    // Empty items resources\n    protected int emptyItemResourceId;\n\t\n    /**\n     * Constructor\n     * @param context the current context\n     */\n    protected AbstractWheelTextAdapter(Context context) {\n        this(context, TEXT_VIEW_ITEM_RESOURCE);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views\n     */\n    protected AbstractWheelTextAdapter(Context context, int itemResource) {\n        this(context, itemResource, NO_RESOURCE);\n    }\n    \n    /**\n     * Constructor\n     * @param context the current context\n     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views\n     * @param itemTextResource the resource ID for a text view in the item layout\n     */\n    protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) {\n        this.context = context;\n        itemResourceId = itemResource;\n        itemTextResourceId = itemTextResource;\n        \n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n    }\n    \n    /**\n     * Gets text color\n     * @return the text color\n     */\n    public int getTextColor() {\n        return textColor;\n    }\n    \n    /**\n     * Sets text color\n     * @param textColor the text color to set\n     */\n    public void setTextColor(int textColor) {\n        this.textColor = textColor;\n    }\n    \n    /**\n     * Gets text size\n     * @return the text size\n     */\n    public int getTextSize() {\n        return textSize;\n    }\n    \n    /**\n     * Sets text size\n     * @param textSize the text size to set\n     */\n    public void setTextSize(int textSize) {\n        this.textSize = textSize;\n    }\n    \n    /**\n     * Gets resource Id for items views\n     * @return the item resource Id\n     */\n    public int getItemResource() {\n        return itemResourceId;\n    }\n    \n    /**\n     * Sets resource Id for items views\n     * @param itemResourceId the resource Id to set\n     */\n    public void setItemResource(int itemResourceId) {\n        this.itemResourceId = itemResourceId;\n    }\n    \n    /**\n     * Gets resource Id for text view in item layout \n     * @return the item text resource Id\n     */\n    public int getItemTextResource() {\n        return itemTextResourceId;\n    }\n    \n    /**\n     * Sets resource Id for text view in item layout \n     * @param itemTextResourceId the item text resource Id to set\n     */\n    public void setItemTextResource(int itemTextResourceId) {\n        this.itemTextResourceId = itemTextResourceId;\n    }\n\n    /**\n     * Gets resource Id for empty items views\n     * @return the empty item resource Id\n     */\n    public int getEmptyItemResource() {\n        return emptyItemResourceId;\n    }\n\n    /**\n     * Sets resource Id for empty items views\n     * @param emptyItemResourceId the empty item resource Id to set\n     */\n    public void setEmptyItemResource(int emptyItemResourceId) {\n        this.emptyItemResourceId = emptyItemResourceId;\n    }\n    \n    \n    /**\n     * Returns text for specified item\n     * @param index the item index\n     * @return the text of specified items\n     */\n    protected abstract CharSequence getItemText(int index);\n\n    @Override\n    public View getItem(int index, View convertView, ViewGroup parent) {\n        if (index >= 0 && index < getItemsCount()) {\n            if (convertView == null) {\n                convertView = getView(itemResourceId, parent);\n            }\n            TextView textView = getTextView(convertView, itemTextResourceId);\n            if (textView != null) {\n                CharSequence text = getItemText(index);\n                if (text == null) {\n                    text = \"\";\n                }\n                textView.setText(text);\n    \n                if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {\n                    configureTextView(textView);\n                }\n            }\n            return convertView;\n        }\n    \treturn null;\n    }\n\n    @Override\n    public View getEmptyItem(View convertView, ViewGroup parent) {\n        if (convertView == null) {\n            convertView = getView(emptyItemResourceId, parent);\n        }\n        if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {\n            configureTextView((TextView)convertView);\n        }\n            \n        return convertView;\n\t}\n\n    /**\n     * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.\n     * @param view the text view to be configured\n     */\n    protected void configureTextView(TextView view) {\n        view.setTextColor(textColor);\n        view.setGravity(Gravity.CENTER);\n        view.setTextSize(textSize);\n        view.setEllipsize(TextUtils.TruncateAt.END);\n        view.setLines(1);\n//        view.setCompoundDrawablePadding(20);\n//        view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);\n    }\n    \n    /**\n     * Loads a text view from view\n     * @param view the text view or layout containing it\n     * @param textResource the text resource Id in layout\n     * @return the loaded text view\n     */\n    private TextView getTextView(View view, int textResource) {\n    \tTextView text = null;\n    \ttry {\n            if (textResource == NO_RESOURCE && view instanceof TextView) {\n                text = (TextView) view;\n            } else if (textResource != NO_RESOURCE) {\n                text = (TextView) view.findViewById(textResource);\n            }\n        } catch (ClassCastException e) {\n            Log.e(\"AbstractWheelAdapter\", \"You must supply a resource ID for a TextView\");\n            throw new IllegalStateException(\n                    \"AbstractWheelAdapter requires the resource ID to be a TextView\", e);\n        }\n        \n        return text;\n    }\n    \n    /**\n     * Loads view from resources\n     * @param resource the resource Id\n     * @return the loaded view or null if resource is not set\n     */\n    private View getView(int resource, ViewGroup parent) {\n        switch (resource) {\n        case NO_RESOURCE:\n            return null;\n        case TEXT_VIEW_ITEM_RESOURCE:\n            return new TextView(context);\n        default:\n            return inflater.inflate(resource, parent, false);    \n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AdapterWheel.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.view.wheel.WheelAdapter;\n\n/**\n * Adapter class for old wheel adapter (deprecated WheelAdapter class).\n * \n * @deprecated Will be removed soon\n */\npublic class AdapterWheel extends AbstractWheelTextAdapter {\n\n    // Source adapter\n    private WheelAdapter adapter;\n    \n    /**\n     * Constructor\n     * @param context the current context\n     * @param adapter the source adapter\n     */\n    public AdapterWheel(Context context, WheelAdapter adapter) {\n        super(context);\n        \n        this.adapter = adapter;\n    }\n\n    /**\n     * Gets original adapter\n     * @return the original adapter\n     */\n    public WheelAdapter getAdapter() {\n        return adapter;\n    }\n    \n    @Override\n    public int getItemsCount() {\n        return adapter.getItemsCount();\n    }\n\n    @Override\n    protected CharSequence getItemText(int index) {\n        return adapter.getItem(index);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/ArrayWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.entity.city.BaseAddressModel;\n\nimport java.util.ArrayList;\n\n/**\n * The simple Array wheel adapter\n *\n * @param <T> the element type\n */\npublic class ArrayWheelAdapter<T> extends AbstractWheelTextAdapter {\n\n    // items\n    private ArrayList<T> items;\n\n    /**\n     * Constructor\n     *\n     * @param context the current context\n     * @param items   the items\n     */\n    public ArrayWheelAdapter(Context context, ArrayList<T> items) {\n        super(context);\n\n        //setEmptyItemResource(TEXT_VIEW_ITEM_RESOURCE);\n        this.items = items;\n    }\n\n    @Override\n    public CharSequence getItemText(int index) {\n        if (index >= 0 && index < items.size()) {\n            T item = items.get(index);\n            if (item instanceof BaseAddressModel) {\n                return ((BaseAddressModel) item).name;\n            } else if(item instanceof String) {\n                return item.toString();\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public int getItemsCount() {\n        return items.size();\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/NumericWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\n\n/**\n * Numeric Wheel adapter.\n */\npublic class NumericWheelAdapter extends AbstractWheelTextAdapter {\n    \n    /** The default min value */\n    public static final int DEFAULT_MAX_VALUE = 9;\n\n    /** The default max value */\n    private static final int DEFAULT_MIN_VALUE = 0;\n    \n    // Values\n    private int minValue;\n    private int maxValue;\n    \n    // format\n    private String format;\n    \n    /**\n     * Constructor\n     * @param context the current context\n     */\n    public NumericWheelAdapter(Context context) {\n        this(context, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param minValue the wheel min value\n     * @param maxValue the wheel max value\n     */\n    public NumericWheelAdapter(Context context, int minValue, int maxValue) {\n        this(context, minValue, maxValue, null);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param minValue the wheel min value\n     * @param maxValue the wheel max value\n     * @param format the format string\n     */\n    public NumericWheelAdapter(Context context, int minValue, int maxValue, String format) {\n        super(context);\n        \n        this.minValue = minValue;\n        this.maxValue = maxValue;\n        this.format = format;\n    }\n\n    @Override\n    public CharSequence getItemText(int index) {\n        if (index >= 0 && index < getItemsCount()) {\n            int value = minValue + index;\n            return format != null ? String.format(format, value) : Integer.toString(value);\n        }\n        return null;\n    }\n\n    @Override\n    public int getItemsCount() {\n        return maxValue - minValue + 1;\n    }    \n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/WheelViewAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.database.DataSetObserver;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * Wheel items adapter interface\n */\npublic interface WheelViewAdapter {\n\t/**\n\t * Gets items count\n\t * @return the count of wheel items\n\t */\n\tpublic int getItemsCount();\n\t\n\t/**\n\t * Get a View that displays the data at the specified position in the data set\n\t * \n\t * @param index the item index\n\t * @param convertView the old view to reuse if possible\n\t * @param parent the parent that this view will eventually be attached to\n\t * @return the wheel item View\n\t */\n\tpublic View getItem(int index, View convertView, ViewGroup parent);\n\n\t/**\n\t * Get a View that displays an empty wheel item placed before the first or after\n\t * the last wheel item.\n\t * \n\t * @param convertView the old view to reuse if possible\n     * @param parent the parent that this view will eventually be attached to\n\t * @return the empty item View\n\t */\n\tpublic View getEmptyItem(View convertView, ViewGroup parent);\n\t\n\t/**\n\t * Register an observer that is called when changes happen to the data used by this adapter.\n\t * @param observer the observer to be registered\n\t */\n\tpublic void registerDataSetObserver(DataSetObserver observer);\n\t\n\t/**\n\t * Unregister an observer that has previously been registered\n\t * @param observer the observer to be unregistered\n\t */\n\tvoid unregisterDataSetObserver(DataSetObserver observer);\n}\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/anim/dd_mask_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <alpha\n        android:fromAlpha=\"0\"\n        android:toAlpha=\"1\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/anim/dd_mask_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <alpha\n        android:fromAlpha=\"1\"\n        android:toAlpha=\"0\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/anim/dd_menu_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <translate\n        android:fromYDelta=\"-100%p\"\n        android:toYDelta=\"0\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/anim/dd_menu_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <translate\n        android:fromYDelta=\"0\"\n        android:toYDelta=\"-100%p\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/color/txt_blue2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@color/txt_link_blue\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/color/txt_gray2primarydark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/colorPrimaryDark\" android:state_checked=\"true\" />\n    <item android:color=\"@color/txt_gray\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/color/txt_lgray2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@android:color/white\" android:state_checked=\"true\" />\n    <item android:color=\"@color/txt_light_gray\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/color/txt_primary2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@android:color/white\" android:state_checked=\"true\" />\n    <item android:color=\"@color/colorPrimary\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/color/txt_white2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@android:color/white\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/bg_gray2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@color/bg_gray\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/bg_primary2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/colorPrimaryDark\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@color/colorPrimaryDark\" android:state_pressed=\"true\"/>\n    <item android:drawable=\"@color/colorPrimary\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/bg_primarydark_indicator_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/layerlist_primarydark_indicator\" android:state_checked=\"true\" />\n    <item android:drawable=\"@android:color/transparent\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/bg_tran2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@android:color/transparent\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/bg_white2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@android:color/white\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/cirrect_10a_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/bg_position_bar_down\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/cirrect_5a_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/bg_position_bar_up\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/cirrect_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/correct_gray_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/divider_gray\" />\n\n    <solid android:color=\"@android:color/white\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/correct_primary.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/correct_primary2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/correct_primary_light\" android:state_enabled=\"false\" />\n    <item android:drawable=\"@drawable/correct_primary_dark\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@drawable/correct_primary\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/correct_primary_dark.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimaryDark\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/correct_primary_light.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimaryLight\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/correct_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/correct_primary_stroke2solid_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/correct_primary\" android:state_checked=\"true\" />\n    <item android:drawable=\"@drawable/correct_primary_stroke\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/layerlist_primarydark_indicator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:top=\"28dp\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"@color/colorPrimaryDark\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/oval_primary_light_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@color/colorPrimaryLight\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/oval_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@color/colorPrimary\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/shape_bottom_line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:left=\"-1dp\"\n        android:right=\"-1dp\">\n        <shape>\n            <stroke\n                android:width=\"1dp\"\n                android:color=\"@color/divider_gray\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/shape_oval_primary2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/oval_primary_solid\" android:state_checked=\"true\" />\n\n    <item android:drawable=\"@drawable/shape_oval_white_solid\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/shape_oval_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/transparent\"></solid>\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\"></stroke>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/shape_oval_primary_stroke2solid_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/oval_primary_solid\" android:state_checked=\"true\" />\n\n    <item android:drawable=\"@drawable/shape_oval_primary_stroke\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/shape_oval_red_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/holo_red_dark\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/shape_oval_white_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/white\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/shape_top_line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:bottom=\"-2dp\"\n        android:left=\"-2dp\"\n        android:right=\"-2dp\">\n        <shape>\n            <stroke\n                android:width=\"1dp\"\n                android:color=\"@color/divider_gray\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/wheel_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- \n    Android Wheel Control.\n    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html\n   \n    Copyright 2010 Yuri Kanivets\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/drawable/wheel_val.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- \n    Android Wheel Control.\n    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html\n   \n    Copyright 2010 Yuri Kanivets\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- \n\t<gradient\n\t\tandroid:startColor=\"#70222222\"\n\t\tandroid:centerColor=\"#70222222\"\n\t\tandroid:endColor=\"#70EEEEEE\"\n\t\tandroid:angle=\"90\" />\n\t\t -->\n\n\t<stroke android:width=\"1dp\" android:color=\"#C7C7C7\" /> \n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/activity_image_browser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\">\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/vp_image_brower\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </android.support.v4.view.ViewPager>\n\n    <TextView\n        android:id=\"@+id/tv_image_index\"\n        style=\"@style/TextAppearance.AppCompat.Headline\"\n        android:layout_width=\"88dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginTop=\"8dp\"\n        android:gravity=\"center\"\n        android:padding=\"4dp\"\n        android:text=\"1/9\"\n        android:textColor=\"@android:color/white\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/activity_web_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <WebView\n        android:id=\"@+id/webview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </WebView>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/footer_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\"\n    android:padding=\"@dimen/margin_medium\">\n\n    <ProgressBar\n        android:id=\"@+id/pb_footer_progress\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:indeterminateDuration=\"900\" />\n\n    <TextView\n        android:id=\"@+id/tv_footer_progress\"\n        style=\"@style/TextViewCaption\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"没有更多数据\"\n        android:visibility=\"gone\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/formitem_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        android:id=\"@+id/tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"56dp\"\n        android:gravity=\"center_vertical\"\n        android:layout_centerVertical=\"true\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <EditText\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@null\"\n        android:paddingLeft=\"80dp\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/formitem_select.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        android:id=\"@+id/tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"56dp\"\n        android:layout_centerVertical=\"true\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_mid_container\"\n        android:layout_width=\"match_parent\"\n        android:visibility=\"gone\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"80dp\"\n        android:paddingRight=\"@dimen/margin_large\">\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:paddingLeft=\"80dp\"\n        android:paddingRight=\"@dimen/margin_large\" />\n\n    <ImageView\n        android:id=\"@+id/iv_right\"\n        android:layout_width=\"18dp\"\n        android:layout_height=\"18dp\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\" />\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/include_banner_with_indicator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/include_banner_with_indicator\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/banner_height\">\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/vp_banner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/banner_height\">\n    </android.support.v4.view.ViewPager>\n\n    <RadioGroup\n        android:id=\"@+id/rg_indicator\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignBottom=\"@+id/vp_banner\"\n        android:layout_alignRight=\"@+id/vp_banner\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"@dimen/margin_small\"\n        android:layout_marginRight=\"@dimen/margin_medium\"\n        android:orientation=\"horizontal\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/include_ddm_listview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ListView\n        android:id=\"@+id/lv_ddm\"\n        style=\"@style/AbsListViewCommon\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/margin_large\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/include_group_divider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/margin_small\"\n    android:orientation=\"vertical\">\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:background=\"@color/bg_gray\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/include_refresh_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.SwipeRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/srl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n</android.support.v4.widget.SwipeRefreshLayout>\n"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/include_titlebar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/rl_titlebar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48dp\"\n    android:background=\"@color/colorPrimary\"\n    android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/titlebar_iv_left\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:padding=\"13dp\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\"\n        android:textColor=\"@android:color/white\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv\"\n        style=\"@style/TextViewTitle\"\n        android:layout_centerInParent=\"true\"\n        android:gravity=\"center\"\n        android:maxWidth=\"224dp\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"26sp\" />\n\n    <ImageView\n        android:id=\"@+id/titlebar_iv_right\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:padding=\"13dp\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv_right\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\"\n        android:textColor=\"@android:color/white\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/item_default_drop_down.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"32dp\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        style=\"@style/TextViewCaption\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"32dp\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"54dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/item_image_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/banner_height\">\n\n    <ImageView\n        android:id=\"@+id/iv_image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/banner_height\"\n        android:scaleType=\"centerCrop\" />\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"24dp\"\n        android:layout_alignBottom=\"@id/iv_image\"\n        android:background=\"#3000\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_huge\"\n        android:textColor=\"@android:color/white\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/item_image_browser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/iv_image_browser\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitCenter\" />\n\n    <ProgressBar\n        android:id=\"@+id/pb_loading\"\n        style=\"@style/Widget.AppCompat.ProgressBar\"\n        android:layout_width=\"56dp\"\n        android:layout_height=\"56dp\"\n        android:layout_centerInParent=\"true\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/item_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"?listPreferredItemHeightSmall\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <ImageView\n        android:id=\"@+id/iv_left\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\" />\n\n    <TextView\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_small\" />\n\n    <ImageView\n        android:id=\"@+id/iv_red_dot\"\n        android:layout_width=\"8dp\"\n        android:layout_height=\"8dp\"\n        android:layout_gravity=\"top\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:src=\"@drawable/shape_oval_red_solid\"\n        android:visibility=\"gone\" />\n\n    <View\n        android:layout_width=\"0dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\" />\n\n    <TextView\n        android:id=\"@+id/tv_right\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_small\"\n        android:textColor=\"@color/txt_light_gray\"\n        android:visibility=\"gone\" />\n\n    <ImageView\n        android:id=\"@+id/iv_right\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:visibility=\"gone\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/listview_dropdown_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    style=\"@style/ListViewLineDivider\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n</ListView>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/layout/wheel_dialog_address.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"#E9E9E9\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"20dip\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"5dip\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"20dip\"\n            android:text=\"请选择省市区\"\n            android:textColor=\"#000000\"\n            android:textSize=\"20sp\" />\n    </RelativeLayout>\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"30dip\"\n        android:orientation=\"horizontal\">\n\n        <com.boredream.bdcodehelper.view.wheel.WheelView\n            android:id=\"@+id/id_province\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"></com.boredream.bdcodehelper.view.wheel.WheelView>\n\n        <com.boredream.bdcodehelper.view.wheel.WheelView\n            android:id=\"@+id/id_city\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"></com.boredream.bdcodehelper.view.wheel.WheelView>\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/btn_confirm\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dip\"\n        android:gravity=\"center\"\n        android:text=\"确定\"\n        android:textColor=\"#000000\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <declare-styleable name=\"DrawableTextView\">\n        <attr name=\"drawableWidth\" format=\"dimension\" />\n        <attr name=\"drawableHeight\" format=\"dimension\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"DropDownMenu\">\n        <attr name=\"ddunderlineColor\" format=\"color\" />\n        <attr name=\"dddividerColor\" format=\"color\" />\n        <attr name=\"ddtextSelectedColor\" format=\"color\" />\n        <attr name=\"ddtextUnselectedColor\" format=\"color\" />\n        <attr name=\"ddmenuBackgroundColor\" format=\"color\" />\n        <attr name=\"ddmaskColor\" format=\"color\" />\n        <attr name=\"ddmenuTextSize\" format=\"dimension\" />\n        <attr name=\"ddmenuSelectedIcon\" format=\"reference\" />\n        <attr name=\"ddmenuUnselectedIcon\" format=\"reference\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"BottomTabRadioButton\">\n        <attr name=\"hint_mode\" format=\"enum\">\n            <enum name=\"none\" value=\"0\" />\n            <enum name=\"point\" value=\"1\" />\n            <enum name=\"num\" value=\"2\" />\n        </attr>\n        <attr name=\"hint_color\" format=\"color\" />\n        <attr name=\"hint_toppadding\" format=\"dimension\" />\n        <attr name=\"hint_rightpadding\" format=\"dimension\" />\n        <attr name=\"point_radius\" format=\"dimension\" />\n        <attr name=\"num\" format=\"integer\" />\n        <attr name=\"num_radius\" format=\"dimension\" />\n        <attr name=\"num_size\" format=\"dimension\" />\n        <attr name=\"num_color\" format=\"color\" />\n    </declare-styleable>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- basic -->\n    <!-- 主色调 -->\n    <color name=\"colorPrimary\">#8BC34A</color>\n    <color name=\"colorPrimaryDark\">#76A63E</color>\n    <color name=\"colorPrimaryLight\">#E8F3BD</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"colorSecondary\">#ff9900</color>\n    <color name=\"colorSecondaryDark\">#d88200</color>\n    <!-- 主体文字,标题/标签 -->\n    <color name=\"txt_black\">#212121</color>\n    <!-- 内容文字,正文 -->\n    <color name=\"txt_gray\">#808080</color>\n    <!-- 辅助文字,提示 -->\n    <color name=\"txt_light_gray\">#CCCCCC</color>\n    <!-- 背景色 -->\n    <color name=\"bg_gray\">#f1f1f1</color>\n    <!-- 按下灰色 -->\n    <color name=\"bg_gray_pressed\">#e8e8e8</color>\n    <!-- 高亮,红棕色 -->\n    <color name=\"brown\">#d54c1c</color>\n    <!-- 分割线 -->\n    <color name=\"divider_gray\">#cbcbcb</color>\n    <!-- other -->\n    <color name=\"txt_link_blue\">#1ea5ff</color>\n\n    <!-- wheel -->\n    <color name=\"province_line_border\">#C7C7C7</color>\n\n    <!-- drop down menu -->\n    <color name=\"white\">#ffffff</color>\n    <color name=\"gray\">#cccccc</color>\n\n    <color name=\"drop_down_selected\">#8BC34A</color>\n    <color name=\"drop_down_unselected\">#808080</color>\n\n    <color name=\"mask_color\">#88888888</color>\n    <color name=\"check_bg\">#f1f1f1</color>\n    <color name=\"un_press_color\">#8BC34A</color>\n\n    <!-- position bar -->\n    <color name=\"bg_position_bar_up\">#0D8BC34A</color>\n    <color name=\"bg_position_bar_down\">#1A8BC34A</color>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/values/dimens.xml",
    "content": "<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n    <!-- margin -->\n    <dimen name=\"margin_tiny\">4dp</dimen>\n    <dimen name=\"margin_small\">8dp</dimen>\n    <dimen name=\"margin_medium\">16dp</dimen>\n    <dimen name=\"margin_large\">32dp</dimen>\n    <dimen name=\"margin_huge\">64dp</dimen>\n    <dimen name=\"margin_only_txt\">48dp</dimen>\n\n    <!-- txtsize -->\n    <dimen name=\"txtsize_display1\">34sp</dimen>\n    <dimen name=\"txtsize_headline\">24sp</dimen>\n    <dimen name=\"txtsize_title\">20sp</dimen>\n    <dimen name=\"txtsize_subhead\">16sp</dimen>\n    <dimen name=\"txtsize_body\">14sp</dimen>\n    <dimen name=\"txtsize_caption\">12sp</dimen>\n\n    <!-- other size -->\n    <dimen name=\"corner_radius\">2dp</dimen>\n    <dimen name=\"banner_height\">136dp</dimen>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"dialog_positive\">确定</string>\n    <string name=\"dialog_negative\">取消</string>\n</resources>"
  },
  {
    "path": "DesignResCollection_MVC/bdcodehelper/src/main/res/values/styles.xml",
    "content": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <style name=\"AppBaseTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n\n    </style>\n\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowFullscreen\">false</item>\n        <item name=\"android:windowActionBar\">false</item>\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"colorButtonNormal\">@color/colorPrimary</item>\n        <item name=\"colorControlActivated\">@color/colorPrimary</item>\n        <item name=\"android:windowBackground\">@color/bg_gray</item>\n    </style>\n\n    <style name=\"TextViewHeadline\" parent=\"TextAppearance.AppCompat.Headline\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:singleLine\">true</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewTitle\" parent=\"TextAppearance.AppCompat.Title\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:singleLine\">true</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewSubhead\" parent=\"TextAppearance.AppCompat.Subhead\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewBody\" parent=\"TextAppearance.AppCompat.Body1\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewCaption\" parent=\"TextAppearance.AppCompat.Caption\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_light_gray</item>\n    </style>\n\n    <style name=\"EditTextSingleLine\" parent=\"@style/Widget.AppCompat.EditText\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">48dp</item>\n        <item name=\"android:textColorHint\">@color/txt_light_gray</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n        <item name=\"android:textSize\">@dimen/txtsize_subhead</item>\n        <item name=\"android:singleLine\">true</item>\n    </style>\n\n    <style name=\"ButtonPrimary\" parent=\"TextViewSubhead\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:textSize\">20sp</item>\n        <item name=\"android:textColor\">@color/txt_white2gray_sel</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:background\">@drawable/correct_primary2dark_sel</item>\n    </style>\n\n    <style name=\"RadioButtonBottomTab\">\n        <item name=\"android:layout_weight\">1</item>\n        <item name=\"android:layout_width\">0dp</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:button\">@null</item>\n        <item name=\"android:background\">@drawable/bg_white2gray_sel</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:paddingBottom\">@dimen/margin_small</item>\n        <item name=\"android:paddingTop\">@dimen/margin_small</item>\n    </style>\n\n    <style name=\"AbsListViewCommon\" parent=\"Widget.AppCompat.ListView\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:cacheColorHint\">@android:color/transparent</item>\n        <item name=\"android:listSelector\">@android:color/transparent</item>\n        <item name=\"android:divider\">@null</item>\n        <item name=\"android:dividerHeight\">0dp</item>\n        <item name=\"android:scrollbars\">none</item>\n    </style>\n\n    <style name=\"ListViewLineDivider\" parent=\"AbsListViewCommon\">\n        <item name=\"android:divider\">@color/divider_gray</item>\n        <item name=\"android:dividerHeight\">1px</item>\n    </style>\n\n    <style name=\"GridViewImages\" parent=\"AbsListViewCommon\">\n        <item name=\"android:horizontalSpacing\">4dp</item>\n        <item name=\"android:verticalSpacing\">4dp</item>\n    </style>\n\n    <!-- 自定义对话框 -->\n    <style name=\"custom_dialog\" parent=\"Theme.AppCompat.Dialog\">\n        <item name=\"android:windowFrame\">@null</item>\n        <item name=\"android:windowIsFloating\">true</item>\n        <item name=\"android:windowIsTranslucent\">false</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:background\">@android:color/transparent</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n\n    </style>\n</resources>"
  },
  {
    "path": "DesignResCollection_MVC/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.1.2'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n\n// Define versions in a single place\next {\n    // Sdk and tools\n    minSdkVersion = 15\n    targetSdkVersion = 23\n    compileSdkVersion = 23\n    buildToolsVersion = '23.0.3'\n\n    // App dependencies\n    supportLibraryVersion = '23.4.0'\n    guavaVersion = '18.0'\n    junitVersion = '4.12'\n    mockitoVersion = '1.10.19'\n    powerMockito = '1.6.2'\n    hamcrestVersion = '1.3'\n    runnerVersion = '0.4.1'\n    rulesVersion = '0.4.1'\n    espressoVersion = '2.2.1'\n    retrofitVersion = '2.0.0-beta2'\n    okhttploggingVersion = '2.6.0'\n    rxjavaVersion = '1.1.0'\n    rxbindingVersion = '0.2.0'\n    glideVersion = '3.6.1'\n    glideokhttpVersion = '1.3.1'\n    photoviewVersion = '1.2.4'\n}"
  },
  {
    "path": "DesignResCollection_MVC/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Dec 28 10:00:20 PST 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip\n"
  },
  {
    "path": "DesignResCollection_MVC/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "DesignResCollection_MVC/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "DesignResCollection_MVC/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "DesignResCollection_MVC/settings.gradle",
    "content": "include ':app', ':bdcodehelper'\n"
  },
  {
    "path": "DesignResCollection_MVP/README.md",
    "content": "## 为什么选择MVP？\n\n相信大部分人都听过这个框架，或者已经使用过。\n了解和简单运用的过程中大家一定会有这样几个问题或者痛点：\n* [**MVP有什么好处，为什么要用它？**](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP#mvp有什么好处为什么要用它)  \n* [**MVP结构代码怎么写？**](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP#mvp结构代码怎么写) \n* [**为什么MVP结构利于单元测试？而且我为什么要写测试代码呢？**](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP#我为什么要写测试代码呢不是浪费时间吗) \n* [**好了你说服我了，但是我不会写单元测试啊！**](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP#怎么写测试代码呢) \n* [**MVP多了好多类，还要写测试代码，写起来好累啊！老娘不想这么麻烦啊！**](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP#mvp多了好多类还要写测试代码写起来好累啊老娘不想这么麻烦啊) \n\n这里班门弄斧的分享下我的经验，挨个解决这几个问题。\n\n---\n\n## MVP有什么好处，为什么要用它？\n网上文章一大堆，总结下来主要有下面几个优点：\n* 代码解耦、结构更清晰\n* 更好的拓展性\n* 可复用性\n* 利于单元测试\n\n优点其实主要是相对传统MVC结构而言的，简单对比下：\n* MVC（Model-View-Controller）\n传统MVC结构中，C承担着一个总控制器的作用，处理Model数据，再控制View的显示。\n大部分时候Activity类就是这个角色，我们在Activity中调用接口，接口返回数据后各种setText setImage显示到UI上。\n* MVP（Model-View-Presenter）\n重点在于Presenter，它其实是将Model和View分开了，在其中起到一个中转站的角色。\n把Model数据拿来一通处理，然后丢给View让它自己去解决具体的UI显示。\n\n**打个比方\n如果处理Model处理业务逻辑就是加工食材做菜。把菜送到客户手里呈现给客户就是View的展示。\n那MVC就是大排档。C就是独自运营的老板，自己炒菜，做完再自己送到小桌子上的客户面前，一条龙。\nMVP就是正规大餐厅，P则是后厨中心，海绵宝宝做好蟹黄堡后放到窗口处，叮一下通知前台好了可以送餐了，不用关心菜是怎么送到客户手里的。然后由服务员章鱼哥在窗口处取了餐，再或跑或跳或踩着轱辘鞋最后送到客户手里，合作完成。**\n\n所以这里也可以看出来，MVP最重要的特点就是：\n**将 Model业务逻辑处理 和 View页面处理 分开！！！**\n\nMVP的良好拓展性、解耦、利于单元测试等优点基本都是来源于此。\n\n纯语言描述大家可能还是不好理解，下面上实战项目。\n\n---\n\n## MVP结构代码怎么写？\n示例项目中的MVP结构参考了[谷歌官方MVP示例项目](https://github.com/googlesamples/android-architecture/tree/todo-mvp/)中的写法。每个功能模块都包含以下几部分：\n* **Contract协议类**  \n这个Contract协议类不是MVP中的任何一个模块，是把所有View和Presenter的方法都提取成了接口放在这里，作为一个总的规则、协议，方便统一管理。\n比如下面的代码，就是示例项目中意见反馈页面的Contract协议类，提供了View和Presenter的接口。\n其中BaseView和BasePresenter是提供了一些基础方法，比如显示进度showProgress等，自己可以按需添加。\n```java\npublic interface FeedBackContract {    \n    interface View extends BaseView<Presenter> {        \n        void addFeedbackSuccess();    \n    }    \n\n    interface Presenter extends BasePresenter {        \n        void addFeedback(String content, String email);    \n    }\n}\n```\n* **Model**  \n数据层，和MVC结构中的无区别，没啥好说的。\n\n* **Presenter**  \n负责处理业务逻辑代码，处理Model数据，然后分发给View层的抽象接口。\n注意，这里是将处理好的数据派发给View的抽象接口，是一个简单的中转分发出去，并不负责具体展示\n```java\npublic class FeedBackPresenter implements FeedBackContract.Presenter {\n    private final FeedBackContract.View view;\n    private final HttpRequest.ApiService api;\n\n    public FeedBackPresenter(FeedBackContract.View view, HttpRequest.ApiService api) {\n        this.view = view;\n        this.api = api;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void addFeedback(String content, String email) {\n        // 开始验证输入内容\n        if (StringUtils.isEmpty(content)) {\n            view.showTip(\"反馈内容不能为空\");\n            return;\n        }\n        if (StringUtils.isEmpty(email)) {\n            view.showTip(\"请输入邮箱地址,方便我们对您的意见进行及时回复\");\n            return;\n        }\n\n        view.showProgress();\n\n        // 使用自定义对象存至云平台,作为简易版的反馈意见收集\n        FeedBack fb = new FeedBack();\n        fb.setContent(content);\n        fb.setEmail(email);\n        Observable<BaseEntity> observable = ObservableDecorator.decorate(api.addFeedBack(fb));\n        observable.subscribe(new Subscriber<BaseEntity>() {\n            @Override\n            public void onCompleted() {\n            }\n            @Override\n            public void onError(Throwable e) {\n                if (!view.isActive()) {\n                    return;\n                }\n\n                view.dismissProgress();\n                view.showTip(\"反馈提交失败\");\n            }\n            @Override\n            public void onNext(BaseEntity entity) {\n                if (!view.isActive()) {\n                    return;\n                }\n\n                view.dismissProgress();\n                view.addFeedbackSuccess();\n            }\n        });\n    }\n}\n```\n\n* **View**  \n负责UI具体实现展现。比如Presenter派发过来一个动作是showProgress显示进度命令，那由我这个View负责实现具体UI，是显示进度框还是显示一个下拉刷新圈圈等，都是View这里自行控制。\nGoogle的例子中，每个Activity中都会添加一个Fragment作为View实现，Activity仅仅作为一个容器，包含一个Fragment在其中显示各种控件。我觉得其实也可以直接将Activity作为View。本示例代码中两种方式都有，可以根据需要自行选择方式~ \n```java\npublic class FeedBackActivity extends BaseActivity implements FeedBackContract.View {\n    private FeedBackContract.Presenter presenter;\n    private EditText et_content;\n    private EditText et_email;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_feed_back);\n        initView();\n    }\n\n    private void initView() {\n        presenter = new FeedBackPresenter(this, HttpRequest.getInstance().service);\n        initBackTitle(\"意见反馈\")\n                .setRightText(\"提交\")\n                .setRightOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        submit();\n                    }\n                });\n        et_content = (EditText) findViewById(R.id.et_content);\n        et_email = (EditText) findViewById(R.id.et_email);\n    }\n\n    private void submit() {\n        // 开始验证输入内容\n        String content = et_content.getText().toString().trim();\n        String email = et_email.getText().toString().trim();\n        presenter.addFeedback(content, email);\n    }\n\n    @Override\n    public void addFeedbackSuccess() {\n        showToast(\"反馈成功\");\n        finish();\n    }\n\n    @Override\n    public void setPresenter(FeedBackContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}\n```\n\n  注意，这里BaseView中会有一个isActivite方法，用于判断视图是否被销毁。我在BaseActivity中会统一处理，添加一个isActivite变量，onStart时设为true，onStop时设为false。\n然后在presenter里的接口返回数据后，判断view是否被销毁然后再控制显示，因为接口是异步的，所以返回数据后视图可能已经销毁，那就没必要更新了，更新反而还会崩溃报错。\n\n**好了，现在再回头看看MVP的几个优点，可能就有更好的理解了（当然，还是要自己撸过一遍最好）**\n  1. 更好的拓展性。  \n    * 某天页面需要加功能了，协议类中先写好对应的P逻辑方法、V页面方法，然后在实现类中分别编写具体代码即可。\n    * 某天突然改功能了，说所有错误提示我们不用Toast，用Dialog吧，那直接在showTip处修改即可。\n    * 某天产品突然告诉你说意见反馈，失败我们也让用户觉得成功，那直接在Error回调里调用view抽象方法即可。\n  2. 解耦、更好的代码结构。  \n    * 业务逻辑 和 页面UI 代码分开，不揉在一起，改逻辑的时候不用关心UI，反之亦然。\n    * 想了解某个模块功能时，直接在协议类中看一个个抽象方法，不用关心代码，清晰明了。\n    * 还有代码可以分工合作，核心业务逻辑你在P中自己写，UI的具体实现直接给其他人合作写。\n  3. 可复用性。  \n  比如本项目中的注册功能，注册步骤1和步骤2页面中都有发送验证码功能，那就可以使用同一个P了，在其中调用获取验证码接口。然后各自实现具体View显示，步骤1页面获取验证码成功后跳转到页面2，页面2获取成功后开始数字倒计时。\n\n---\n\n## 为什么MVP结构利于单元测试？\n之前提到过，MVP结构最大的特点是，P将逻辑和UI分开了。即P 中没有任何Android相关的代码，比如Toast啊、setText等等。这意味着~ 你可以针对Presenter写junit测试了。只对java代码的测试，不用涉及任何UI！！！不用运行模拟器的测试！！！！！速度起飞的测试！！！！！！！！\n\n说的这么热闹，那么\n\n## 我为什么要写测试代码呢？不是浪费时间吗？\n测试其实除了检测bug验证逻辑之外，还有最重要的一个功能是**提高开发速度！**\n你没有看错，虽然写了更多的代码，但实际效率是提升的，尤其对越庞大越复杂的应用来说。\n可能我这样说不够权威，可以看下经典书籍《重构》然后自己尝试一下，可能就会有感受了。\n\n---\n\n## 怎么写测试代码呢？\n我们先介绍下Android中的两种测试\n* **UI测试（本项目中使用框架Espresso）**  \nUI测试其实就是模拟机器上的操作行为，让它自动进行的“点击某个位置”、“输入某些字符串”等行为。\n是依赖安卓设备的，测试的时候可以在手机或模拟器屏幕上看到页面被各种点点点，输输输，跳来跳去。\n\n  这个其实和MVP结构关系不大，MVC，MVP，或者MVABCDEFG都可以进行UI测试，所以这里暂时不多做介绍，可以直接参考示例项目中的代码。UI测试部分的内容其实也很多，以后单独拿出来再详细展开。\n\n  项目中androidTest文件夹里的就是UI测试代码，而test文件夹才是Junit部分的单元测试代码。\n\n* **对Presenter进行Junit单元测试（本项目中使用框架Mockito）**  \nUI测试虽然接近真实场景，但是有个缺点是要运行应用到模拟器上，所以速度就会有影响，慢~\n而且开发中也会常有这样一个需要，调试接口时，我不想点点点跳转到那个页面再输入东西再点按钮，费时间啊~而用postman啥的工具也麻烦，header还要重新写，如果有参数加密就更蛋疼了。\n\n  所以，这个时候你就需要Junit单元测试了，最大的特点就是**不用运行安卓设备，直接run代码，速度飞快！**\n\n* **单元测试代码示例**  \n正式开始介绍怎么写之前，先感受下单元测试是什么样的，如下图\n\n![意见反馈Presenter代码截图](http://upload-images.jianshu.io/upload_images/1513977-e63720e22dbfd3c8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n这里针对示例项目中意见反馈Presenter分别测试了几个场景\n  * 真实接口提交成功\n  * 模拟接口提交成功\n  * 模拟接口提交失败\n\n三个Test方法，针对三个测试场景。\n突破左下角运行情况可以看到，一共用了852ms，1秒不到！！！\n第一个测试方法因为是真实调用接口数据，所以稍微耗费点时间。\n右下角也可以看到3个用例全测试成功通过，也打印了真实调用数据的接口日志。\n完美~\n\n---\n##如何写单元测试代码\n编写步骤按照以下进行\n\n**1. 新建Presenter的测试类**  \n右键Presenter类 -> Go To -> Test -> create new test  \n![](http://upload-images.jianshu.io/upload_images/1513977-d4e327220c223843.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/620)  \n弹出一个创建测试类对话框，然后勾选需要测试的方法（当然也可以自己手动创建方法）。然后OK，选择test文件夹完成测试类创建。  \n![](http://upload-images.jianshu.io/upload_images/1513977-91538231b56a4d2e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/620)\n\n**2. 测试类的初始化**  \n  代码如下（mockito的gradle配置等参考项目中build.gradle）\n\n```java\n// 用于测试真实接口返回数据\nprivate FeedBackPresenter presenter;\n\n// 用于测试模拟接口返回数据\nprivate FeedBackPresenter mockPresenter;\n\n@Mock\nprivate FeedBackContract.View view;\n@Mock\nprivate HttpRequest.ApiService api;\n\n@Before\npublic void setupMocksAndView() {\n    // 使用Mock标签等需要先init初始化一下\n    MockitoAnnotations.initMocks(this);\n\n    // 当view调用isActive方法时，就返回true表示UI已激活。方便测试接口返回数据后测试view的方法\n    when(view.isActive()).thenReturn(true);\n\n    // 设置单元测试标识\n    BoreConstants.isUnitTest = true;\n\n    // 用真实接口创建反馈\n    Presenter presenter = new FeedBackPresenter(view, HttpRequest.getInstance().service);\n    // 用mock模拟接口创建反馈\n    Presenter mockPresenter = new FeedBackPresenter(view, api);\n}\n```\n\n这里用到了一个很重要的框架 Mockito。\n#### Mockito框架介绍\n* **Mockito框架是干什么的？**  \nmockito框架是用来模拟数据和情景的，方便我们的测试工作进行。\n* **为什么要用Mockito框架？**  \n比如我们MVP结构中P的测试，有个问题是：创建Presenter对象的时候这个View怎么办？传入null会空指针啊。还有很多接口调用等逻辑，很多奇怪的失败情况怎么测试？\n这个时候就可以用mockito了~ 直接模拟一个view接口对象，不用关心它的具体实现；失败情况直接用when方法搞定；此外还提供了其他一系列方便测试的方法，比如verify用于判断某对象是否执行了某个方法等。后面会根据例子挨个介绍。\n\n网上很多例子其实是纯mock模拟测试，也就是接口api也是模拟的，模拟接口调用，模拟接口返回数据。\n虽然这样速度快且方便模拟各种错误情况，但是有时候也会想要测试真实的接口返回情况，因此本项目示例中提供了两种模拟和真实接口的写法和处理。参考上面代码里的presenter和mockPresenter对象。\n\n注意，mock相关方法比如verify、when等使用者也都必须是mock对象，所以使用presenter的时候不能用when什么的方法模拟接口返回。\n\n@Before标签的方法，是每个测试方法调用前都会走一遍的方法，因此在里面放了一系列的初始化操作，每个操作都添加了注释。其中需要单独解释的是when方法。\n```java\nwhen(view.isActive()).thenReturn(true);\n```\n这个是mockito框架提供的一个方法，看英文基本就能了解什么意思了，当xx方法调用时就返回xx\n因为我们的view的模拟的，所以没有实现isActive方法，则p中数据返回后就无法继续走下去了，因此这里when处理一下。只要调用这个方法就返回true。\n  \n**3. 测试方法编写**  \n通常Presenter中的一个业务方法会对应至少一个测试方法。\n比如这里的意见反馈业务，就分别对应意见提交成功、失败两种情景。\n方法名字可以随便定，有个@Test标签即可，推荐方法取名为：test+待测方法原名+测试场景\n测试场景一共有哪些呢？这个最好问测试要个测试用例按照待测功能对应的所有情景挨个来。\n\n我这里写的单元测试代码，对于接口又分了两种：** 模拟接口 ** 和 ** 真实接口 **\n\n直接全部用真实接口测不很好吗，为什么要mock模拟测试呢？\n好吧，比如我们这个意见反馈，不像登录还有密码错误的情况，很少有场景能失败。怎么办？\n所以对于难以模拟的情景，还是需要用mockito框架模拟的，模拟个失败，然后验证失败后的一系列逻辑~\n\n下面挨个介绍测试方法，模拟成功和失败差不多就只介绍失败了。\n\n* **模拟接口测试方法示例 - 模拟提交失败**\n```java\n@Test\npublic void testAddFeedback_Mock_Error() throws Exception {\n    // 模拟数据，当api调用addFeedBack接口传入任意值时，就抛出错误error\n    when(api.addFeedBack(any(FeedBack.class)))\n        .thenReturn(Observable.<BaseEntity>error(new Exception(\"孙贼你说谁辣鸡呢？\")));\n\n    String content = \"这个App真是辣鸡！\";\n    String email = \"120@qq.com\";\n    mockPresenter.addFeedback(content, email);\n\n    verify(view).showProgress();\n    verify(view).dismissProgress();\n    verify(view).showTip(\"反馈提交失败\");\n}\n```\n这里重点是when的运用，当模拟的api调用addFeedBack时，就返回error结果。\n然后调用mockPresenter的意见反馈业务方法，最后验证结果。\n注意，这个verify方法也是特别常用的一个mockito方法，用于验证某个对象是否执行了某个方法。\n最后运行测试，成功，完美~\n\n\n* **真实接口测试方法示例 - 提交成功**  \n```java\n@Test\npublic void testAddFeedback_Success() throws Exception {\n    // 真实数据，调用实际接口\n    String content = \"这个App真是好！\";\n    String email = \"110@qq.com\";\n    presenter.addFeedback(content, email);\n\n    verify(view).showProgress();\n    verify(view).dismissProgress();\n    verify(view).addFeedbackSuccess();\n}\n```\n这里用了真实接口对应的presenter对象，调用接口，然后验证成功结果。\n运行测试，成功，完美~\n\n  再次强调，mockito的方法都是针对模拟对象的，所以调用真实请求api时，你也想用when去处理，那就会报错~\n\n  注意，真实接口由于是异步的，所以如果不做任何处理是无法测试通过的，接口数据还没返回就运行下面的验证了，自然失败。因此需要对回调做一个处理，将其修改为同步请求，这样就能一条线下来了，运行完接口再进行验证。项目是基于Retrofit框架的，使用RxJava处理回调，我这里所有的回调都会用一个ObservableDecorator处理一下，而在其中我会判断，如果当前是测试状态（也就是Before中的那个isUnitTest 参数），就将回调设置为同步，具体代码参考项目中。\n\n**4. 运行单元测试用例**  \n* 右键方法，run 测试单个用例方法\n* 右键类，run 测试该类中包含的全部用例方法\n\n最后控制台看结果\n参考最上面单元测试代码示例中的截图，下面控制台会显示测试了哪些方法，测试成功通过了几个方法，然后打印相应日志，如果不通过还会打印对应错误信息。\n\n好了，写法介绍完毕~\n更多例子请去项目中查看，这里篇幅有限就不太详细的展开了，简单列举几个例子让大家感受下。\n\n---\n\n## MVP多了好多类，还要写测试代码，写起来好累啊！老娘不想这么麻烦啊！\n这一点估计是最重要的原因把绝大部分人阻挡在门外。\n毕竟平常普通的撸就那么累了，还要这么麻烦，没时间啊没精力啊！！！\n\n* **不一定所有功能都用MVP**  \n就像之前例子举得那样，大排档和正规餐厅。你在一个超级偏远没人流量生意差到爆的地方还整个后厨中心，就过了。同理，如果你有的功能业务逻辑比较简单，自然就没必要MVP了，简单的关于页面你也一顿MVP可能就有点猛了，所以不一定所有功能都使用MVP。\n\n* **单元测试利于开发**  \n代码结构啥的就不说了，单元测试这个有时候真的很方便，尤其是运行快。相信大部分人都有经验，遇到个不靠谱后台的时候，经常要陪他们调接口，再遇到那种特别深的页面简直是浪费人生。单元测试代码，run，唰~秒搞定。自测某些逻辑功能时也很有用，这一点上看来绝对是节省时间的。\n\n* **LiveTemplate（干货！！！一键生成模板代码，模板可自定义！！！）**  \n我通常撸的时候特别特别注重速度效率。之前也开发过很多插件工作，比如已经发布的自动生成代码布局的开源AndroidStudio插件。https://github.com/boredream/BorePlugin\n\n  然后就寻思，写这种特别有规律的MVP各种类，还有测试类等的时候，要不也弄个插件生成下？\n但是想了下觉得插件生成模板代码的话，模板怎么写呢？尤其MVP这种不同的人写法也不同啊。\n最后突然想起来了AndroidStudio里自带的LiveTemplate这东西，是AS中自带的一个模板代码系统。\n\n####使用LiveTemplate模板\n先展示下该功能的强大，这里我以前提前写好过几个模板了。拿协议类举例。  \n1. 右键需要生成的位置 -> New -> 选择模板（如下图的MvpContract）  \n![](http://upload-images.jianshu.io/upload_images/1513977-01bbba5d35b7cbd6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  \n2. 然后弹出对话框，为模板输入需要的变量，OK生成  \n![](http://upload-images.jianshu.io/upload_images/1513977-7ddead582f672c79.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  \n3. 这样就按照我们的模板创建了一个文件，右侧文件代码全部都是自动生成的，然后按需修改加入方法即可。  \n![](http://upload-images.jianshu.io/upload_images/1513977-8dbb18d5fc8bddff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  \n\n那么模板哪里来的呢~下面介绍\n\n####编辑/创建LiveTemplate模板\n1. **编辑已有模板**： New -> 选择模板的时候，模板底部有个Edit File Template，点击之。参见上面使用步骤1的图。  \n2. **创建新的模板**：打开你希望生成模板的文件，选择工具栏中的Tool -> Save File as Template  \n3. 步骤1、 2都会打开下面这样一个编辑页面，区别在于创建比编辑少个左侧的已有模板列表  \n给模板起个名字，然后在内容页面里根据需要删删改改即可，模板里所有${NAME}的地方都会替换成你创建模板时候输入的文件名，其他的${XXX}的作用可参考下面Description里的描述。最后OK保存模板。  \n![](http://upload-images.jianshu.io/upload_images/1513977-4b5be95db3d361d5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)  \n\nLiveTemplate虽然无法替你搞定绝大部分代码，但是这样一个快捷的模板，可以灵活的随时编辑还是很方便的，还是能节省相当代码量的。\n\n和本期主题无关的插个话，LiveTemplate是个很神奇的东西，很多地方都可以用，不光有文件的模板，代码也是。比如输入sout+回车就会自动生成System.out.print()代码，输入Toast+回车就会自动生成Toast.make blablabl的代码，超级方便。比如你们项目有BaseActivity，需要复写几个方法，那就可以自定义创建个页面类文件模板里面处理好继承和方法，就不用每次新建完Activity都去写一下继承了。更多用法期待你滴挖掘~\n\n---\n\n## 结语\n好了，之前提的所有问题和痛点都挨个解答过了，尤其最后的LiveTemplate，对于还不知道的同学，即使最后你还是不愿意用MVP和写单元测试，那这部分你也算赚到了哈哈。\n\n因为要介绍的内容比较多，MVP啊~测试啊~Junit单元测试啊~LiveTemplate啊~ 所以介绍的比较精简，主旨在抛砖引玉，希望大家对这几个东西能有个了解，感兴趣后再深入研究，也希望与我多多交流大家共同进步。\n\n本项目里Junit测试模块其实还是有几个问题的，比如Presenter我是将接口Api作为构造函数参数依赖注入的，所以其实还可以再加入Dagger2改进一番，下一个框架就会在MVP的结构上加入Dagger2。\n\n谷歌例子中RxJava是单独拎出来说的，我这里Retrofit2+RxJava是作为所有例子通用框架的，用法可以给大家作为一个参考，这里就不扫盲Retrofit用法了。\n\n最后，如果文章对你有一点作用和启发，希望能支持一下，欢迎follow我和star本项目\n"
  },
  {
    "path": "DesignResCollection_MVP/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.boredream.designrescollection\"\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode 70\n        versionName \"0.7.0\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'\n        }\n    }\n\n    packagingOptions {\n        exclude 'META-INF/DEPENDENCIES'\n        exclude 'META-INF/LICENSE'\n        exclude 'META-INF/NOTICE'\n    }\n\n    android.applicationVariants.all { variant ->\n        renameAPK(variant, defaultConfig, \"release\")\n    }\n}\n\ndef renameAPK(variant, defaultConfig, buildType) {\n    variant.outputs.each { output ->\n        def applicationName = 'DesignResCollection'\n        def formattedDate = new Date().format('yyyyMMdd')\n        def file = output.packageApplication.outputFile\n        def fileName = applicationName + \"_v\" + defaultConfig.versionName + \"_\" + formattedDate + \"_\" + buildType + \".apk\"\n        output.packageApplication.outputFile = new File(file.parent, fileName)\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(path: ':bdcodehelper')\n\n    // Dependencies for local unit tests\n    testCompile \"junit:junit:$rootProject.ext.junitVersion\"\n    testCompile \"org.mockito:mockito-all:$rootProject.ext.mockitoVersion\"\n    testCompile \"org.hamcrest:hamcrest-all:$rootProject.ext.hamcrestVersion\"\n\n    // Espresso UI Testing\n    androidTestCompile \"com.android.support.test:runner:$rootProject.runnerVersion\"\n    androidTestCompile \"com.android.support.test:rules:$rootProject.rulesVersion\"\n    androidTestCompile \"com.android.support.test.espresso:espresso-core:$rootProject.espressoVersion\"\n    androidTestCompile \"com.android.support.test.espresso:espresso-contrib:$rootProject.espressoVersion\"\n    androidTestCompile \"com.android.support.test.espresso:espresso-intents:$rootProject.espressoVersion\"\n\n    // Resolve conflicts between main and test APK:\n    androidTestCompile \"com.android.support:support-annotations:$rootProject.supportLibraryVersion\"\n    androidTestCompile \"com.android.support:support-v4:$rootProject.supportLibraryVersion\"\n    androidTestCompile \"com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion\"\n}\n\nconfigurations {\n    androidTestCompile.exclude group: 'com.android.support', module: 'support-v4'\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/proguard.cfg",
    "content": "######################## 固定部分 ########################\n\n#1.基本指令区\n-optimizationpasses 5\n-dontusemixedcaseclassnames\n-dontskipnonpubliclibraryclasses\n-dontskipnonpubliclibraryclassmembers\n-dontpreverify\n-verbose\n-ignorewarning\n-printmapping proguardMapping.txt\n-optimizations !code/simplification/cast,!field/*,!class/merging/*\n-keepattributes *Annotation*,InnerClasses\n-keepattributes Signature\n-keepattributes SourceFile,LineNumberTable\n\n#2.默认保留区\n-keep public class * extends android.app.Activity\n-keep public class * extends android.app.Application\n-keep public class * extends android.app.Service\n-keep public class * extends android.content.BroadcastReceiver\n-keep public class * extends android.content.ContentProvider\n-keep public class * extends android.app.backup.BackupAgentHelper\n-keep public class * extends android.preference.Preference\n-keep public class * extends android.view.View\n-keep public class com.android.vending.licensing.ILicensingService\n-keep class android.support.** {*;}\n\n-keepclasseswithmembernames class * {\n    native <methods>;\n}\n-keepclassmembers class * extends android.app.Activity{\n    public void *(android.view.View);\n}\n-keepclassmembers enum * {\n    public static **[] values();\n    public static ** valueOf(java.lang.String);\n}\n-keep public class * extends android.view.View{\n    *** get*();\n    void set*(***);\n    public <init>(android.content.Context);\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keepclasseswithmembers class * {\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keep class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n-keepclassmembers class * implements java.io.Serializable {\n    static final long serialVersionUID;\n    private static final java.io.ObjectStreamField[] serialPersistentFields;\n    private void writeObject(java.io.ObjectOutputStream);\n    private void readObject(java.io.ObjectInputStream);\n    java.lang.Object writeReplace();\n    java.lang.Object readResolve();\n}\n-keep class **.R$* {\n *;\n}\n-keepclassmembers class * {\n    void *(**On*Event);\n}\n\n#3.webview\n-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n   public *;\n}\n-keepclassmembers class * extends android.webkit.webViewClient {\n    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);\n    public boolean *(android.webkit.WebView, java.lang.String);\n}\n-keepclassmembers class * extends android.webkit.webViewClient {\n    public void *(android.webkit.webView, jav.lang.String);\n}\n\n######################## 非固定部分 ########################\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/androidTest/java/com/boredream/designrescollection/ApplicationTest.java",
    "content": "package com.boredream.designrescollection;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/androidTest/java/com/boredream/designrescollection/idlingres/RxIdlingResource.java",
    "content": "package com.boredream.designrescollection.idlingres;\n\nimport android.support.test.espresso.Espresso;\nimport android.support.test.espresso.IdlingResource;\nimport android.util.Log;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.plugins.RxJavaObservableExecutionHook;\n\npublic class RxIdlingResource extends RxJavaObservableExecutionHook implements IdlingResource {\n\n    private static final String TAG = \"RxIdlingResource\";\n\n    private final AtomicInteger subscriptions = new AtomicInteger(0);\n\n    private static RxIdlingResource INSTANCE;\n\n    private ResourceCallback resourceCallback;\n\n    private RxIdlingResource() {\n        //private\n    }\n\n    public static RxIdlingResource get() {\n        if (INSTANCE == null) {\n            INSTANCE = new RxIdlingResource();\n            Espresso.registerIdlingResources(INSTANCE);\n        }\n        return INSTANCE;\n    }\n\n    /* ======================== */\n    /* IdlingResource Overrides */\n    /* ======================== */\n\n    @Override\n    public String getName() {\n        return TAG;\n    }\n\n    @Override\n    public boolean isIdleNow() {\n        int activeSubscriptionCount = subscriptions.get();\n        return activeSubscriptionCount == 0;\n    }\n\n    @Override\n    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {\n        this.resourceCallback = resourceCallback;\n    }\n\n    /* ======================================= */\n    /* RxJavaObservableExecutionHook Overrides */\n    /* ======================================= */\n\n    @Override\n    public <T> Observable.OnSubscribe<T> onSubscribeStart(Observable<? extends T> observableInstance,\n                                                          final Observable.OnSubscribe<T> onSubscribe) {\n        int activeSubscriptionCount = subscriptions.incrementAndGet();\n        Log.d(TAG, onSubscribe + \" - onSubscribeStart: \" + activeSubscriptionCount);\n\n        return new Observable.OnSubscribe<T>() {\n            @Override\n            public void call(final Subscriber<? super T> subscriber) {\n                onSubscribe.call(new Subscriber<T>() {\n                    @Override\n                    public void onCompleted() {\n                        subscriber.onCompleted();\n                        onFinally(onSubscribe, \"onCompleted\");\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        subscriber.onError(e);\n                        onFinally(onSubscribe, \"onError\");\n                    }\n\n                    @Override\n                    public void onNext(T t) {\n                        subscriber.onNext(t);\n                    }\n                });\n            }\n        };\n    }\n\n    private <T> void onFinally(Observable.OnSubscribe<T> onSubscribe, final String finalizeCaller) {\n        int activeSubscriptionCount = subscriptions.decrementAndGet();\n        Log.d(TAG, onSubscribe + \" - \" + finalizeCaller + \": \" + activeSubscriptionCount);\n\n        if (activeSubscriptionCount == 0) {\n            Log.d(TAG, \"onTransitionToIdle\");\n            resourceCallback.onTransitionToIdle();\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/androidTest/java/com/boredream/designrescollection/ui/login/LoginActivityTest.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport android.content.Intent;\nimport android.support.test.rule.ActivityTestRule;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.idlingres.RxIdlingResource;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport rx.plugins.RxJavaPlugins;\n\nimport static android.support.test.espresso.Espresso.onView;\nimport static android.support.test.espresso.action.ViewActions.click;\nimport static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;\nimport static android.support.test.espresso.action.ViewActions.typeText;\nimport static android.support.test.espresso.assertion.ViewAssertions.matches;\nimport static android.support.test.espresso.matcher.RootMatchers.withDecorView;\nimport static android.support.test.espresso.matcher.ViewMatchers.withId;\nimport static android.support.test.espresso.matcher.ViewMatchers.withText;\nimport static org.hamcrest.core.Is.is;\nimport static org.hamcrest.core.IsNot.not;\n\n@RunWith(AndroidJUnit4.class)\npublic class LoginActivityTest {\n\n\t@Rule\n\tpublic ActivityTestRule<LoginActivity> mActivityRule = new ActivityTestRule<>(LoginActivity.class, true, false);\n\n\tstatic {\n\t\tRxJavaPlugins.getInstance().registerObservableExecutionHook(RxIdlingResource.get());\n\t}\n\n\t@Test\n\tpublic void testLogin_EmptyPassword() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"13913391521\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"密码不能为空\")));\n\t}\n\n\t@Test\n\tpublic void testLogin_EmptyUsername() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"123456\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"用户名不能为空\")));\n\t}\n\n\t@Test\n\tpublic void testLogin_Success() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tintent.putExtra(\"checkLogin\", true);\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"18551681236\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"123456\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tAssert.assertTrue(UserInfoKeeper.getCurrentUser() != null);\n\t}\n\n\t@Test\n\tpublic void testLogin_UserNotExit() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"110110110\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"123456\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"找不到用户\")));\n\t}\n\n\t@Test\n\tpublic void testLogin_PswError() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"18551681236\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"110\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"密码不正确\")));\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/androidTest/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditActivityTest.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport android.app.Activity;\nimport android.app.Instrumentation;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.support.test.espresso.intent.Intents;\nimport android.support.test.rule.ActivityTestRule;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.idlingres.RxIdlingResource;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.hamcrest.core.IsNot;\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport java.util.Random;\n\nimport rx.plugins.RxJavaPlugins;\n\nimport static android.support.test.espresso.Espresso.onView;\nimport static android.support.test.espresso.action.ViewActions.click;\nimport static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;\nimport static android.support.test.espresso.action.ViewActions.typeText;\nimport static android.support.test.espresso.assertion.ViewAssertions.matches;\nimport static android.support.test.espresso.intent.Intents.intending;\nimport static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;\nimport static android.support.test.espresso.matcher.RootMatchers.withDecorView;\nimport static android.support.test.espresso.matcher.ViewMatchers.withId;\nimport static android.support.test.espresso.matcher.ViewMatchers.withText;\nimport static org.hamcrest.core.Is.is;\n\n@RunWith(AndroidJUnit4.class)\npublic class UserInfoEditActivityTest {\n\n    @Rule\n    public ActivityTestRule<UserInfoEditActivity> mActivityRule = new ActivityTestRule<>(UserInfoEditActivity.class, true, true);\n\n    static {\n        User user = new User();\n        user.setObjectId(\"57abf85e2e958a00543737da\");\n        user.setUsername(\"18551681236\");\n        user.setNickname(\"\");\n        user.setSessionToken(\"hh45pryl55lbm6n3l6sfbuywg\");\n        UserInfoKeeper.setCurrentUser(user);\n\n        RxJavaPlugins.getInstance().registerObservableExecutionHook(RxIdlingResource.get());\n    }\n\n    @Test\n    public void testUploadAvatar() throws Exception {\n        Intents.init();\n\n        // Stub the Intent.\n        Instrumentation.ActivityResult resultGallery = createImageGalleryActivityResultStub();\n        intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(resultGallery);\n\n        // actions\n        onView(withId(R.id.ll_avatar)).perform(click());\n        onView(withText(\"相册\"))\n                .inRoot(withDecorView(IsNot.not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n                .perform(click());\n\n        // assertions\n        Assert.assertTrue(UserInfoKeeper.getCurrentUser().getAvatar() != null);\n    }\n\n    private Instrumentation.ActivityResult createImageGalleryActivityResultStub() {\n        Uri uri = Uri.parse(\"file:///android_asset/test_avatar.jpg\");\n\n        Intent resultData = new Intent();\n        resultData.setData(uri);\n\n        // Create the ActivityResult with the Intent.\n        return new Instrumentation.ActivityResult(Activity.RESULT_OK, resultData);\n    }\n\n    @Test\n    public void testUpdateNickname() throws Exception {\n        String newName = \"boredream\" + new Random().nextInt(10);\n\n        // actions\n        onView(withId(R.id.ll_username)).perform(click());\n        onView(withId(R.id.et_input)).perform(typeText(newName), closeSoftKeyboard());\n        onView(withText(\"保存\")).perform(click());\n\n        // assertions\n        onView(withId(R.id.tv_username)).check(matches(withText(newName)));\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.boredream.designrescollection\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_LOGS\" />\n    <uses-permission android:name=\"android.permission.CALL_PHONE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n\n    <application\n        android:name=\".base.BaseApplication\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".ui.MainActivity\"\n            android:launchMode=\"singleTask\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\".ui.register.RegisterStep1Activity\" />\n        <activity android:name=\".ui.register.RegisterStep2Activity\" />\n        <activity android:name=\".ui.login.LoginActivity\" />\n        <activity android:name=\".ui.SettingActivity\" />\n        <activity android:name=\".ui.AboutActivity\" />\n        <activity android:name=\".ui.userinfoedit.UserInfoEditActivity\" />\n        <activity android:name=\".ui.modifytext.ModifyTextActivity\" />\n        <activity android:name=\".ui.feedback.FeedBackActivity\" />\n        <activity\n            android:name=\".ui.login.Main2Activity\"\n            android:label=\"@string/title_activity_main2\"></activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/adapter/DesignResAdapter.java",
    "content": "package com.boredream.designrescollection.adapter;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.activity.WebViewActivity;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.net.GlideHelper;\n\nimport java.util.ArrayList;\n\npublic class DesignResAdapter extends RecyclerView.Adapter<DesignResAdapter.ViewHolder> {\n\n    private Context context;\n    private ArrayList<DesignRes> datas;\n\n    public DesignResAdapter(Context context, ArrayList<DesignRes> datas) {\n        this.context = context;\n        this.datas = datas;\n    }\n\n    @Override\n    public int getItemCount() {\n        return datas.size();\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        public ImageView iv_image;\n        public TextView tv_name;\n\n        public ViewHolder(View rootView) {\n            super(rootView);\n\n            this.iv_image = (ImageView) rootView.findViewById(R.id.iv_image);\n            this.tv_name = (TextView) rootView.findViewById(R.id.tv_name);\n        }\n\n    }\n\n    @Override\n    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(context).inflate(R.layout.item_design_res, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(ViewHolder holder, int position) {\n        final DesignRes data = datas.get(position);\n\n        GlideHelper.showImage(context, data.getImgUrl(), holder.iv_image);\n        String str = String.format(\"[%s] %s\", data.getSrcTag(), data.getName());\n        holder.tv_name.setText(str);\n\n        holder.itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Intent intent = new Intent(context, WebViewActivity.class);\n                intent.putExtra(WebViewActivity.EXTRA_TITLE, data.getName());\n                intent.putExtra(WebViewActivity.EXTRA_URL, data.getSrcLink());\n                context.startActivity(intent);\n            }\n        });\n    }\n\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/adapter/MoreRecyclerAdapter.java",
    "content": "package com.boredream.designrescollection.adapter;\n\nimport android.content.Intent;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.adapter.SettingRecyclerAdapter;\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.GlideHelper;\nimport com.boredream.designrescollection.ui.login.LoginActivity;\n\nimport java.util.List;\n\n/**\n * 更多选项列表适配器\n * <p>\n * 第一个位置为HEADER类型,对应用户信息<br/>\n * 其他位置为LIST类型,对应选项item\n */\npublic class MoreRecyclerAdapter extends SettingRecyclerAdapter {\n\n    private static final int ITEM_VIEW_TYPE_HEADER = 0;\n\n    private User user;\n\n    public MoreRecyclerAdapter(List<SettingItem> datas, OnItemClickListener listener) {\n        super(datas, listener);\n    }\n\n    @Override\n    public int getItemCount() {\n        // header + 1\n        return datas.size() + 1;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return position == 0 ? ITEM_VIEW_TYPE_HEADER : super.getItemViewType(position);\n    }\n\n    public void setUser(User user) {\n        this.user = user;\n    }\n\n    public static class ViewHolderUserHeader extends RecyclerView.ViewHolder {\n\n        public View include_more_header;\n        public ImageView iv_avatar;\n        public TextView tv_name;\n        // not login\n        public View include_more_no_header;\n        public Button btn_login;\n\n        public ViewHolderUserHeader(final View itemView) {\n            super(itemView);\n\n            include_more_header = itemView.findViewById(R.id.include_more_header);\n            iv_avatar = (ImageView) itemView.findViewById(R.id.iv_avatar);\n            tv_name = (TextView) itemView.findViewById(R.id.tv_name);\n            include_more_no_header = itemView.findViewById(R.id.include_more_no_header);\n            btn_login = (Button) itemView.findViewById(R.id.btn_login);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        if (viewType == ITEM_VIEW_TYPE_HEADER) {\n            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_more_header, parent, false);\n            return new ViewHolderUserHeader(v);\n        } else {\n            return super.onCreateViewHolder(parent, viewType);\n        }\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {\n        int itemViewType = getItemViewType(position);\n        if (itemViewType == ITEM_VIEW_TYPE_HEADER) {\n            // header\n            ViewHolderUserHeader viewHolderHeader = (ViewHolderUserHeader) holder;\n            if (user != null) {\n                // 如果已登录,用户数据非空,则显示用户信息\n                viewHolderHeader.include_more_header.setVisibility(View.VISIBLE);\n                viewHolderHeader.include_more_no_header.setVisibility(View.GONE);\n\n                GlideHelper.showAvatar(holder.itemView.getContext(), user.getAvatar(), viewHolderHeader.iv_avatar);\n                viewHolderHeader.tv_name.setText(user.getNickname());\n\n                viewHolderHeader.itemView.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        if (mOnItemClickListener != null) {\n                            // header使用特殊的position -1\n                            mOnItemClickListener.onItemClick(null, view, -1, -1);\n                        }\n                    }\n                });\n            } else {\n                // 未登录,提供登录按钮,点击进入登录页\n                viewHolderHeader.include_more_header.setVisibility(View.GONE);\n                viewHolderHeader.include_more_no_header.setVisibility(View.VISIBLE);\n\n                viewHolderHeader.btn_login.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        Intent intent = new Intent(view.getContext(), LoginActivity.class);\n                        view.getContext().startActivity(intent);\n                    }\n                });\n            }\n        } else {\n            // setting item\n            // 第一个位置多了个HEADER,所以position差1\n            super.onBindViewHolder(holder, position - 1);\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/base/BaseActivity.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\n\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.designrescollection.ui.MainActivity;\nimport com.boredream.designrescollection.constants.CommonConstants;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\nimport rx.functions.Action1;\n\npublic class BaseActivity extends BoreBaseActivity {\n\n    public BaseApplication application;\n    public SharedPreferences sp;\n\n    private boolean couldDoubleBackExit;\n    private boolean doubleBackExitPressedOnce;\n\n    protected boolean isActive;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // 如果是退出应用flag,则直接关闭当前页面,不加载UI\n        boolean exit = getIntent().getBooleanExtra(\"exit\", false);\n        if (exit) {\n            finish();\n            return;\n        }\n\n        application = (BaseApplication) getApplication();\n        sp = getSharedPreferences(CommonConstants.SP_NAME, MODE_PRIVATE);\n    }\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n        isActive = true;\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        isActive = false;\n    }\n\n    /**\n     * 设置是否可以双击返回退出，需要有该功能的页面set true即可\n     *\n     * @param couldDoubleBackExit true-开启双击退出\n     */\n    public void setCouldDoubleBackExit(boolean couldDoubleBackExit) {\n        this.couldDoubleBackExit = couldDoubleBackExit;\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (!couldDoubleBackExit) {\n            // 非双击退出状态，使用原back逻辑\n            super.onBackPressed();\n            return;\n        }\n\n        // 双击返回键关闭程序\n        // 如果两秒重置时间内再次点击返回,则退出程序\n        if (doubleBackExitPressedOnce) {\n            exit();\n            return;\n        }\n\n        doubleBackExitPressedOnce = true;\n        showToast(\"再按一次返回键关闭程序\");\n        Observable.just(null)\n                .delay(2, TimeUnit.SECONDS)\n                .subscribe(new Action1<Object>() {\n                    @Override\n                    public void call(Object o) {\n                        // 延迟两秒后重置标志位为false\n                        doubleBackExitPressedOnce = false;\n                    }\n                });\n    }\n\n    /**\n     * 退出程序\n     */\n    protected void exit() {\n        // 退出程序方法有多种\n        // 这里使用clear + new task的方式清空整个任务栈,只保留新打开的Main页面\n        // 然后Main页面接收到退出的标志位exit=true,finish自己,这样就关闭了全部页面\n        Intent intent = new Intent(this, MainActivity.class);\n        intent.putExtra(\"exit\", true);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);\n        startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/base/BaseApplication.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.app.Application;\n\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.integration.okhttp.OkHttpUrlLoader;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.squareup.okhttp.OkHttpClient;\n\nimport java.io.InputStream;\n\npublic class BaseApplication extends Application {\n\n    private static BaseApplication instance;\n\n    public static BaseApplication getInstance() {\n        return instance;\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        instance = this;\n\n        initGlide();\n    }\n\n    /**\n     * 图片加载框架Glide,使用OkHttp处理网络请求\n     */\n    private void initGlide() {\n        OkHttpClient okHttpClient = HttpRequest.getInstance().getHttpClient();\n        Glide.get(this).register(GlideUrl.class, InputStream.class,\n                new OkHttpUrlLoader.Factory(okHttpClient));\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/base/BaseEntity.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class BaseEntity extends BoreBaseEntity {\n\n    @Override\n    public boolean equals(Object o) {\n        if (o instanceof BaseEntity) {\n            BaseEntity oEntity = (BaseEntity) o;\n            return this.objectId.equals(oEntity.objectId);\n        }\n        return super.equals(o);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/base/BaseFragment.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\npublic abstract class BaseFragment extends Fragment {\n\n    protected String TAG;\n    protected BaseActivity activity;\n    // progressDialog/sp/application 等使用activity.xx 调用\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        TAG = getClass().getSimpleName();\n\n        activity = (BaseActivity) getActivity();\n    }\n\n    protected void intent2Activity(Class<? extends Activity> tarActivity) {\n        Intent intent = new Intent(activity, tarActivity);\n        startActivity(intent);\n    }\n\n    protected void showToast(String msg) {\n        ToastUtils.showToast(activity, msg, Toast.LENGTH_SHORT);\n    }\n\n    protected void showLog(String msg) {\n        Log.i(TAG, msg);\n    }\n\n    protected void showProgressDialog() {\n        activity.showProgressDialog();\n    }\n\n    protected void dismissProgressDialog() {\n        activity.dismissProgressDialog();\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/base/BasePresenter.java",
    "content": "/*\n * Copyright 2016, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.boredream.designrescollection.base;\n\npublic interface BasePresenter {\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/base/BaseView.java",
    "content": "/*\n * Copyright 2016, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.boredream.designrescollection.base;\n\npublic interface BaseView<T> {\n\n    void setPresenter(T presenter);\n\n    boolean isActive();\n\n    void showProgress();\n\n    void dismissProgress();\n\n    void showTip(String message);\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/constants/CommonConstants.java",
    "content": "package com.boredream.designrescollection.constants;\n\n/**\n * 通用常量\n */\npublic class CommonConstants {\n\n    private CommonConstants() {\n    }\n\n    /**\n     * SharedPreferences 名称\n     */\n    public static final String SP_NAME = \"config\";\n\n    /**\n     * 每页加载的数量\n     */\n    public static final int COUNT_OF_PAGE = 20;\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/entity/Comment.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class Comment extends BaseEntity {\n    /**\n     * 所属资源\n     */\n    private DesignRes designRes;\n\n    /**\n     * 发送用户, Pointer or User\n     */\n    private User user;\n\n    /**\n     * 评论内容\n     */\n    private String content;\n\n    public DesignRes getDesignRes() {\n        return designRes;\n    }\n\n    public void setDesignRes(DesignRes designRes) {\n        this.designRes = designRes;\n    }\n\n    public User getUser() {\n        return user;\n    }\n\n    public void setUser(User user) {\n        this.user = user;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/entity/DesignRes.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\n/**\n * 设计资源\n */\npublic class DesignRes extends BaseEntity {\n\n    private String desc;\n    private String srcTag;\n    private String name;\n    private String imgUrl;\n    private String srcLink;\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getSrcTag() {\n        return srcTag;\n    }\n\n    public void setSrcTag(String srcTag) {\n        this.srcTag = srcTag;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getImgUrl() {\n        return imgUrl;\n    }\n\n    public void setImgUrl(String imgUrl) {\n        this.imgUrl = imgUrl;\n    }\n\n    public String getSrcLink() {\n        return srcLink;\n    }\n\n    public void setSrcLink(String srcLink) {\n        this.srcLink = srcLink;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        if (!super.equals(o)) return false;\n\n        DesignRes designRes = (DesignRes) o;\n\n        if (desc != null ? !desc.equals(designRes.desc) : designRes.desc != null) return false;\n        if (srcTag != null ? !srcTag.equals(designRes.srcTag) : designRes.srcTag != null)\n            return false;\n        if (name != null ? !name.equals(designRes.name) : designRes.name != null) return false;\n        if (imgUrl != null ? !imgUrl.equals(designRes.imgUrl) : designRes.imgUrl != null)\n            return false;\n        return srcLink != null ? srcLink.equals(designRes.srcLink) : designRes.srcLink == null;\n\n    }\n\n    @Override\n    public int hashCode() {\n        int result = desc != null ? desc.hashCode() : 0;\n        result = 31 * result + (srcTag != null ? srcTag.hashCode() : 0);\n        result = 31 * result + (name != null ? name.hashCode() : 0);\n        result = 31 * result + (imgUrl != null ? imgUrl.hashCode() : 0);\n        result = 31 * result + (srcLink != null ? srcLink.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/entity/FeedBack.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class FeedBack extends BaseEntity {\n\n    private String content;\n    private String email;\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/entity/User.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class User extends BaseEntity {\n\n    private String sessionToken;\n\n    private String nickname;\n\n    private String username;\n\n    /**\n     * 验证手机号\n     */\n    private String mobilePhoneNumber;\n\n    /**\n     * 密码\n     */\n    private String password;\n\n    /**\n     * 手机号验证码,发送短信验证时请求使用\n     */\n    private String smsCode;\n\n    /**\n     * 头像图片地址\n     */\n    private String avatar;\n\n    private String company;\n\n    public String getSessionToken() {\n        return sessionToken;\n    }\n\n    public void setSessionToken(String sessionToken) {\n        this.sessionToken = sessionToken;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n\n    public String getAvatar() {\n        return avatar;\n    }\n\n    public void setAvatar(String avatar) {\n        this.avatar = avatar;\n    }\n\n    public String getSmsCode() {\n        return smsCode;\n    }\n\n    public void setSmsCode(String smsCode) {\n        this.smsCode = smsCode;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getMobilePhoneNumber() {\n        return mobilePhoneNumber;\n    }\n\n    public void setMobilePhoneNumber(String mobilePhoneNumber) {\n        this.mobilePhoneNumber = mobilePhoneNumber;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getNickname() {\n        return nickname;\n    }\n\n    public void setNickname(String nickname) {\n        this.nickname = nickname;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/net/GlideHelper.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.content.Context;\nimport android.widget.ImageView;\n\nimport com.boredream.bdcodehelper.net.GlideCircleTransform;\nimport com.boredream.designrescollection.R;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\n\n/**\n * Glide\n */\npublic class GlideHelper {\n\n    public static void showAvatar(Context context, String avatar, ImageView iv) {\n        Glide.with(context)\n                .load(avatar)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .transform(new GlideCircleTransform(context))\n                .crossFade()\n                .into(iv);\n    }\n\n    public static void showImage(Context context, String imageUrl, ImageView iv) {\n        Glide.with(context)\n                .load(imageUrl)\n                .asBitmap()\n                .animate(android.R.anim.fade_in)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n                .into(iv);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/net/HttpRequest.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.text.TextUtils;\n\nimport com.boredream.bdcodehelper.entity.AppUpdateInfo;\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.constants.CommonConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\nimport com.squareup.okhttp.Interceptor;\nimport com.squareup.okhttp.MediaType;\nimport com.squareup.okhttp.OkHttpClient;\nimport com.squareup.okhttp.Request;\nimport com.squareup.okhttp.RequestBody;\nimport com.squareup.okhttp.Response;\nimport com.squareup.okhttp.logging.HttpLoggingInterceptor;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport retrofit.GsonConverterFactory;\nimport retrofit.Retrofit;\nimport retrofit.RxJavaCallAdapterFactory;\nimport retrofit.http.Body;\nimport retrofit.http.GET;\nimport retrofit.http.POST;\nimport retrofit.http.PUT;\nimport retrofit.http.Path;\nimport retrofit.http.Query;\nimport rx.Observable;\nimport rx.functions.Action1;\n\npublic class HttpRequest {\n    // LeanCloud\n    public static final String HOST = \"https://api.leancloud.cn\";\n    public static final String FILE_HOST = \"\";\n\n    private static final String APP_ID_NAME = \"X-LC-Id\";\n    private static final String API_KEY_NAME = \"X-LC-Key\";\n    public static final String SESSION_TOKEN_KEY = \"X-LC-Session\";\n\n    private static final String APP_ID_VALUE = \"iaEH7ObIA4sPY8RSs3VCVXBg-gzGzoHsz\";\n    private static final String API_KEY_VALUE = \"dXfhXIVyeWMN2czJkd4ehwzs\";\n\n    public ApiService service;\n\n    private OkHttpClient httpClient;\n    public OkHttpClient getHttpClient() {\n        return httpClient;\n    }\n\n    private static HttpRequest ourInstance = new HttpRequest();\n    public static HttpRequest getInstance() {\n        return ourInstance;\n    }\n    private HttpRequest() {\n        // OkHttpClient\n        httpClient = new OkHttpClient();\n\n        // 统一添加的Header\n        httpClient.networkInterceptors().add(new Interceptor() {\n            @Override\n            public Response intercept(Chain chain) throws IOException {\n                Request request = chain.request().newBuilder()\n                        .addHeader(\"Content-Type\", \"application/json\")\n                        .addHeader(APP_ID_NAME, APP_ID_VALUE)\n                        .addHeader(API_KEY_NAME, API_KEY_VALUE)\n                        .addHeader(SESSION_TOKEN_KEY, UserInfoKeeper.getToken())\n                        .build();\n                return chain.proceed(request);\n            }\n        });\n\n        // log\n        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();\n        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);\n        httpClient.interceptors().add(interceptor);\n\n        // Retrofit\n        Retrofit retrofit = new Retrofit.Builder()\n                .baseUrl(HOST)\n                .addConverterFactory(GsonConverterFactory.create()) // gson\n                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // rxjava\n                .client(httpClient)\n                //.callbackExecutor(AsyncTask.THREAD_POOL_EXECUTOR)\n                .build();\n\n        service = retrofit.create(ApiService.class);\n    }\n\n    public interface ApiService {\n        ////////////////////////////// 通用接口 //////////////////////////////\n        // 登录用户\n        @GET(\"/1/login\")\n        Observable<User> login(\n                @Query(\"username\") String username,\n                @Query(\"password\") String password);\n\n        // 注册用户\n        @POST(\"/1/users\")\n        Observable<User> register(\n                @Body User user);\n\n        // 修改用户详情(注意, 提交什么参数修改什么参数)\n        @PUT(\"/1/users/{objectId}\")\n        Observable<BaseEntity> updateUserById(\n                @Path(\"objectId\") String userId,\n                @Body Map<String, Object> updateInfo);\n\n        // 上传图片接口\n        @POST(\"/1/files/{fileName}\")\n        Observable<FileUploadResponse> fileUpload(\n                @Path(\"fileName\") String fileName,\n                @Body RequestBody image);\n\n        // 查询app更新信息\n        @GET(\"/1/classes/AppUpdateInfo\")\n        Observable<ListResponse<AppUpdateInfo>> getAppUpdateInfo();\n\n        // 提交意见反馈\n        @POST(\"/1/classes/FeedBack\")\n        Observable<BaseEntity> addFeedBack(\n                @Body FeedBack feedBack);\n\n\n        ////////////////////////////// 业务接口 //////////////////////////////\n\n        // 查询设计资源\n        @GET(\"/1/classes/DesignRes\")\n        Observable<ListResponse<DesignRes>> getDesignRes(\n                @Query(\"limit\") int perPageCount,\n                @Query(\"skip\") int page,\n                @Query(\"where\") String where,\n                @Query(\"include\") String include);\n    }\n\n    ////////////////////////////// 业务接口方法 //////////////////////////////\n\n    /**\n     * 查询设计资源\n     */\n    public Observable<ListResponse<DesignRes>> getDesignRes(int page) {\n        String where = \"{}\";\n        return service.getDesignRes(CommonConstants.COUNT_OF_PAGE,\n                (page - 1) * CommonConstants.COUNT_OF_PAGE, where, null);\n    }\n\n    /**\n     * 查询设计资源\n     *\n     * @param page\n     * @param name 搜索名称\n     */\n    public Observable<ListResponse<DesignRes>> getDesignRes(int page, String name) {\n        String whereName = \"{}\";\n        if (!TextUtils.isEmpty(name)) {\n            whereName = \"{\\\"name\\\":{\\\"$regex\\\":\\\".*\" + name + \".*\\\"}}\";\n        }\n        String where = whereName;\n        return service.getDesignRes(CommonConstants.COUNT_OF_PAGE,\n                (page - 1) * CommonConstants.COUNT_OF_PAGE, where, null);\n    }\n\n    public Observable<BaseEntity> updateNickname(String userid, String nickname) {\n        Map<String, Object> updateMap = new HashMap<>();\n        updateMap.put(\"nickname\", nickname);\n\n        return service.updateUserById(userid, updateMap);\n    }\n\n\n    ////////////////////////////// 通用接口方法 //////////////////////////////\n\n    /**\n     * 登录用户\n     *\n     * @param username 用户名\n     * @param password 密码\n     */\n    public Observable<User> login(String username, String password) {\n        return service.login(username, password)\n                .doOnNext(new Action1<User>() {\n                    @Override\n                    public void call(User user) {\n                        // 保存登录用户数据以及token信息\n                        UserInfoKeeper.setCurrentUser(user);\n                    }\n                });\n    }\n\n    /**\n     * 上传文件\n     *\n     * @param bytes\n     */\n    public Observable<FileUploadResponse> fileUpload(byte[] bytes, String filename, MediaType type) {\n        RequestBody requestBody = RequestBody.create(type, bytes);\n        return service.fileUpload(filename, requestBody);\n    }\n\n}\n\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/net/SimpleSubscriber.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\nimport rx.Subscriber;\n\n/**\n * 通用订阅者,用于统一处理回调\n */\npublic class SimpleSubscriber<T> extends Subscriber<T> {\n\n    private Context context;\n\n    public SimpleSubscriber(Context context) {\n        this.context = context;\n    }\n\n    @Override\n    public void onCompleted() {\n        // sub\n    }\n\n    @Override\n    public void onError(Throwable throwable) {\n        // 统一处理错误回调，显示Toast\n        String errorInfo = ErrorInfoUtils.parseHttpErrorInfo(throwable);\n        ToastUtils.showToast(context, errorInfo);\n    }\n\n    @Override\n    public void onNext(T t) {\n        // sub\n    }\n\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/AboutActivity.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.SpannableString;\nimport android.text.Spanned;\nimport android.text.method.LinkMovementMethod;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\n\npublic class AboutActivity extends BaseActivity {\n\n    private TextView tv_version;\n    private TextView tv_about;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_about);\n        initView();\n    }\n\n    private void initView() {\n        initBackTitle(\"关于我\");\n\n        tv_version = (TextView) findViewById(R.id.tv_version);\n        tv_about = (TextView) findViewById(R.id.tv_about);\n\n        tv_version.setText(\"Version \" + AppUtils.getAppVersionName(this));\n\n        SpannableString ss = getAboutString();\n        tv_about.setMovementMethod(LinkMovementMethod.getInstance());\n        tv_about.setText(ss);\n    }\n\n    private SpannableString getAboutString() {\n        final String githubLink = getString(R.string.github);\n        String format = String.format(getString(R.string.about), githubLink);\n        SpannableString ss = new SpannableString(format);\n        // 网址部分可点击,跳转到网页\n        StringUtils.PrimaryClickableSpan span = new StringUtils.PrimaryClickableSpan(this) {\n            @Override\n            public void onClick(View widget) {\n                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(githubLink));\n                startActivity(intent);\n            }\n        };\n        int start = format.indexOf(githubLink);\n        ss.setSpan(span, start, start + githubLink.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        return ss;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/MainActivity.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\n\nimport com.boredream.bdcodehelper.fragment.FragmentController;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.ui.home.HomeFragment;\nimport com.boredream.designrescollection.utils.UpdateUtils;\n\nimport java.util.ArrayList;\n\n\npublic class MainActivity extends BaseActivity implements RadioGroup.OnCheckedChangeListener {\n\n    private RadioGroup rg_bottom_tab;\n    private RadioButton rb1;\n    private FragmentController controller;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        initView();\n        initData();\n    }\n\n    private void initView() {\n        setCouldDoubleBackExit(true);\n\n        rg_bottom_tab = (RadioGroup) findViewById(R.id.rg_bottom_tab);\n        rb1 = (RadioButton) findViewById(R.id.rb1);\n\n        rg_bottom_tab.setOnCheckedChangeListener(this);\n    }\n\n    private void initData() {\n        ArrayList<Fragment> fragments = new ArrayList<>();\n        fragments.add(new HomeFragment());\n        fragments.add(new UserFragment());\n\n        controller = new FragmentController(this, R.id.fl_content, fragments);\n\n        // 默认Fragment\n        rb1.setChecked(true);\n        controller.showFragment(0);\n\n        UpdateUtils.checkUpdate(this, false);\n    }\n\n    @Override\n    public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {\n        switch (checkedId) {\n            case R.id.rb1:\n                controller.showFragment(0);\n                break;\n            case R.id.rb2:\n                controller.showFragment(1);\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/SettingActivity.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.Button;\n\nimport com.boredream.bdcodehelper.adapter.SettingRecyclerAdapter;\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.ui.feedback.FeedBackActivity;\nimport com.boredream.designrescollection.utils.UpdateUtils;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SettingActivity extends BaseActivity implements View.OnClickListener, AdapterView.OnItemClickListener {\n\n    private RecyclerView rv_setting;\n    private Button btn_logout;\n\n    private SettingRecyclerAdapter adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_setting);\n        initView();\n        initData();\n    }\n\n    private void initView() {\n        initBackTitle(\"设置\");\n\n        rv_setting = (RecyclerView) findViewById(R.id.rv_setting);\n        btn_logout = (Button) findViewById(R.id.btn_logout);\n\n        btn_logout.setOnClickListener(this);\n    }\n\n    private void initData() {\n        // 使用列表显示多个选项条\n        List<SettingItem> items = new ArrayList<>();\n\n        items.add(new SettingItem(\n                R.mipmap.ic_cached_grey600_24dp,\n                \"检查更新\",\n                AppUtils.getAppVersionName(this),\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n        items.add(new SettingItem(\n                R.mipmap.ic_announcement_grey600_24dp,\n                \"反馈\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n\n        adapter = new SettingRecyclerAdapter(items, this);\n        rv_setting.setAdapter(adapter);\n\n        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(\n                this, LinearLayoutManager.VERTICAL, false);\n        rv_setting.setLayoutManager(linearLayoutManager);\n        // 每个item之间的分割线\n        rv_setting.addItemDecoration(new DividerItemDecoration(this));\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        switch (position) {\n            case 0:\n                showProgressDialog();\n                // 强制检查更新,并添加额外回调用于处理进度框\n                UpdateUtils.checkUpdate(this, true);\n                break;\n            case 1:\n                if(UserInfoKeeper.checkLogin(this)) {\n                    // 一般意见反馈不需要登录，这里模拟下需登录场景的处理方法\n                    intent2Activity(FeedBackActivity.class);\n                }\n                break;\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_logout:\n                // 登出,清理用户数据同时跳转到主页\n                UserInfoKeeper.logout();\n                intent2Activity(MainActivity.class);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/UserFragment.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\n\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\nimport com.boredream.bdcodehelper.view.EmptyItemDecoration;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.adapter.MoreRecyclerAdapter;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.ui.userinfoedit.UserInfoEditActivity;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class UserFragment extends BaseFragment implements AdapterView.OnItemClickListener {\n\n    private RecyclerView rv_user;\n    private MoreRecyclerAdapter adapter;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = View.inflate(activity, R.layout.frag_user, null);\n        initView(view);\n        initData();\n        return view;\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n\n        // 如果未登录进入本页面,然后跳转登录页面成功后返回,此时应该再次更新用户信息\n        adapter.setUser(UserInfoKeeper.getCurrentUser());\n        adapter.notifyDataSetChanged();\n    }\n\n    private void initView(View view) {\n        new TitleBuilder(view).setTitleText(\"更多\");\n\n        rv_user = (RecyclerView) view.findViewById(R.id.rv_user);\n    }\n\n    private void initData() {\n        // more items\n        List<SettingItem> items = new ArrayList<>();\n        items.add(new SettingItem(\n                R.mipmap.ic_info_grey600_24dp,\n                \"关于\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n        items.add(new SettingItem(\n                R.mipmap.ic_settings_grey600_24dp,\n                \"设置\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n\n        adapter = new MoreRecyclerAdapter(items, this);\n        rv_user.setAdapter(adapter);\n\n        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(\n                activity, LinearLayoutManager.VERTICAL, false);\n        rv_user.setLayoutManager(linearLayoutManager);\n        // 每个item之间的分割线\n        rv_user.addItemDecoration(new DividerItemDecoration(activity));\n        // 每组item之间的分割间隔\n        rv_user.addItemDecoration(new EmptyItemDecoration(\n                new Integer[]{0, 1}, DisplayUtils.dp2px(activity, 16)));\n\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        switch (position) {\n            case -1:\n                // 给特殊的用户信息header位置设为了position=-1的item click事件\n                intent2Activity(UserInfoEditActivity.class);\n                break;\n            case 0:\n                intent2Activity(AboutActivity.class);\n                break;\n            case 1:\n                intent2Activity(SettingActivity.class);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/feedback/FeedBackActivity.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\n\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.EditText;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.HttpRequest;\n\npublic class FeedBackActivity extends BaseActivity implements FeedBackContract.View {\n\n    private FeedBackContract.Presenter presenter;\n    private EditText et_content;\n    private EditText et_email;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_feed_back);\n\n        initView();\n    }\n\n    private void initView() {\n        presenter = new FeedBackPresenter(this, HttpRequest.getInstance().service);\n\n        initBackTitle(\"意见反馈\")\n                .setRightText(\"提交\")\n                .setRightOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        submit();\n                    }\n                });\n\n        et_content = (EditText) findViewById(R.id.et_content);\n        et_email = (EditText) findViewById(R.id.et_email);\n\n    }\n\n    private void submit() {\n        // 开始验证输入内容\n        String content = et_content.getText().toString().trim();\n        String email = et_email.getText().toString().trim();\n\n        presenter.addFeedback(content, email);\n    }\n\n    @Override\n    public void addFeedbackSuccess() {\n        showToast(\"反馈成功\");\n        finish();\n    }\n\n    @Override\n    public void setPresenter(FeedBackContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/feedback/FeedBackContract.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\n\npublic interface FeedBackContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void addFeedbackSuccess();\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void addFeedback(String content, String email);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/feedback/FeedBackPresenter.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.net.HttpRequest;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class FeedBackPresenter implements FeedBackContract.Presenter {\n\n    private final FeedBackContract.View view;\n    private final HttpRequest.ApiService api;\n\n    public FeedBackPresenter(FeedBackContract.View view, HttpRequest.ApiService api) {\n        this.view = view;\n        this.api = api;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void addFeedback(String content, String email) {\n        // 开始验证输入内容\n        if (StringUtils.isEmpty(content)) {\n            view.showTip(\"反馈内容不能为空\");\n            return;\n        }\n\n        if (StringUtils.isEmpty(email)) {\n            view.showTip(\"请输入邮箱地址,方便我们对您的意见进行及时回复\");\n            return;\n        }\n\n        view.showProgress();\n\n        // 使用自定义对象存至云平台,作为简易版的反馈意见收集\n        FeedBack fb = new FeedBack();\n        fb.setContent(content);\n        fb.setEmail(email);\n\n        Observable<BaseEntity> observable = ObservableDecorator.decorate(api.addFeedBack(fb));\n        observable.subscribe(new Subscriber<BaseEntity>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.showTip(\"反馈提交失败\");\n            }\n\n            @Override\n            public void onNext(BaseEntity entity) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.addFeedbackSuccess();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/home/HomeContract.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\nimport com.boredream.designrescollection.entity.DesignRes;\n\nimport java.util.List;\n\npublic interface HomeContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void loadListSuccess(int page, List<DesignRes> datas);\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void loadList(int page);\n\n        void pullToLoadList();\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/home/HomeFragment.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\n\nimport android.os.Bundle;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.view.GridSpacingDecorator;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.adapter.DesignResAdapter;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.constants.CommonConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class HomeFragment extends BaseFragment implements HomeContract.View {\n\n    private View view;\n    private SwipeRefreshLayout srl;\n    private RecyclerView rv;\n\n    private HomeContract.Presenter presenter;\n    private int curPage = 1;\n    private ArrayList<DesignRes> datas = new ArrayList<>();\n    private LoadMoreAdapter adapter;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        view = View.inflate(activity, R.layout.frag_home, null);\n        initView();\n        initData();\n        return view;\n    }\n\n    private void initView() {\n        presenter = new HomePresenter(this);\n        new TitleBuilder(view).setTitleText(getString(R.string.tab1));\n\n        srl = (SwipeRefreshLayout) view.findViewById(R.id.srl);\n        srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {\n            @Override\n            public void onRefresh() {\n                presenter.pullToLoadList();\n            }\n        });\n\n        rv = (RecyclerView) view.findViewById(R.id.rv);\n        rv.addItemDecoration(new GridSpacingDecorator(DisplayUtils.dp2px(activity, 8)));\n        GridLayoutManager gridLayoutManager = new GridLayoutManager(activity, 2);\n        rv.setLayoutManager(gridLayoutManager);\n\n        adapter = new LoadMoreAdapter(rv,\n                new DesignResAdapter(activity, datas),\n                new LoadMoreAdapter.OnLoadMoreListener() {\n                    @Override\n                    public void onLoadMore() {\n                        presenter.loadList(curPage + 1);\n                    }\n                });\n        rv.setAdapter(adapter);\n    }\n\n    private void initData() {\n        presenter.loadList(1);\n    }\n\n    @Override\n    public void loadListSuccess(int page, List<DesignRes> datas) {\n        curPage = page;\n        if (curPage == 1) {\n            this.datas.clear();\n        }\n        this.datas.addAll(datas);\n\n        // 设置是否已加载完全部数据状态\n        adapter.setStatus(datas.size() == CommonConstants.COUNT_OF_PAGE\n                ? LoadMoreAdapter.STATUS_HAVE_MORE : LoadMoreAdapter.STATUS_LOADED_ALL);\n        adapter.notifyDataSetChanged();\n    }\n\n    @Override\n    public void setPresenter(HomeContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isAdded();\n    }\n\n    @Override\n    public void showProgress() {\n        srl.post(new Runnable() {\n            @Override\n            public void run() {\n                srl.setRefreshing(true);\n            }\n        });\n    }\n\n    @Override\n    public void dismissProgress() {\n        srl.setRefreshing(false);\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/home/HomePresenter.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.net.HttpRequest;\n\nimport java.util.List;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class HomePresenter implements HomeContract.Presenter {\n\n    private final HomeContract.View view;\n    public List<DesignRes> datas;\n\n    public HomePresenter(HomeContract.View view) {\n        this.view = view;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void pullToLoadList() {\n        loadData(1);\n    }\n\n    @Override\n    public void loadList(final int page) {\n        if(page == 1) {\n            view.showProgress();\n        }\n\n        loadData(page);\n    }\n\n    private void loadData(final int page) {\n        Observable<ListResponse<DesignRes>> observable = HttpRequest.getInstance().getDesignRes(page);\n        ObservableDecorator.decorate(observable).subscribe(\n                new Subscriber<ListResponse<DesignRes>>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        if (!view.isActive()) {\n                            return;\n                        }\n                        view.dismissProgress();\n\n                        String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                        view.showTip(error);\n                    }\n\n                    @Override\n                    public void onNext(ListResponse<DesignRes> response) {\n                        if (!view.isActive()) {\n                            return;\n                        }\n                        view.dismissProgress();\n\n                        datas = response.getResults();\n                        view.loadListSuccess(page, datas);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/login/LoginActivity.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\n\nimport android.os.Bundle;\n\nimport com.boredream.bdcodehelper.utils.ActivityUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.HttpRequest;\n\npublic class LoginActivity extends BaseActivity {\n\n    /**\n     * 是否为验证登录,true-登录成功后,直接finish返回到来源页 false-登录成功后跳转到主页\n     */\n    private boolean checkLogin;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_login);\n\n        initExtras();\n        initView();\n    }\n\n    private void initExtras() {\n        checkLogin = getIntent().getBooleanExtra(\"checkLogin\", false);\n    }\n\n    private void initView() {\n        initBackTitle(\"登录\");\n\n        LoginFragment loginFragment = (LoginFragment) getSupportFragmentManager().findFragmentById(R.id.fl_content);\n        if (loginFragment == null) {\n            loginFragment = LoginFragment.newInstance(checkLogin);\n            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), loginFragment, R.id.fl_content);\n        }\n\n        new LoginPresenter(loginFragment, HttpRequest.getInstance());\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/login/LoginContract.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\nimport com.boredream.designrescollection.entity.User;\n\n/**\n * This specifies the contract between the view and the presenter.\n */\npublic interface LoginContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void loginSuccess(User user);\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void login(String username, String password);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/login/LoginFragment.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.ui.MainActivity;\nimport com.boredream.designrescollection.ui.register.RegisterStep1Activity;\n\npublic class LoginFragment extends BaseFragment implements LoginContract.View, View.OnClickListener {\n\n    private static final String ARGUMENT_CHECK_LOGIN = \"checkLogin\";\n    private boolean checkLogin;\n\n    private LoginContract.Presenter presenter;\n\n    private EditText et_username;\n    private EditText et_password;\n    private TextView tv_forget_psw;\n    private Button btn_login;\n    private LinearLayout ll_regist;\n\n    public static LoginFragment newInstance(boolean checkLogin) {\n        Bundle arguments = new Bundle();\n        arguments.putBoolean(ARGUMENT_CHECK_LOGIN, checkLogin);\n        LoginFragment fragment = new LoginFragment();\n        fragment.setArguments(arguments);\n        return fragment;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = View.inflate(activity, R.layout.frag_login, null);\n        initExtras();\n        initView(view);\n        return view;\n    }\n\n    private void initExtras() {\n        checkLogin = getArguments().getBoolean(ARGUMENT_CHECK_LOGIN);\n    }\n\n    private void initView(View view) {\n        et_username = (EditText) view.findViewById(R.id.et_username);\n        et_password = (EditText) view.findViewById(R.id.et_password);\n        tv_forget_psw = (TextView) view.findViewById(R.id.tv_forget_psw);\n        btn_login = (Button) view.findViewById(R.id.btn_login);\n        ll_regist = (LinearLayout) view.findViewById(R.id.ll_regist);\n\n        tv_forget_psw.setOnClickListener(this);\n        btn_login.setOnClickListener(this);\n        ll_regist.setOnClickListener(this);\n    }\n\n    @Override\n    public void onClick(View v) {\n        Intent intent = new Intent(activity, RegisterStep1Activity.class);\n        switch (v.getId()) {\n            case R.id.btn_login:\n                String username = et_username.getText().toString().trim();\n                String password = et_password.getText().toString().trim();\n                presenter.login(username, password);\n                break;\n            case R.id.tv_forget_psw:\n                intent.putExtra(\"type\", 1);\n                startActivity(intent);\n                break;\n            case R.id.ll_regist:\n                intent.putExtra(\"type\", 0);\n                startActivity(intent);\n                break;\n        }\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void loginSuccess(User user) {\n        dismissProgressDialog();\n\n        if (checkLogin) {\n            activity.finish();\n        } else {\n            intent2Activity(MainActivity.class);\n        }\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n\n    @Override\n    public boolean isActive() {\n        return isAdded();\n    }\n\n    @Override\n    public void setPresenter(LoginContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/login/LoginPresenter.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class LoginPresenter implements LoginContract.Presenter {\n\n    private final LoginContract.View view;\n    private final HttpRequest httpRequest;\n\n    public LoginPresenter(LoginContract.View view, HttpRequest httpRequest) {\n        this.view = view;\n        this.httpRequest = httpRequest;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void login(String username, String password) {\n        if (StringUtils.isEmpty(username)) {\n            view.showTip(\"用户名不能为空\");\n            return;\n        }\n\n        if (StringUtils.isEmpty(password)) {\n            view.showTip(\"密码不能为空\");\n            return;\n        }\n\n        view.showProgress();\n\n        Observable<User> observable = httpRequest.login(username, password);\n        ObservableDecorator.decorate(observable).subscribe(new Subscriber<User>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                view.showTip(error);\n            }\n\n            @Override\n            public void onNext(User user) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.loginSuccess(user);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/modifytext/ModifyTextActivity.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.EditText;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\n\n/**\n * 修改文字内容输入框页面\n */\npublic class ModifyTextActivity extends BaseActivity implements ModifyTextContract.View {\n\n    public static final String EXTRA_TITLE = \"title\";\n    public static final String EXTRA_OLD_STRING = \"oldString\";\n\n    public static final String RESULT_IS_MODIFY = \"isModify\";\n    public static final String RESULT_NEW_STRING = \"newString\";\n\n    private String title;\n    private String oldString;\n\n    private ModifyTextContract.Presenter presenter;\n    private EditText et_input;\n\n    public static void start(Activity context, int requestCode, String title, String oldString) {\n        Intent intent = new Intent(context, ModifyTextActivity.class);\n        intent.putExtra(ModifyTextActivity.EXTRA_TITLE, title);\n        intent.putExtra(ModifyTextActivity.EXTRA_OLD_STRING, oldString);\n        context.startActivityForResult(intent, requestCode);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_input);\n\n        initExtras();\n        initView();\n        initData();\n    }\n\n    private void initExtras() {\n        Intent intent = getIntent();\n        title = intent.getStringExtra(EXTRA_TITLE);\n        oldString = intent.getStringExtra(EXTRA_OLD_STRING);\n    }\n\n    private void initView() {\n        presenter = new ModifyTextPresenter(this);\n\n        initBackTitle(title + \"修改\")\n                .setRightText(\"保存\")\n                .setRightOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        submit();\n                    }\n                });\n        et_input = (EditText) findViewById(R.id.et_input);\n    }\n\n    private void initData() {\n        if (oldString != null) {\n            et_input.setText(oldString);\n        }\n    }\n\n    private void submit() {\n        String str = et_input.getText().toString().trim();\n        presenter.modifyText(title, oldString, str);\n    }\n\n    @Override\n    public void modifyTextSuccess(boolean isModify, String newString) {\n        Intent intent = new Intent();\n        intent.putExtra(RESULT_NEW_STRING, newString);\n        intent.putExtra(RESULT_IS_MODIFY, isModify);\n        setResult(RESULT_OK, intent);\n        finish();\n    }\n\n    @Override\n    public void setPresenter(ModifyTextContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n\n    }\n\n    @Override\n    public void dismissProgress() {\n\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/modifytext/ModifyTextContract.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\n\npublic interface ModifyTextContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void modifyTextSuccess(boolean isModify, String newString);\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void modifyText(String title, String oldString, String modifyString);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/modifytext/ModifyTextPresenter.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport com.boredream.bdcodehelper.utils.StringUtils;\n\npublic class ModifyTextPresenter implements ModifyTextContract.Presenter {\n\n    private final ModifyTextContract.View view;\n\n    public ModifyTextPresenter(ModifyTextContract.View view) {\n        this.view = view;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void modifyText(String title, String oldString, String modifyString) {\n        if (StringUtils.isEmpty(modifyString)) {\n            view.showTip(title + \"不能为空\");\n            return;\n        }\n\n        // 旧文字为空或旧文字和新文字不相等，视为已修改\n        boolean isModify = oldString == null || !oldString.equals(modifyString);\n        view.modifyTextSuccess(isModify, modifyString);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterContract.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\nimport com.boredream.designrescollection.entity.User;\n\npublic class RegisterContract {\n    interface View extends BaseView<Presenter> {\n\n        void requestSmsSuccess(String phone, String password);\n\n        void registerSuccess(User user);\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void requestSms(String phone, String password);\n\n        void register(String phone, String password, String code);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterPresenter.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class RegisterPresenter implements RegisterContract.Presenter {\n\n    private final RegisterContract.View view;\n\n    public RegisterPresenter(RegisterContract.View view) {\n        this.view = view;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void requestSms(final String phone, final String password) {\n        if (StringUtils.isEmpty(phone)) {\n            view.showTip(\"请输入用户名\");\n            return;\n        }\n\n        if (StringUtils.isEmpty(password) || password.length() < 6) {\n            view.showTip(\"请设置登录密码，不少于6位\");\n            return;\n        }\n\n        view.showProgress();\n\n        // FIXME 模拟获取短信接口\n        Observable<String> observable = Observable.just(\"发送验证码咯~\");\n        ObservableDecorator.decorate(observable).subscribe(new Subscriber<String>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                view.showTip(error);\n            }\n\n            @Override\n            public void onNext(String string) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.requestSmsSuccess(phone, password);\n            }\n        });\n    }\n\n    @Override\n    public void register(String phone, String password, String code) {\n        if (StringUtils.isEmpty(code)) {\n            view.showTip(\"请输入验证码\");\n            return;\n        }\n\n        view.showProgress();\n\n        // 注册接口\n        User user = new User();\n        user.setMobilePhoneNumber(phone);\n        user.setUsername(phone);\n        user.setPassword(password);\n        user.setSmsCode(code);\n        Observable<User> observable = HttpRequest.getInstance().service.register(user);\n        ObservableDecorator.decorate(observable).subscribe(new Subscriber<User>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        if (!view.isActive()) {\n                            return;\n                        }\n\n                        view.dismissProgress();\n\n                        String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                        view.showTip(error);\n                    }\n\n                    @Override\n                    public void onNext(User user) {\n                        UserInfoKeeper.setCurrentUser(user);\n\n                        if (!view.isActive()) {\n                            return;\n                        }\n\n                        view.dismissProgress();\n\n                        view.registerSuccess(user);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterStep1Activity.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\n\n/**\n * 注册页面步骤一\n */\npublic class RegisterStep1Activity extends BaseActivity implements View.OnClickListener, RegisterContract.View {\n\n    private RegisterContract.Presenter presenter;\n    private EditText et_username;\n    private EditText et_password;\n    private Button btn_next;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_register_step1);\n\n        initView();\n    }\n\n    private void initView() {\n        presenter = new RegisterPresenter(this);\n        initBackTitle(\"注册\");\n\n        et_username = (EditText) findViewById(R.id.et_username);\n        et_password = (EditText) findViewById(R.id.et_password);\n        btn_next = (Button) findViewById(R.id.btn_next);\n\n        btn_next.setOnClickListener(this);\n    }\n\n    private void next() {\n        String phone = et_username.getText().toString().trim();\n        String password = et_password.getText().toString().trim();\n\n        presenter.requestSms(phone, password);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_next:\n                next();\n                break;\n        }\n    }\n\n    @Override\n    public void requestSmsSuccess(String phone, String password) {\n        // 短信验证码发送成功后,跳转到短信验证页,同时传递所需数据\n        Intent intent = new Intent(this, RegisterStep2Activity.class);\n        intent.putExtra(\"phone\", phone);\n        intent.putExtra(\"password\", password);\n        startActivity(intent);\n    }\n\n    @Override\n    public void registerSuccess(User user) {\n        // do nothing\n    }\n\n    @Override\n    public void setPresenter(RegisterContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterStep2Activity.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\n\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.CountDownTimer;\nimport android.support.v7.app.AlertDialog;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\n\nimport com.boredream.bdcodehelper.utils.DateUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.ui.MainActivity;\n\n/**\n * 注册页面步骤二\n */\npublic class RegisterStep2Activity extends BaseActivity implements View.OnClickListener, RegisterContract.View {\n\n    // 总倒计时60秒\n    private static final long TOTCAL_TIME = 60 * DateUtils.ONE_SECOND_MILLIONS;\n    // 每次减少1秒\n    private static final long COUNT_DOWN_INTERVAL = DateUtils.ONE_SECOND_MILLIONS;\n\n    private RegisterContract.Presenter presenter;\n    private EditText et_verification_code;\n    private Button btn_code_info;\n    private Button btn_next;\n\n    private String phone;\n    private String password;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_register_step2);\n\n        initExtras();\n        initView();\n        initData();\n    }\n\n    private void initExtras() {\n        Intent intent = getIntent();\n        phone = intent.getStringExtra(\"phone\");\n        password = intent.getStringExtra(\"password\");\n    }\n\n    private void initView() {\n        presenter = new RegisterPresenter(this);\n        initBackTitle(\"手机号验证\");\n\n        et_verification_code = (EditText) findViewById(R.id.et_verification_code);\n        btn_code_info = (Button) findViewById(R.id.btn_code_info);\n        btn_next = (Button) findViewById(R.id.btn_next);\n\n        btn_code_info.setOnClickListener(this);\n        btn_next.setOnClickListener(this);\n    }\n\n    private void initData() {\n        startCountDown();\n    }\n\n    /**\n     * 开始倒计时\n     */\n    private void startCountDown() {\n        showToast(\"短信验证码发送成功\");\n\n        btn_code_info.setText(\"60秒\");\n        btn_code_info.setEnabled(false);\n\n        // 倒计时开始,共60秒,每次减少1秒\n        CountDownTimer timer = new CountDownTimer(TOTCAL_TIME, COUNT_DOWN_INTERVAL) {\n            @Override\n            public void onTick(long l) {\n                // 重新获取(60)\n                String restTime = (int) (l / COUNT_DOWN_INTERVAL) + \"秒\";\n                btn_code_info.setText(restTime);\n            }\n\n            @Override\n            public void onFinish() {\n                // 倒计时结束,重置按钮\n                btn_code_info.setText(\"重新获取\");\n                btn_code_info.setEnabled(true);\n            }\n        };\n        timer.start();\n    }\n\n    /**\n     * 根据类型提交注册或重置密码接口\n     */\n    private void submit() {\n        String code = et_verification_code.getText().toString().trim();\n        presenter.register(phone, password, code);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_code_info:\n                presenter.requestSms(phone, password);\n                break;\n            case R.id.btn_next:\n                submit();\n                break;\n        }\n    }\n\n    @Override\n    public void requestSmsSuccess(String phone, String password) {\n        startCountDown();\n    }\n\n    @Override\n    public void registerSuccess(User user) {\n        // 注册成功提示框,提醒用户完善资料\n        new AlertDialog.Builder(this)\n                .setMessage(\"注册成功，你可以在个人详情中修改或完善用户信息。\")\n                .setPositiveButton(\"确定\", null)\n                .setOnDismissListener(new DialogInterface.OnDismissListener() {\n                    @Override\n                    public void onDismiss(DialogInterface dialog) {\n                        // 确定或者返回键关闭对话框都走此\n                        intent2Activity(MainActivity.class);\n                    }\n                })\n                .setCancelable(false) // cancelable设为false,防止用户点击返回键关闭对话框停留在当前页面\n                .show();\n    }\n\n    @Override\n    public void setPresenter(RegisterContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditActivity.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ImageUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.GlideHelper;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.ui.modifytext.ModifyTextActivity;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class UserInfoEditActivity extends BaseActivity implements View.OnClickListener, UserInfoEditContract.View {\n\n    private static final int REQUEST_CODE_MODIFY_NICKNAME = 110;\n\n    private UserInfoEditContract.Presenter presenter;\n    private ImageView iv_avatar;\n    private LinearLayout ll_avatar;\n    private TextView tv_username;\n    private LinearLayout ll_username;\n\n    private User currentUser;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_user_info_edit);\n\n        initView();\n        initData();\n    }\n\n    private void initData() {\n        currentUser = UserInfoKeeper.getCurrentUser();\n        GlideHelper.showAvatar(this, currentUser.getAvatar(), iv_avatar);\n        tv_username.setText(currentUser.getNickname());\n    }\n\n    private void initView() {\n        presenter = new UserInfoEditPresenter(this,\n                HttpRequest.getInstance(), UserInfoKeeper.getCurrentUser());\n\n        initBackTitle(\"修改个人资料\");\n\n        iv_avatar = (ImageView) findViewById(R.id.iv_avatar);\n        ll_avatar = (LinearLayout) findViewById(R.id.ll_avatar);\n        tv_username = (TextView) findViewById(R.id.tv_username);\n        ll_username = (LinearLayout) findViewById(R.id.ll_username);\n\n        ll_avatar.setOnClickListener(this);\n        ll_username.setOnClickListener(this);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.ll_avatar:\n                ImageUtils.showImagePickDialog(this);\n                break;\n            case R.id.ll_username:\n                ModifyTextActivity.start(this, REQUEST_CODE_MODIFY_NICKNAME,\n                        \"昵称\", currentUser.getNickname());\n                break;\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n\n        Uri uri;\n        switch (requestCode) {\n            case ImageUtils.REQUEST_CODE_FROM_ALBUM:\n                // 从相册选择\n                uri = data.getData();\n                compressAndUpload(uri);\n                break;\n            case ImageUtils.REQUEST_CODE_FROM_CAMERA:\n                // 相机拍照\n                uri = ImageUtils.imageUriFromCamera;\n                compressAndUpload(uri);\n                break;\n            case REQUEST_CODE_MODIFY_NICKNAME:\n                boolean isModify = data.getBooleanExtra(ModifyTextActivity.RESULT_IS_MODIFY, true);\n                if (!isModify) {\n                    // 未修改，不做任何操作\n                    return;\n                }\n                presenter.updateNickname(data.getStringExtra(ModifyTextActivity.RESULT_NEW_STRING));\n                break;\n        }\n    }\n\n    private void compressAndUpload(final Uri uri) {\n        showProgress();\n\n        Observable<byte[]> observable = ImageUtils.compressImage(this, uri, iv_avatar.getWidth(), iv_avatar.getHeight());\n        ObservableDecorator.decorate(observable)\n                .subscribe(new Subscriber<byte[]>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        showToast(e.getMessage());\n                        dismissProgress();\n                    }\n\n                    @Override\n                    public void onNext(byte[] bytes) {\n                        presenter.uploadAvatar(bytes);\n                    }\n                });\n    }\n\n    @Override\n    public void uploadUserInfoSuccess() {\n        initData();\n    }\n\n    @Override\n    public void setPresenter(UserInfoEditContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditContract.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\n\npublic interface UserInfoEditContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void uploadUserInfoSuccess();\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        /**\n         * 上传用户头像\n         */\n        void uploadAvatar(byte[] bytes);\n\n        /**\n         * 修改昵称\n         */\n        void updateNickname(String nickname);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditPresenter.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.squareup.okhttp.MediaType;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class UserInfoEditPresenter implements UserInfoEditContract.Presenter {\n\n    private final UserInfoEditContract.View view;\n    private final HttpRequest httpRequest;\n    private final User user;\n\n    public UserInfoEditPresenter(UserInfoEditContract.View view,\n                                 HttpRequest httpRequest,\n                                 User user) {\n        this.view = view;\n        this.httpRequest = httpRequest;\n        this.user = user;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void uploadAvatar(byte[] bytes) {\n        final String filename = \"image_\" + System.currentTimeMillis() + \".jpg\";\n\n        // 第一步,上传头像文件到服务器\n        Observable<FileUploadResponse> observable = httpRequest.fileUpload(bytes, filename, MediaType.parse(\"image/jpeg\"));\n        ObservableDecorator.decorate(observable).subscribe(\n                new Subscriber<FileUploadResponse>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onNext(FileUploadResponse fileUploadResponse) {\n                        // 第二步,将上传图片返回的url地址更新至用户对象中\n                        updateUserAvatar(HttpRequest.FILE_HOST + fileUploadResponse.getUrl());\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        view.dismissProgress();\n                    }\n                });\n    }\n\n    /**\n     * 更新用户头像\n     *\n     * @param avatarUrl 头像图片地址\n     */\n    public void updateUserAvatar(final String avatarUrl) {\n        Map<String, Object> updateMap = new HashMap<>();\n        updateMap.put(\"avatar\", avatarUrl);\n\n        Observable<BaseEntity> observable = httpRequest.service.updateUserById(\n                user.getObjectId(), updateMap);\n        ObservableDecorator.decorate(observable)\n                .subscribe(new Subscriber<BaseEntity>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onNext(BaseEntity entity) {\n                        view.dismissProgress();\n\n                        // 成功后更新当前用户的头像数据\n                        user.setAvatar(avatarUrl);\n\n                        view.uploadUserInfoSuccess();\n\n                        view.showTip(\"上传修改头像成功\");\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        view.dismissProgress();\n\n                        view.showTip(\"上传修改头像失败\");\n                    }\n                });\n    }\n\n    @Override\n    public void updateNickname(final String nickname) {\n        // validate\n        if (StringUtils.isEmpty(nickname)) {\n            view.showTip(\"昵称不能为空\");\n            return;\n        }\n\n        view.showProgress();\n\n        Observable<BaseEntity> observable = httpRequest.updateNickname(\n                user.getObjectId(), nickname);\n        ObservableDecorator.decorate(observable)\n                .subscribe(new Subscriber<BaseEntity>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onNext(BaseEntity entity) {\n                        view.dismissProgress();\n\n                        // 修改成功后更新当前用户的昵称\n                        user.setNickname(nickname);\n\n                        view.showTip(\"昵称修改成功\");\n                        view.uploadUserInfoSuccess();\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        view.dismissProgress();\n\n                        String error = ErrorInfoUtils.parseHttpErrorInfo(throwable);\n                        view.showTip(error);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/utils/UpdateUtils.java",
    "content": "package com.boredream.designrescollection.utils;\n\n\nimport android.app.Activity;\nimport android.app.DownloadManager;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.support.annotation.NonNull;\nimport android.support.v7.app.AlertDialog;\n\nimport com.boredream.bdcodehelper.entity.AppUpdateInfo;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.DialogUtils;\nimport com.boredream.bdcodehelper.utils.NetUtils;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\n\nimport java.util.ArrayList;\nimport java.util.Locale;\n\nimport rx.Observable;\n\n/**\n * 检查更新工具类\n * <p>\n * 可以注册下载完成广播，在其中进行提示跳转安装等行为\n * <p>\n * <li>注册广播</li>\n * <pre>\n *      context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));\n * </pre>\n * <p>\n * <li>使用广播</li>\n * <pre>\n *      String action = intent.getAction();\n *      if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {\n *          long enqueueId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);\n *          Uri uri = UpdateUtils.getDownloadUriById(context, enqueueId);\n *          // do something\n *      }\n * </pre>\n * </p>\n */\npublic class UpdateUtils {\n\n    public static final int DOWNLOAD_STATUS_NEED_LOAD = 1;\n    public static final int DOWNLOAD_STATUS_RUNNING = 2;\n    public static final int DOWNLOAD_STATUS_LOADED = 3;\n\n    /**\n     * 检测版本更新\n     *\n     * @param context\n     * @param isForceCheck 是否强制检测更新\n     *                     true强制 - 无论什么网络环境都会提示更新\n     *                     false非强制 - WiFi情况下才提示更新\n     */\n    public static void checkUpdate(final BaseActivity context, final boolean isForceCheck) {\n        if (!NetUtils.isConnected(context)) {\n            // 无网络时\n            if (isForceCheck) {\n                // 手动强制检测更新时，提示文字\n                ToastUtils.showToast(context, \"请检查网络连接\");\n            } else {\n                // 非强制不做操作\n            }\n            return;\n        }\n\n        // 开始检测更新\n\n        if (isForceCheck) {\n            // 强制更新时，才提示进度框\n            context.showProgressDialog();\n        }\n\n        Observable<ListResponse<AppUpdateInfo>> observable = HttpRequest.getInstance().service.getAppUpdateInfo();\n        ObservableDecorator.decorate(observable).subscribe(\n                new SimpleSubscriber<ListResponse<AppUpdateInfo>>(context) {\n                    @Override\n                    public void onError(Throwable throwable) {\n                        if (isForceCheck) {\n                            // 强制更新时，才提示错误\n                            super.onError(throwable);\n                        }\n                        context.dismissProgressDialog();\n                    }\n\n                    @Override\n                    public void onNext(ListResponse<AppUpdateInfo> response) {\n                        context.dismissProgressDialog();\n\n                        ArrayList<AppUpdateInfo> results = response.getResults();\n                        if (results.size() == 0) {\n                            if (isForceCheck) {\n                                ToastUtils.showToast(context, \"当前已经是最新版本\");\n                            }\n                        }\n\n\n                        AppUpdateInfo newestUpdateInfo = results.get(0);\n                        for (AppUpdateInfo updateInfo : results) {\n                            if (updateInfo.getVersion() > newestUpdateInfo.getVersion()) {\n                                // 取最大版本号的作为最新版本\n                                newestUpdateInfo = updateInfo;\n                            }\n                        }\n\n                        if (newestUpdateInfo.getVersion() <= AppUtils.getAppVersionCode(context)) {\n                            if (isForceCheck) {\n                                ToastUtils.showToast(context, \"当前已经是最新版本\");\n                            }\n                        } else {\n                            showUpdateConfirmDialog(context, newestUpdateInfo);\n                        }\n                    }\n                }\n        );\n    }\n\n    /**\n     * 无Wifi状态确认更新对话框\n     */\n    private static void showNoWifiConfirmDialog(final BaseActivity context, final AppUpdateInfo updateInfo) {\n        DialogUtils.showCommonDialog(context, \"没有wifi连接，是否继续选择更新？\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        startDownload(context, updateInfo);\n                    }\n                });\n    }\n\n    /**\n     * 显示更新对话框,包含版本相关信息\n     */\n    private static void showUpdateConfirmDialog(final BaseActivity context, final AppUpdateInfo updateInfo) {\n        String content = String.format(Locale.CHINESE,\n                context.getResources().getString(R.string.update_info),\n                updateInfo.getVersionName(),\n                updateInfo.getUpdateInfo() == null ? \"无\" : updateInfo.getUpdateInfo());\n\n        new AlertDialog.Builder(context)\n                .setTitle(\"发现新版本\")\n                .setMessage(content)\n                .setPositiveButton(\"立即更新\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        if (NetUtils.isWifi(context)) {\n                            startDownload(context, updateInfo);\n                        } else {\n                            showNoWifiConfirmDialog(context, updateInfo);\n                        }\n                    }\n                })\n                .setNegativeButton(\"以后再说\", null)\n                .show();\n    }\n\n    /**\n     * 开始下载\n     *\n     * @param context\n     * @param updateInfo\n     */\n    private static void startDownload(BaseActivity context, AppUpdateInfo updateInfo) {\n        int status = getDownloadStatus(context, updateInfo);\n        if (status != DOWNLOAD_STATUS_NEED_LOAD) {\n            // 不用下载则无需下列操作\n            return;\n        }\n\n        ToastUtils.showToast(context, \"开始下载安装包...\");\n\n        // parse url\n        Uri mUri = Uri.parse(updateInfo.getFileUrl());\n\n        // create request\n        DownloadManager.Request r = new DownloadManager.Request(mUri);\n\n        // set request property\n        String apkName = getDownloadApkName(context, updateInfo);\n        r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);\n        r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);\n\n        // create manager\n        DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);\n\n        // key code, set mine type\n        r.setMimeType(\"application/vnd.android.package-archive\");\n\n        // add to queue\n        dm.enqueue(r);\n    }\n\n    @NonNull\n    private static String getDownloadApkName(BaseActivity context, AppUpdateInfo updateInfo) {\n        return context.getString(R.string.app_name) + \"_\" + updateInfo.getVersionName() + \".apk\";\n    }\n\n    /**\n     * 判断当前版本文件下载状态\n     *\n     * @param context\n     * @param updateInfo\n     * @return\n     */\n    private static int getDownloadStatus(BaseActivity context, AppUpdateInfo updateInfo) {\n        DownloadManager.Query query = new DownloadManager.Query();\n        DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);\n        Cursor c = dm.query(query);\n\n        if (!c.moveToFirst()) {\n            // 无下载内容\n            return DOWNLOAD_STATUS_NEED_LOAD;\n        }\n\n        do {\n            int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));\n            String title = c.getString(c.getColumnIndex(DownloadManager.COLUMN_TITLE));\n            String apkName = getDownloadApkName(context, updateInfo);\n            if (title.equals(apkName)) {\n                // 如果下载列表中文件是当前版本应用，则继续判断下载状态\n                if (status == DownloadManager.STATUS_SUCCESSFUL) {\n                    // 如果已经下载，返回状态，同时直接提示安装\n                    String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));\n                    AppUtils.promptInstall(context, Uri.parse(uri));\n                    return DOWNLOAD_STATUS_LOADED;\n                } else if (status == DownloadManager.STATUS_RUNNING\n                        || status == DownloadManager.STATUS_PAUSED\n                        || status == DownloadManager.STATUS_PENDING) {\n                    return DOWNLOAD_STATUS_RUNNING;\n                } else {\n                    // 失败也视为可以再次下载\n                    return DOWNLOAD_STATUS_NEED_LOAD;\n                }\n            }\n        } while (c.moveToNext());\n\n        return DOWNLOAD_STATUS_NEED_LOAD;\n    }\n\n    /**\n     * 根据下载队列id获取下载Uri\n     *\n     * @param enqueueId\n     * @return null-获取不到\n     */\n    public static Uri getDownloadUriById(Context context, long enqueueId) {\n        DownloadManager.Query query = new DownloadManager.Query();\n        query.setFilterById(enqueueId);\n        DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);\n        Cursor c = dm.query(query);\n        if (c.moveToFirst()) {\n            int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);\n            if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {\n                String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));\n                return Uri.parse(uri);\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/java/com/boredream/designrescollection/utils/UserInfoKeeper.java",
    "content": "package com.boredream.designrescollection.utils;\n\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.ui.login.LoginActivity;\n\n/**\n * 用户信息保存工具\n */\npublic class UserInfoKeeper {\n\n    private static User currentUser;\n\n    /**\n     * 获取当前登录用户\n     */\n    public static User getCurrentUser() {\n        return currentUser;\n    }\n\n    /**\n     * 保存设置当前登录用户\n     */\n    public static void setCurrentUser(User user) {\n        currentUser = user;\n    }\n\n    /**\n     * 清空当前登录用户\n     */\n    public static void clearCurrentUser() {\n        currentUser = null;\n    }\n\n    public static String getToken() {\n        // 统一Header配置时用的token,没有的话要用空字符串,不能为null\n        String token = \"\";\n        if (currentUser != null && currentUser.getSessionToken() != null) {\n            token = currentUser.getSessionToken();\n        }\n        return token;\n    }\n\n    /**\n     * 登出\n     */\n    public static void logout() {\n        clearCurrentUser();\n    }\n\n    /**\n     * 检测登录状态\n     *\n     * @return true-已登录 false-未登录,会自动跳转至登录页\n     */\n    public static boolean checkLogin(Context context) {\n        if (currentUser == null) {\n            Intent intent = new Intent(context, LoginActivity.class);\n            intent.putExtra(\"checkLogin\", true);\n            context.startActivity(intent);\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/anim/loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <rotate\n        android:duration=\"500\"\n        android:fromDegrees=\"0\"\n        android:pivotX=\"50%\"\n        android:pivotY=\"50%\"\n        android:repeatCount=\"-1\"\n        android:toDegrees=\"359\" />\n</set>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/color/txt_blue2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@color/txt_link_blue\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/drawable/ic_fav_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_favorite_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_favorite_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/drawable/ic_home_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_home_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_home_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/drawable/ic_more_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_timer_auto_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_timer_auto_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/drawable/ic_search_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_search_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_search_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/drawable/ic_settings_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_settings_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_settings_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/drawable/oval_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/bg_pull_to_refresh\" />\n\n    <item>\n        <rotate\n            android:drawable=\"@mipmap/ic_loading\"\n            android:fromDegrees=\"0\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n            android:toDegrees=\"360\" />\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center_horizontal\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <ImageView\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@mipmap/ic_launcher\" />\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:text=\"@string/app_name\" />\n\n        <TextView\n            android:id=\"@+id/tv_version\"\n            style=\"@style/TextViewCaption\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_tiny\"\n            android:text=\"Version 1.0.0\" />\n\n        <TextView\n            android:id=\"@+id/tv_about\"\n            style=\"@style/TextViewBody\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:gravity=\"center\"\n            android:text=\"@string/about\"\n            android:textColor=\"@color/txt_gray\" />\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_feed_back.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/white\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/margin_medium\">\n\n        <EditText\n            android:id=\"@+id/et_content\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"top\"\n            android:hint=\"请输入您的意见反馈\"\n            android:maxLines=\"10\"\n            android:minLines=\"3\"\n            android:padding=\"@dimen/margin_medium\" />\n\n        <EditText\n            android:id=\"@+id/et_email\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"请输入您的邮箱\" />\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <TextView\n        style=\"@style/TextViewSubhead\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:text=\"名字不得超过12个字符\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <EditText\n        android:id=\"@+id/et_input\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"48dp\"\n        android:layout_margin=\"@dimen/margin_medium\"\n        android:maxLength=\"12\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <FrameLayout\n        android:id=\"@+id/fl_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </FrameLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:id=\"@+id/fl_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\">\n    </FrameLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <include layout=\"@layout/include_bottom_tab\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_regist.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <EditText\n            android:id=\"@+id/et_username\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入手机号\"\n            android:inputType=\"number\"\n            android:maxEms=\"11\" />\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"设置登录密码，不少于6位\"\n            android:inputType=\"textPassword\" />\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_register_step1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <EditText\n            android:id=\"@+id/et_username\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入手机号\"\n            android:inputType=\"number\"\n            android:maxEms=\"11\" />\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"设置登录密码，不少于6位\"\n            android:inputType=\"textPassword\" />\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_register_step2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <TextView\n            style=\"@style/TextViewBody\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"你会收到一条带验证码的短信，请输入验证码：\"\n            android:textColor=\"@color/txt_gray\" />\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\">\n\n            <EditText\n                android:id=\"@+id/et_verification_code\"\n                style=\"@style/EditTextSingleLine\"\n                android:hint=\"请输入验证码\"\n                android:inputType=\"number\"\n                android:maxEms=\"10\" />\n\n            <Button\n                android:id=\"@+id/btn_code_info\"\n                style=\"@style/TextViewBody\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:background=\"@null\"\n                android:text=\"60秒\"\n                android:textColor=\"@color/txt_blue2gray_sel\" />\n        </RelativeLayout>\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv_setting\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:layout_weight=\"1\"></android.support.v7.widget.RecyclerView>\n\n    <Button\n        android:id=\"@+id/btn_logout\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/margin_large\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_medium\"\n        android:text=\"退出登录\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/activity_user_info_edit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_avatar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"72dp\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:background=\"@drawable/bg_white2gray_sel\"\n        android:clickable=\"true\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\">\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"头像\" />\n\n        <ImageView\n            android:id=\"@+id/iv_avatar\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@mipmap/ic_launcher\" />\n\n        <ImageView\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_username\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:background=\"@drawable/bg_white2gray_sel\"\n        android:clickable=\"true\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\">\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"昵称\" />\n\n        <TextView\n            android:id=\"@+id/tv_username\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"boredream\"\n            android:textColor=\"@color/txt_gray\" />\n\n        <ImageView\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/frag_home.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <include layout=\"@layout/include_refresh_list\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/frag_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"@dimen/activity_vertical_margin\">\n\n    <EditText\n        android:id=\"@+id/et_username\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"48dp\"\n        android:hint=\"请输入手机号\"\n        android:inputType=\"number\"\n        android:maxEms=\"11\" />\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"@dimen/margin_small\">\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入密码\"\n            android:inputType=\"textPassword\" />\n\n        <TextView\n            android:id=\"@+id/tv_forget_psw\"\n            style=\"@style/TextViewBody\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:clickable=\"true\"\n            android:padding=\"@dimen/margin_small\"\n            android:text=\"忘记密码?\"\n            android:textColor=\"@color/colorPrimary\" />\n    </RelativeLayout>\n\n    <Button\n        android:id=\"@+id/btn_login\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"@dimen/margin_large\"\n        android:text=\"登录\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_regist\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/margin_medium\"\n        android:clickable=\"true\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            style=\"@style/TextViewBody\"\n            android:text=\"还没有账号?  赶紧\"\n            android:textColor=\"@color/txt_light_gray\" />\n\n        <TextView\n            style=\"@style/TextViewBody\"\n            android:text=\"注册\"\n            android:textColor=\"@color/colorPrimary\" />\n\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/frag_user.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv_user\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginTop=\"@dimen/margin_medium\">\n    </android.support.v7.widget.RecyclerView>\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/include_bottom_tab.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RadioGroup xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/rg_bottom_tab\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:background=\"@android:color/white\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\">\n\n    <com.boredream.bdcodehelper.view.DrawableRadioButton\n        android:id=\"@+id/rb1\"\n        style=\"@style/RadioButtonBottomTab\"\n        android:drawableTop=\"@drawable/ic_home_grey2black_sel\"\n        app:drawableHeight=\"40dp\"\n        app:drawableWidth=\"40dp\" />\n\n    <com.boredream.bdcodehelper.view.DrawableRadioButton\n        android:id=\"@+id/rb2\"\n        style=\"@style/RadioButtonBottomTab\"\n        android:drawableTop=\"@drawable/ic_more_grey2black_sel\"\n        app:drawableHeight=\"40dp\"\n        app:drawableWidth=\"40dp\" />\n</RadioGroup>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/include_more_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"96dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <ImageView\n        android:id=\"@+id/iv_avatar\"\n        android:layout_width=\"68dp\"\n        android:layout_height=\"68dp\"\n        android:scaleType=\"centerCrop\" />\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"68dp\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/tv_name\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <ImageView\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/include_more_no_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"96dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"尚未登录，无法进行收藏等操作。\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <Button\n        android:id=\"@+id/btn_login\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"120dp\"\n        android:layout_height=\"40dp\"\n        android:layout_marginTop=\"@dimen/margin_small\"\n        android:text=\"立即登录\" />\n\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/item_design_res.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"vertical\">\n\n    <ImageView\n        android:id=\"@+id/iv_image\"\n        android:layout_width=\"172dp\"\n        android:layout_height=\"172dp\"\n        android:scaleType=\"centerCrop\" />\n\n    <TextView\n        android:id=\"@+id/tv_name\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"@dimen/margin_tiny\"\n        android:lines=\"2\" />\n\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/layout/item_more_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <include\n        android:id=\"@+id/include_more_header\"\n        layout=\"@layout/include_more_header\" />\n\n    <include\n        android:id=\"@+id/include_more_no_header\"\n        layout=\"@layout/include_more_no_header\" />\n\n</FrameLayout>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/menu/menu_main2.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\"com.boredream.designrescollection.ui.login.Main2Activity\">\n    <item\n        android:id=\"@+id/action_settings\"\n        android:orderInCategory=\"100\"\n        android:showAsAction=\"never\"\n        android:title=\"@string/action_settings\" />\n</menu>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">DesignResCollection</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"tab1\">首页</string>\n    <string name=\"tab2\">搜索</string>\n    <string name=\"tab3\">收藏</string>\n    <string name=\"tab4\">我</string>\n    <string name=\"about\">\n        使用LeanCloud的Restful API作为后端支持\\n\n        使用LeanCloud的定时云代码，自动按时爬取数据并保存至LeanCloud中\\n\n        使用Retrofit2.0 + RxJava 实现网络请求部分\\n\n        使用Glide实现图片部分\\n\n        \\n\n        开源项目, 地址为\\n\n        %1$s\\n\n        \\n\n        欢迎follow我以及star项目\\n\n        有任何应用问题可以在反馈中提出\\n\n        对于项目代码有任何疑问,也可以在github项目中提issue\n    </string>\n    <string name=\"github\">https://github.com/boredream/DesignResCollection</string>\n    <string name=\"update_info\">\n        最新版本：%1$s\n        \\n\\n更新内容：\\n%2$s\n    </string>\n    <string name=\"title_activity_main2\">Main2Activity</string>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/values/styles.xml",
    "content": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP/app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/test/java/com/boredream/designrescollection/net/HttpRequestTest.java",
    "content": "package com.boredream.designrescollection.net;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.entity.User;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport rx.Subscriber;\n\npublic class HttpRequestTest {\n\n    @Before\n    public void setUp() {\n        BoreConstants.isUnitTest = true;\n    }\n\n    @Test\n    public void test() {\n        HttpRequest.getInstance().login(\"18551681236\", \"123456\").subscribe(new Subscriber<User>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(e.toString());\n            }\n\n            @Override\n            public void onNext(User user) {\n                System.out.println(user.toString());\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/test/java/com/boredream/designrescollection/ui/feedback/FeedBackPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.net.HttpRequest;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport rx.Observable;\n\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n/**\n * 提交反馈很少有失败情况，所以使用mock模拟接口部分手动返回错误结果，以验证对应场景\n * 同时也提供真实接口的presenter，用于测试真实数据\n */\npublic class FeedBackPresenterTest {\n\n    // 用于测试真实接口返回数据\n    private FeedBackPresenter presenter;\n\n    // 用于测试模拟接口返回数据\n    private FeedBackPresenter mockPresenter;\n\n    @Mock\n    private FeedBackContract.View view;\n\n    @Mock\n    private HttpRequest.ApiService api;\n\n    @Before\n    public void setupMocksAndView() {\n        // 使用Mock标签等需要先init初始化一下\n        MockitoAnnotations.initMocks(this);\n\n        // 当view调用isActive方法时，就返回true表示UI已激活。方便测试接口返回数据后测试view的方法\n        when(view.isActive()).thenReturn(true);\n\n        // 设置单元测试标识\n        BoreConstants.isUnitTest = true;\n\n        // 用真实接口创建反馈Presenter\n        presenter = new FeedBackPresenter(view, HttpRequest.getInstance().service);\n        // 用mock模拟接口创建反馈Presenter\n        mockPresenter = new FeedBackPresenter(view, api);\n    }\n\n    @Test\n    public void testAddFeedback_Success() throws Exception {\n        // 真实数据，调用实际接口\n        String content = \"这个App真是好！\";\n        String email = \"110@qq.com\";\n        presenter.addFeedback(content, email);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).addFeedbackSuccess();\n    }\n\n    @Test\n    public void testAddFeedback_Mock_Success() throws Exception {\n        // 模拟数据，当api调用addFeedBack接口传入任意值时，就返回成功的基本数据BaseEntity\n        when(api.addFeedBack(any(FeedBack.class))).thenReturn(Observable.just(new BaseEntity()));\n\n        String content = \"这个App真是棒！\";\n        String email = \"119@qq.com\";\n        mockPresenter.addFeedback(content, email);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).addFeedbackSuccess();\n    }\n\n    @Test\n    public void testAddFeedback_Mock_Error() throws Exception {\n        // 模拟数据，当api调用addFeedBack接口传入任意值时，就抛出错误error\n        when(api.addFeedBack(any(FeedBack.class))).thenReturn(Observable.<BaseEntity>error(new Exception(\"孙贼你说谁辣鸡呢？\")));\n\n        String content = \"这个App真是辣鸡！\";\n        String email = \"120@qq.com\";\n        mockPresenter.addFeedback(content, email);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).showTip(\"反馈提交失败\");\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/test/java/com/boredream/designrescollection/ui/home/HomePresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport java.util.Collections;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class HomePresenterTest {\n\n    private HomePresenter presenter;\n\n    @Mock\n    private HomeContract.View view;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        presenter = new HomePresenter(view);\n    }\n\n    @Test\n    public void testPullToLoadList() throws Exception {\n        presenter.pullToLoadList();\n\n        verify(view).dismissProgress();\n        verify(view).loadListSuccess(1, presenter.datas);\n        Assert.assertTrue(presenter.datas.size() > 0);\n    }\n\n    @Test\n    public void testLoadList() throws Exception {\n        presenter.loadList(1);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).loadListSuccess(1, presenter.datas);\n        Assert.assertTrue(presenter.datas.size() > 0);\n    }\n\n    @Test\n    public void testLoadList_overPage() throws Exception {\n        presenter.loadList(999);\n\n        verify(view).dismissProgress();\n        verify(view).loadListSuccess(999, Collections.<DesignRes>emptyList());\n        Assert.assertFalse(presenter.datas.size() > 0);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/test/java/com/boredream/designrescollection/ui/login/LoginPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n/**\n * 接口部分使用真实数据，只进行了view的mock测试，验证各种数据返回后的view的处理是否符合预期\n */\npublic class LoginPresenterTest {\n\n    private LoginPresenter presenter;\n\n    @Mock\n    private LoginContract.View view;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        // 设置标识，用于区分处理Observer的线程等情况\n        BoreConstants.isUnitTest = true;\n\n        presenter = new LoginPresenter(view, HttpRequest.getInstance());\n    }\n\n    @Test\n    public void testLogin_EmptyPassword() throws Exception {\n        presenter.login(\"13913391521\", \"\");\n\n        verify(view).showTip(\"密码不能为空\");\n    }\n\n    @Test\n    public void testLogin_EmptyUsername() throws Exception {\n        presenter.login(null, \"123456\");\n\n        verify(view).showTip(\"用户名不能为空\");\n    }\n\n    @Test\n    public void testLogin_Success() throws Exception {\n        String phone = \"18551681236\";\n        presenter.login(phone, \"123456\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).loginSuccess(UserInfoKeeper.getCurrentUser());\n        Assert.assertEquals(UserInfoKeeper.getCurrentUser().getUsername(), phone);\n    }\n\n    @Test\n    public void testLogin_UserNotExit() throws Exception {\n        String phone = \"110110110\";\n        presenter.login(phone, \"123456\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).showTip(\"找不到用户\");\n    }\n\n    @Test\n    public void testLogin_PswError() throws Exception {\n        String phone = \"18551681236\";\n        presenter.login(phone, \"110119120\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).showTip(\"密码不正确\");\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/app/src/test/java/com/boredream/designrescollection/ui/modifytext/ModifyTextPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport com.boredream.bdcodehelper.BoreConstants;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class ModifyTextPresenterTest {\n\n    @Mock\n    private ModifyTextContract.View view;\n\n    private ModifyTextPresenter presenter;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        presenter = new ModifyTextPresenter(view);\n    }\n\n    @Test\n    public void testModifyText_Empty1() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = null;\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).showTip(\"昵称不能为空\");\n    }\n\n    @Test\n    public void testModifyText_Empty2() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = \"\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).showTip(\"昵称不能为空\");\n    }\n\n    @Test\n    public void testModifyText_NoModify() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = \"aaa\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(false, \"aaa\");\n    }\n\n    @Test\n    public void testModifyText_Success1() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = \"bbb\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(true, \"bbb\");\n    }\n\n    @Test\n    public void testModifyText_Success2() throws Exception {\n        String title = \"昵称\";\n        String oldString = null;\n        String modifyString = \"bbb\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(true, \"bbb\");\n    }\n\n    @Test\n    public void testModifyText_Success3() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"\";\n        String modifyString = \"bbb\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(true, \"bbb\");\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/test/java/com/boredream/designrescollection/ui/register/RegisterPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class RegisterPresenterTest {\n\n    @Mock\n    private RegisterContract.View view;\n\n    private RegisterPresenter presenter;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        presenter = new RegisterPresenter(view);\n    }\n\n    @Test\n    public void testRequestSms() throws Exception {\n        // 模拟发送短信，无需测试\n        String phone = \"13913391235\";\n        String password = \"123456\";\n        presenter.requestSms(phone, password);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).requestSmsSuccess(phone, password);\n    }\n\n    @Test\n    public void testRegister() throws Exception {\n        String phone = \"13913391238\";\n        String password = \"123456\";\n        String code = \"1234\";\n        presenter.register(phone, password, code);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).registerSuccess(UserInfoKeeper.getCurrentUser());\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/app/src/test/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.squareup.okhttp.MediaType;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport rx.Observable;\n\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Matchers.anyMap;\nimport static org.mockito.Matchers.anyString;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class UserInfoEditPresenterTest {\n\n    @Mock\n    private UserInfoEditContract.View view;\n\n    @Mock\n    private HttpRequest httpRequest;\n\n    private UserInfoEditPresenter presenter;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        User user = new User();\n        user.setObjectId(\"123456\");\n        presenter = new UserInfoEditPresenter(view, httpRequest, user);\n    }\n\n    @Test\n    public void testFileUpload() throws Exception {\n        FileUploadResponse response = new FileUploadResponse();\n        response.setFilename(\"image\");\n        response.setUrl(\"www.baidu.com\");\n\n        when(httpRequest.fileUpload(any(byte[].class), anyString(), any(MediaType.class)))\n                .thenReturn(Observable.just(response));\n\n        // 如果不加updateUserById的when处理，由于httpRequest的是mock的对象，updateUserById方法会毫无反应\n        // 但是updateUserById是ApiService方法，加空指针报错。\n        // 因为虽然mock了httpRequest对象，但是没mock该对象中的service变量的对象\n        when(httpRequest.service.updateUserById(anyString(), anyMap()))\n                .thenReturn(Observable.just(new BaseEntity()));\n\n        byte[] image = new byte[1024];\n        presenter.uploadAvatar(image);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).uploadUserInfoSuccess();\n    }\n\n    @Test\n    public void testUpdateNickname() throws Exception {\n        // 无法使用由于httpRequest.service，只能创建一个httpRequest方法使用之\n        when(httpRequest.updateNickname(anyString(), anyString()))\n                .thenReturn(Observable.just(new BaseEntity()));\n\n        presenter.updateNickname(\"new name~~\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).uploadUserInfoSuccess();\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/README.md",
    "content": "# BDCodeHelper 代码助手\nCode Helper Model for android develper (Android Studio)  \n代码为Android Studio 的 Model，不是完整App应用。需要主项目依赖导入作为辅助开发工具。\n\n---\n# 功能介绍\nModel封装了应用中常用的功能，包括\n####adapter包\n* **LoadMoreAdapter** 加载更多适配器，用于包装普通RecyclerView.Adapter增添一个加载更多功能。适用于所有LayoutManager。  \n装饰器设计模式。无需自定义控件，无需写一大堆监听代码，包装即用~   \n感谢[飞飞大神](https://github.com/jeffreyhappy)的贡献，我在他代码基础上做了简单修改。\n\n* **SettingRecyclerAdapter** 设置选项列表适配器  。\nItem通用样式为：左侧图标、中间文字、右侧文字、右侧图标。  \n使用数据类SettingItem，不同字段对应不同控件，图片资源为-1或者字符为null时，对应位置控件不显示。\n\n####fragment包\n* **FragmentController** fragment切换控制器。  \n初始化时直接add全部fragment, 然后利用show和hide进行切换控制。\n\n####utils包\n大部分常用工具类，比较特殊的单独介绍下\n* **TitleBuilder** 标题栏构造器。\n使用构造器模式设置标题栏，结合layout中的include_titlebar.xml一起使用，先在布局中include引入标题栏布局，  \n再于Activity或Fragment中使用TitleBuilder设置标题栏内容，标题栏格式为：标题文字、左右各自是文字/图片按钮。\n\n####views包\n封装了一些有用的自定义控件\n* **BottomTabRadioButton** 底部导航栏选项卡RadioButton\n利用onDraw绘制红色圆点、带数字的红色圆圈，提供各种自定义attrs属性可以对红点的颜色、数字大小、数字颜色等进行配置。\n感谢[程序媛大神燕姐](https://github.com/xiaoxuyan)的贡献，我在他代码基础上做了简单修改。\n\n\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n\n        versionCode 1\n        versionName \"1.0\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\n// App dependencies\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n\n    // Android support\n    compile \"com.android.support:appcompat-v7:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:cardview-v7:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:design:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion\"\n\n    // Retrofit\n    compile \"com.squareup.retrofit:retrofit:$rootProject.retrofitVersion\"\n    compile \"com.squareup.retrofit:converter-gson:$rootProject.retrofitVersion\"\n    compile \"com.squareup.retrofit:adapter-rxjava:$rootProject.retrofitVersion\"\n    compile \"com.squareup.okhttp:logging-interceptor:$rootProject.okhttploggingVersion\"\n\n    // RxJava\n    compile \"io.reactivex:rxandroid:$rootProject.rxjavaVersion\"\n    compile \"com.jakewharton.rxbinding:rxbinding:$rootProject.rxbindingVersion\"\n\n    // Glide\n    compile \"com.github.bumptech.glide:glide:$rootProject.glideVersion\"\n    compile \"com.github.bumptech.glide:okhttp-integration:$rootProject.glideokhttpVersion\"\n\n    // Others\n    compile \"com.commit451:PhotoView:$rootProject.photoviewVersion\"\n    compile \"com.github.promeg:tinypinyin:1.0.0\"\n    compile \"org.greenrobot:eventbus:3.0.0\"\n\n\n\n    /////////////////   put test in main project below   //////////////////\n//    // Dependencies for local unit tests\n//    testCompile \"junit:junit:$rootProject.ext.junitVersion\"\n//    testCompile \"org.mockito:mockito-all:$rootProject.ext.mockitoVersion\"\n//    testCompile \"org.hamcrest:hamcrest-all:$rootProject.ext.hamcrestVersion\"\n//\n//    // Espresso UI Testing\n//    androidTestCompile \"com.android.support.test:runner:$rootProject.runnerVersion\"\n//    androidTestCompile \"com.android.support.test:rules:$rootProject.rulesVersion\"\n//    androidTestCompile \"com.android.support.test.espresso:espresso-core:$rootProject.espressoVersion\"\n//    androidTestCompile \"com.android.support.test.espresso:espresso-contrib:$rootProject.espressoVersion\"\n//    androidTestCompile \"com.android.support.test.espresso:espresso-intents:$rootProject.espressoVersion\"\n//\n//    // Resolve conflicts between main and test APK:\n//    androidTestCompile \"com.android.support:support-annotations:$rootProject.supportLibraryVersion\"\n//    androidTestCompile \"com.android.support:support-v4:$rootProject.supportLibraryVersion\"\n//    androidTestCompile \"com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion\"\n\n}\n\n// copy to rootProject build.gradle\n//// Define versions in a single place\n//ext {\n//    // Sdk and tools\n//    minSdkVersion = 15\n//    targetSdkVersion = 23\n//    compileSdkVersion = 23\n//    buildToolsVersion = '23.0.3'\n//\n//    // App dependencies\n//    supportLibraryVersion = '23.4.0'\n//    guavaVersion = '18.0'\n//    junitVersion = '4.12'\n//    mockitoVersion = '1.10.19'\n//    powerMockito = '1.6.2'\n//    hamcrestVersion = '1.3'\n//    runnerVersion = '0.4.1'\n//    rulesVersion = '0.4.1'\n//    espressoVersion = '2.2.1'\n//    retrofitVersion = '2.0.0-beta2'\n//    okhttploggingVersion = '2.6.0'\n//    rxjavaVersion = '1.1.0'\n//    rxbindingVersion = '0.2.0'\n//    glideVersion = '3.6.1'\n//    glideokhttpVersion = '1.3.1'\n//    photoviewVersion = '1.2.4'\n//}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\adt-bundle-windows-x86_64-20140702\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.boredream.bdcodehelper\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:supportsRtl=\"true\">\n\n        <activity android:name=\".activity.ImageBrowserActivity\" />\n        <activity android:name=\".activity.WebViewActivity\" />\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/BoreConstants.java",
    "content": "package com.boredream.bdcodehelper;\n\npublic class BoreConstants {\n    private BoreConstants() {\n    }\n\n    public static boolean isUnitTest = false;\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/activity/ImageBrowserActivity.java",
    "content": "package com.boredream.bdcodehelper.activity;\n\n\nimport android.os.Bundle;\nimport android.support.v4.view.ViewPager;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.ImageBrowserAdapter;\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\n\nimport java.util.ArrayList;\n\npublic class ImageBrowserActivity extends BoreBaseActivity {\n\n    private ViewPager vp_image_brower;\n    private TextView tv_image_index;\n\n    private int position;\n    private ImageBrowserAdapter adapter;\n    private ArrayList<? extends ImageUrlInterface> images;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_image_browser);\n\n        initData();\n        initView();\n        setData();\n    }\n\n    private void initData() {\n        images = (ArrayList<ImageUrlInterface>) getIntent().getSerializableExtra(\"images\");\n        position = getIntent().getIntExtra(\"position\", 0);\n    }\n\n    private void initView() {\n        vp_image_brower = (ViewPager) findViewById(R.id.vp_image_brower);\n        tv_image_index = (TextView) findViewById(R.id.tv_image_index);\n    }\n\n    private void setData() {\n        adapter = new ImageBrowserAdapter(this, images);\n        vp_image_brower.setAdapter(adapter);\n\n        final int size = images.size();\n//        int initPosition = Integer.MAX_VALUE / 2 / size * size + position;\n        int initPosition = position;\n\n        if (size > 1) {\n            tv_image_index.setVisibility(View.VISIBLE);\n            tv_image_index.setText((position + 1) + \"/\" + size);\n        } else {\n            tv_image_index.setVisibility(View.GONE);\n        }\n\n        vp_image_brower.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n\n            @Override\n            public void onPageSelected(int arg0) {\n                int index = arg0 % size;\n                tv_image_index.setText((index + 1) + \"/\" + size);\n            }\n\n            @Override\n            public void onPageScrolled(int arg0, float arg1, int arg2) {\n\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int arg0) {\n\n            }\n        });\n\n        vp_image_brower.setCurrentItem(initPosition);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/activity/WebViewActivity.java",
    "content": "package com.boredream.bdcodehelper.activity;\n\nimport android.annotation.SuppressLint;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.webkit.WebSettings;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\n\npublic class WebViewActivity extends BoreBaseActivity {\n\n    public static final String EXTRA_TITLE = \"title\";\n    public static final String EXTRA_URL = \"url\";\n\n    private WebView webview;\n    private String title;\n    private TitleBuilder titleBuilder;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_web_view);\n\n        title = getIntent().getStringExtra(EXTRA_TITLE);\n        String url = getIntent().getStringExtra(EXTRA_URL);\n\n        initView();\n\n        showProgressDialog();\n        webview.loadUrl(url);\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\")\n    private void initView() {\n        titleBuilder = initBackTitle(title);\n        titleBuilder.getRootView().setOnLongClickListener(new View.OnLongClickListener() {\n            @Override\n            public boolean onLongClick(View v) {\n                String url = webview.getUrl();\n                if(!TextUtils.isEmpty(url)) {\n                    AppUtils.copy2clipboard(WebViewActivity.this, url);\n                    showToast(\"网址已经复制到剪贴板\");\n                }\n                return false;\n            }\n        });\n\n        webview = (WebView) findViewById(R.id.webview);\n        webview.setWebViewClient(new MyWebClient());\n\n        WebSettings settings = webview.getSettings();\n        settings.setJavaScriptEnabled(true);\n        settings.setSupportZoom(false);\n        settings.setBuiltInZoomControls(false);\n        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);\n    }\n\n    private class MyWebClient extends WebViewClient {\n\n        @Override\n        public void onPageStarted(WebView view, String url, Bitmap favicon) {\n            super.onPageStarted(view, url, favicon);\n        }\n\n        @Override\n        public void onPageFinished(WebView view, String url) {\n            super.onPageFinished(view, url);\n            titleBuilder.setTitleText(view.getTitle());\n            dismissProgressDialog();\n        }\n\n        public boolean shouldOverrideUrlLoading(WebView view, String url) {\n            webview.loadUrl(url);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/BannerPagerAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.support.v4.view.PagerAdapter;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.activity.ImageBrowserActivity;\nimport com.boredream.bdcodehelper.activity.WebViewActivity;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\n\nimport java.util.ArrayList;\n\npublic class BannerPagerAdapter extends PagerAdapter {\n\n    private Context context;\n    private ArrayList<? extends ImageUrlInterface> images;\n\n    public BannerPagerAdapter(Context context, ArrayList<? extends ImageUrlInterface> images) {\n        this.context = context;\n        this.images = images;\n    }\n\n    @Override\n    public int getCount() {\n        if (images.size() > 1) {\n            return Integer.MAX_VALUE;\n        }\n        return images.size();\n    }\n\n    @Override\n    public boolean isViewFromObject(View arg0, Object arg1) {\n        return arg0 == arg1;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        container.removeView((View) object);\n    }\n\n    @Override\n    public Object instantiateItem(ViewGroup container, final int position) {\n        final ImageUrlInterface image = images.get(position % images.size());\n\n        View view = View.inflate(context, R.layout.item_image_banner, null);\n        TextView tv_title = (TextView) view.findViewById(R.id.tv_title);\n        final ImageView iv = (ImageView) view.findViewById(R.id.iv_image);\n\n        String title = image.getImageTitle();\n        if (TextUtils.isEmpty(title)) {\n            tv_title.setVisibility(View.GONE);\n        } else {\n            tv_title.setVisibility(View.VISIBLE);\n            tv_title.setText(title);\n        }\n\n        final String url = image.getImageUrl();\n        Glide.with(context)\n                .load(url)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n//                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n//                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .centerCrop()\n                .crossFade()\n                .into(iv);\n\n        iv.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (!TextUtils.isEmpty(image.getImageLink())) {\n//                    Intent intent = new Intent();\n//                    intent.setAction(Intent.ACTION_VIEW);\n//                    Uri url = Uri.parse(link);\n//                    intent.setData(url);\n//                    context.startActivity(intent);\n                    Intent intent = new Intent(context, WebViewActivity.class);\n                    intent.putExtra(\"title\", image.getImageTitle());\n                    intent.putExtra(\"url\", image.getImageLink());\n                    context.startActivity(intent);\n                } else {\n                    Intent intent = new Intent(context, ImageBrowserActivity.class);\n                    intent.putExtra(\"images\", images);\n                    intent.putExtra(\"position\", position);\n                    context.startActivity(intent);\n                }\n            }\n        });\n\n        container.addView(view);\n        return view;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/ImageBrowserAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.app.Activity;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.PagerAdapter;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\nimport com.bumptech.glide.load.resource.drawable.GlideDrawable;\nimport com.bumptech.glide.request.animation.GlideAnimation;\nimport com.bumptech.glide.request.target.SimpleTarget;\n\nimport java.util.List;\n\nimport uk.co.senab.photoview.PhotoViewAttacher;\n\npublic class ImageBrowserAdapter extends PagerAdapter {\n\n    private Activity context;\n    private List<? extends ImageUrlInterface> picUrls;\n\n    public ImageBrowserAdapter(Activity context, List<? extends ImageUrlInterface> picUrls) {\n        this.context = context;\n        this.picUrls = picUrls;\n    }\n\n    @Override\n    public int getCount() {\n        if (picUrls.size() > 1) {\n            return Integer.MAX_VALUE;\n        }\n        return picUrls.size();\n    }\n\n    @Override\n    public boolean isViewFromObject(View view, Object object) {\n        return view == object;\n    }\n\n    @Override\n    public View instantiateItem(final ViewGroup container, int position) {\n        final View rootView = View.inflate(context, R.layout.item_image_browser, null);\n\n        int index = position % picUrls.size();\n        final ProgressBar pb_loading = (ProgressBar) rootView.findViewById(R.id.pb_loading);\n        final ImageView iv_image_browser = (ImageView) rootView.findViewById(R.id.iv_image_browser);\n        final PhotoViewAttacher pva = new PhotoViewAttacher(iv_image_browser);\n        String url = picUrls.get(index).getImageUrl();\n\n        Glide.with(context)\n                .load(url)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n//                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n//                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .centerCrop()\n                .crossFade()\n                .into(new SimpleTarget<GlideDrawable>() {\n\n                    @Override\n                    public void onLoadFailed(Exception e, Drawable errorDrawable) {\n                        super.onLoadFailed(e, errorDrawable);\n                        pb_loading.setVisibility(View.GONE);\n                        iv_image_browser.setVisibility(View.VISIBLE);\n                    }\n\n                    @Override\n                    public void onLoadStarted(Drawable placeholder) {\n                        super.onLoadStarted(placeholder);\n                        pb_loading.setVisibility(View.VISIBLE);\n                        iv_image_browser.setVisibility(View.GONE);\n                    }\n\n                    @Override\n                    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {\n                        pb_loading.setVisibility(View.GONE);\n                        iv_image_browser.setVisibility(View.VISIBLE);\n\n                        iv_image_browser.setImageDrawable(resource);\n                        pva.update();\n                    }\n                });\n\n        pva.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {\n            @Override\n            public void onPhotoTap(View view, float x, float y) {\n                context.onBackPressed();\n            }\n        });\n\n        container.addView(rootView);\n        return rootView;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        container.removeView((View) object);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/ListDropDownAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.util.List;\n\npublic class ListDropDownAdapter extends BaseAdapter {\n\n    private Context context;\n    private List<String> list;\n    private int checkItemPosition = 0;\n\n    public void setCheckItem(int position) {\n        checkItemPosition = position;\n        notifyDataSetChanged();\n    }\n\n    public ListDropDownAdapter(Context context, List<String> list) {\n        this.context = context;\n        this.list = list;\n    }\n\n    @Override\n    public int getCount() {\n        return list.size();\n    }\n\n    @Override\n    public Object getItem(int position) {\n        return null;\n    }\n\n    @Override\n    public long getItemId(int position) {\n        return position;\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n        ViewHolder viewHolder;\n        if (convertView != null) {\n            viewHolder = (ViewHolder) convertView.getTag();\n        } else {\n            convertView = LayoutInflater.from(context).inflate(R.layout.item_default_drop_down, null);\n            viewHolder = new ViewHolder(convertView);\n            convertView.setTag(viewHolder);\n        }\n        fillValue(position, viewHolder);\n        return convertView;\n    }\n\n    private void fillValue(int position, ViewHolder viewHolder) {\n        viewHolder.tv_title.setText(list.get(position));\n        if (checkItemPosition != -1) {\n            if (checkItemPosition == position) {\n                viewHolder.tv_title.setTextColor(context.getResources().getColor(R.color.drop_down_selected));\n                viewHolder.tv_title.setBackgroundResource(R.color.check_bg);\n            } else {\n                viewHolder.tv_title.setTextColor(context.getResources().getColor(R.color.drop_down_unselected));\n                viewHolder.tv_title.setBackgroundResource(R.color.white);\n            }\n        }\n    }\n\n    static class ViewHolder {\n        TextView tv_title;\n\n        ViewHolder(View view) {\n            tv_title = (TextView) view.findViewById(R.id.tv_title);\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/LoadMoreAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.graphics.drawable.Drawable;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 加载更多装饰适配器,用于包装普通RecyclerView.Adapter增添一个加载更多功能\n */\npublic class LoadMoreAdapter extends RecyclerView.Adapter {\n\n    /**\n     * 下拉状态 - 无内容。footer位置不做任何显示\n     */\n    public static final int STATUS_NONE = 0;\n\n    /**\n     * 下拉状态 - 有更多。footer位置有progressbar进度框\n     */\n    public static final int STATUS_HAVE_MORE = 1;\n\n    /**\n     * 下拉状态 - 已经加载全部数据。footer位置显示文字\n     */\n    public static final int STATUS_LOADED_ALL = 2;\n\n    /**\n     * 当前状态, 默认为 STATUS_NONE\n     */\n    private int status = STATUS_NONE;\n\n    private int ITEM_VIEW_TYPE_FOOTER = 0x10002;\n\n    /**\n     * 正在加载更多中\n     */\n    private boolean isLoadingMore = false;\n\n    private RecyclerView mRecyclerView;\n    private RecyclerView.Adapter mAdapter;\n    private OnLoadMoreListener mOnLoadMoreListener;\n    private Drawable mLoadMoreProgressDrawable;\n\n    public LoadMoreAdapter(RecyclerView recyclerView,\n                           RecyclerView.Adapter adapter,\n                           OnLoadMoreListener onLoadMoreListener) {\n        // 不设置加载更多progressbar的drawable,使用默认的样式\n        this(recyclerView, adapter, onLoadMoreListener, null);\n    }\n\n    public LoadMoreAdapter(RecyclerView recyclerView,\n                           RecyclerView.Adapter adapter,\n                           OnLoadMoreListener onLoadMoreListener,\n                           Drawable loadMoreProgressDrawable) {\n        mRecyclerView = recyclerView;\n        mAdapter = adapter;\n        mOnLoadMoreListener = onLoadMoreListener;\n        mLoadMoreProgressDrawable = loadMoreProgressDrawable;\n        setScrollListener();\n    }\n\n    public RecyclerView.Adapter getSrcAdapter() {\n        return mAdapter;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        isLoadingMore = false;\n        this.status = status;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        if (position == mAdapter.getItemCount()) {\n            // 最后一个位置是FOOTER\n            return ITEM_VIEW_TYPE_FOOTER;\n        } else {\n            return mAdapter.getItemViewType(position);\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        // 原adapter数量上+1,多了个footer\n        return mAdapter.getItemCount() + 1;\n    }\n\n    public class LoadMoreViewHolder extends RecyclerView.ViewHolder {\n\n        public ProgressBar pb_footer_progress;\n        public TextView tv_footer_progress;\n\n        public LoadMoreViewHolder(View itemView) {\n            super(itemView);\n\n            pb_footer_progress = (ProgressBar) itemView.findViewById(R.id.pb_footer_progress);\n            tv_footer_progress = (TextView) itemView.findViewById(R.id.tv_footer_progress);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        if (viewType == ITEM_VIEW_TYPE_FOOTER) {\n            LayoutInflater inflater = LayoutInflater.from(parent.getContext());\n            View loadMore = inflater.inflate(R.layout.footer_progress, parent, false);\n            LoadMoreViewHolder holder = new LoadMoreViewHolder(loadMore);\n            return holder;\n        } else {\n            return mAdapter.onCreateViewHolder(parent, viewType);\n        }\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {\n        if (holder instanceof LoadMoreViewHolder) {\n            handleFooter((LoadMoreViewHolder) holder);\n        } else {\n            mAdapter.onBindViewHolder(holder, position);\n        }\n    }\n\n    /**\n     * 处理footer的view显示\n     */\n    private void handleFooter(final LoadMoreViewHolder holder) {\n        if (mLoadMoreProgressDrawable != null) {\n            // 设置自定义进度框样式\n            holder.pb_footer_progress.setIndeterminateDrawable(mLoadMoreProgressDrawable);\n        }\n\n        // 设置item占满屏幕宽度, 网格列表类型使用\n        RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();\n        if (layoutManager instanceof StaggeredGridLayoutManager) {\n            StaggeredGridLayoutManager.LayoutParams layoutParams =\n                    (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();\n            layoutParams.setFullSpan(true);\n        } else if (layoutManager instanceof GridLayoutManager) {\n            final GridLayoutManager manager = (GridLayoutManager) layoutManager;\n            manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {\n                @Override\n                public int getSpanSize(int position) {\n                    int spanSize = 1;\n                    if (getItemViewType(position) == ITEM_VIEW_TYPE_FOOTER) {\n                        spanSize = manager.getSpanCount();\n                    }\n                    return spanSize;\n                }\n            });\n        }\n\n        // 根据不同状态显示footer样式\n        switch (status) {\n            case STATUS_HAVE_MORE:\n                holder.itemView.setVisibility(View.VISIBLE);\n\n                holder.tv_footer_progress.setVisibility(View.GONE);\n                holder.pb_footer_progress.setVisibility(View.VISIBLE);\n                break;\n            case STATUS_LOADED_ALL:\n                holder.itemView.setVisibility(View.VISIBLE);\n\n                holder.tv_footer_progress.setVisibility(View.VISIBLE);\n                holder.pb_footer_progress.setVisibility(View.GONE);\n                break;\n            case STATUS_NONE:\n            default:\n                holder.itemView.setVisibility(View.GONE);\n                break;\n        }\n    }\n\n    /**\n     * 设置滚动监听, 判断当列表滚动到底部时, 触发加载更多回调\n     */\n    private void setScrollListener() {\n        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {\n            @Override\n            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {\n                RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();\n                if (layoutManager instanceof StaggeredGridLayoutManager) {\n                    StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;\n                    int pastVisibleItems = -1;\n                    int visibleItemCount = staggeredGridLayoutManager.getChildCount();\n                    int totalItemCount = staggeredGridLayoutManager.getItemCount();\n                    int[] firstVisibleItems = null;\n                    firstVisibleItems = staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);\n                    if (firstVisibleItems != null && firstVisibleItems.length > 0) {\n                        pastVisibleItems = firstVisibleItems[0];\n                    }\n\n                    if (visibleItemCount + pastVisibleItems >= totalItemCount) {\n                        triggerLoadMore();\n                    }\n                } else if (layoutManager instanceof LinearLayoutManager) {\n                    // GridLayoutManager 是 LinearLayoutManager 的子类, 也符合这个条件\n                    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;\n                    int visibleItemCount = linearLayoutManager.getChildCount();\n                    int totalItemCount = linearLayoutManager.getItemCount();\n                    int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();\n\n                    if (visibleItemCount + firstVisibleItemPosition >= totalItemCount) {\n                        triggerLoadMore();\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * 触发加载更多回调\n     */\n    private synchronized void triggerLoadMore() {\n        // 如果是正在加载更多中,不再重复触发\n        if (isLoadingMore) {\n            return;\n        }\n\n        // 如果状态不是STATUS_HAVE_MORE则不触发\n        if (status != STATUS_HAVE_MORE) {\n            return;\n        }\n\n        isLoadingMore = true;\n        mOnLoadMoreListener.onLoadMore();\n        onLoadMore();\n    }\n\n    protected void onLoadMore() {\n        // sub\n    }\n\n    public interface OnLoadMoreListener {\n        void onLoadMore();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/SettingRecyclerAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\n\nimport android.support.v7.widget.RecyclerView;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.SettingItem;\n\nimport java.util.List;\n\n/**\n * 设置选项列表适配器\n * <p>\n * Item通用样式为：左侧图标、中间文字、右侧文字、右侧图标。\n */\npublic class SettingRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {\n\n    private static final int ITEM_VIEW_TYPE_SETTING_ITEM = 0x10001;\n\n    protected List<SettingItem> datas;\n    protected AdapterView.OnItemClickListener mOnItemClickListener;\n\n    public SettingRecyclerAdapter(List<SettingItem> datas, AdapterView.OnItemClickListener listener) {\n        this.datas = datas;\n        mOnItemClickListener = listener;\n    }\n\n    @Override\n    public int getItemCount() {\n        return datas.size();\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return ITEM_VIEW_TYPE_SETTING_ITEM;\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n\n        public ImageView iv_left;\n        public TextView tv_mid;\n        public TextView tv_right;\n        public ImageView iv_right;\n\n        public ViewHolder(final View itemView) {\n            super(itemView);\n\n            iv_left = (ImageView) itemView.findViewById(R.id.iv_left);\n            tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n            tv_right = (TextView) itemView.findViewById(R.id.tv_right);\n            iv_right = (ImageView) itemView.findViewById(R.id.iv_right);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_setting, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {\n        ViewHolder settingViewHolder = (ViewHolder) holder;\n        holder.itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                if (mOnItemClickListener != null) {\n                    mOnItemClickListener.onItemClick(null, view, position, -1);\n                }\n            }\n        });\n        SettingItem data = datas.get(position);\n\n        settingViewHolder.iv_left.setImageResource(data.leftImgRes);\n        if (!TextUtils.isEmpty(data.rightText)) {\n            settingViewHolder.tv_right.setVisibility(View.VISIBLE);\n            settingViewHolder.tv_right.setText(data.rightText);\n        } else {\n            settingViewHolder.tv_right.setVisibility(View.GONE);\n        }\n        settingViewHolder.tv_mid.setText(data.midText);\n\n        if (data.rightImage != -1) {\n            settingViewHolder.iv_right.setVisibility(View.VISIBLE);\n            settingViewHolder.iv_right.setImageResource(data.rightImage);\n        } else {\n            settingViewHolder.iv_right.setVisibility(View.GONE);\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/base/BoreBaseActivity.java",
    "content": "package com.boredream.bdcodehelper.base;\n\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.utils.DialogUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\npublic class BoreBaseActivity extends AppCompatActivity {\n\n    protected String TAG;\n    private Dialog progressDialog;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        init();\n    }\n\n    private void init() {\n        TAG = getClass().getSimpleName();\n        progressDialog = DialogUtils.createProgressDialog(this);\n    }\n\n    /**\n     * 左侧有返回键的标题栏\n     * <p>如果在此基础上还要加其他内容,比如右侧有文字按钮,可以获取该方法返回值继续设置其他内容\n     *\n     * @param title 标题\n     */\n    protected TitleBuilder initBackTitle(String title) {\n        return new TitleBuilder(this)\n                .setTitleText(title)\n                .setLeftImage(R.mipmap.ic_back)\n                .setLeftOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        finish();\n                    }\n                });\n    }\n\n    /**\n     * 跳转页面,无extra简易型\n     *\n     * @param tarActivity 目标页面\n     */\n    public void intent2Activity(Class<? extends Activity> tarActivity) {\n        Intent intent = new Intent(this, tarActivity);\n        startActivity(intent);\n    }\n\n    public void showToast(String msg) {\n        ToastUtils.showToast(this, msg, Toast.LENGTH_SHORT);\n    }\n\n    public void showLog(String msg) {\n        Log.i(TAG, msg);\n    }\n\n    public void showProgressDialog() {\n        progressDialog.show();\n    }\n\n    public void dismissProgressDialog() {\n        progressDialog.dismiss();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/base/BoreBaseEntity.java",
    "content": "package com.boredream.bdcodehelper.base;\n\n\nimport com.boredream.bdcodehelper.entity.Pointer;\n\n/**\n * 数据实体基类\n * <p>\n * 之所以继承Pointer对象,是因为接口用法的限制,具体可以参考Bmob/LeanCloud/Parse的相关文档<br/>\n * 这样的接口可以让对象在提交创建和获取的时候都更加方便<br/>\n * 提交时只要添加Pointer的type和className等所需字段即可,获取时基本不用做任何额外处理\n */\npublic class BoreBaseEntity extends Pointer {\n\n    // 添加新数据时,返回为objectId + createdAt\n    // 更新数据时,返回为updateAt\n\n    private String createdAt;\n    private String updatedAt;\n\n    public String getCreatedAt() {\n        return createdAt;\n    }\n\n    public void setCreatedAt(String createdAt) {\n        this.createdAt = createdAt;\n    }\n\n    public String getUpdatedAt() {\n        return updatedAt;\n    }\n\n    public void setUpdatedAt(String updatedAt) {\n        this.updatedAt = updatedAt;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o instanceof BoreBaseEntity) {\n            BoreBaseEntity oEntity = (BoreBaseEntity) o;\n            return this.objectId.equals(oEntity.objectId);\n        }\n        return super.equals(o);\n    }\n\n    @Override\n    public String toString() {\n        return \"BaseEntity{\" +\n                \"objectId='\" + objectId + '\\'' +\n                \", createdAt='\" + createdAt + '\\'' +\n                \", updatedAt='\" + updatedAt + '\\'' +\n                '}';\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/db/AddressData.java",
    "content": "package com.boredream.bdcodehelper.db;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\n\nimport com.boredream.bdcodehelper.entity.city.CityModel;\nimport com.github.promeg.pinyinhelper.Pinyin;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\n\npublic class AddressData {\n    public static ArrayList<String> mProvinceDatas = new ArrayList<>();\n    public static HashMap<String, ArrayList<CityModel>> mCitisDatasMap = new HashMap<>();\n    public static ArrayList<CityModel> allCities = new ArrayList<>();\n    public static CityModel currentCity;\n\n    public static void init(final Context context) {\n        new Thread() {\n            @Override\n            public void run() {\n                // 初始化，只需要调用一次\n                AssetsDatabaseManager.initManager(context);\n                // 获取管理对象，因为数据库需要通过管理对象才能够获取\n                AssetsDatabaseManager adm = AssetsDatabaseManager.getManager();\n                // 通过管理对象获取数据库\n                SQLiteDatabase sql = adm.getDatabase(\"city\");\n\n                // city\n                Cursor cursorCity = sql.rawQuery(\"select *,* from T_City, T_Province where T_City.ProID = T_Province.ProSort\", null);\n                if (!cursorCity.moveToFirst()) {\n                    return;\n                }\n                do {\n                    String province = cursorCity.getString(cursorCity.getColumnIndex(\"ProName\"));\n\n                    CityModel city = new CityModel();\n                    city.province = province;\n                    city.id = cursorCity.getString(cursorCity.getColumnIndex(\"CitySort\"));\n                    city.name = cursorCity.getString(cursorCity.getColumnIndex(\"CityName\"));\n\n                    if(!city.name.endsWith(\"市\")) {\n                        continue;\n                    }\n\n                    city.name = city.name.substring(0, city.name.length() - 1);\n\n                    StringBuilder sbLetter = new StringBuilder();\n                    for(char c : city.name.toCharArray()) {\n                        String letter;\n                        if(c == '长') {\n                            letter = \"CHANG\";\n                        } else if(c == '重'){\n                            letter = \"CHONG\";\n                        } else if(c == '厦'){\n                            letter = \"XIA\";\n                        } else {\n                            letter = Pinyin.toPinyin(c);\n                        }\n                        sbLetter.append(letter);\n                    }\n                    city.letter = sbLetter.toString();\n\n                    allCities.add(city);\n\n                    if(!mProvinceDatas.contains(province)) {\n                        mProvinceDatas.add(province);\n                    }\n\n                    ArrayList<CityModel> cities = mCitisDatasMap.get(province);\n                    if(cities == null) {\n                        cities = new ArrayList<>();\n                        cities.add(city);\n                        mCitisDatasMap.put(province, cities);\n                    } else {\n                        cities.add(city);\n                    }\n\n                    // 默认城市\n                    if(city.name.equals(\"上海\")) {\n                        currentCity = city;\n                    }\n\n                } while (cursorCity.moveToNext());\n\n                Collections.sort(allCities, new Comparator<CityModel>() {\n                    @Override\n                    public int compare(CityModel cityModel, CityModel t1) {\n                        return cityModel.letter.compareTo(t1.letter);\n                    }\n                });\n            }\n        }.start();\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/db/AssetsDatabaseManager.java",
    "content": "package com.boredream.bdcodehelper.db;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.AssetManager;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * This is a Assets Database Manager\n * Use it, you can use a assets database file in you application\n * It will copy the database file to \"/data/data/[your application package name]/database\" when you first time you use it\n * Then you can get a SQLiteDatabase object by the assets database file\n *\n * How to use:\n * 1. Initialize AssetsDatabaseManager\n * 2. Get AssetsDatabaseManager\n * 3. Get a SQLiteDatabase object through database file\n * 4. Use this database object\n *\n * Using example:\n * AssetsDatabaseManager.initManager(getApplication()); // this method is only need call one time\n * AssetsDatabaseManager mg = AssetsDatabaseManager.getManager();   // get a AssetsDatabaseManager object\n * SQLiteDatabase db1 = mg.getDatabase(\"db1.db\");   // get SQLiteDatabase object, db1.db is a file in assets folder\n * db1.???  // every operate by you want\n * Of cause, you can use AssetsDatabaseManager.getManager().getDatabase(\"xx\") to get a database when you need use a database\n */\npublic class AssetsDatabaseManager {\n    private static String tag = \"AssetsDatabase\"; // for LogCat\n    private static String databasepath = \"/data/data/%s/database\"; // %s is packageName\n\n\n    // A mapping from assets database file to SQLiteDatabase object\n    private Map<String, SQLiteDatabase> databases = new HashMap<String, SQLiteDatabase>();\n\n    // Context of application\n    private Context context = null;\n\n    // Singleton Pattern\n    private static AssetsDatabaseManager mInstance = null;\n\n    /**\n     * Initialize AssetsDatabaseManager\n     * @param context, context of application\n     */\n    public static void initManager(Context context){\n        if(mInstance == null){\n            mInstance = new AssetsDatabaseManager(context);\n        }\n    }\n\n    /**\n     * Get a AssetsDatabaseManager object\n     * @return, if success return a AssetsDatabaseManager object, else return null\n     */\n    public static AssetsDatabaseManager getManager(){\n        return mInstance;\n    }\n\n    private AssetsDatabaseManager(Context context){\n        this.context = context;\n    }\n\n    /**\n     * Get a assets database, if this database is opened this method is only return a copy of the opened database\n     * @param dbfile, the assets file which will be opened for a database\n     * @return, if success it return a SQLiteDatabase object else return null\n     */\n    public SQLiteDatabase getDatabase(String dbfile) {\n        if(databases.get(dbfile) != null){\n            Log.i(tag, String.format(\"Return a database copy of %s\", dbfile));\n            return (SQLiteDatabase) databases.get(dbfile);\n        }\n        if(context==null)\n            return null;\n\n        Log.i(tag, String.format(\"Create database %s\", dbfile));\n        String spath = getDatabaseFilepath();\n        String sfile = getDatabaseFile(dbfile);\n\n        File file = new File(sfile);\n        SharedPreferences dbs = context.getSharedPreferences(AssetsDatabaseManager.class.toString(), 0);\n        boolean flag = dbs.getBoolean(dbfile, false); // Get Database file flag, if true means this database file was copied and valid\n        if(!flag || !file.exists()){\n            file = new File(spath);\n            if(!file.exists() && !file.mkdirs()){\n                Log.i(tag, \"Create \\\"\"+spath+\"\\\" fail!\");\n                return null;\n            }\n            if(!copyAssetsToFilesystem(dbfile, sfile)){\n                Log.i(tag, String.format(\"Copy %s to %s fail!\", dbfile, sfile));\n                return null;\n            }\n\n            dbs.edit().putBoolean(dbfile, true).commit();\n        }\n\n        SQLiteDatabase db = SQLiteDatabase.openDatabase(sfile, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);\n        if(db != null){\n            databases.put(dbfile, db);\n        }\n        return db;\n    }\n\n    private String getDatabaseFilepath(){\n        return String.format(databasepath, context.getApplicationInfo().packageName);\n    }\n\n    private String getDatabaseFile(String dbfile){\n        return getDatabaseFilepath()+\"/\"+dbfile;\n    }\n\n    private boolean copyAssetsToFilesystem(String assetsSrc, String des){\n        Log.i(tag, \"Copy \"+assetsSrc+\" to \"+des);\n        InputStream istream = null;\n        OutputStream ostream = null;\n        try{\n            AssetManager am = context.getAssets();\n            istream = am.open(assetsSrc);\n            ostream = new FileOutputStream(des);\n            byte[] buffer = new byte[1024];\n            int length;\n            while ((length = istream.read(buffer))>0){\n                ostream.write(buffer, 0, length);\n            }\n            istream.close();\n            ostream.close();\n        }\n        catch(Exception e){\n            e.printStackTrace();\n            try{\n                if(istream!=null)\n                    istream.close();\n                if(ostream!=null)\n                    ostream.close();\n            }\n            catch(Exception ee){\n                ee.printStackTrace();\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Close assets database\n     * @param dbfile, the assets file which will be closed soon\n     * @return, the status of this operating\n     */\n    public boolean closeDatabase(String dbfile){\n        if(databases.get(dbfile) != null){\n            SQLiteDatabase db = (SQLiteDatabase) databases.get(dbfile);\n            db.close();\n            databases.remove(dbfile);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Close all assets database\n     */\n    static public void closeAllDatabase(){\n        Log.i(tag, \"closeAllDatabase\");\n        if(mInstance != null){\n            for(int i=0; i<mInstance.databases.size(); ++i){\n                if(mInstance.databases.get(i)!=null){\n                    mInstance.databases.get(i).close();\n                }\n            }\n            mInstance.databases.clear();\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/AppUpdateInfo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class AppUpdateInfo extends BoreBaseEntity {\n    private int version;\n    private String versionName;\n    private String fileUrl;\n    private String updateInfo;\n\n    public int getVersion() {\n        return version;\n    }\n\n    public void setVersion(int version) {\n        this.version = version;\n    }\n\n    public String getVersionName() {\n        return versionName;\n    }\n\n    public void setVersionName(String versionName) {\n        this.versionName = versionName;\n    }\n\n    public String getFileUrl() {\n        return fileUrl;\n    }\n\n    public void setFileUrl(String fileUrl) {\n        this.fileUrl = fileUrl;\n    }\n\n    public String getUpdateInfo() {\n        return updateInfo;\n    }\n\n    public void setUpdateInfo(String updateInfo) {\n        this.updateInfo = updateInfo;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ErrorResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class ErrorResponse {\n\n    private int code;\n    private String error;\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public void setError(String error) {\n        this.error = error;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getError() {\n        return error;\n    }\n\n    @Override\n    public String toString() {\n        return \"ErrorResponse{\" +\n                \"code=\" + code +\n                \", error='\" + error + '\\'' +\n                '}';\n    }\n}\n\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FileInfo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class FileInfo extends BoreBaseEntity {\n    private String cdn;\n    private String fiilename;\n    private String url;\n\n    public String getCdn() {\n        return cdn;\n    }\n\n    public void setCdn(String cdn) {\n        this.cdn = cdn;\n    }\n\n    public String getFiilename() {\n        return fiilename;\n    }\n\n    public void setFiilename(String fiilename) {\n        this.fiilename = fiilename;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FileUploadResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class FileUploadResponse {\n    private String filename;\n    private String group;\n    private String url;\n\n    public void setFilename(String filename) {\n        this.filename = filename;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getFilename() {\n        return filename;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if(o instanceof FileUploadResponse) {\n            return this.url.equals(((FileUploadResponse)o).url);\n        }\n        return super.equals(o);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FormItem.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport android.text.InputType;\n\npublic class FormItem {\n\n    public static final int TYPE_INPUT = 0;\n    public static final int TYPE_SELECT = 1;\n\n    /**\n     * 类型，0-输入，1-选择\n     */\n    public int type;\n\n    /**\n     * 左侧文字\n     */\n    public String leftText;\n\n    /**\n     * 中间文字，hint使用\n     */\n    public String midText;\n\n    /**\n     * 输入框类型\n     */\n    public int inputType;\n\n    /**\n     * 右侧图片id\n     */\n    public int rightImg;\n\n    public FormItem() {\n\n    }\n\n    public static FormItem getInputItem(String leftText, String hint) {\n        return getInputItem(leftText, hint, InputType.TYPE_CLASS_TEXT);\n    }\n\n    public static FormItem getInputItem(String leftText, String hint, int inputType) {\n        FormItem formItem = new FormItem();\n        formItem.type = TYPE_INPUT;\n        formItem.leftText = leftText;\n        formItem.midText = hint;\n        formItem.inputType = inputType;\n        return formItem;\n    }\n\n    public static FormItem getSelectItem(String leftText, int rightImg) {\n        FormItem formItem = new FormItem();\n        formItem.type = TYPE_SELECT;\n        formItem.leftText = leftText;\n        formItem.rightImg = rightImg;\n        return formItem;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ImageUrlInterface.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.io.Serializable;\n\npublic interface ImageUrlInterface extends Serializable {\n    String getImageUrl();\n    String getImageTitle();\n    String getImageLink();\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ListResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.util.ArrayList;\n\npublic class ListResponse<T> {\n    private ArrayList<T> results;\n\n    public ArrayList<T> getResults() {\n        return results;\n    }\n\n    public void setResults(ArrayList<T> results) {\n        this.results = results;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/PageIndex.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\n\nimport java.util.List;\n\n/**\n * 页数索引, 多页加载时使用\n */\npublic class PageIndex {\n\n    /**\n     * 起始页\n     */\n    private int startPage;\n\n    /**\n     * 请求加载的新页数\n     */\n    private int newPage;\n\n    /**\n     * 当前已加载的页数\n     */\n    private int currentPage;\n\n    /**\n     * 每页加载的数量\n     */\n    private int countPerPage;\n\n    public int getStartPage() {\n        return startPage;\n    }\n\n    /**\n     * 页数索引\n     *\n     * @param startPage 起始页, 通常是 0 或 1\n     */\n    public PageIndex(int startPage, int countPerPage) {\n        this.startPage = startPage;\n        this.countPerPage = countPerPage;\n        init();\n    }\n\n    /**\n     * 重置初始化\n     */\n    public void init() {\n        this.currentPage = startPage;\n    }\n\n    /**\n     * 新页数数据获取成功, 将当前页数更新未新页数\n     */\n    private void success() {\n        currentPage = newPage;\n    }\n\n    /**\n     * 起始页\n     *\n     * @return 起始页\n     */\n    public int toStartPage() {\n        newPage = startPage;\n        return newPage;\n    }\n\n    /**\n     * 下一页\n     *\n     * @return 当前页+1作为下一页\n     */\n    public int toNextPage() {\n        newPage = currentPage + 1;\n        return newPage;\n    }\n\n    /**\n     * 数据获取成功, 设置返回结果\n     *\n     * @param adapter\n     * @param currentList 当前已有数据\n     * @param newList     请求获取的新数据\n     * @param <T>\n     */\n    public <T> void setResponse(LoadMoreAdapter adapter, List<T> currentList, List<T> newList) {\n        // 更新当前页数\n        success();\n\n        // 如果当前页为起始页, 则清空数据\n        if (currentPage == startPage) {\n            currentList.clear();\n        }\n\n        if (newList == null) {\n            return;\n        }\n\n        // 添加数据\n        currentList.addAll(newList);\n\n        // 设置是否已加载完全部数据状态\n        adapter.setStatus(newList.size() == countPerPage\n                ? LoadMoreAdapter.STATUS_HAVE_MORE : LoadMoreAdapter.STATUS_LOADED_ALL);\n\n        // 更新UI\n        adapter.notifyDataSetChanged();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Pointer.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.google.gson.Gson;\n\nimport java.io.Serializable;\n\npublic class Pointer implements Serializable {\n    public static final String TYPE = \"Pointer\";\n\n    protected String __type;\n    protected String className;\n    protected String objectId;\n\n    public Pointer() {\n    }\n\n    public Pointer(String className, String objectId) {\n        this.__type = TYPE;\n        this.setClassName(className);\n        this.setObjectId(objectId);\n    }\n\n    public String get__type() {\n        return __type;\n    }\n\n    public void set__type(String __type) {\n        this.__type = __type;\n    }\n\n    public String getClassName() {\n        return this.className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n\n    public String getObjectId() {\n        return this.objectId;\n    }\n\n    public void setObjectId(String objectId) {\n        this.objectId = objectId;\n    }\n\n    /**\n     * 将Pointer转换为所需对象\n     *\n     * @param clazz 转换目标类型\n     * @return 转换后的对象, 转换失败时为null\n     */\n    public <T> T parseToObject(Class<T> clazz) {\n        T t = null;\n        Gson gson = new Gson();\n        try {\n            // 原Pointer对象转为json, 如果用include查询的话, Pointer中除了className还会包含目标对象的数据\n            String json = gson.toJson(this);\n            // 转为目标对象, 多余的className正好通过转换过滤掉\n\n            t = gson.fromJson(json, clazz);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return t;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Relation.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Relation implements Serializable {\n    private String __op = \"AddRelation\";\n    private List<Pointer> objects = new ArrayList();\n\n    public Relation(Pointer pointer) {\n        this.objects.add(pointer);\n    }\n\n    public Relation() {\n    }\n\n    public void add(Pointer pointer) {\n        this.objects.add(pointer);\n    }\n\n    public void remove(Pointer pointer) {\n        this.__op = \"RemoveRelation\";\n        this.objects.add(pointer);\n    }\n\n    public String get__op() {\n        return this.__op;\n    }\n\n    public List<Pointer> getObjects() {\n        return this.objects;\n    }\n\n    public void setObjects(List<Pointer> objects) {\n        this.objects = objects;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/RelationTo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class RelationTo {\n    public static final String OP_RELATEDTO = \"$relatedTo\";\n\n    private String key;\n    private Pointer object;\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public Pointer getObject() {\n        return object;\n    }\n\n    public void setObject(Pointer object) {\n        this.object = object;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/SettingItem.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\n/**\n * 更多item信息\n */\npublic class SettingItem {\n\n    /**\n     * 左侧图片\n     */\n    public int leftImgRes;\n\n    /**\n     * 中间文字\n     */\n    public String midText;\n\n    /**\n     * 右侧文字\n     */\n    public String rightText;\n\n    /**\n     * 右侧图片\n     */\n    public int rightImage;\n\n    public SettingItem() {\n\n    }\n\n    public SettingItem(int leftImgRes, String midText, String rightText, int rightImage) {\n        this.leftImgRes = leftImgRes;\n        this.midText = midText;\n        this.rightText = rightText;\n        this.rightImage = rightImage;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/UpdatePswRequest.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class UpdatePswRequest {\n    private String oldPassword;\n    private String newPassword;\n\n    public String getOldPassword() {\n        return oldPassword;\n    }\n\n    public void setOldPassword(String oldPassword) {\n        this.oldPassword = oldPassword;\n    }\n\n    public String getNewPassword() {\n        return newPassword;\n    }\n\n    public void setNewPassword(String newPassword) {\n        this.newPassword = newPassword;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Where.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.util.Map;\n\npublic class Where {\n    public static final String OP_INQUERY = \"$inQuery\";\n\n    private Map<String, String> where;\n    private String className;\n\n    public Map<String, String> getWhere() {\n        return where;\n    }\n\n    public void setWhere(Map<String, String> where) {\n        this.where = where;\n    }\n\n    public String getClassName() {\n        return className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/city/BaseAddressModel.java",
    "content": "package com.boredream.bdcodehelper.entity.city;\n\nimport java.io.Serializable;\n\npublic class BaseAddressModel implements Serializable {\n    public String id;\n    public String name;\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/city/CityModel.java",
    "content": "package com.boredream.bdcodehelper.entity.city;\n\npublic class CityModel extends BaseAddressModel {\n\tpublic String province;\n\tpublic String letter;\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif(o instanceof CityModel) {\n\t\t\treturn ((CityModel)o).id.equals(this.id);\n\t\t}\n\t\treturn super.equals(o);\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/fragment/FragmentController.java",
    "content": "package com.boredream.bdcodehelper.fragment;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v7.app.AppCompatActivity;\n\nimport java.util.ArrayList;\n\n/**\n * fragment切换控制器, 初始化时直接add全部fragment, 然后利用show和hide进行切换控制\n */\npublic class FragmentController {\n\n    private int containerId;\n    private FragmentManager fm;\n    private ArrayList<Fragment> fragments;\n\n    public FragmentController(AppCompatActivity activity, int containerId, ArrayList<Fragment> fragments) {\n        this.containerId = containerId;\n        this.fragments = fragments;\n        this.fm = activity.getSupportFragmentManager();\n        initFragment();\n    }\n\n    public void initFragment() {\n        FragmentTransaction ft = fm.beginTransaction();\n        for (int i = 0; i < fragments.size(); i++) {\n            ft.add(containerId, fragments.get(i), String.valueOf(i));\n        }\n        ft.commit();\n    }\n\n    public void showFragment(int position) {\n        hideFragments();\n        Fragment fragment = fragments.get(position);\n        FragmentTransaction ft = fm.beginTransaction();\n        ft.show(fragment);\n        ft.commit();\n    }\n\n    public void hideFragments() {\n        FragmentTransaction ft = fm.beginTransaction();\n        for (Fragment fragment : fragments) {\n            if (fragment != null) {\n                ft.hide(fragment);\n            }\n        }\n        ft.commit();\n    }\n\n    public Fragment getFragment(int position) {\n        return fragments.get(position);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/ErrorConstants.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ErrorConstants {\n    public static Map<Integer, String> errors;\n\n    static {\n        errors = new HashMap<>();\n        errors.put(9001, \"Application Id为空，请初始化.\");\n        errors.put(9002, \"解析返回数据出错\");\n        errors.put(9003, \"上传文件出错\");\n        errors.put(9004, \"文件上传失败\");\n        errors.put(9005, \"批量操作只支持最多50条\");\n        errors.put(9006, \"objectId为空\");\n        errors.put(9007, \"文件大小超过10M\");\n        errors.put(9008, \"上传文件不存在\");\n        errors.put(9009, \"没有缓存数据\");\n        errors.put(9010, \"网络超时\");\n        errors.put(9011, \"BmobUser类不支持批量操作\");\n        errors.put(9012, \"上下文为空\");\n        errors.put(9013, \"BmobObject（数据表名称）格式不正确\");\n        errors.put(9014, \"第三方账号授权失败\");\n        errors.put(9015, \"其他错误均返回此code\");\n        errors.put(9016, \"无网络连接，请检查您的手机网络.\");\n        errors.put(9017, \"与第三方登录有关的错误，具体请看对应的错误描述\");\n        errors.put(9018, \"参数不能为空\");\n        errors.put(9019, \"格式不正确：手机号码、邮箱地址、验证码\");\n\n        errors.put(401, \"用户登陆信息失效\");\n        errors.put(500, \"服务器忙，请稍后再试\");\n\n        errors.put(101, \"用户名或密码不正确\");\n        errors.put(102, \"格式不正确\");\n        errors.put(103, \"查询单个对象或更新对象时必须提供objectId 或 非法的 class 名称，class 名称是大小写敏感的，并且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线.\");\n        errors.put(104, \"关联的class名称不存在\");\n        errors.put(105, \"字段名是大小写敏感的，且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线 或 字段名是\");\n        errors.put(106, \"不是一个正确的指针类型\");\n        errors.put(107, \"数据格式不正确\");\n        errors.put(108, \"用户名和密码是必需的\");\n        errors.put(109, \"登录信息是必需的，如邮箱和密码时缺少其中一个提示此信息\");\n        errors.put(111, \"传入的字段值与字段类型不匹配\");\n        errors.put(112, \"请求的值必须是数组\");\n        errors.put(113, \"请求数组中每个元素应该是一个像这样子的json对象\");\n        errors.put(114, \"请求数组大于50\");\n        errors.put(117, \"纬度范围在[-90, 90] 或 经度范围在[-180, 180]\");\n        errors.put(120, \"要使用此功能，请在\");\n        errors.put(131, \"不正确的deviceToken\");\n        errors.put(132, \"不正确的installationId\");\n        errors.put(133, \"不正确的deviceType\");\n        errors.put(134, \"deviceToken已经存在\");\n        errors.put(135, \"installationId已经存在\");\n        errors.put(136, \"只读属性不能修改 或 android设备不需要设置deviceToken\");\n        errors.put(138, \"表是只读的\");\n        errors.put(139, \"角色名称是大小写敏感的，并且必须以英文字母开头，有效的字符仅限在英文字母、数字、空格、横线以及下划线。\");\n        errors.put(141, \"缺失推送需要的data参数\");\n        errors.put(142, \"时间格式应该如下： 2013-12-04 00:51:13\");\n        errors.put(143, \"必须是一个数字\");\n        errors.put(144, \"不能是之前的时间\");\n        errors.put(145, \"文件大小错误\");\n        errors.put(146, \"文件名错误\");\n        errors.put(147, \"文件分页上传偏移量错误\");\n        errors.put(148, \"文件上下文错误\");\n        errors.put(149, \"空文件\");\n        errors.put(150, \"文件上传错误\");\n        errors.put(151, \"文件删除错误\");\n        errors.put(160, \"图片错误\");\n        errors.put(161, \"图片模式错误\");\n        errors.put(162, \"图片宽度错误\");\n        errors.put(163, \"图片高度错误\");\n        errors.put(164, \"图片长边错误\");\n        errors.put(165, \"图片短边错误\");\n        errors.put(201, \"缺失数据\");\n        errors.put(202, \"用户名已经存在\");\n        errors.put(203, \"邮箱已经存在\");\n        errors.put(204, \"必须提供一个邮箱地址\");\n        errors.put(205, \"没有找到此邮件的用户\");\n        errors.put(206, \"登录用户才能修改自己的信息。RestAPI的Http Header中没有提供sessionToken的正确值，不能修改或删除用户\");\n        errors.put(207, \"验证码错误\");\n        errors.put(208, \"authData不正确\");\n        errors.put(209, \"该手机号码已经存在\");\n        errors.put(210, \"密码不正确\");\n        errors.put(211, \"找不到用户\");\n        errors.put(301, \"验证错误详细提示，如邮箱格式不正确\");\n        errors.put(302, \"Bmob后台设置了应用设置值， 如'不允许SDK创建表 '\");\n        errors.put(310, \"云端逻辑运行错误的详细信息\");\n        errors.put(311, \"云端逻辑名称是大小写敏感的，且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线。\");\n        errors.put(401, \"唯一键不能存在重复的值\");\n        errors.put(402, \"查询的wher语句长度大于具体多少个字节\");\n        errors.put(601, \"不正确的BQL查询语句\");\n        errors.put(1002, \"该应用能创建的表数已达到限制\");\n        errors.put(1003, \"该表的行数已达到限制\");\n        errors.put(1004, \"该表的列数已达到限制\");\n        errors.put(1005, \"每月api请求数量已达到限制\");\n        errors.put(1006, \"该应用能创建定时任务数已达到限制\");\n        errors.put(1007, \"该应用能创建云端逻辑数已达到限制\");\n        errors.put(1500, \"你上传的文件大小已超出限制\");\n\n        errors.put(10010, \"该手机号发送短信达到限制(对于一个应用来说，一天给同一手机号发送短信不能超过10条，一小时给同一手机号发送短信不能超过5条，一分钟给同一手机号发送短信不能超过1条)\");\n        errors.put(10011, \"该账户无可用的发送短信条数\");\n        errors.put(10012, \"身份信息必须审核通过才能使用该功能\");\n        errors.put(10013, \"非法短信内容\");\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/GlideCircleTransform.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapShader;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\n\nimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;\nimport com.bumptech.glide.load.resource.bitmap.BitmapTransformation;\n\npublic class GlideCircleTransform extends BitmapTransformation {\n    public GlideCircleTransform(Context context) {\n        super(context);\n    }\n\n    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {\n        return circleCrop(pool, toTransform);\n    }\n\n    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {\n        if (source == null) return null;\n        int size = Math.min(source.getWidth(), source.getHeight());\n        int x = (source.getWidth() - size) / 2;\n        int y = (source.getHeight() - size) / 2;\n        // TODO this could be acquired from the pool too\n        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);\n        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);\n        if (result == null) {\n            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);\n        }\n        Canvas canvas = new Canvas(result);\n        Paint paint = new Paint();\n        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));\n        paint.setAntiAlias(true);\n        float r = size / 2f;\n        canvas.drawCircle(r, r, r, paint);\n        return result;\n    }\n\n    @Override\n    public String getId() {\n        return getClass().getName();\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/MultiPageRequest.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport rx.Observable;\n\npublic abstract class MultiPageRequest<T> {\n\n    public abstract Observable<T> request(int page);\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/ObservableDecorator.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport com.boredream.bdcodehelper.BoreConstants;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\nimport rx.android.schedulers.AndroidSchedulers;\nimport rx.schedulers.Schedulers;\n\n/**\n * 观察者装饰器\n */\npublic class ObservableDecorator {\n\n    public static <T> Observable<T> decorate(Observable<T> observable) {\n        Observable<T> newObservable;\n        if(BoreConstants.isUnitTest) {\n            newObservable = observable.subscribeOn(Schedulers.immediate())\n                    .observeOn(Schedulers.immediate());\n        } else {\n            newObservable = observable.subscribeOn(Schedulers.newThread())\n                    .observeOn(AndroidSchedulers.mainThread())\n                    .delay(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread()); // FIXME 模拟延迟,用于观察加载框等效果\n        }\n        return newObservable;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/RoundedCornersTransformation.java",
    "content": "package com.boredream.bdcodehelper.net;\n\n/**\n * Copyright (C) 2015 Wasabeef\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapShader;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.Transformation;\nimport com.bumptech.glide.load.engine.Resource;\nimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;\nimport com.bumptech.glide.load.resource.bitmap.BitmapResource;\n\npublic class RoundedCornersTransformation implements Transformation<Bitmap> {\n\n  public enum CornerType {\n    ALL,\n    TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,\n    TOP, BOTTOM, LEFT, RIGHT,\n    OTHER_TOP_LEFT, OTHER_TOP_RIGHT, OTHER_BOTTOM_LEFT, OTHER_BOTTOM_RIGHT,\n    DIAGONAL_FROM_TOP_LEFT, DIAGONAL_FROM_TOP_RIGHT\n  }\n\n  private BitmapPool mBitmapPool;\n  private int mRadius;\n  private int mDiameter;\n  private int mMargin;\n  private CornerType mCornerType;\n\n  public RoundedCornersTransformation(Context context, int radius, int margin) {\n    this(context, radius, margin, CornerType.ALL);\n  }\n\n  public RoundedCornersTransformation(BitmapPool pool, int radius, int margin) {\n    this(pool, radius, margin, CornerType.ALL);\n  }\n\n  public RoundedCornersTransformation(Context context, int radius, int margin,\n      CornerType cornerType) {\n    this(Glide.get(context).getBitmapPool(), radius, margin, cornerType);\n  }\n\n  public RoundedCornersTransformation(BitmapPool pool, int radius, int margin,\n      CornerType cornerType) {\n    mBitmapPool = pool;\n    mRadius = radius;\n    mDiameter = mRadius * 2;\n    mMargin = margin;\n    mCornerType = cornerType;\n  }\n\n  @Override\n  public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {\n    Bitmap source = resource.get();\n\n    int width = source.getWidth();\n    int height = source.getHeight();\n\n    Bitmap bitmap = mBitmapPool.get(width, height, Bitmap.Config.ARGB_8888);\n    if (bitmap == null) {\n      bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n    }\n\n    Canvas canvas = new Canvas(bitmap);\n    Paint paint = new Paint();\n    paint.setAntiAlias(true);\n    paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));\n    drawRoundRect(canvas, paint, width, height);\n    return BitmapResource.obtain(bitmap, mBitmapPool);\n  }\n\n  private void drawRoundRect(Canvas canvas, Paint paint, float width, float height) {\n    float right = width - mMargin;\n    float bottom = height - mMargin;\n\n    switch (mCornerType) {\n      case ALL:\n        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);\n        break;\n      case TOP_LEFT:\n        drawTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case TOP_RIGHT:\n        drawTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM_LEFT:\n        drawBottomLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM_RIGHT:\n        drawBottomRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case TOP:\n        drawTopRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM:\n        drawBottomRoundRect(canvas, paint, right, bottom);\n        break;\n      case LEFT:\n        drawLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case RIGHT:\n        drawRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_TOP_LEFT:\n        drawOtherTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_TOP_RIGHT:\n        drawOtherTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_BOTTOM_LEFT:\n        drawOtherBottomLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_BOTTOM_RIGHT:\n        drawOtherBottomRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case DIAGONAL_FROM_TOP_LEFT:\n        drawDiagonalFromTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case DIAGONAL_FROM_TOP_RIGHT:\n        drawDiagonalFromTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      default:\n        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);\n        break;\n    }\n  }\n\n  private void drawTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, mMargin + mRadius, bottom), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n    canvas.drawRect(new RectF(right - mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom - mRadius), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawBottomRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n    canvas.drawRect(new RectF(right - mRadius, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawTopRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawBottomRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n  }\n\n  private void drawOtherTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);\n  }\n\n  private void drawOtherTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawOtherBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mRadius, bottom), paint);\n  }\n\n  private void drawOtherBottomRightRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawDiagonalFromTopLeftRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),\n        mRadius, mRadius, paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mDiameter, bottom), paint);\n    canvas.drawRect(new RectF(mMargin + mDiameter, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawDiagonalFromTopRightRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,\n        mRadius, paint);\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  @Override public String getId() {\n    return \"RoundedTransformation(radius=\" + mRadius + \", margin=\" + mMargin + \", diameter=\"\n        + mDiameter + \", cornerType=\" + mCornerType.name() + \")\";\n  }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/FormItemsPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.FormItem;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class FormItemsPresent {\n\n    public interface OnSelectItemClickListener {\n        void onSelectItemClick(String leftText);\n    }\n\n    private Context context;\n    private LinearLayout ll_container;\n    private List<FormItem> items;\n\n    public FormItemsPresent(LinearLayout ll_container) {\n        this.context = ll_container.getContext();\n        this.ll_container = ll_container;\n    }\n\n    public void load(List<FormItem> items, Integer[] emptyIndexs,\n                     final OnSelectItemClickListener listener) {\n        this.items = items;\n        List<Integer> emptyIndexList = Arrays.asList(emptyIndexs);\n\n        for (int i = 0; i < items.size(); i++) {\n            final FormItem formItem = items.get(i);\n\n            // item\n            View itemView;\n            if (formItem.type == FormItem.TYPE_INPUT) {\n                // input\n                itemView = View.inflate(context, R.layout.formitem_input, null);\n                EditText tv_mid = (EditText) itemView.findViewById(R.id.tv_mid);\n                tv_mid.setInputType(formItem.inputType);\n                tv_mid.setHint(formItem.midText);\n            } else {\n                // select\n                itemView = View.inflate(context, R.layout.formitem_select, null);\n\n                ImageView iv_right = (ImageView) itemView.findViewById(R.id.iv_right);\n                if (formItem.rightImg != -1) {\n                    iv_right.setImageResource(formItem.rightImg);\n                }\n\n                itemView.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        if (listener != null) {\n                            listener.onSelectItemClick(formItem.leftText);\n                        }\n                    }\n                });\n            }\n            TextView tv_left = (TextView) itemView.findViewById(R.id.tv_left);\n            tv_left.setText(formItem.leftText);\n            itemView.setTag(formItem.leftText);\n            ll_container.addView(itemView);\n\n            // divider\n            View dividerView;\n            if (emptyIndexList.contains(i)) {\n                dividerView = View.inflate(context, R.layout.include_group_divider, null);\n            } else {\n                dividerView = new View(context);\n                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(\n                        LinearLayout.LayoutParams.MATCH_PARENT, 1);\n                dividerView.setLayoutParams(params);\n                dividerView.setBackgroundResource(R.color.divider_gray);\n            }\n            ll_container.addView(dividerView);\n        }\n    }\n\n    public ViewGroup getItemView(String leftText) {\n        ViewGroup itemView = (ViewGroup) ll_container.findViewWithTag(leftText);\n        return itemView;\n    }\n\n    public String getString(String leftText) {\n        ViewGroup itemView = getItemView(leftText);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        return tv_mid.getText().toString().trim();\n    }\n\n    public LinearLayout showMidContainer(String leftText) {\n        ViewGroup itemView = getItemView(leftText);\n        LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        ll_mid_container.setVisibility(View.VISIBLE);\n        tv_mid.setVisibility(View.GONE);\n        return ll_mid_container;\n    }\n\n    public TextView showMidText(String leftText, String midText) {\n        ViewGroup itemView = getItemView(leftText);\n        LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        ll_mid_container.setVisibility(View.GONE);\n        tv_mid.setVisibility(View.VISIBLE);\n        tv_mid.setText(midText);\n        return tv_mid;\n    }\n\n    public boolean validate() {\n        for (FormItem item : items) {\n            ViewGroup itemView = getItemView(item.leftText);\n            if (item.type == FormItem.TYPE_INPUT) {\n                // input\n                EditText tv_mid = (EditText) itemView.findViewById(R.id.tv_mid);\n                if (TextUtils.isEmpty(tv_mid.getText().toString().trim())) {\n                    ToastUtils.showToast(context, tv_mid.getHint());\n                    return false;\n                }\n            } else {\n                // select\n                TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n                LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n                if (tv_mid.getVisibility() == View.VISIBLE) {\n                    if (TextUtils.isEmpty(tv_mid.getText().toString().trim())) {\n                        ToastUtils.showToast(context, \"请选择\" + item.leftText);\n                        return false;\n                    }\n                } else {\n                    if (ll_mid_container.getChildCount() == 0) {\n                        ToastUtils.showToast(context, \"请选择\" + item.leftText);\n                        return false;\n                    }\n                }\n            }\n        }\n        return true;\n\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/GroupEtEmptyCheckPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.widget.EditText;\n\npublic class GroupEtEmptyCheckPresent {\n\n    private EditText[] ets;\n\n    public interface OnEtEmptyListener {\n        void onEtEmpty(boolean hasOneEmpty);\n    }\n\n    public GroupEtEmptyCheckPresent(EditText... ets) {\n        this.ets = ets;\n    }\n\n    public void check(final OnEtEmptyListener listener) {\n        for(EditText et : ets) {\n            et.addTextChangedListener(new TextWatcher() {\n                @Override\n                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {\n\n                }\n\n                @Override\n                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {\n                    checkAllEt(listener, ets);\n                }\n\n                @Override\n                public void afterTextChanged(Editable editable) {\n\n                }\n            });\n        }\n    }\n\n    private void checkAllEt(OnEtEmptyListener listener, EditText[] ets) {\n        boolean hasEmpty = false;\n\n        for(EditText et : ets) {\n            String s = et.getText().toString().trim();\n            if(TextUtils.isEmpty(s)) {\n                hasEmpty = true;\n                break;\n            }\n         }\n\n        listener.onEtEmpty(hasEmpty);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/ImageBannerPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.content.Context;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.CountDownTimer;\nimport android.support.v4.view.ViewPager;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.BannerPagerAdapter;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\n\nimport java.util.ArrayList;\n\npublic class ImageBannerPresent {\n\n    private static final int AUTO_SCROLL_GAP_TIME = 4000;\n    private static final int STATE_STOP = 0;\n    private static final int STATE_AUTO_SCROLLING = 1;\n    private int currentState;\n\n    private Context context;\n    private final CountDownTimer countDownTimer;\n\n    private ArrayList<? extends ImageUrlInterface> images;\n    private ViewPager vp_banner;\n\n    private RadioGroup rg_indicator;\n    private BannerPagerAdapter adapter;\n\n    public ImageBannerPresent(Context context, View include_banner_with_indicator) {\n        this.context = context;\n\n        vp_banner = (ViewPager) include_banner_with_indicator.findViewById(R.id.vp_banner);\n        rg_indicator = (RadioGroup) include_banner_with_indicator.findViewById(R.id.rg_indicator);\n\n        vp_banner.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\n            @Override\n            public void onPageScrollStateChanged(int state) {\n                // FIXME\n//                if (state == ViewPager.SCROLL_STATE_DRAGGING) {\n//                    stopAutoScroll();\n//                } else {\n//                    startAutoScroll();\n//                }\n            }\n        });\n\n        countDownTimer = new CountDownTimer(\n                Long.MAX_VALUE, AUTO_SCROLL_GAP_TIME) {\n            @Override\n            public void onTick(long l) {\n                vp_banner.setCurrentItem(vp_banner.getCurrentItem() + 1);\n            }\n\n            @Override\n            public void onFinish() {\n\n            }\n        };\n    }\n\n    public void load(ArrayList<? extends ImageUrlInterface> images) {\n        this.images = images;\n\n        adapter = new BannerPagerAdapter(context, images);\n        vp_banner.setAdapter(adapter);\n\n        setIndicator();\n        startAutoScroll();\n    }\n\n    public void startAutoScroll() {\n        if (currentState == STATE_AUTO_SCROLLING) {\n            return;\n        }\n\n        currentState = STATE_AUTO_SCROLLING;\n        countDownTimer.start();\n    }\n\n    public void stopAutoScroll() {\n        currentState = STATE_STOP;\n        countDownTimer.cancel();\n    }\n\n    private void setIndicator() {\n        if (images.size() <= 1) {\n            rg_indicator.setVisibility(View.GONE);\n            return;\n        }\n\n        rg_indicator.setVisibility(View.VISIBLE);\n\n        vp_banner.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n            @Override\n            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {\n\n            }\n\n            @Override\n            public void onPageSelected(int position) {\n                if (rg_indicator.getChildCount() > 1) {\n                    ((RadioButton) rg_indicator.getChildAt(position % images.size())).setChecked(true);\n                }\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int state) {\n\n            }\n        });\n\n        rg_indicator.removeAllViews();\n        for (int i = 0; i < images.size(); i++) {\n            RadioButton rb = new RadioButton(context);\n            RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(\n                    DisplayUtils.dp2px(context, 8), DisplayUtils.dp2px(context, 8));\n            if (i > 0) {\n                params.setMargins(DisplayUtils.dp2px(context, 8), 0, 0, 0);\n            }\n            rb.setLayoutParams(params);\n            rb.setButtonDrawable(new ColorDrawable());\n            rb.setBackgroundResource(R.drawable.shape_oval_primary2white_sel);\n            rb.setOnTouchListener(new View.OnTouchListener() {\n                @Override\n                public boolean onTouch(View view, MotionEvent motionEvent) {\n                    // do nothing\n                    return true;\n                }\n            });\n            rg_indicator.addView(rb);\n        }\n\n        ((RadioButton) rg_indicator.getChildAt(0)).setChecked(true);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/ImageBrowserPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.app.Activity;\nimport android.support.v4.view.ViewPager;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.adapter.ImageBrowserAdapter;\n\nimport java.util.ArrayList;\n\npublic class ImageBrowserPresent {\n    private Activity activity;\n    private ViewPager vp_image_brower;\n    private TextView tv_image_index;\n\n    private int position;\n    private ImageBrowserAdapter adapter;\n    private ArrayList<String> images;\n\n    public ImageBrowserPresent(Activity activity, ImageBrowserAdapter adapter,\n                               ViewPager vp_image_brower, TextView tv_image_index) {\n        this.activity = activity;\n        this.adapter = adapter;\n        this.vp_image_brower = vp_image_brower;\n        this.tv_image_index = tv_image_index;\n    }\n\n    public void init() {\n        initData();\n        setData();\n    }\n\n    private void initData() {\n        images = (ArrayList<String>) activity.getIntent().getSerializableExtra(\"images\");\n        position = activity.getIntent().getIntExtra(\"position\", 0);\n    }\n\n    private void setData() {\n        vp_image_brower.setAdapter(adapter);\n\n        final int size = images.size();\n        int initPosition = position;\n\n        if (size > 1) {\n            tv_image_index.setVisibility(View.VISIBLE);\n            tv_image_index.setText((position + 1) + \"/\" + size);\n        } else {\n            tv_image_index.setVisibility(View.GONE);\n        }\n\n        vp_image_brower.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n\n            @Override\n            public void onPageSelected(int arg0) {\n                int index = arg0 % size;\n                tv_image_index.setText((index + 1) + \"/\" + size);\n            }\n\n            @Override\n            public void onPageScrolled(int arg0, float arg1, int arg2) {\n\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int arg0) {\n\n            }\n        });\n\n        vp_image_brower.setCurrentItem(initPosition);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/MultiPageLoadPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.app.Activity;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.View;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.entity.PageIndex;\nimport com.boredream.bdcodehelper.net.MultiPageRequest;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\n\nimport java.util.ArrayList;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\n\npublic class MultiPageLoadPresent {\n\n    private Activity activity;\n    private LoadMoreAdapter loadMoreAdapter;\n\n    private SwipeRefreshLayout srl;\n    private RecyclerView rv;\n    private RecyclerView.ItemDecoration itemDecoration;\n\n    public RecyclerView getRv() {\n        return rv;\n    }\n\n    public MultiPageLoadPresent(Activity activity, View include_refresh_list, PageIndex pageIndex) {\n        this.activity = activity;\n        this.srl = (SwipeRefreshLayout) include_refresh_list;\n        this.pageIndex = pageIndex;\n        initView();\n    }\n\n    private void initView() {\n        srl.setColorSchemeColors(activity.getResources().getColor(R.color.colorPrimary));\n        rv = (RecyclerView) srl.findViewById(R.id.rv);\n\n        LinearLayoutManager layoutManager = new LinearLayoutManager(\n                activity, StaggeredGridLayoutManager.VERTICAL, false);\n        rv.setLayoutManager(layoutManager);\n        itemDecoration = new DividerItemDecoration(activity);\n        rv.addItemDecoration(itemDecoration);\n    }\n\n    public void setItemDecoration(RecyclerView.ItemDecoration itemDecoration) {\n        rv.removeItemDecoration(this.itemDecoration);\n        this.itemDecoration = itemDecoration;\n        if (this.itemDecoration != null) {\n            rv.addItemDecoration(this.itemDecoration);\n        }\n    }\n\n    private ArrayList datas;\n    private PageIndex pageIndex;\n    private MultiPageRequest request;\n    private Subscriber subscriber;\n\n    public void setDatas(ArrayList datas) {\n        this.datas = datas;\n        rv.post(new Runnable() {\n            @Override\n            public void run() {\n                loadMoreAdapter.notifyDataSetChanged();\n            }\n        });\n    }\n\n    public <T> Subscription load(RecyclerView.Adapter adapter,\n                                 ArrayList datas,\n                                 MultiPageRequest<T> request,\n                                 Subscriber<T> subscriber) {\n        this.datas = datas;\n        this.request = request;\n        this.subscriber = subscriber;\n\n        loadMoreAdapter = new LoadMoreAdapter(rv, adapter,\n                new LoadMoreAdapter.OnLoadMoreListener() {\n                    @Override\n                    public void onLoadMore() {\n                        // 列表拉到底部时,加载下一页\n                        loadData(pageIndex.toNextPage());\n                    }\n                });\n        rv.setAdapter(loadMoreAdapter);\n        srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {\n            @Override\n            public void onRefresh() {\n                // 下拉刷新时,重新加载起始页\n                loadData(pageIndex.toStartPage());\n            }\n        });\n\n        return loadData(this.pageIndex.toStartPage());\n    }\n\n    public void setStatus(int status) {\n        if(loadMoreAdapter != null) {\n            loadMoreAdapter.setStatus(status);\n        }\n    }\n\n    public void notifyDataSetChanged() {\n        if(loadMoreAdapter != null) {\n            loadMoreAdapter.notifyDataSetChanged();\n        }\n    }\n\n    public void initPage() {\n        pageIndex.init();\n    }\n\n    public boolean isRefreshing() {\n        return srl.isRefreshing();\n    }\n\n    public void setRefreshing(final boolean refreshing) {\n        srl.post(new Runnable() {\n            @Override\n            public void run() {\n                srl.setRefreshing(refreshing);\n            }\n        });\n    }\n\n    /**\n     * 加载列表\n     *\n     * @param page 页数\n     */\n    private Subscription loadData(final int page) {\n        Observable observable = this.request.request(page);\n        return ObservableDecorator.decorate(observable).subscribe(\n                new Subscriber<ListResponse>() {\n                    @Override\n                    public void onNext(ListResponse response) {\n                        if (subscriber != null) {\n                            subscriber.onNext(response);\n                        }\n                        setRefreshing(false);\n\n                        // 加载成功后更新数据\n                        pageIndex.setResponse(loadMoreAdapter, datas, response.getResults());\n                    }\n\n                    @Override\n                    public void onCompleted() {\n                        if (subscriber != null) {\n                            subscriber.onCompleted();\n                        }\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        if (subscriber != null) {\n                            subscriber.onError(throwable);\n                        }\n                        setRefreshing(false);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ActivityUtils.java",
    "content": "/*\n * Copyright 2016, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.utils;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\n\n/**\n * This provides methods to help Activities load their UI.\n */\npublic class ActivityUtils {\n\n    /**\n     * The {@code fragment} is added to the container view with id {@code frameId}. The operation is\n     * performed by the {@code fragmentManager}.\n     */\n    public static void addFragmentToActivity(FragmentManager fragmentManager,\n                                             Fragment fragment, int frameId) {\n        FragmentTransaction transaction = fragmentManager.beginTransaction();\n        transaction.add(frameId, fragment);\n        transaction.commit();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/AppUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.telephony.TelephonyManager;\nimport android.util.Log;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\n\nimport java.io.File;\n\npublic class AppUtils {\n\n    /**\n     * 获取版本名称\n     */\n    public static String getAppVersionName(Context context) {\n        String versionName = \"\";\n        try {\n            // ---get the package info---\n            PackageManager pm = context.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);\n            versionName = pi.versionName;\n            if (versionName == null || versionName.length() <= 0) {\n                return \"\";\n            }\n        } catch (Exception e) {\n            Log.e(\"VersionInfo\", \"Exception\", e);\n        }\n        return versionName;\n    }\n\n    /**\n     * 获取版本号\n     */\n    public static int getAppVersionCode(Context context) {\n        int versioncode = -1;\n        try {\n            // ---get the package info---\n            PackageManager pm = context.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);\n            versioncode = pi.versionCode;\n        } catch (Exception e) {\n            Log.e(\"VersionInfo\", \"Exception\", e);\n        }\n        return versioncode;\n    }\n\n    public static String getIMEI(Context context) {\n        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);\n        return tm.getDeviceId();\n    }\n\n    /**\n     * 显示软键盘\n     */\n    public static void openSoftInput(EditText et) {\n        InputMethodManager inputMethodManager = (InputMethodManager) et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.showSoftInput(et, InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    /**\n     * 隐藏软键盘\n     */\n    public static void hideSoftInput(EditText et) {\n        InputMethodManager inputMethodManager = (InputMethodManager) et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.hideSoftInputFromWindow(et.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    /**\n     * 获取SD卡路径\n     *\n     * @return 如果sd卡不存在则返回null\n     */\n    public static File getSDPath() {\n        File sdDir = null;\n        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);   //判断sd卡是否存在\n        if (sdCardExist) {\n            sdDir = Environment.getExternalStorageDirectory();//获取跟目录\n        }\n        return sdDir;\n    }\n\n    /**\n     * 安装文件\n     *\n     * @param data\n     */\n    public static void promptInstall(Context context, Uri data) {\n        Intent promptInstall = new Intent(Intent.ACTION_VIEW)\n                .setDataAndType(data, \"application/vnd.android.package-archive\");\n        // FLAG_ACTIVITY_NEW_TASK 可以保证安装成功时可以正常打开 app\n        promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(promptInstall);\n    }\n\n    public static void copy2clipboard(Context context, String text){\n        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);\n        ClipData clip = ClipData.newPlainText(\"clip\", text);\n        cm.setPrimaryClip(clip);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DateUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.text.TextUtils;\nimport android.text.format.DateFormat;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * 日期时间工具类\n */\npublic class DateUtils {\n\n    public static final long ONE_SECOND_MILLIONS = 1000;\n    public static final long ONE_MINUTE_MILLIONS = 60 * ONE_SECOND_MILLIONS;\n    public static final long ONE_HOUR_MILLIONS = 60 * ONE_MINUTE_MILLIONS;\n    public static final long ONE_DAY_MILLIONS = 24 * ONE_HOUR_MILLIONS;\n    public static final int DAY_OF_YEAR = 365;\n\n    // 日期格式为 2016-02-03 17:04:58\n    public static final String PATTERN_DATE = \"yyyy年MM月dd日\";\n    public static final String PATTERN_TIME = \"HH:mm:ss\";\n    public static final String PATTERN_SPLIT = \" \";\n    public static final String PATTERN = PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME;\n\n    public static String getShortTime(String dateStr) {\n        String str;\n\n        Date date = str2date(dateStr);\n        Date curDate = new Date();\n\n        long durTime = curDate.getTime() - date.getTime();\n        int dayDiff = calculateDayDiff(date, curDate);\n\n        if (durTime <= 10 * ONE_MINUTE_MILLIONS) {\n            str = \"刚刚\";\n        } else if (durTime < ONE_HOUR_MILLIONS) {\n            str = durTime / ONE_MINUTE_MILLIONS + \"分钟前\";\n        } else if (dayDiff == 0) {\n            str = durTime / ONE_HOUR_MILLIONS + \"小时前\";\n        } else if (dayDiff == -1) {\n            str = \"昨天\" + DateFormat.format(\"HH:mm\", date);\n        } else if (isSameYear(date, curDate) && dayDiff < -1) {\n            str = DateFormat.format(\"MM-dd\", date).toString();\n        } else {\n            str = DateFormat.format(\"yyyy-MM\", date).toString();\n        }\n\n        return str;\n    }\n\n    /**\n     * 获取日期 PATTERN_DATE 部分\n     */\n    public static String getDate(String date) {\n        if (TextUtils.isEmpty(date) || !date.contains(PATTERN_SPLIT)) {\n            return \"\";\n        }\n        return date.split(PATTERN_SPLIT)[0];\n    }\n\n    /**\n     * 原有日期上累加月\n     *\n     * @return 累加后的日期 PATTERN_DATE 部分\n     */\n    public static String addMonth(String date, int moonCount) {\n        //如果date为空 就用当前时间\n        if (TextUtils.isEmpty(date)) {\n            SimpleDateFormat df = new SimpleDateFormat(PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME);\n            date = df.format(new Date());\n        }\n        Calendar calendar = str2calendar(date);\n        calendar.add(Calendar.MONTH, moonCount);\n        return getDate(calendar2str(calendar));\n    }\n\n    /**\n     * 计算天数差\n     */\n    public static int calculateDayDiff(Date targetTime, Date compareTime) {\n        boolean sameYear = isSameYear(targetTime, compareTime);\n        if (sameYear) {\n            return calculateDayDiffOfSameYear(targetTime, compareTime);\n        } else {\n            int dayDiff = 0;\n\n            // 累计年数差的整年天数\n            int yearDiff = calculateYearDiff(targetTime, compareTime);\n            dayDiff += yearDiff * DAY_OF_YEAR;\n\n            // 累计同一年内的天数\n            dayDiff += calculateDayDiffOfSameYear(targetTime, compareTime);\n\n            return dayDiff;\n        }\n    }\n\n    /**\n     * 计算同一年内的天数差\n     */\n    public static int calculateDayDiffOfSameYear(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return 0;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarDayOfYear = tarCalendar.get(Calendar.DAY_OF_YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comDayOfYear = compareCalendar.get(Calendar.DAY_OF_YEAR);\n\n        return tarDayOfYear - comDayOfYear;\n    }\n\n    /**\n     * 计算年数差\n     */\n    public static int calculateYearDiff(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return 0;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n\n        return tarYear - comYear;\n    }\n\n    /**\n     * 计算月数差\n     *\n     * @param targetTime\n     * @param compareTime\n     * @return\n     */\n    public static int calculateMonthDiff(String targetTime, String compareTime) {\n        return calculateMonthDiff(str2date(targetTime, PATTERN_DATE),\n                str2date(compareTime, PATTERN_DATE));\n    }\n\n    /**\n     * 计算月数差\n     *\n     * @param targetTime\n     * @param compareTime\n     * @return\n     */\n    public static int calculateMonthDiff(Date targetTime, Date compareTime) {\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n        int tarMonth = tarCalendar.get(Calendar.MONTH);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n        int comMonth = compareCalendar.get(Calendar.MONTH);\n        return ((tarYear - comYear) * 12 + tarMonth - comMonth);\n\n    }\n\n    /**\n     * 是否为同一年\n     */\n    public static boolean isSameYear(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return false;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n\n        return tarYear == comYear;\n    }\n\n    public static Date str2date(String str, String format) {\n        Date date = null;\n        try {\n            if (str != null) {\n                SimpleDateFormat sdf = new SimpleDateFormat(format);\n                date = sdf.parse(str);\n            }\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        return date;\n    }\n\n    public static Date str2date(String str) {\n        return str2date(str, PATTERN);\n    }\n\n    public static String date2str(Date date) {\n        return date2str(date, PATTERN);\n    }\n\n    public static String date2str(Date date, String format) {\n        SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.CHINA);\n        return sdf.format(date);\n    }\n\n    public static Calendar str2calendar(String str) {\n        Calendar calendar = null;\n        Date date = str2date(str);\n        if (date != null) {\n            calendar = Calendar.getInstance();\n            calendar.setTime(date);\n        }\n        return calendar;\n    }\n\n\n    public static Calendar str2calendar(String str, String format) {\n        Calendar calendar = null;\n        Date date = str2date(str, format);\n        if (date != null) {\n            calendar = Calendar.getInstance();\n            calendar.setTime(date);\n        }\n        return calendar;\n    }\n\n    public static String calendar2str(Calendar calendar) {\n        return date2str(calendar.getTime());\n    }\n\n    public static String calendar2str(Calendar calendar, String format) {\n        return date2str(calendar.getTime(), format);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DialogUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.support.v7.app.AlertDialog;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 对话框工具类, 提供常用对话框显示, 使用support.v7包内的AlertDialog样式\n */\npublic class DialogUtils {\n\n    public static Dialog createProgressDialog(Context context) {\n        return createProgressDialog(context, true);\n    }\n\n    public static Dialog createProgressDialog(Context context, boolean needCancle) {\n        ProgressDialog dialog = new ProgressDialog(context);\n        dialog.setMessage(\"Loading ...\");\n        dialog.setCancelable(needCancle);\n        dialog.setCanceledOnTouchOutside(false);\n        return dialog;\n    }\n\n    public static Dialog showCommonDialog(Context context, String message,\n                                          DialogInterface.OnClickListener listener) {\n        return new AlertDialog.Builder(context)\n                .setMessage(message)\n                .setPositiveButton(context.getString(R.string.dialog_positive), listener)\n                .setNegativeButton(context.getString(R.string.dialog_negative), null)\n                .show();\n    }\n\n    public static Dialog showConfirmDialog(Context context, String message,\n                                           DialogInterface.OnClickListener listener) {\n        return new AlertDialog.Builder(context)\n                .setMessage(message)\n                .setPositiveButton(context.getString(R.string.dialog_positive), listener)\n                .show();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DisplayUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.util.DisplayMetrics;\n\npublic class DisplayUtils {\n\t/**\n\t * 将px值转换为dp值\n\t */\n\tpublic static int px2dp(Context context, float pxValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().density;\n\t\treturn (int) (pxValue / scale + 0.5f);\n\t}\n\n\t/**\n\t * 将dp值转换为px值\n\t */\n\tpublic static int dp2px(Context context, float dpValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().density;\n\t\treturn (int) (dpValue * scale + 0.5f);\n\t}\n\n\t/**\n\t * 将px值转换为sp值\n\t */\n\tpublic static int px2sp(Context context, float pxValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().scaledDensity;\n\t\treturn (int) (pxValue / scale + 0.5f);\n\t}\n\n\t/**\n\t * 将sp值转换为px值\n\t */\n\tpublic static int sp2px(Context context, float dpValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().scaledDensity;\n\t\treturn (int) (dpValue * scale + 0.5f);\n\t}\n\n\t/**\n\t * 获取屏幕宽度\n\t */\n\tpublic static int getScreenWidthPixels(Activity context) {\n\t\tDisplayMetrics metric = new DisplayMetrics();\n\t\tcontext.getWindowManager().getDefaultDisplay().getMetrics(metric);\n\t\treturn metric.widthPixels;\n\t}\n\n\t/**\n\t * 获取屏幕高度\n\t */\n\tpublic static int getScreenHeightPixels(Activity context) {\n\t\tDisplayMetrics metric = new DisplayMetrics();\n\t\tcontext.getWindowManager().getDefaultDisplay().getMetrics(metric);\n\t\treturn metric.heightPixels;\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ErrorInfoUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport com.boredream.bdcodehelper.entity.ErrorResponse;\nimport com.boredream.bdcodehelper.net.ErrorConstants;\nimport com.google.gson.Gson;\nimport com.squareup.okhttp.MediaType;\nimport com.squareup.okhttp.ResponseBody;\n\nimport java.net.UnknownHostException;\n\nimport retrofit.HttpException;\n\npublic class ErrorInfoUtils {\n\n    /**\n     * 解析服务器错误信息\n     */\n    public static String parseHttpErrorInfo(Throwable throwable) {\n        String errorInfo = throwable.getMessage();\n\n        if (throwable instanceof HttpException) {\n            // 如果是Retrofit的Http错误,则转换类型,获取信息\n            HttpException exception = (HttpException) throwable;\n            ResponseBody responseBody = exception.response().errorBody();\n            MediaType type = responseBody.contentType();\n\n            // 如果是application/json类型数据,则解析返回内容\n            if (type.type().equals(\"application\") && type.subtype().equals(\"json\")) {\n                try {\n                    // 这里的返回内容是Bmob/AVOS/Parse等RestFul API文档中的错误代码和错误信息对象\n                    ErrorResponse errorResponse = new Gson().fromJson(\n                            responseBody.string(), ErrorResponse.class);\n\n                    errorInfo = getLocalErrorInfo(errorResponse);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        } else {\n            if (throwable instanceof UnknownHostException) {\n                errorInfo = \"无法连接到服务器\";\n            }\n        }\n\n        return errorInfo;\n    }\n\n    /**\n     * 获取本地预设错误信息\n     */\n    private static String getLocalErrorInfo(ErrorResponse error) {\n        String s = ErrorConstants.errors.get(error.getCode());\n        if (StringUtils.isEmpty(s)) {\n            return error.getError();\n        } else {\n            return s;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ImageUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.provider.DocumentsContract;\nimport android.provider.MediaStore;\nimport android.support.v7.app.AlertDialog;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.request.FutureTarget;\n\nimport rx.Observable;\nimport rx.functions.Func1;\n\n/**\n * 图片工具类\n */\npublic class ImageUtils {\n\n    /**\n     * 拍照\n     */\n    public static final int REQUEST_CODE_FROM_CAMERA = 1 << 10;\n\n    /**\n     * 相册\n     */\n    public static final int REQUEST_CODE_FROM_ALBUM = 1 << 12;\n\n    /**\n     * 裁剪\n     */\n    public static final int REQUEST_CODE_CROP_IMAGE = 1 << 14;\n\n    /**\n     * 存放拍照图片的uri地址\n     */\n    public static Uri imageUriFromCamera;\n\n    /**\n     * 存放裁剪图片的uri地址\n     */\n    public static Uri cropImageUri;\n\n    /**\n     * 显示获取照片不同方式对话框\n     */\n    public static void showImagePickDialog(final Activity activity) {\n        showImagePickDialog(activity, 0);\n    }\n\n    /**\n     * 显示获取照片不同方式对话框\n     */\n    public static void showImagePickDialog(final Activity activity, final int addRequest) {\n        String title = \"选择获取图片方式\";\n        String[] items = new String[]{\"拍照\", \"相册\"};\n        new AlertDialog.Builder(activity)\n                .setTitle(title)\n                .setItems(items, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                        switch (which) {\n                            case 0:\n                                pickImageFromCamera(activity, addRequest);\n                                break;\n                            case 1:\n                                pickImageFromAlbum(activity, addRequest);\n                                break;\n                            default:\n                                break;\n                        }\n                    }\n                })\n                .setNegativeButton(\"取消\", null)\n                .show();\n    }\n\n    /**\n     * 打开相机拍照获取图片\n     */\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public static void pickImageFromCamera(final Activity activity, int addRequest) {\n        // 先生成一个uri地址用于存放拍照获取的图片\n        imageUriFromCamera = createImageUri(activity);\n\n        Intent intent = new Intent();\n        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUriFromCamera);\n        activity.startActivityForResult(intent, REQUEST_CODE_FROM_CAMERA + addRequest);\n    }\n\n    /**\n     * 打开相机拍照获取图片\n     */\n    public static void pickImageFromCamera(final Activity activity) {\n        pickImageFromCamera(activity, 0);\n    }\n\n    /**\n     * 打开本地相册选取图片\n     */\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public static void pickImageFromAlbum(final Activity activity, int addRequest) {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_GET_CONTENT);\n        intent.setType(\"image/*\");\n        activity.startActivityForResult(intent, REQUEST_CODE_FROM_ALBUM + addRequest);\n    }\n\n    /**\n     * 打开本地相册选取图片\n     */\n    public static void pickImageFromAlbum(final Activity activity) {\n        pickImageFromAlbum(activity, 0);\n    }\n\n    /**\n     * 亚索图片\n     *\n     * @param context\n     * @param uri     图片uri\n     * @param reqW    上传图片需要压缩的宽度\n     * @param reqH    上传图片需要压缩的高度\n     * @return 上传成功回调\n     */\n    public static Observable<byte[]> compressImage(final Context context,\n                                                   Uri uri,\n                                                   final int reqW,\n                                                   final int reqH) {\n        // 先从本地获取图片,利用Glide压缩图片后获取byte[]\n        return Observable.just(uri)\n                .flatMap(new Func1<Uri, Observable<byte[]>>() {\n                    @Override\n                    public Observable<byte[]> call(Uri uri) {\n                        // 在work线程中，同步压缩图片，然后Observable返回\n                        // 即将Glide的回调封装成RxJava的Observable\n                        FutureTarget<byte[]> future = Glide.with(context)\n                                .load(uri)\n                                .asBitmap()\n                                .toBytes()\n                                .into(reqW, reqH);\n\n                        byte[] bytes;\n                        try {\n                            bytes = future.get();\n                        } catch (Exception e) {\n                            // 获取失败时，抛出runtime异常\n                            // 该异常会被Subscriber捕捉，进onError\n                            throw new RuntimeException(e);\n                        }\n                        return Observable.just(bytes);\n                    }\n                });\n    }\n\n    /**\n     * 图片裁剪\n     */\n    public static void cropImage(Activity activity, Uri srcUri) {\n        cropImageUri = createImageUri(activity);\n\n        Intent intent = new Intent(\"com.android.camera.action.CROP\");\n        intent.setDataAndType(srcUri, \"image/*\");\n        intent.putExtra(\"crop\", \"true\");\n\n        ////////////////////////////////////////////////////////////////\n        // 1.宽高和比例都不设置时,裁剪框可以自行调整(比例和大小都可以随意调整)\n        ////////////////////////////////////////////////////////////////\n        // 2.只设置裁剪框宽高比(aspect)后,裁剪框比例固定不可调整,只能调整大小\n        /////////////////////////////////\n        // 3.裁剪后生成图片宽高(output)的设置和裁剪框无关,只决定最终生成图片大小\n        ////////////////////////////////////////////////////////////////\n        // 4.裁剪框宽高比例(aspect)可以和裁剪后生成图片比例(output)不同,此时,\n        //\t会以裁剪框的宽为准,按照裁剪宽高比例生成一个图片,该图和框选部分可能不同,\n        //  不同的情况可能是截取框选的一部分,也可能超出框选部分,向下延伸补足\n        ////////////////////////////////////////////////////////////////\n\n        // aspectX aspectY 是裁剪框宽高的比例\n        intent.putExtra(\"aspectX\", 1);\n        intent.putExtra(\"aspectY\", 1);\n        // outputX outputY 是裁剪后生成图片的宽高\n//\t\tintent.putExtra(\"outputX\", 300);\n//\t\tintent.putExtra(\"outputY\", 100);\n\n        // return-data为true时,会直接返回bitmap数据,但是大图裁剪时会出现OOM,推荐下面为false时的方式\n        // return-data为false时,不会返回bitmap,但需要指定一个MediaStore.EXTRA_OUTPUT保存图片uri\n        intent.putExtra(\"return-data\", false);\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);\n\n        activity.startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE);\n    }\n\n    /**\n     * 创建一条图片uri,用于保存拍照后的照片\n     */\n    private static Uri createImageUri(Context context) {\n        String name = \"boreImg\" + System.currentTimeMillis();\n        ContentValues values = new ContentValues();\n        values.put(MediaStore.Images.Media.TITLE, name);\n        values.put(MediaStore.Images.Media.DISPLAY_NAME, name + \".jpeg\");\n        values.put(MediaStore.Images.Media.MIME_TYPE, \"image/jpeg\");\n        Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);\n        return uri;\n    }\n\n    /**\n     * 删除一条图片\n     */\n    public static void deleteImageUri(Context context, Uri uri) {\n        context.getContentResolver().delete(uri, null, null);\n    }\n\n    /**\n     * 用第三方应用app打开图片\n     */\n    public static void openImageByOtherApp(Context context, Uri imageUri) {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_VIEW);\n        intent.setDataAndType(imageUri, \"image/*\");\n        context.startActivity(intent);\n    }\n\n    /**\n     * 根据Uri获取图片绝对路径，解决Android4.4以上版本Uri转换\n     */\n    public static String getImageAbsolutePath19(Context context, Uri imageUri) {\n        if (context == null || imageUri == null)\n            return null;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT\n                && DocumentsContract.isDocumentUri(context, imageUri)) {\n            if (isExternalStorageDocument(imageUri)) {\n                String docId = DocumentsContract.getDocumentId(imageUri);\n                String[] split = docId.split(\":\");\n                String type = split[0];\n                if (\"primary\".equalsIgnoreCase(type)) {\n                    return Environment.getExternalStorageDirectory() + \"/\" + split[1];\n                }\n            } else if (isDownloadsDocument(imageUri)) {\n                String id = DocumentsContract.getDocumentId(imageUri);\n                Uri contentUri = ContentUris.withAppendedId(Uri.parse(\"content://downloads/public_downloads\"), Long.valueOf(id));\n                return getDataColumn(context, contentUri, null, null);\n            } else if (isMediaDocument(imageUri)) {\n                String docId = DocumentsContract.getDocumentId(imageUri);\n                String[] split = docId.split(\":\");\n                String type = split[0];\n                Uri contentUri = null;\n                if (\"image\".equals(type)) {\n                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;\n                } else if (\"video\".equals(type)) {\n                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;\n                } else if (\"audio\".equals(type)) {\n                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;\n                }\n                String selection = MediaStore.Images.Media._ID + \"=?\";\n                String[] selectionArgs = new String[]{split[1]};\n                return getDataColumn(context, contentUri, selection, selectionArgs);\n            }\n        }\n\n        // MediaStore (and general)\n        if (\"content\".equalsIgnoreCase(imageUri.getScheme())) {\n            // Return the remote address\n            if (isGooglePhotosUri(imageUri))\n                return imageUri.getLastPathSegment();\n            return getDataColumn(context, imageUri, null, null);\n        }\n        // File\n        else if (\"file\".equalsIgnoreCase(imageUri.getScheme())) {\n            return imageUri.getPath();\n        }\n        return null;\n    }\n\n    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {\n        Cursor cursor = null;\n        String column = MediaStore.Images.Media.DATA;\n        String[] projection = {column};\n        try {\n            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);\n            if (cursor != null && cursor.moveToFirst()) {\n                int index = cursor.getColumnIndexOrThrow(column);\n                return cursor.getString(index);\n            }\n        } finally {\n            if (cursor != null)\n                cursor.close();\n        }\n        return null;\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is ExternalStorageProvider.\n     */\n    private static boolean isExternalStorageDocument(Uri uri) {\n        return \"com.android.externalstorage.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is DownloadsProvider.\n     */\n    private static boolean isDownloadsDocument(Uri uri) {\n        return \"com.android.providers.downloads.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is MediaProvider.\n     */\n    private static boolean isMediaDocument(Uri uri) {\n        return \"com.android.providers.media.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is Google Photos.\n     */\n    private static boolean isGooglePhotosUri(Uri uri) {\n        return \"com.google.android.apps.photos.content\".equals(uri.getAuthority());\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/LogUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.util.Log;\n\npublic class LogUtils {\n\n    public static void showLog(String log) {\n        showLog(\"DDD\", log);\n    }\n\n    public static void showLog(String tag, String log) {\n        Log.i(tag, log);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/NetUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\n\npublic class NetUtils {\n\n    private NetUtils() {\n        /* cannot be instantiated */\n        throw new UnsupportedOperationException(\"cannot be instantiated\");\n    }\n\n    /**\n     * 判断网络是否连接\n     */\n    public static boolean isConnected(Context context) {\n        ConnectivityManager cm = (ConnectivityManager)\n                context.getSystemService(Context.CONNECTIVITY_SERVICE);\n\n        if (null == cm) {\n            return false;\n        }\n\n        NetworkInfo info = cm.getActiveNetworkInfo();\n        if (null != info && info.isConnected()) {\n            if (info.getState() == NetworkInfo.State.CONNECTED) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 判断是否是wifi连接\n     */\n    public static boolean isWifi(Context context) {\n        ConnectivityManager cm = (ConnectivityManager)\n                context.getSystemService(Context.CONNECTIVITY_SERVICE);\n\n        if (null == cm) {\n            return false;\n        }\n\n        NetworkInfo info = cm.getActiveNetworkInfo();\n        if (null != info) {\n            if (info.getType() == ConnectivityManager.TYPE_WIFI) {\n                return true;\n            }\n        }\n        return false;\n\n    }\n\n    /**\n     * 打开网络设置界面\n     */\n    public static void openSetting(Activity activity, int requestCode) {\n        Intent intent = new Intent(\"/\");\n        ComponentName cm = new ComponentName(\"com.android.settings\",\n                \"com.android.settings.WirelessSettings\");\n        intent.setComponent(cm);\n        intent.setAction(Intent.ACTION_VIEW);\n        activity.startActivityForResult(intent, requestCode);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/StringUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.Context;\nimport android.text.TextPaint;\nimport android.text.style.ClickableSpan;\nimport android.view.View;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.text.DecimalFormat;\n\npublic class StringUtils {\n\n    public static boolean isEmpty(CharSequence str) {\n        return str == null || str.length() == 0;\n    }\n\n    public static String getMoney(float cost) {\n        DecimalFormat decimalFormat = new DecimalFormat(\"0.00\");\n        return \"￥\" + decimalFormat.format(cost);\n    }\n\n    public static class PrimaryClickableSpan extends ClickableSpan {\n\n        private Context context;\n\n        public PrimaryClickableSpan(Context context) {\n            this.context = context;\n        }\n\n        @Override\n        public void onClick(View widget) {\n            // do nothing\n        }\n\n        @Override\n        public void updateDrawState(TextPaint ds) {\n            ds.setColor(context.getResources().getColor(R.color.colorPrimary));\n            ds.setUnderlineText(false);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/TitleBuilder.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 标题栏构造器,使用方法 new TitleBuilder().setMethod().setMethod()......\n * <p/>\n * 统一格式为标题文字,左右各自是文字/图片按钮\n * 按钮都默认不显示,只有在你调用setLeftText时才会显示左侧按钮文字,图片同理\n * 图片或文字的点击事件都用Left/RightOnClickListener\n */\npublic class TitleBuilder {\n\n    private View rootView;\n    private TextView tvTitle;\n    private ImageView ivLeft;\n    private ImageView ivRight;\n    private TextView tvLeft;\n    private TextView tvRight;\n\n    public View getRootView() {\n        return rootView;\n    }\n\n    public TextView getTvTitle() {\n        return tvTitle;\n    }\n\n    public ImageView getIvLeft() {\n        return ivLeft;\n    }\n\n    public ImageView getIvRight() {\n        return ivRight;\n    }\n\n    public TextView getTvLeft() {\n        return tvLeft;\n    }\n\n    public TextView getTvRight() {\n        return tvRight;\n    }\n\n    /**\n     * Activity中使用这个构造方法\n     */\n    public TitleBuilder(Activity context) {\n        rootView = context.findViewById(R.id.rl_titlebar);\n        if (rootView == null) {\n            return;\n        }\n        tvTitle = (TextView) rootView.findViewById(R.id.titlebar_tv);\n        ivLeft = (ImageView) rootView.findViewById(R.id.titlebar_iv_left);\n        ivRight = (ImageView) rootView.findViewById(R.id.titlebar_iv_right);\n        tvLeft = (TextView) rootView.findViewById(R.id.titlebar_tv_left);\n        tvRight = (TextView) rootView.findViewById(R.id.titlebar_tv_right);\n    }\n\n    /**\n     * Fragment中使用这个构造方法\n     */\n    public TitleBuilder(View context) {\n        rootView = context.findViewById(R.id.rl_titlebar);\n        if (rootView == null) {\n            return;\n        }\n        tvTitle = (TextView) rootView.findViewById(R.id.titlebar_tv);\n        ivLeft = (ImageView) rootView.findViewById(R.id.titlebar_iv_left);\n        ivRight = (ImageView) rootView.findViewById(R.id.titlebar_iv_right);\n        tvLeft = (TextView) rootView.findViewById(R.id.titlebar_tv_left);\n        tvRight = (TextView) rootView.findViewById(R.id.titlebar_tv_right);\n    }\n\n    // title\n    public TitleBuilder setTitleBgRes(int resid) {\n        rootView.setBackgroundResource(resid);\n        return this;\n    }\n\n    public TitleBuilder setTitleText(String text) {\n        tvTitle.setVisibility(TextUtils.isEmpty(text) ? View.GONE\n                : View.VISIBLE);\n        tvTitle.setText(text);\n        return this;\n    }\n\n    // left\n    public TitleBuilder setLeftImage(int resId) {\n        ivLeft.setVisibility(resId > 0 ? View.VISIBLE : View.GONE);\n        ivLeft.setImageResource(resId);\n        return this;\n    }\n\n    public TitleBuilder setLeftText(String text) {\n        tvLeft.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);\n        tvLeft.setText(text);\n        return this;\n    }\n\n    public TitleBuilder setLeftOnClickListener(OnClickListener listener) {\n        if (ivLeft.getVisibility() == View.VISIBLE) {\n            ivLeft.setOnClickListener(listener);\n        } else if (tvLeft.getVisibility() == View.VISIBLE) {\n            tvLeft.setOnClickListener(listener);\n        }\n        return this;\n    }\n\n    // right\n    public TitleBuilder setRightImage(int resId) {\n        ivRight.setVisibility(resId > 0 ? View.VISIBLE : View.GONE);\n        ivRight.setImageResource(resId);\n        return this;\n    }\n\n    public TitleBuilder setRightText(String text) {\n        tvRight.setVisibility(TextUtils.isEmpty(text) ? View.GONE\n                : View.VISIBLE);\n        tvRight.setText(text);\n        return this;\n    }\n\n    public TitleBuilder setRightTextColor(Context context, int resId) {\n        tvRight.setTextColor(context.getResources().getColor(resId));\n        return this;\n    }\n\n    public TitleBuilder setTitleTextColor(Context context, int resId) {\n        tvTitle.setTextColor(context.getResources().getColor(resId));\n        return this;\n    }\n\n\n    public TitleBuilder setRightOnClickListener(OnClickListener listener) {\n        if (ivRight.getVisibility() == View.VISIBLE) {\n            ivRight.setOnClickListener(listener);\n        } else if (tvRight.getVisibility() == View.VISIBLE) {\n            tvRight.setOnClickListener(listener);\n        }\n        return this;\n    }\n\n    public View build() {\n        return rootView;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ToastUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\npublic class ToastUtils {\n\n    private static Toast mToast;\n\n    /**\n     * 非阻塞试显示Toast,防止出现连续点击Toast时的显示问题\n     */\n    public static void showToast(Context context, CharSequence text, int duration) {\n        if (mToast == null) {\n            mToast = Toast.makeText(context, text, duration);\n        } else {\n            mToast.setText(text);\n            mToast.setDuration(duration);\n        }\n        mToast.show();\n    }\n\n    public static void showToast(Context context, CharSequence text) {\n        showToast(context, text, Toast.LENGTH_SHORT);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ViewUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\npublic class ViewUtils {\n\n//    public static void setIndicator(Context context, final int size,\n//                                    final ViewPager vp_banner, final RadioGroup rg_indicator) {\n//        // 无图片和只有一张时不要indicator\n//        if (size <= 1) {\n//            rg_indicator.setVisibility(View.GONE);\n//            return;\n//        }\n//        rg_indicator.setVisibility(View.VISIBLE);\n//\n//        vp_banner.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\n//\n//            @Override\n//            public void onPageSelected(int position) {\n//                // ViewPager和RadioGroup联动\n//                if (rg_indicator.getChildCount() > 1) {\n//                    ((RadioButton) rg_indicator.getChildAt(position % size)).setChecked(true);\n//                }\n//            }\n//        });\n//\n//        // 根据图片数量添加RadioButton\n//        rg_indicator.removeAllViews();\n//        for (int i = 0; i < size; i++) {\n//            RadioButton rb = new RadioButton(context);\n//            // TODO 圆形大小\n//            RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(\n//                    DisplayUtils.dp2px(context, 8), DisplayUtils.dp2px(context, 8));\n//            if (i > 0) {\n//                params.setMargins(DisplayUtils.dp2px(context, 8), 0, 0, 0);\n//            }\n//            rb.setLayoutParams(params);\n//            rb.setButtonDrawable(new ColorDrawable());\n//            rb.setBackgroundResource(R.drawable.shape_oval_yellow_stroke2solid_sel);\n//            rb.setOnTouchListener(new View.OnTouchListener() {\n//                @Override\n//                public boolean onTouch(View view, MotionEvent motionEvent) {\n//                    // 圆不可点击选择\n//                    return true;\n//                }\n//            });\n//            rg_indicator.addView(rb);\n//        }\n//\n//        // 默认选中第一个\n//        if (rg_indicator.getChildCount() > 0) {\n//            ((RadioButton) rg_indicator.getChildAt(0)).setChecked(true);\n//        }\n//    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/AddressWheelDialog.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.view.View;\nimport android.widget.Button;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.db.AddressData;\nimport com.boredream.bdcodehelper.entity.city.CityModel;\nimport com.boredream.bdcodehelper.view.wheel.OnWheelChangedListener;\nimport com.boredream.bdcodehelper.view.wheel.WheelView;\nimport com.boredream.bdcodehelper.view.wheel.adapters.ArrayWheelAdapter;\n\nimport java.util.ArrayList;\n\npublic class AddressWheelDialog extends Dialog implements OnWheelChangedListener {\n\n    private String mCurrentProvice;\n    private CityModel mCurrentCity;\n\n    private WheelView mViewProvince;\n    private WheelView mViewCity;\n    private Button mBtnConfirm;\n\n    public AddressWheelDialog(Context context) {\n        super(context);\n\n        initViews();\n        initData();\n    }\n\n    private void initViews() {\n        setContentView(R.layout.wheel_dialog_address);\n\n        mViewProvince = (WheelView) findViewById(R.id.id_province);\n        mViewCity = (WheelView) findViewById(R.id.id_city);\n        mBtnConfirm = (Button) findViewById(R.id.btn_confirm);\n\n        mViewProvince.addChangingListener(this);\n        mViewCity.addChangingListener(this);\n        mBtnConfirm.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                if(onAddressSelectListener != null) {\n                    CityModel address = new CityModel();\n                    onAddressSelectListener.onAddressSelected(address);\n                }\n            }\n        });\n    }\n\n    private void initData() {\n        mViewProvince.setViewAdapter(new ArrayWheelAdapter<>(getContext(), AddressData.mProvinceDatas));\n        mViewProvince.setVisibleItems(7);\n        mViewCity.setVisibleItems(7);\n        updateCities();\n    }\n\n    @Override\n    public void onChanged(WheelView wheel, int oldValue, int newValue) {\n        if (wheel == mViewProvince) {\n            updateCities();\n        }\n    }\n\n    private void updateCities() {\n        int pCurrent = mViewProvince.getCurrentItem();\n        mCurrentProvice = AddressData.mProvinceDatas.get(pCurrent);\n        ArrayList<CityModel> cities = AddressData.mCitisDatasMap.get(mCurrentProvice);\n        if (cities == null) {\n            cities = new ArrayList<>();\n        }\n        mViewCity.setViewAdapter(new ArrayWheelAdapter<>(getContext(), cities));\n        mViewCity.setCurrentItem(0);\n    }\n\n    private OnAddressSelectListener onAddressSelectListener;\n\n    public void setOnAddressSelectListener(OnAddressSelectListener onAddressSelectListener) {\n        this.onAddressSelectListener = onAddressSelectListener;\n    }\n\n    public interface OnAddressSelectListener {\n        void onAddressSelected(CityModel address);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/BottomTabRadioButton.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.widget.RadioButton;\n\nimport com.boredream.bdcodehelper.R;\n\npublic class BottomTabRadioButton extends RadioButton {\n\n    /**\n     * 提示模式 - 无提示\n     */\n    private static final int MODE_NONE = 0;\n\n    /**\n     * 提示模式 - 红点提示\n     */\n    private static final int MODE_POINT = 1;\n\n    /**\n     * 提示模式 - 数字提示\n     */\n    private static final int MODE_NUM = 2;\n\n    /**\n     * 默认红点默认半径\n     */\n    private static final float DEFAULT_POINT_RADIUS = 4; //dp\n\n    /**\n     * 默认数字圆圈半径\n     */\n    private static final float DEFAULT_NUM_RADIUS = 8; //dp\n\n    /**\n     * 默认数字文字大小\n     */\n    private static final float DEFAULT_NUM_SIZE = 10; //sp\n\n    private Paint hintPaint;\n    private Paint textPaint;\n    private Rect textRect = new Rect();\n\n    /**\n     * 提示模式\n     */\n    private int hint_mode;\n\n    /**\n     * 圆填充色\n     */\n    private int hint_color;\n\n    /**\n     * 据顶部距离\n     */\n    private int hint_toppadding;\n\n    /**\n     * 据右侧距离\n     */\n    private int hint_rightpadding;\n\n    /**\n     * 圆点半径\n     */\n    private int point_radius;\n\n    /**\n     * 数字\n     */\n    private int num;\n\n    /**\n     * 数字圆圈半径\n     */\n    private int num_radius;\n\n    /**\n     * 数字文字大小\n     */\n    private int num_size;\n\n    /**\n     * 数字文字颜色\n     */\n    private int num_color;\n\n    public int getHint_mode() {\n        return hint_mode;\n    }\n\n    public void setHint_mode(int hint_mode) {\n        this.hint_mode = hint_mode;\n        invalidate();\n    }\n\n    public int getHint_color() {\n        return hint_color;\n    }\n\n    public void setHint_color(int hint_color) {\n        this.hint_color = hint_color;\n        invalidate();\n    }\n\n    public int getHint_toppadding() {\n        return hint_toppadding;\n    }\n\n    public void setHint_toppadding(int hint_toppadding) {\n        this.hint_toppadding = hint_toppadding;\n        invalidate();\n    }\n\n    public int getHint_rightpadding() {\n        return hint_rightpadding;\n    }\n\n    public void setHint_rightpadding(int hint_rightpadding) {\n        this.hint_rightpadding = hint_rightpadding;\n        invalidate();\n    }\n\n    public int getPoint_radius() {\n        return point_radius;\n    }\n\n    public void setPoint_radius(int point_radius) {\n        this.point_radius = point_radius;\n        invalidate();\n    }\n\n    public int getNum() {\n        return num;\n    }\n\n    public void setNum(int num) {\n        this.num = num;\n        invalidate();\n    }\n\n    public int getNum_radius() {\n        return num_radius;\n    }\n\n    public void setNum_radius(int num_radius) {\n        this.num_radius = num_radius;\n        invalidate();\n    }\n\n    public int getNum_size() {\n        return num_size;\n    }\n\n    public void setNum_size(int num_size) {\n        this.num_size = num_size;\n        invalidate();\n    }\n\n    public int getNum_color() {\n        return num_color;\n    }\n\n    public void setNum_color(int num_color) {\n        this.num_color = num_color;\n        invalidate();\n    }\n\n    public BottomTabRadioButton(Context context) {\n        super(context);\n    }\n\n    public BottomTabRadioButton(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView(attrs);\n    }\n\n    public BottomTabRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView(attrs);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public BottomTabRadioButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        initView(attrs);\n    }\n\n    private void initView(AttributeSet attrs) {\n        Context context = getContext();\n        DisplayMetrics metrics = context.getResources().getDisplayMetrics();\n\n        // 根据attrs获取属性\n        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BottomTabRadioButton);\n\n        hint_mode = ta.getInt(R.styleable.BottomTabRadioButton_hint_mode,\n                MODE_NONE);\n        hint_color = ta.getColor(R.styleable.BottomTabRadioButton_hint_color,\n                Color.RED);\n\n        hint_toppadding = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_hint_toppadding,\n                0);\n        hint_rightpadding = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_hint_rightpadding,\n                0);\n\n        float defaultPointRadius = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_POINT_RADIUS, metrics);\n        point_radius = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_point_radius,\n                (int) (defaultPointRadius + 0.5f));\n\n        num = ta.getInt(R.styleable.BottomTabRadioButton_num,\n                -1);\n        float defaultNumRadius = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_NUM_RADIUS, metrics);\n        num_radius = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_radius,\n                (int) (defaultNumRadius + 0.5f));\n        float defaultNumSize = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_SP, DEFAULT_NUM_SIZE, metrics);\n        num_size = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_size,\n                (int) (defaultNumSize + 0.5f));\n        num_color = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_color,\n                Color.WHITE);\n\n        ta.recycle();\n\n        // 初始化背景圆画笔\n        hintPaint = new Paint();\n        hintPaint.setAntiAlias(true);\n        hintPaint.setStyle(Paint.Style.FILL);\n        hintPaint.setColor(hint_color);\n\n        // 初始化数字文字画笔\n        textPaint = new Paint();\n        textPaint.setAntiAlias(true);\n        textPaint.setColor(num_color);\n        textPaint.setTextSize(num_size);\n        textPaint.setFakeBoldText(true);\n        textPaint.setTextAlign(Paint.Align.CENTER);\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        if (hint_mode == MODE_POINT) { // 如果是圆点模式\n            // 直接画一个圆点\n            float width = getWidth();\n            float centerX = width - hint_rightpadding - point_radius;\n            float centerY = hint_toppadding + point_radius;\n\n            canvas.drawCircle(centerX, centerY, point_radius, hintPaint);\n        } else if (hint_mode == MODE_NUM) { // 如果是数字模式\n            // 1.画一个背景圆\n            float width = getWidth();\n            float centerX = width - hint_rightpadding - num_radius;\n            float centerY = hint_toppadding + num_radius;\n\n            canvas.drawCircle(centerX, centerY, num_radius, hintPaint);\n\n            // 2.画数字\n            if (num >= 0) {\n                String numStr = String.valueOf(num);\n\n                if (num >= 100) {\n                    // 如果超过100使用\"...\"\n                    numStr = \"...\";\n                }\n                textPaint.getTextBounds(numStr, 0, numStr.length(), textRect);\n                float textCenterY = centerY + textRect.bottom - textRect.top / 2;\n                canvas.drawText(numStr, centerX, textCenterY, textPaint);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/CheckableLinearLayout.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.Checkable;\nimport android.widget.LinearLayout;\n\n/**\n * This is a simple wrapper for {@link LinearLayout} that implements the {@link Checkable}\n * interface by keeping an internal 'checked' state flag.\n * <p>\n * This can be used as the root view for a custom list item layout for\n * {@link android.widget.AbsListView} elements with a\n * {@link android.widget.AbsListView#setChoiceMode(int) choiceMode} set.\n */\npublic class CheckableLinearLayout extends LinearLayout implements Checkable {\n    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};\n\n    private boolean mChecked = false;\n\n    public CheckableLinearLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public boolean isChecked() {\n        return mChecked;\n    }\n\n    public void setChecked(boolean b) {\n        if (b != mChecked) {\n            mChecked = b;\n            refreshDrawableState();\n        }\n    }\n\n    public void toggle() {\n        setChecked(!mChecked);\n    }\n\n    @Override\n    public int[] onCreateDrawableState(int extraSpace) {\n        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);\n        if (isChecked()) {\n            mergeDrawableStates(drawableState, CHECKED_STATE_SET);\n        }\n        return drawableState;\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DividerItemDecoration.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class DividerItemDecoration extends RecyclerView.ItemDecoration {\n\n    private static final int[] ATTRS = new int[]{\n            android.R.attr.listDivider\n    };\n\n    private List<Integer> ignorePositionList;\n\n    private Drawable mDivider;\n\n    public DividerItemDecoration(Context context) {\n        final TypedArray a = context.obtainStyledAttributes(ATTRS);\n        mDivider = a.getDrawable(0);\n        a.recycle();\n    }\n\n    /**\n     * 忽略分割线的position,即该位置不添加\n     */\n    public void setIgnorePositions(Integer[] ignorePositions) {\n        ignorePositionList = Arrays.asList(ignorePositions);\n    }\n\n    @Override\n    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {\n        drawVertical(c, parent);\n    }\n\n    public void drawVertical(Canvas c, RecyclerView parent) {\n        final int left = parent.getPaddingLeft();\n        final int right = parent.getWidth() - parent.getPaddingRight();\n\n        final int childCount = parent.getChildCount();\n        for (int i = 0; i < childCount; i++) {\n            if (ignorePositionList != null && ignorePositionList.contains(i)) {\n                continue;\n            }\n\n            final View child = parent.getChildAt(i);\n            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child\n                    .getLayoutParams();\n            final int top = child.getBottom() + params.bottomMargin +\n                    Math.round(ViewCompat.getTranslationY(child));\n//            final int bottom = top + mDivider.getIntrinsicHeight();\n            final int bottom = top + 1;\n            mDivider.setBounds(left, top, right, bottom);\n            mDivider.draw(c);\n        }\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n//        outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());\n        outRect.set(0, 0, 0, 1);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DrawableRadioButton.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.widget.RadioButton;\n\nimport com.boredream.bdcodehelper.R;\n\n\npublic class DrawableRadioButton extends RadioButton {\n\n    private int widthPx;\n    private int heightPx;\n\n    public DrawableRadioButton(Context context) {\n        super(context);\n    }\n\n    public DrawableRadioButton(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        initView(context, attrs);\n    }\n\n    public DrawableRadioButton(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        initView(context, attrs);\n    }\n\n    private void initView(Context context, AttributeSet attrs) {\n        TypedArray ta = context.obtainStyledAttributes(attrs,\n                R.styleable.DrawableTextView);\n\n        widthPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableWidth, -1);\n        heightPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableHeight, -1);\n\n        // 左右上下四个图片\n        Drawable[] drawables = getCompoundDrawables();\n\n        setDrawables(drawables);\n\n        ta.recycle();\n    }\n\n    /**\n     * 左上右下四个图片,只会取一个方向图片使用\n     */\n    public void setDrawables(Drawable[] drawables) {\n        // 左右上下四个图片\n        Drawable drawable = null;\n        // 如果其中一个方向有图片,获取之\n        for (int i = 0; i < drawables.length; i++) {\n            if (drawables[i] != null) {\n                drawable = drawables[i];\n                break;\n            }\n        }\n\n        // 设置宽高\n        if (drawable != null && widthPx != -1 && heightPx != -1) {\n            drawable.setBounds(0, 0, widthPx, heightPx);\n        }\n\n        // 将图片放回到TextView中\n        setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DrawableTextView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n\npublic class DrawableTextView extends TextView {\n\n    private final int widthPx;\n    private final int heightPx;\n\n    public DrawableTextView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        TypedArray ta = context.obtainStyledAttributes(attrs,\n                R.styleable.DrawableTextView);\n\n        widthPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableWidth, -1);\n        heightPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableHeight, -1);\n\n        // 左右上下四个图片\n        Drawable[] drawables = getCompoundDrawables();\n\n        setDrawables(drawables);\n\n        ta.recycle();\n    }\n\n    /**\n     * 左上右下四个图片,只会取一个方向图片使用\n     */\n    public void setDrawables(Drawable[] drawables) {\n        // 左右上下四个图片\n        Drawable drawable = null;\n        // 如果其中一个方向有图片,获取之\n        for (int i = 0; i < drawables.length; i++) {\n            if (drawables[i] != null) {\n                drawable = drawables[i];\n                break;\n            }\n        }\n\n        // 设置宽高\n        if (drawable != null && widthPx != -1 && heightPx != -1) {\n            drawable.setBounds(0, 0, widthPx, heightPx);\n        }\n\n        // 将图片放回到TextView中\n        setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);\n    }\n\n    public DrawableTextView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public DrawableTextView(Context context) {\n        this(context, null);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DropDownMenu.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.animation.AnimationUtils;\nimport android.widget.FrameLayout;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.util.List;\n\npublic class DropDownMenu extends LinearLayout {\n\n    //顶部菜单布局\n    private LinearLayout tabMenuView;\n    //底部容器，包含popupMenuViews，maskView\n    private FrameLayout containerView;\n    //弹出菜单父布局\n    private FrameLayout popupMenuViews;\n    //遮罩半透明View，点击可关闭DropDownMenu\n    private View maskView;\n    //tabMenuView里面选中的tab位置，-1表示未选中\n    private int current_tab_position = -1;\n\n    //分割线颜色\n    private int dividerColor = getResources().getColor(R.color.divider_gray);\n    //tab选中颜色\n    private int textSelectedColor = getResources().getColor(R.color.colorPrimary);\n    //tab未选中颜色\n    private int textUnselectedColor = getResources().getColor(R.color.txt_black);\n    //遮罩颜色\n    private int maskColor = 0x88888888;\n    //tab字体大小\n    private int menuTextSize = 12;\n\n    //tab选中图标\n    private int menuSelectedIcon;\n    //tab未选中图标\n    private int menuUnselectedIcon;\n\n\n    public DropDownMenu(Context context) {\n        super(context, null);\n    }\n\n    public DropDownMenu(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    @TargetApi(Build.VERSION_CODES.HONEYCOMB)\n    public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        setOrientation(VERTICAL);\n\n        //为DropDownMenu添加自定义属性\n        int menuBackgroundColor = 0xffffffff;\n        int underlineColor = 0xffcccccc;\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DropDownMenu);\n        underlineColor = a.getColor(R.styleable.DropDownMenu_ddunderlineColor, underlineColor);\n        dividerColor = a.getColor(R.styleable.DropDownMenu_dddividerColor, dividerColor);\n        textSelectedColor = a.getColor(R.styleable.DropDownMenu_ddtextSelectedColor, textSelectedColor);\n        textUnselectedColor = a.getColor(R.styleable.DropDownMenu_ddtextUnselectedColor, textUnselectedColor);\n        menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_ddmenuBackgroundColor, menuBackgroundColor);\n        maskColor = a.getColor(R.styleable.DropDownMenu_ddmaskColor, maskColor);\n        menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_ddmenuTextSize, menuTextSize);\n        menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuSelectedIcon, menuSelectedIcon);\n        menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuUnselectedIcon, menuUnselectedIcon);\n        a.recycle();\n\n        //初始化tabMenuView并添加到tabMenuView\n        tabMenuView = new LinearLayout(context);\n        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n        tabMenuView.setOrientation(HORIZONTAL);\n        tabMenuView.setBackgroundColor(menuBackgroundColor);\n        tabMenuView.setLayoutParams(params);\n        addView(tabMenuView, 0);\n\n        //为tabMenuView添加下划线\n        View underLine = new View(getContext());\n        underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpTpPx(1.0f)));\n        underLine.setBackgroundColor(underlineColor);\n        addView(underLine, 1);\n\n        //初始化containerView并将其添加到DropDownMenu\n        containerView = new FrameLayout(context);\n        containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));\n        addView(containerView, 2);\n\n    }\n\n    /**\n     * 初始化DropDownMenu\n     *\n     * @param tabTexts\n     * @param popupViews\n     * @param contentView\n     */\n    public void setDropDownMenu(List<String> tabTexts, List<View> popupViews, View contentView) {\n        if (tabTexts.size() != popupViews.size()) {\n            throw new IllegalArgumentException(\"params not match, tabTexts.size() should be equal popupViews.size()\");\n        }\n\n        for (int i = 0; i < tabTexts.size(); i++) {\n            addTab(tabTexts, i);\n        }\n\n        containerView.addView(contentView, 0);\n\n        maskView = new View(getContext());\n        maskView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));\n        maskView.setBackgroundColor(maskColor);\n        maskView.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                closeMenu();\n            }\n        });\n        containerView.addView(maskView, 1);\n        maskView.setVisibility(GONE);\n\n        popupMenuViews = new FrameLayout(getContext());\n        popupMenuViews.setVisibility(GONE);\n        containerView.addView(popupMenuViews, 2);\n\n        for (int i = 0; i < popupViews.size(); i++) {\n            popupViews.get(i).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n            popupMenuViews.addView(popupViews.get(i), i);\n        }\n\n    }\n\n    private void addTab(List<String> tabTexts, int i) {\n        final TextView tab = new TextView(getContext());\n        tab.setSingleLine();\n        tab.setEllipsize(TextUtils.TruncateAt.END);\n        tab.setGravity(Gravity.CENTER);\n        tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, menuTextSize);\n        tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));\n        tab.setTextColor(textUnselectedColor);\n        tab.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(menuUnselectedIcon), null);\n        tab.setText(tabTexts.get(i));\n        tab.setPadding(dpTpPx(48), dpTpPx(8), dpTpPx(48), dpTpPx(8));\n        //添加点击事件\n        tab.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                switchMenu(tab);\n            }\n        });\n        tabMenuView.addView(tab);\n        //添加分割线\n        if (i < tabTexts.size() - 1) {\n            View view = new View(getContext());\n            LayoutParams params = new LayoutParams(\n                    dpTpPx(0.5f), ViewGroup.LayoutParams.MATCH_PARENT);\n            params.setMargins(0, dpTpPx(4), 0, dpTpPx(4));\n            view.setLayoutParams(params);\n            view.setBackgroundColor(dividerColor);\n            tabMenuView.addView(view);\n        }\n    }\n\n    /**\n     * 改变tab文字\n     *\n     * @param text\n     */\n    public void setTabText(String text) {\n        if (current_tab_position != -1) {\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setText(text);\n        }\n    }\n\n    public void setTabClickable(boolean clickable) {\n        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {\n            tabMenuView.getChildAt(i).setClickable(clickable);\n        }\n    }\n\n    /**\n     * 关闭菜单\n     */\n    public void closeMenu() {\n        if (current_tab_position != -1) {\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setTextColor(textUnselectedColor);\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                    getResources().getDrawable(menuUnselectedIcon), null);\n            popupMenuViews.setVisibility(View.GONE);\n            popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_out));\n            maskView.setVisibility(GONE);\n            maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_out));\n            current_tab_position = -1;\n        }\n\n    }\n\n    /**\n     * DropDownMenu是否处于可见状态\n     *\n     * @return\n     */\n    public boolean isShowing() {\n        return current_tab_position != -1;\n    }\n\n    /**\n     * 切换菜单\n     *\n     * @param target\n     */\n    private void switchMenu(View target) {\n        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {\n            if (target == tabMenuView.getChildAt(i)) {\n                if (current_tab_position == i) {\n                    closeMenu();\n                } else {\n                    if (current_tab_position == -1) {\n                        popupMenuViews.setVisibility(View.VISIBLE);\n                        popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_in));\n                        maskView.setVisibility(VISIBLE);\n                        maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_in));\n                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);\n                    } else {\n                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);\n                    }\n                    current_tab_position = i;\n                    ((TextView) tabMenuView.getChildAt(i)).setTextColor(textSelectedColor);\n                    ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                            getResources().getDrawable(menuSelectedIcon), null);\n                }\n            } else {\n                ((TextView) tabMenuView.getChildAt(i)).setTextColor(textUnselectedColor);\n                ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                        getResources().getDrawable(menuUnselectedIcon), null);\n                popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);\n            }\n        }\n    }\n\n    public int dpTpPx(float value) {\n        DisplayMetrics dm = getResources().getDisplayMetrics();\n        return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm) + 0.5);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/EmptyItemDecoration.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.graphics.Rect;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npublic class EmptyItemDecoration extends RecyclerView.ItemDecoration {\n\n    /**\n     * decoration添加的位置,为空时所有item都添加\n     */\n    private List<Integer> dividerPositionList;\n    private int height;\n\n    public EmptyItemDecoration(int height) {\n        this.height = height;\n    }\n\n    public EmptyItemDecoration(Integer[] dividerPositions, int height) {\n        this.dividerPositionList = Arrays.asList(dividerPositions);\n        this.height = height;\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n        int position = parent.getChildAdapterPosition(view);\n        if (dividerPositionList == null || dividerPositionList.contains(position)) {\n            outRect.set(0, 0, 0, height);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/GridSpacingDecorator.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.graphics.Rect;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\npublic class GridSpacingDecorator extends RecyclerView.ItemDecoration {\n\n    private int space;\n\n    public GridSpacingDecorator(int space) {\n        this.space = space;\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n        outRect.left = space / 2;\n        outRect.right = space / 2;\n        outRect.bottom = space;\n        if (parent.getChildAdapterPosition(view) <= 1) {\n            outRect.top = space;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/PinnedSectionListView.java",
    "content": "package com.boredream.bdcodehelper.view;\n/*\n * Copyright (C) 2013 Sergej Shafarenka, halfbit.de\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file kt in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.database.DataSetObserver;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.PointF;\nimport android.graphics.Rect;\nimport android.graphics.drawable.GradientDrawable;\nimport android.graphics.drawable.GradientDrawable.Orientation;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.SoundEffectConstants;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.widget.AbsListView;\nimport android.widget.HeaderViewListAdapter;\nimport android.widget.ListAdapter;\nimport android.widget.ListView;\nimport android.widget.SectionIndexer;\n\nimport com.boredream.bdcodehelper.BuildConfig;\n\n/**\n * ListView, which is capable to pin section views at its top while the rest is still scrolled.\n */\npublic class PinnedSectionListView extends ListView {\n\n\n    //-- inner classes\n\n\t/** List adapter to be implemented for being used with PinnedSectionListView adapter. */\n\tpublic static interface PinnedSectionListAdapter extends ListAdapter {\n\t\t/** This method shall return 'true' if views of given type has to be pinned. */\n\t\tboolean isItemViewTypePinned(int viewType);\n\t}\n\n\t/** Wrapper class for pinned section view and its position in the list. */\n\tstatic class PinnedSection {\n\t\tpublic View view;\n\t\tpublic int position;\n\t\tpublic long id;\n\t}\n\n\t//-- class fields\n\n    // fields used for handling touch events\n    private final Rect mTouchRect = new Rect();\n    private final PointF mTouchPoint = new PointF();\n    private int mTouchSlop;\n    private View mTouchTarget;\n    private MotionEvent mDownEvent;\n\n    // fields used for drawing shadow under a pinned section\n    private GradientDrawable mShadowDrawable;\n    private int mSectionsDistanceY;\n    private int mShadowHeight;\n\n    /** Delegating listener, can be null. */\n    OnScrollListener mDelegateOnScrollListener;\n\n    /** Shadow for being recycled, can be null. */\n    PinnedSection mRecycleSection;\n\n    /** shadow instance with a pinned view, can be null. */\n    PinnedSection mPinnedSection;\n\n    /** Pinned view Y-translation. We use it to stick pinned view to the next section. */\n    int mTranslateY;\n\n\t/** Scroll listener which does the magic */\n\tprivate final OnScrollListener mOnScrollListener = new OnScrollListener() {\n\n\t\t// boredream-view which need to hide\n\t\tprivate View hideView;\n\n\t\t@Override public void onScrollStateChanged(AbsListView view, int scrollState) {\n\t\t\tif (mDelegateOnScrollListener != null) { // delegate\n\t\t\t\tmDelegateOnScrollListener.onScrollStateChanged(view, scrollState);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {\n\n            if (mDelegateOnScrollListener != null) { // delegate\n                mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);\n            }\n\n            // get expected adapter or fail fast\n            ListAdapter adapter = getAdapter();\n            if (adapter == null || visibleItemCount == 0) return; // nothing to do\n\n            final boolean isFirstVisibleItemSection =\n                    isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem));\n\n            if (isFirstVisibleItemSection) {\n                View sectionView = getChildAt(0);\n                if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow\n                    destroyPinnedShadow();\n                \t// boredream-re show pinned item of list\n                \tif(hideView != null && hideView.getVisibility() == View.INVISIBLE) {\n                \t\thideView.setVisibility(View.VISIBLE);\n                \t}\n                } else { // section doesn't stick to the top, make sure we have a pinned shadow\n                    ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount);\n                    \n                    // boredream-hide pinned item of list\n                    if(mPinnedSection != null\n                    \t\t&& firstVisibleItem == mPinnedSection.position\n                    \t\t&& sectionView.getTop() < 0) {\n                    \thideView = sectionView;\n                    \tsectionView.setVisibility(View.INVISIBLE);\n                    }\n                }\n            } else { // section is not at the first visible position\n            \t// boredream-re show pinned item of list\n            \tif(hideView != null && hideView.getVisibility() == View.INVISIBLE) {\n            \t\thideView.setVisibility(View.VISIBLE);\n            \t}\n            \t\n                int sectionPosition = findCurrentSectionPosition(firstVisibleItem);\n                if (sectionPosition > -1) { // we have section position\n                    ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount);\n                } else { // there is no section for the first visible item, destroy shadow\n                    destroyPinnedShadow();\n                }\n            }\n\t\t};\n\n\t};\n\n\t/** Default change observer. */\n    private final DataSetObserver mDataSetObserver = new DataSetObserver() {\n        @Override public void onChanged() {\n            recreatePinnedShadow();\n        };\n        @Override public void onInvalidated() {\n            recreatePinnedShadow();\n        }\n    };\n\n\t//-- constructors\n\n    public PinnedSectionListView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView();\n    }\n\n    public PinnedSectionListView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        initView();\n    }\n\n    private void initView() {\n        setOnScrollListener(mOnScrollListener);\n        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();\n        initShadow(true);\n    }\n\n    //-- public API methods\n\n    public void setShadowVisible(boolean visible) {\n        initShadow(visible);\n        if (mPinnedSection != null) {\n            View v = mPinnedSection.view;\n            invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight);\n        }\n    }\n\n    //-- pinned section drawing methods\n\n    public void initShadow(boolean visible) {\n        if (visible) {\n            if (mShadowDrawable == null) {\n                mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM,\n                        new int[] { Color.parseColor(\"#ffa0a0a0\"), Color.parseColor(\"#50a0a0a0\"), Color.parseColor(\"#00a0a0a0\")});\n                mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density);\n            }\n        } else {\n            if (mShadowDrawable != null) {\n                mShadowDrawable = null;\n                mShadowHeight = 0;\n            }\n        }\n    }\n\n\t/** Create shadow wrapper with a pinned view for a view at given position */\n\tvoid createPinnedShadow(int position) {\n\n\t\t// try to recycle shadow\n\t\tPinnedSection pinnedShadow = mRecycleSection;\n\t\tmRecycleSection = null;\n\n\t\t// create new shadow, if needed\n\t\tif (pinnedShadow == null) pinnedShadow = new PinnedSection();\n\t\t// request new view using recycled view, if such\n\t\tView pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedSectionListView.this);\n\n\t\t// read layout parameters\n\t\tLayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams();\n\t\tif (layoutParams == null) {\n//\t\t    layoutParams = (LayoutParams) generateDefaultLayoutParams();\n\t\t\t// boredream-fix bug\n\t\t\tlayoutParams = (LayoutParams) new LayoutParams(\n\t                LayoutParams.MATCH_PARENT,\n\t                LayoutParams.WRAP_CONTENT, 0);\n\t\t    pinnedView.setLayoutParams(layoutParams);\n\t\t}\n\n\t\tint heightMode = MeasureSpec.getMode(layoutParams.height);\n\t\tint heightSize = MeasureSpec.getSize(layoutParams.height);\n\n\t\tif (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY;\n\n\t\tint maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom();\n\t\tif (heightSize > maxHeight) heightSize = maxHeight;\n\n\t\t// measure & layout\n\t\tint ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY);\n\t\tint hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode);\n\t\tpinnedView.measure(ws, hs);\n\t\tpinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight());\n\t\tmTranslateY = 0;\n\n\t\t// initialize pinned shadow\n\t\tpinnedShadow.view = pinnedView;\n\t\tpinnedShadow.position = position;\n\t\tpinnedShadow.id = getAdapter().getItemId(position);\n\n\t\t// store pinned shadow\n\t\tmPinnedSection = pinnedShadow;\n\t}\n\n\t/** Destroy shadow wrapper for currently pinned view */\n\tvoid destroyPinnedShadow() {\n\t    if (mPinnedSection != null) {\n\t        // keep shadow for being recycled later\n\t        mRecycleSection = mPinnedSection;\n\t        mPinnedSection = null;\n\t    }\n\t}\n\n\t/** Makes sure we have an actual pinned shadow for given position. */\n    void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) {\n        if (visibleItemCount < 2) { // no need for creating shadow at all, we have a single visible item\n            destroyPinnedShadow();\n            return;\n        }\n\n        if (mPinnedSection != null\n                && mPinnedSection.position != sectionPosition) { // invalidate shadow, if required\n            destroyPinnedShadow();\n        }\n\n        if (mPinnedSection == null) { // create shadow, if empty\n            createPinnedShadow(sectionPosition);\n        }\n\n        // align shadow according to next section position, if needed\n        int nextPosition = sectionPosition + 1;\n        if (nextPosition < getCount()) {\n            int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition,\n                    visibleItemCount - (nextPosition - firstVisibleItem));\n            if (nextSectionPosition > -1) {\n                View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem);\n                final int bottom = mPinnedSection.view.getBottom() + getPaddingTop();\n                mSectionsDistanceY = nextSectionView.getTop() - bottom;\n                if (mSectionsDistanceY < 0) {\n                    // next section overlaps pinned shadow, move it up\n                    mTranslateY = mSectionsDistanceY;\n                } else {\n                    // next section does not overlap with pinned, stick to top\n                    mTranslateY = 0;\n                }\n            } else {\n                // no other sections are visible, stick to top\n                mTranslateY = 0;\n                mSectionsDistanceY = Integer.MAX_VALUE;\n            }\n        }\n\n    }\n\n\tint findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) {\n\t\tListAdapter adapter = getAdapter();\n\n        int adapterDataCount = adapter.getCount();\n        if (getLastVisiblePosition() >= adapterDataCount) return -1; // dataset has changed, no candidate\n\n        if (firstVisibleItem+visibleItemCount >= adapterDataCount){//added to prevent index Outofbound (in case)\n            visibleItemCount = adapterDataCount-firstVisibleItem;\n        }\n\n\t\tfor (int childIndex = 0; childIndex < visibleItemCount; childIndex++) {\n\t\t\tint position = firstVisibleItem + childIndex;\n\t\t\tint viewType = adapter.getItemViewType(position);\n\t\t\tif (isItemViewTypePinned(adapter, viewType)) return position;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tint findCurrentSectionPosition(int fromPosition) {\n\t\tListAdapter adapter = getAdapter();\n\n\t\tif (fromPosition >= adapter.getCount()) return -1; // dataset has changed, no candidate\n\t\t\n\t\tif (adapter instanceof SectionIndexer) {\n\t\t\t// try fast way by asking section indexer\n\t\t\tSectionIndexer indexer = (SectionIndexer) adapter;\n\t\t\tint sectionPosition = indexer.getSectionForPosition(fromPosition);\n\t\t\tint itemPosition = indexer.getPositionForSection(sectionPosition);\n\t\t\tint typeView = adapter.getItemViewType(itemPosition);\n\t\t\tif (isItemViewTypePinned(adapter, typeView)) {\n\t\t\t\treturn itemPosition;\n\t\t\t} // else, no luck\n\t\t}\n\n\t\t// try slow way by looking through to the next section item above\n\t\tfor (int position=fromPosition; position>=0; position--) {\n\t\t\tint viewType = adapter.getItemViewType(position);\n\t\t\tif (isItemViewTypePinned(adapter, viewType)) return position;\n\t\t}\n\t\treturn -1; // no candidate found\n\t}\n\n\tvoid recreatePinnedShadow() {\n\t    destroyPinnedShadow();\n        ListAdapter adapter = getAdapter();\n        if (adapter != null && adapter.getCount() > 0) {\n            int firstVisiblePosition = getFirstVisiblePosition();\n            int sectionPosition = findCurrentSectionPosition(firstVisiblePosition);\n            if (sectionPosition == -1) return; // no views to pin, exit\n            ensureShadowForPosition(sectionPosition,\n                    firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition);\n        }\n\t}\n\n\t@Override\n\tpublic void setOnScrollListener(OnScrollListener listener) {\n\t\tif (listener == mOnScrollListener) {\n\t\t\tsuper.setOnScrollListener(listener);\n\t\t} else {\n\t\t\tmDelegateOnScrollListener = listener;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onRestoreInstanceState(Parcelable state) {\n\t\tsuper.onRestoreInstanceState(state);\n\t\tpost(new Runnable() {\n\t\t\t@Override public void run() { // restore pinned view after configuration change\n\t\t\t    recreatePinnedShadow();\n\t\t\t}\n\t\t});\n\t}\n\n\t@Override\n\tpublic void setAdapter(ListAdapter adapter) {\n\n\t    // assert adapter in debug mode\n\t\tif (BuildConfig.DEBUG && adapter != null) {\n\t\t\tif (!(adapter instanceof PinnedSectionListAdapter))\n\t\t\t\tthrow new IllegalArgumentException(\"Does your adapter implement PinnedSectionListAdapter?\");\n\t\t\tif (adapter.getViewTypeCount() < 2)\n\t\t\t\tthrow new IllegalArgumentException(\"Does your adapter handle at least two types\" +\n\t\t\t\t\t\t\" of views in getViewTypeCount() method: items and sections?\");\n\t\t}\n\n\t\t// unregister observer at old adapter and register on new one\n\t\tListAdapter oldAdapter = getAdapter();\n\t\tif (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver);\n\t\tif (adapter != null) adapter.registerDataSetObserver(mDataSetObserver);\n\n\t\t// destroy pinned shadow, if new adapter is not same as old one\n\t\tif (oldAdapter != adapter) destroyPinnedShadow();\n\n\t\tsuper.setAdapter(adapter);\n\t}\n\n\t@Override\n\tprotected void onLayout(boolean changed, int l, int t, int r, int b) {\n\t    super.onLayout(changed, l, t, r, b);\n        if (mPinnedSection != null) {\n            int parentWidth = r - l - getPaddingLeft() - getPaddingRight();\n            int shadowWidth = mPinnedSection.view.getWidth();\n            if (parentWidth != shadowWidth) {\n                recreatePinnedShadow();\n            }\n        }\n\t}\n\n\t@Override\n\tprotected void dispatchDraw(Canvas canvas) {\n\t\tsuper.dispatchDraw(canvas);\n\n\t\tif (mPinnedSection != null) {\n\n\t\t\t// prepare variables\n\t\t\tint pLeft = getListPaddingLeft();\n\t\t\tint pTop = getListPaddingTop();\n\t\t\tView view = mPinnedSection.view;\n\n\t\t\t// draw child\n\t\t\tcanvas.save();\n\n\t\t\tint clipHeight = view.getHeight() +\n\t\t\t        (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY));\n\t\t\tcanvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);\n\n\t\t\tcanvas.translate(pLeft, pTop + mTranslateY);\n\t\t\tdrawChild(canvas, mPinnedSection.view, getDrawingTime());\n\n\t\t\tif (mShadowDrawable != null && mSectionsDistanceY > 0) {\n\t\t\t    mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),\n\t\t\t            mPinnedSection.view.getBottom(),\n\t\t\t            mPinnedSection.view.getRight(),\n\t\t\t            mPinnedSection.view.getBottom() + mShadowHeight);\n\t\t\t    mShadowDrawable.draw(canvas);\n\t\t\t}\n\n\t\t\tcanvas.restore();\n\t\t}\n\t}\n\n\t//-- touch handling methods\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent ev) {\n\n        final float x = ev.getX();\n        final float y = ev.getY();\n        final int action = ev.getAction();\n\n        if (action == MotionEvent.ACTION_DOWN\n                && mTouchTarget == null\n                && mPinnedSection != null\n                && isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target\n\n            // user touched pinned view\n            mTouchTarget = mPinnedSection.view;\n            mTouchPoint.x = x;\n            mTouchPoint.y = y;\n\n            // copy down event for eventually be used later\n            mDownEvent = MotionEvent.obtain(ev);\n        }\n\n        if (mTouchTarget != null) {\n            if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view\n                mTouchTarget.dispatchTouchEvent(ev);\n            }\n\n            if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view\n                super.dispatchTouchEvent(ev);\n                performPinnedItemClick();\n                clearTouchTarget();\n\n            } else if (action == MotionEvent.ACTION_CANCEL) { // cancel\n                clearTouchTarget();\n\n            } else if (action == MotionEvent.ACTION_MOVE) {\n                if (Math.abs(y - mTouchPoint.y) > mTouchSlop) {\n\n                    // cancel sequence on touch target\n                    MotionEvent event = MotionEvent.obtain(ev);\n                    event.setAction(MotionEvent.ACTION_CANCEL);\n                    mTouchTarget.dispatchTouchEvent(event);\n                    event.recycle();\n\n                    // provide correct sequence to super class for further handling\n                    super.dispatchTouchEvent(mDownEvent);\n                    super.dispatchTouchEvent(ev);\n                    clearTouchTarget();\n\n                }\n            }\n\n            return true;\n        }\n\n        // call super if this was not our pinned view\n        return super.dispatchTouchEvent(ev);\n    }\n\n    private boolean isPinnedViewTouched(View view, float x, float y) {\n        view.getHitRect(mTouchRect);\n\n        // by taping top or bottom padding, the list performs on click on a border item.\n        // we don't add top padding here to keep behavior consistent.\n        mTouchRect.top += mTranslateY;\n\n        mTouchRect.bottom += mTranslateY + getPaddingTop();\n        mTouchRect.left += getPaddingLeft();\n        mTouchRect.right -= getPaddingRight();\n        return mTouchRect.contains((int)x, (int)y);\n    }\n\n    private void clearTouchTarget() {\n        mTouchTarget = null;\n        if (mDownEvent != null) {\n            mDownEvent.recycle();\n            mDownEvent = null;\n        }\n    }\n\n    private boolean performPinnedItemClick() {\n        if (mPinnedSection == null) return false;\n\n        OnItemClickListener listener = getOnItemClickListener();\n        if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) {\n            View view =  mPinnedSection.view;\n            playSoundEffect(SoundEffectConstants.CLICK);\n            if (view != null) {\n                view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);\n            }\n            listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id);\n            return true;\n        }\n        return false;\n    }\n\n    public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) {\n        if (adapter instanceof HeaderViewListAdapter) {\n            adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();\n        }\n        return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/PositionBar.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n@SuppressLint(\"ClickableViewAccessibility\")\npublic class PositionBar extends LinearLayout {\n\n\tprivate String[] mItems = { \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\",\n\t\t\t\"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\",\n\t\t\t\"V\", \"W\", \"X\", \"Y\", \"Z\" };\n\n\tprivate OnPositionChangedListener listener;\n\n\tpublic void setOnPositionChangedListener(OnPositionChangedListener listener) {\n\t\tthis.listener = listener;\n\t}\n\n\tpublic PositionBar(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t\t\n\t\tsetOrientation(VERTICAL);\n\t\tsetBackgroundResource(R.drawable.cirrect_5a_primary_solid);\n\t}\n\t\n\tpublic void setItems(String[] items) {\n\t\tmItems = items;\n\t\tfor (CharSequence s : mItems) {\n\t\t\tTextView t = new TextView(getContext());\n\t\t\tt.setText(s);\n\t\t\tt.setTextSize(10);\n\t\t\tLayoutParams params = new LayoutParams(\n\t\t\t\t\tViewGroup.LayoutParams.WRAP_CONTENT, 0);\n\t\t\tparams.weight = 1;\n\t\t\tt.setLayoutParams(params);\n\t\t\tt.setTextColor(getResources().getColor(R.color.txt_black));\n\t\t\taddView(t);\n\t\t}\n\t}\n\n\tpublic String[] getItems() {\n\t\treturn mItems;\n\t}\n\n\tpublic PositionBar(Context context) {\n\t\tthis(context, null);\n\t}\n\n\t@Override\n\tpublic boolean onTouchEvent(MotionEvent ev) {\n\t\tfinal int action = ev.getAction();\n\t\tTextView child = null;\n\n\t\tswitch (action & MotionEvent.ACTION_MASK) {\n\t\tcase MotionEvent.ACTION_DOWN:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_10a_primary_solid);\n\t\t\tchild = findChildByLocation(ev.getX(), ev.getY());\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(child==null?\"\":child.getText().toString());\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MotionEvent.ACTION_MOVE:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_10a_primary_solid);\n\t\t\tchild = findChildByLocation(ev.getX(), ev.getY());\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(child==null?\"\":child.getText().toString());\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MotionEvent.ACTION_UP:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_5a_primary_solid);\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(\"\");\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate TextView findChildByLocation(float x, float y) {\n\t\tTextView child = null;\n\t\tint mContentTop = getChildAt(0).getTop();\n\t\tint mContentBottom = getChildAt(getChildCount() - 1).getBottom();\n\t\tint defSize = (mContentBottom - mContentTop) / mItems.length;\n\n\t\tint index = (int) ((y - mContentTop) / defSize);\n\t\tif (index >= 0 && index < mItems.length\n\t\t\t\t&& x >= 0 && x <= getWidth()) {\n\t\t\tchild = (TextView) getChildAt(index);\n\t\t}\n\t\treturn child;\n\t}\n\n\tpublic interface OnPositionChangedListener {\n\t\tvoid onPositionSelected(String key);\n\t}\n\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightGridView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.GridView;\n\npublic class WrapHeightGridView extends GridView {\n\n    public WrapHeightGridView(Context context) {\n        super(context);\n    }\n\n    public WrapHeightGridView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public WrapHeightGridView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int heightSpec = MeasureSpec.makeMeasureSpec(\n                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);\n\n        super.onMeasure(widthMeasureSpec, heightSpec);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightLinearLayoutManager.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * 用作wrap_content的RecyclerView\n */\npublic class WrapHeightLinearLayoutManager extends LinearLayoutManager {\n\n    public WrapHeightLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {\n        super(context, orientation, reverseLayout);\n    }\n\n    private int[] mMeasuredDimension = new int[2];\n\n    @Override\n    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,\n                          int widthSpec, int heightSpec) {\n        final int widthMode = View.MeasureSpec.getMode(widthSpec);\n        final int heightMode = View.MeasureSpec.getMode(heightSpec);\n        final int widthSize = View.MeasureSpec.getSize(widthSpec);\n        final int heightSize = View.MeasureSpec.getSize(heightSpec);\n        int width = 0;\n        int height = 0;\n        for (int i = 0; i < getItemCount(); i++) {\n            measureScrapChild(recycler, i,\n                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),\n                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),\n                    mMeasuredDimension);\n\n            if (getOrientation() == HORIZONTAL) {\n                width = width + mMeasuredDimension[0];\n                if (i == 0) {\n                    height = mMeasuredDimension[1];\n                }\n            } else {\n                height = height + mMeasuredDimension[1];\n                if (i == 0) {\n                    width = mMeasuredDimension[0];\n                }\n            }\n        }\n        switch (widthMode) {\n            case View.MeasureSpec.EXACTLY:\n                width = widthSize;\n            case View.MeasureSpec.AT_MOST:\n            case View.MeasureSpec.UNSPECIFIED:\n        }\n\n        switch (heightMode) {\n            case View.MeasureSpec.EXACTLY:\n                height = heightSize;\n            case View.MeasureSpec.AT_MOST:\n            case View.MeasureSpec.UNSPECIFIED:\n        }\n\n        setMeasuredDimension(width, height);\n    }\n\n    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,\n                                   int heightSpec, int[] measuredDimension) {\n        View view = recycler.getViewForPosition(position);\n        if (view != null) {\n            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();\n            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,\n                    getPaddingLeft() + getPaddingRight(), p.width);\n            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,\n                    getPaddingTop() + getPaddingBottom(), p.height);\n            view.measure(childWidthSpec, childHeightSpec);\n            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;\n            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;\n            recycler.recycleView(view);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightListView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.ListView;\n\npublic class WrapHeightListView extends ListView {\n\n    public WrapHeightListView(Context context) {\n        super(context);\n    }\n\n    public WrapHeightListView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public WrapHeightListView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int heightSpec = MeasureSpec.makeMeasureSpec(\n                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);\n\n        super.onMeasure(widthMeasureSpec, heightSpec);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/ItemsRange.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Range for visible items.\n */\npublic class ItemsRange {\n\t// First item number\n\tprivate int first;\n\t\n\t// Items count\n\tprivate int count;\n\n\t/**\n\t * Default constructor. Creates an empty range\n\t */\n    public ItemsRange() {\n        this(0, 0);\n    }\n    \n\t/**\n\t * Constructor\n\t * @param first the number of first item\n\t * @param count the count of items\n\t */\n\tpublic ItemsRange(int first, int count) {\n\t\tthis.first = first;\n\t\tthis.count = count;\n\t}\n\t\n\t/**\n\t * Gets number of  first item\n\t * @return the number of the first item\n\t */\n\tpublic int getFirst() {\n\t\treturn first;\n\t}\n\t\n\t/**\n\t * Gets number of last item\n\t * @return the number of last item\n\t */\n\tpublic int getLast() {\n\t\treturn getFirst() + getCount() - 1;\n\t}\n\t\n\t/**\n\t * Get items count\n\t * @return the count of items\n\t */\n\tpublic int getCount() {\n\t\treturn count;\n\t}\n\t\n\t/**\n\t * Tests whether item is contained by range\n\t * @param index the item number\n\t * @return true if item is contained\n\t */\n\tpublic boolean contains(int index) {\n\t\treturn index >= getFirst() && index <= getLast();\n\t}\n}"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelChangedListener.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel changed listener interface.\n * <p>The onChanged() method is called whenever current wheel positions is changed:\n * <li> New Wheel position is set\n * <li> Wheel view is scrolled\n */\npublic interface OnWheelChangedListener {\n\t/**\n\t * Callback method to be invoked when current item changed\n\t * @param wheel the wheel view whose state has changed\n\t * @param oldValue the old value of current item\n\t * @param newValue the new value of current item\n\t */\n\tvoid onChanged(WheelView wheel, int oldValue, int newValue);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelClickedListener.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel clicked listener interface.\n * <p>The onItemClicked() method is called whenever a wheel item is clicked\n * <li> New Wheel position is set\n * <li> Wheel view is scrolled\n */\npublic interface OnWheelClickedListener {\n    /**\n     * Callback method to be invoked when current item clicked\n     * @param wheel the wheel view\n     * @param itemIndex the index of clicked item\n     */\n    void onItemClicked(WheelView wheel, int itemIndex);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelScrollListener.java",
    "content": "/*\n *  Copyright 2010 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel scrolled listener interface.\n */\npublic interface OnWheelScrollListener {\n\t/**\n\t * Callback method to be invoked when scrolling started.\n\t * @param wheel the wheel view whose state has changed.\n\t */\n\tvoid onScrollingStarted(WheelView wheel);\n\t\n\t/**\n\t * Callback method to be invoked when scrolling ended.\n\t * @param wheel the wheel view whose state has changed.\n\t */\n\tvoid onScrollingFinished(WheelView wheel);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelAdapter.java",
    "content": "/*\n *  Copyright 2010 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel adapter interface\n * \n * @deprecated Use WheelViewAdapter\n */\npublic interface WheelAdapter {\n\t/**\n\t * Gets items count\n\t * @return the count of wheel items\n\t */\n\tpublic int getItemsCount();\n\t\n\t/**\n\t * Gets a wheel item by index.\n\t * \n\t * @param index the item index\n\t * @return the wheel item text or null\n\t */\n\tpublic String getItem(int index);\n\t\n\t/**\n\t * Gets maximum item length. It is used to determine the wheel width. \n\t * If -1 is returned there will be used the default wheel width.\n\t * \n\t * @return the maximum item length or -1\n\t */\n\tpublic int getMaximumLength();\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelRecycle.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.view.View;\nimport android.widget.LinearLayout;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Recycle stores wheel items to reuse. \n */\npublic class WheelRecycle {\n\t// Cached items\n\tprivate List<View> items;\n\t\n\t// Cached empty items\n\tprivate List<View> emptyItems;\n\t\n\t// Wheel view\n\tprivate WheelView wheel;\n\t\n\t/**\n\t * Constructor\n\t * @param wheel the wheel view\n\t */\n\tpublic WheelRecycle(WheelView wheel) {\n\t\tthis.wheel = wheel;\n\t}\n\n\t/**\n\t * Recycles items from specified layout.\n\t * There are saved only items not included to specified range.\n\t * All the cached items are removed from original layout.\n\t * \n\t * @param layout the layout containing items to be cached\n\t * @param firstItem the number of first item in layout\n\t * @param range the range of current wheel items \n\t * @return the new value of first item number\n\t */\n\tpublic int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) {\n\t\tint index = firstItem;\n\t\tfor (int i = 0; i < layout.getChildCount();) {\n\t\t\tif (!range.contains(index)) {\n\t\t\t\trecycleView(layout.getChildAt(i), index);\n\t\t\t\tlayout.removeViewAt(i);\n\t\t\t\tif (i == 0) { // first item\n\t\t\t\t\tfirstItem++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ti++; // go to next item\n\t\t\t}\n\t\t\tindex++;\n\t\t}\n\t\treturn firstItem;\n\t}\n\t\n\t/**\n\t * Gets item view\n\t * @return the cached view\n\t */\n\tpublic View getItem() {\n\t\treturn getCachedView(items);\n\t}\n\n\t/**\n\t * Gets empty item view\n\t * @return the cached empty view\n\t */\n\tpublic View getEmptyItem() {\n\t\treturn getCachedView(emptyItems);\n\t}\n\t\n\t/**\n\t * Clears all views \n\t */\n\tpublic void clearAll() {\n\t\tif (items != null) {\n\t\t\titems.clear();\n\t\t}\n\t\tif (emptyItems != null) {\n\t\t\temptyItems.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Adds view to specified cache. Creates a cache list if it is null.\n\t * @param view the view to be cached\n\t * @param cache the cache list\n\t * @return the cache list\n\t */\n\tprivate List<View> addView(View view, List<View> cache) {\n\t\tif (cache == null) {\n\t\t\tcache = new LinkedList<View>();\n\t\t}\n\t\t\n\t\tcache.add(view);\n\t\treturn cache;\n\t}\n\n\t/**\n\t * Adds view to cache. Determines view type (item view or empty one) by index.\n\t * @param view the view to be cached\n\t * @param index the index of view\n\t */\n\tprivate void recycleView(View view, int index) {\n\t\tint count = wheel.getViewAdapter().getItemsCount();\n\n\t\tif ((index < 0 || index >= count) && !wheel.isCyclic()) {\n\t\t\t// empty view\n\t\t\temptyItems = addView(view, emptyItems);\n\t\t} else {\n\t\t\twhile (index < 0) {\n\t\t\t\tindex = count + index;\n\t\t\t}\n\t\t\tindex %= count;\n\t\t\titems = addView(view, items);\n\t\t}\n\t}\n\t\n\t/**\n\t * Gets view from specified cache.\n\t * @param cache the cache\n\t * @return the first view from cache.\n\t */\n\tprivate View getCachedView(List<View> cache) {\n\t\tif (cache != null && cache.size() > 0) {\n\t\t\tView view = cache.get(0);\n\t\t\tcache.remove(0);\n\t\t\treturn view;\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelScroller.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\nimport android.view.GestureDetector.SimpleOnGestureListener;\nimport android.view.animation.Interpolator;\nimport android.widget.Scroller;\n\n/**\n * Scroller class handles scrolling events and updates the \n */\npublic class WheelScroller {\n    /**\n     * Scrolling listener interface\n     */\n    public interface ScrollingListener {\n        /**\n         * Scrolling callback called when scrolling is performed.\n         * @param distance the distance to scroll\n         */\n        void onScroll(int distance);\n\n        /**\n         * Starting callback called when scrolling is started\n         */\n        void onStarted();\n        \n        /**\n         * Finishing callback called after justifying\n         */\n        void onFinished();\n        \n        /**\n         * Justifying callback called to justify a view when scrolling is ended\n         */\n        void onJustify();\n    }\n    \n    /** Scrolling duration */\n    private static final int SCROLLING_DURATION = 400;\n\n    /** Minimum delta for scrolling */\n    public static final int MIN_DELTA_FOR_SCROLLING = 1;\n\n    // Listener\n    private ScrollingListener listener;\n    \n    // Context\n    private Context context;\n    \n    // Scrolling\n    private GestureDetector gestureDetector;\n    private Scroller scroller;\n    private int lastScrollY;\n    private float lastTouchedY;\n    private boolean isScrollingPerformed;\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param listener the scrolling listener\n     */\n    public WheelScroller(Context context, ScrollingListener listener) {\n        gestureDetector = new GestureDetector(context, gestureListener);\n        gestureDetector.setIsLongpressEnabled(false);\n        \n        scroller = new Scroller(context);\n\n        this.listener = listener;\n        this.context = context;\n    }\n    \n    /**\n     * Set the the specified scrolling interpolator\n     * @param interpolator the interpolator\n     */\n    public void setInterpolator(Interpolator interpolator) {\n        scroller.forceFinished(true);\n        scroller = new Scroller(context, interpolator);\n    }\n    \n    /**\n     * Scroll the wheel\n     * @param distance the scrolling distance\n     * @param time the scrolling duration\n     */\n    public void scroll(int distance, int time) {\n        scroller.forceFinished(true);\n\n        lastScrollY = 0;\n        \n        scroller.startScroll(0, 0, 0, distance, time != 0 ? time : SCROLLING_DURATION);\n        setNextMessage(MESSAGE_SCROLL);\n        \n        startScrolling();\n    }\n   \n    /**\n     * Stops scrolling\n     */\n    public void stopScrolling() {\n        scroller.forceFinished(true);\n    }\n    \n    /**\n     * Handles Touch event \n     * @param event the motion event\n     * @return\n     */\n    public boolean onTouchEvent(MotionEvent event) {\n        switch (event.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n                lastTouchedY = event.getY();\n                scroller.forceFinished(true);\n                clearMessages();\n                break;\n    \n            case MotionEvent.ACTION_MOVE:\n                // perform scrolling\n                int distanceY = (int)(event.getY() - lastTouchedY);\n                if (distanceY != 0) {\n                    startScrolling();\n                    listener.onScroll(distanceY);\n                    lastTouchedY = event.getY();\n                }\n                break;\n        }\n        \n        if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {\n            justify();\n        }\n\n        return true;\n    }\n    \n    // gesture listener\n    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {\n        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {\n            // Do scrolling in onTouchEvent() since onScroll() are not call immediately\n            //  when user touch and move the wheel\n            return true;\n        }\n        \n        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {\n            lastScrollY = 0;\n            final int maxY = 0x7FFFFFFF;\n            final int minY = -maxY;\n            scroller.fling(0, lastScrollY, 0, (int) -velocityY, 0, 0, minY, maxY);\n            setNextMessage(MESSAGE_SCROLL);\n            return true;\n        }\n    };\n\n    // Messages\n    private final int MESSAGE_SCROLL = 0;\n    private final int MESSAGE_JUSTIFY = 1;\n    \n    /**\n     * Set next message to queue. Clears queue before.\n     * \n     * @param message the message to set\n     */\n    private void setNextMessage(int message) {\n        clearMessages();\n        animationHandler.sendEmptyMessage(message);\n    }\n\n    /**\n     * Clears messages from queue\n     */\n    private void clearMessages() {\n        animationHandler.removeMessages(MESSAGE_SCROLL);\n        animationHandler.removeMessages(MESSAGE_JUSTIFY);\n    }\n    \n    // animation handler\n    private Handler animationHandler = new Handler() {\n        public void handleMessage(Message msg) {\n            scroller.computeScrollOffset();\n            int currY = scroller.getCurrY();\n            int delta = lastScrollY - currY;\n            lastScrollY = currY;\n            if (delta != 0) {\n                listener.onScroll(delta);\n            }\n            \n            // scrolling is not finished when it comes to final Y\n            // so, finish it manually \n            if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {\n                currY = scroller.getFinalY();\n                scroller.forceFinished(true);\n            }\n            if (!scroller.isFinished()) {\n                animationHandler.sendEmptyMessage(msg.what);\n            } else if (msg.what == MESSAGE_SCROLL) {\n                justify();\n            } else {\n                finishScrolling();\n            }\n        }\n    };\n    \n    /**\n     * Justifies wheel\n     */\n    private void justify() {\n        listener.onJustify();\n        setNextMessage(MESSAGE_JUSTIFY);\n    }\n\n    /**\n     * Starts scrolling\n     */\n    private void startScrolling() {\n        if (!isScrollingPerformed) {\n            isScrollingPerformed = true;\n            listener.onStarted();\n        }\n    }\n\n    /**\n     * Finishes scrolling\n     */\n    void finishScrolling() {\n        if (isScrollingPerformed) {\n            listener.onFinished();\n            isScrollingPerformed = false;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelView.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n * \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.content.Context;\nimport android.database.DataSetObserver;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.GradientDrawable;\nimport android.graphics.drawable.GradientDrawable.Orientation;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup.LayoutParams;\nimport android.view.animation.Interpolator;\nimport android.widget.LinearLayout;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.view.wheel.adapters.WheelViewAdapter;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Numeric wheel view.\n * \n * @author Yuri Kanivets\n */\npublic class WheelView extends View {\n\n\t/** Top and bottom shadows colors */\n\t/*/ Modified by wulianghuan 2014-11-25\n\tprivate int[] SHADOWS_COLORS = new int[] { 0xFF111111,\n\t\t\t0x00AAAAAA, 0x00AAAAAA };\n\t//*/\n\tprivate int[] SHADOWS_COLORS = new int[] { 0xefE9E9E9,\n\t\t\t0xcfE9E9E9, 0x3fE9E9E9 };\n\n\t/** Top and bottom items offset (to hide that) */\n\tprivate static final int ITEM_OFFSET_PERCENT = 0;\n\n\t/** Left and right padding value */\n\tprivate static final int PADDING = 10;\n\n\t/** Default count of visible items */\n\tprivate static final int DEF_VISIBLE_ITEMS = 5;\n\n\t// Wheel Values\n\tprivate int currentItem = 0;\n\n\t// Count of visible items\n\tprivate int visibleItems = DEF_VISIBLE_ITEMS;\n\n\t// Item height\n\tprivate int itemHeight = 0;\n\n\t// Center Line\n\tprivate Drawable centerDrawable;\n\n\t// Wheel drawables\n\tprivate int wheelBackground = R.drawable.wheel_bg;\n\tprivate int wheelForeground = R.drawable.wheel_val;\n\n\t// Shadows drawables\n\tprivate GradientDrawable topShadow;\n\tprivate GradientDrawable bottomShadow;\n\n\t// Draw Shadows\n\tprivate boolean drawShadows = true;\n\n\t// Scrolling\n\tprivate WheelScroller scroller;\n\tprivate boolean isScrollingPerformed;\n\tprivate int scrollingOffset;\n\n\t// Cyclic\n\tboolean isCyclic = false;\n\n\t// Items layout\n\tprivate LinearLayout itemsLayout;\n\n\t// The number of first item in layout\n\tprivate int firstItem;\n\n\t// View adapter\n\tprivate WheelViewAdapter viewAdapter;\n\n\t// Recycle\n\tprivate WheelRecycle recycle = new WheelRecycle(this);\n\n\t// Listeners\n\tprivate List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();\n\tprivate List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();\n\tprivate List<OnWheelClickedListener> clickingListeners = new LinkedList<OnWheelClickedListener>();\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context, AttributeSet attrs, int defStyle) {\n\t\tsuper(context, attrs, defStyle);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context) {\n\t\tsuper(context);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Initializes class data\n\t * @param context the context\n\t */\n\tprivate void initData(Context context) {\n\t\tscroller = new WheelScroller(getContext(), scrollingListener);\n\t}\n\n\t// Scrolling listener\n\tWheelScroller.ScrollingListener scrollingListener = new WheelScroller.ScrollingListener() {\n\t\t@Override\n\t\tpublic void onStarted() {\n\t\t\tisScrollingPerformed = true;\n\t\t\tnotifyScrollingListenersAboutStart();\n\t\t}\n\n\t\t@Override\n\t\tpublic void onScroll(int distance) {\n\t\t\tdoScroll(distance);\n\n\t\t\tint height = getHeight();\n\t\t\tif (scrollingOffset > height) {\n\t\t\t\tscrollingOffset = height;\n\t\t\t\tscroller.stopScrolling();\n\t\t\t} else if (scrollingOffset < -height) {\n\t\t\t\tscrollingOffset = -height;\n\t\t\t\tscroller.stopScrolling();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void onFinished() {\n\t\t\tif (isScrollingPerformed) {\n\t\t\t\tnotifyScrollingListenersAboutEnd();\n\t\t\t\tisScrollingPerformed = false;\n\t\t\t}\n\n\t\t\tscrollingOffset = 0;\n\t\t\tinvalidate();\n\t\t}\n\n\t\t@Override\n\t\tpublic void onJustify() {\n\t\t\tif (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) {\n\t\t\t\tscroller.scroll(scrollingOffset, 0);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Set the the specified scrolling interpolator\n\t * @param interpolator the interpolator\n\t */\n\tpublic void setInterpolator(Interpolator interpolator) {\n\t\tscroller.setInterpolator(interpolator);\n\t}\n\n\t/**\n\t * Gets count of visible items\n\t * \n\t * @return the count of visible items\n\t */\n\tpublic int getVisibleItems() {\n\t\treturn visibleItems;\n\t}\n\n\t/**\n\t * Sets the desired count of visible items.\n\t * Actual amount of visible items depends on wheel layout parameters.\n\t * To apply changes and rebuild view call measure().\n\t * \n\t * @param count the desired count for visible items\n\t */\n\tpublic void setVisibleItems(int count) {\n\t\tvisibleItems = count;\n\t}\n\n\t/**\n\t * Gets view adapter\n\t * @return the view adapter\n\t */\n\tpublic WheelViewAdapter getViewAdapter() {\n\t\treturn viewAdapter;\n\t}\n\n\t// Adapter listener\n\tprivate DataSetObserver dataObserver = new DataSetObserver() {\n\t\t@Override\n\t\tpublic void onChanged() {\n\t\t\tinvalidateWheel(false);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onInvalidated() {\n\t\t\tinvalidateWheel(true);\n\t\t}\n\t};\n\n\t/**\n\t * Sets view adapter. Usually new adapters contain different views, so\n\t * it needs to rebuild view by calling measure().\n\t * \n\t * @param viewAdapter the view adapter\n\t */\n\tpublic void setViewAdapter(WheelViewAdapter viewAdapter) {\n\t\tif (this.viewAdapter != null) {\n\t\t\tthis.viewAdapter.unregisterDataSetObserver(dataObserver);\n\t\t}\n\t\tthis.viewAdapter = viewAdapter;\n\t\tif (this.viewAdapter != null) {\n\t\t\tthis.viewAdapter.registerDataSetObserver(dataObserver);\n\t\t}\n\n\t\tinvalidateWheel(true);\n\t}\n\n\t/**\n\t * Adds wheel changing listener\n\t * @param listener the listener\n\t */\n\tpublic void addChangingListener(OnWheelChangedListener listener) {\n\t\tchangingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel changing listener\n\t * @param listener the listener\n\t */\n\tpublic void removeChangingListener(OnWheelChangedListener listener) {\n\t\tchangingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies changing listeners\n\t * @param oldValue the old wheel value\n\t * @param newValue the new wheel value\n\t */\n\tprotected void notifyChangingListeners(int oldValue, int newValue) {\n\t\tfor (OnWheelChangedListener listener : changingListeners) {\n\t\t\tlistener.onChanged(this, oldValue, newValue);\n\t\t}\n\t}\n\n\t/**\n\t * Adds wheel scrolling listener\n\t * @param listener the listener\n\t */\n\tpublic void addScrollingListener(OnWheelScrollListener listener) {\n\t\tscrollingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel scrolling listener\n\t * @param listener the listener\n\t */\n\tpublic void removeScrollingListener(OnWheelScrollListener listener) {\n\t\tscrollingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies listeners about starting scrolling\n\t */\n\tprotected void notifyScrollingListenersAboutStart() {\n\t\tfor (OnWheelScrollListener listener : scrollingListeners) {\n\t\t\tlistener.onScrollingStarted(this);\n\t\t}\n\t}\n\n\t/**\n\t * Notifies listeners about ending scrolling\n\t */\n\tprotected void notifyScrollingListenersAboutEnd() {\n\t\tfor (OnWheelScrollListener listener : scrollingListeners) {\n\t\t\tlistener.onScrollingFinished(this);\n\t\t}\n\t}\n\n\t/**\n\t * Adds wheel clicking listener\n\t * @param listener the listener\n\t */\n\tpublic void addClickingListener(OnWheelClickedListener listener) {\n\t\tclickingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel clicking listener\n\t * @param listener the listener\n\t */\n\tpublic void removeClickingListener(OnWheelClickedListener listener) {\n\t\tclickingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies listeners about clicking\n\t */\n\tprotected void notifyClickListenersAboutClick(int item) {\n\t\tfor (OnWheelClickedListener listener : clickingListeners) {\n\t\t\tlistener.onItemClicked(this, item);\n\t\t}\n\t}\n\n\t/**\n\t * Gets current value\n\t * \n\t * @return the current value\n\t */\n\tpublic int getCurrentItem() {\n\t\treturn currentItem;\n\t}\n\n\t/**\n\t * Sets the current item. Does nothing when index is wrong.\n\t * \n\t * @param index the item index\n\t * @param animated the animation flag\n\t */\n\tpublic void setCurrentItem(int index, boolean animated) {\n\t\tif (viewAdapter == null || viewAdapter.getItemsCount() == 0) {\n\t\t\treturn; // throw?\n\t\t}\n\n\t\tint itemCount = viewAdapter.getItemsCount();\n\t\tif (index < 0 || index >= itemCount) {\n\t\t\tif (isCyclic) {\n\t\t\t\twhile (index < 0) {\n\t\t\t\t\tindex += itemCount;\n\t\t\t\t}\n\t\t\t\tindex %= itemCount;\n\t\t\t} else{\n\t\t\t\treturn; // throw?\n\t\t\t}\n\t\t}\n\t\tif (index != currentItem) {\n\t\t\tif (animated) {\n\t\t\t\tint itemsToScroll = index - currentItem;\n\t\t\t\tif (isCyclic) {\n\t\t\t\t\tint scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem);\n\t\t\t\t\tif (scroll < Math.abs(itemsToScroll)) {\n\t\t\t\t\t\titemsToScroll = itemsToScroll < 0 ? scroll : -scroll;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscroll(itemsToScroll, 0);\n\t\t\t} else {\n\t\t\t\tscrollingOffset = 0;\n\n\t\t\t\tint old = currentItem;\n\t\t\t\tcurrentItem = index;\n\n\t\t\t\tnotifyChangingListeners(old, currentItem);\n\n\t\t\t\tinvalidate();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Sets the current item w/o animation. Does nothing when index is wrong.\n\t * \n\t * @param index the item index\n\t */\n\tpublic void setCurrentItem(int index) {\n\t\tsetCurrentItem(index, false);\n\t}\n\n\t/**\n\t * Tests if wheel is cyclic. That means before the 1st item there is shown the last one\n\t * @return true if wheel is cyclic\n\t */\n\tpublic boolean isCyclic() {\n\t\treturn isCyclic;\n\t}\n\n\t/**\n\t * Set wheel cyclic flag\n\t * @param isCyclic the flag to set\n\t */\n\tpublic void setCyclic(boolean isCyclic) {\n\t\tthis.isCyclic = isCyclic;\n\t\tinvalidateWheel(false);\n\t}\n\n\t/**\n\t * Determine whether shadows are drawn\n\t * @return true is shadows are drawn\n\t */\n\tpublic boolean drawShadows() {\n\t\treturn drawShadows;\n\t}\n\n\t/**\n\t * Set whether shadows should be drawn\n\t * @param drawShadows flag as true or false\n\t */\n\tpublic void setDrawShadows(boolean drawShadows) {\n\t\tthis.drawShadows = drawShadows;\n\t}\n\n\t/**\n\t * Set the shadow gradient color\n\t * @param start\n\t * @param middle\n\t * @param end\n\t */\n\tpublic void setShadowColor(int start, int middle, int end) {\n\t\tSHADOWS_COLORS = new int[] {start, middle, end};\n\t}\n\n\t/**\n\t * Sets the drawable for the wheel background\n\t * @param resource\n\t */\n\tpublic void setWheelBackground(int resource) {\n\t\twheelBackground = resource;\n\t\tsetBackgroundResource(wheelBackground);\n\t}\n\n\t/**\n\t * Sets the drawable for the wheel foreground\n\t * @param resource\n\t */\n\tpublic void setWheelForeground(int resource) {\n\t\twheelForeground = resource;\n\t\tcenterDrawable = getContext().getResources().getDrawable(wheelForeground);\n\t}\n\n\t/**\n\t * Invalidates wheel\n\t * @param clearCaches if true then cached views will be clear\n\t */\n\tpublic void invalidateWheel(boolean clearCaches) {\n\t\tif (clearCaches) {\n\t\t\trecycle.clearAll();\n\t\t\tif (itemsLayout != null) {\n\t\t\t\titemsLayout.removeAllViews();\n\t\t\t}\n\t\t\tscrollingOffset = 0;\n\t\t} else if (itemsLayout != null) {\n\t\t\t// cache all items\n\t\t\trecycle.recycleItems(itemsLayout, firstItem, new ItemsRange());\n\t\t}\n\n\t\tinvalidate();\n\t}\n\n\t/**\n\t * Initializes resources\n\t */\n\tprivate void initResourcesIfNecessary() {\n\t\tif (centerDrawable == null) {\n\t\t\tcenterDrawable = getContext().getResources().getDrawable(wheelForeground);\n\t\t}\n\n\t\tif (topShadow == null) {\n\t\t\ttopShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);\n\t\t}\n\n\t\tif (bottomShadow == null) {\n\t\t\tbottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);\n\t\t}\n\n\t\tsetBackgroundResource(wheelBackground);\n\t}\n\n\t/**\n\t * Calculates desired height for layout\n\t * \n\t * @param layout\n\t *            the source layout\n\t * @return the desired layout height\n\t */\n\tprivate int getDesiredHeight(LinearLayout layout) {\n\t\tif (layout != null && layout.getChildAt(0) != null) {\n\t\t\titemHeight = layout.getChildAt(0).getMeasuredHeight();\n\t\t}\n\n\t\tint desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50;\n\n\t\treturn Math.max(desired, getSuggestedMinimumHeight());\n\t}\n\n\t/**\n\t * Returns height of wheel item\n\t * @return the item height\n\t */\n\tprivate int getItemHeight() {\n\t\tif (itemHeight != 0) {\n\t\t\treturn itemHeight;\n\t\t}\n\n\t\tif (itemsLayout != null && itemsLayout.getChildAt(0) != null) {\n\t\t\titemHeight = itemsLayout.getChildAt(0).getHeight();\n\t\t\treturn itemHeight;\n\t\t}\n\n\t\treturn getHeight() / visibleItems;\n\t}\n\n\t/**\n\t * Calculates control width and creates text layouts\n\t * @param widthSize the input layout width\n\t * @param mode the layout mode\n\t * @return the calculated control width\n\t */\n\tprivate int calculateLayoutWidth(int widthSize, int mode) {\n\t\tinitResourcesIfNecessary();\n\n\t\t// TODO: make it static\n\t\titemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));\n\t\titemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED),\n\t\t\t\tMeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));\n\t\tint width = itemsLayout.getMeasuredWidth();\n\n\t\tif (mode == MeasureSpec.EXACTLY) {\n\t\t\twidth = widthSize;\n\t\t} else {\n\t\t\twidth += 2 * PADDING;\n\n\t\t\t// Check against our minimum width\n\t\t\twidth = Math.max(width, getSuggestedMinimumWidth());\n\n\t\t\tif (mode == MeasureSpec.AT_MOST && widthSize < width) {\n\t\t\t\twidth = widthSize;\n\t\t\t}\n\t\t}\n\n\t\titemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY),\n\t\t\t\tMeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));\n\n\t\treturn width;\n\t}\n\n\t@Override\n\tprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\t\tint widthMode = MeasureSpec.getMode(widthMeasureSpec);\n\t\tint heightMode = MeasureSpec.getMode(heightMeasureSpec);\n\t\tint widthSize = MeasureSpec.getSize(widthMeasureSpec);\n\t\tint heightSize = MeasureSpec.getSize(heightMeasureSpec);\n\n\t\tbuildViewForMeasuring();\n\n\t\tint width = calculateLayoutWidth(widthSize, widthMode);\n\n\t\tint height;\n\t\tif (heightMode == MeasureSpec.EXACTLY) {\n\t\t\theight = heightSize;\n\t\t} else {\n\t\t\theight = getDesiredHeight(itemsLayout);\n\n\t\t\tif (heightMode == MeasureSpec.AT_MOST) {\n\t\t\t\theight = Math.min(height, heightSize);\n\t\t\t}\n\t\t}\n\n\t\tsetMeasuredDimension(width, height);\n\t}\n\n\t@Override\n\tprotected void onLayout(boolean changed, int l, int t, int r, int b) {\n\t\tlayout(r - l, b - t);\n\t}\n\n\t/**\n\t * Sets layouts width and height\n\t * @param width the layout width\n\t * @param height the layout height\n\t */\n\tprivate void layout(int width, int height) {\n\t\tint itemsWidth = width - 2 * PADDING;\n\n\t\titemsLayout.layout(0, 0, itemsWidth, height);\n\t}\n\n\t@Override\n\tprotected void onDraw(Canvas canvas) {\n\t\tsuper.onDraw(canvas);\n\n\t\tif (viewAdapter != null && viewAdapter.getItemsCount() > 0) {\n\t\t\tupdateView();\n\n\t\t\tdrawItems(canvas);\n\t\t\tdrawCenterRect(canvas);\n\t\t}\n\n\t\tif (drawShadows) drawShadows(canvas);\n\t}\n\n\t/**\n\t * Draws shadows on top and bottom of control\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawShadows(Canvas canvas) {\n\t\t/*/ Modified by wulianghuan 2014-11-25\n\t\tint height = (int)(1.5 * getItemHeight());\n\t\t//*/\n\t\tint height = (int)(3 * getItemHeight());\n\t\t//*/\n\t\ttopShadow.setBounds(0, 0, getWidth(), height);\n\t\ttopShadow.draw(canvas);\n\n\t\tbottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());\n\t\tbottomShadow.draw(canvas);\n\t}\n\n\t/**\n\t * Draws items\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawItems(Canvas canvas) {\n\t\tcanvas.save();\n\n\t\tint top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2;\n\t\tcanvas.translate(PADDING, - top + scrollingOffset);\n\n\t\titemsLayout.draw(canvas);\n\n\t\tcanvas.restore();\n\t}\n\n\t/**\n\t * Draws rect for current value\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawCenterRect(Canvas canvas) {\n\t\tint center = getHeight() / 2;\n\t\tint offset = (int) (getItemHeight() / 2 * 1.2);\n\t\t/*/ Remarked by wulianghuan 2014-11-27  使用自己的画线，而不是描边\n\t\tRect rect = new Rect(left, top, right, bottom)\n\t\tcenterDrawable.setBounds(bounds)\n\t\tcenterDrawable.setBounds(0, center - offset, getWidth(), center + offset);\n\t\tcenterDrawable.draw(canvas);\n\t\t//*/\n\t\tPaint paint = new Paint();\n\t\tpaint.setColor(getResources().getColor(R.color.province_line_border));\n\t\t// 设置线宽\n\t\tpaint.setStrokeWidth((float) 3);\n\t\t// 绘制上边直线\n\t\tcanvas.drawLine(0, center - offset, getWidth(), center - offset, paint);\n\t\t// 绘制下边直线\n\t\tcanvas.drawLine(0, center + offset, getWidth(), center + offset, paint);\n\t\t//*/\n\t}\n\n\t@Override\n\tpublic boolean onTouchEvent(MotionEvent event) {\n\t\tif (!isEnabled() || getViewAdapter() == null) {\n\t\t\treturn true;\n\t\t}\n\n\t\tswitch (event.getAction()) {\n\t\t\tcase MotionEvent.ACTION_MOVE:\n\t\t\t\tif (getParent() != null) {\n\t\t\t\t\tgetParent().requestDisallowInterceptTouchEvent(true);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase MotionEvent.ACTION_UP:\n\t\t\t\tif (!isScrollingPerformed) {\n\t\t\t\t\tint distance = (int) event.getY() - getHeight() / 2;\n\t\t\t\t\tif (distance > 0) {\n\t\t\t\t\t\tdistance += getItemHeight() / 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdistance -= getItemHeight() / 2;\n\t\t\t\t\t}\n\t\t\t\t\tint items = distance / getItemHeight();\n\t\t\t\t\tif (items != 0 && isValidItemIndex(currentItem + items)) {\n\t\t\t\t\t\tnotifyClickListenersAboutClick(currentItem + items);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn scroller.onTouchEvent(event);\n\t}\n\n\t/**\n\t * Scrolls the wheel\n\t * @param delta the scrolling value\n\t */\n\tprivate void doScroll(int delta) {\n\t\tscrollingOffset += delta;\n\n\t\tint itemHeight = getItemHeight();\n\t\tint count = scrollingOffset / itemHeight;\n\n\t\tint pos = currentItem - count;\n\t\tint itemCount = viewAdapter.getItemsCount();\n\n\t\tint fixPos = scrollingOffset % itemHeight;\n\t\tif (Math.abs(fixPos) <= itemHeight / 2) {\n\t\t\tfixPos = 0;\n\t\t}\n\t\tif (isCyclic && itemCount > 0) {\n\t\t\tif (fixPos > 0) {\n\t\t\t\tpos--;\n\t\t\t\tcount++;\n\t\t\t} else if (fixPos < 0) {\n\t\t\t\tpos++;\n\t\t\t\tcount--;\n\t\t\t}\n\t\t\t// fix position by rotating\n\t\t\twhile (pos < 0) {\n\t\t\t\tpos += itemCount;\n\t\t\t}\n\t\t\tpos %= itemCount;\n\t\t} else {\n\t\t\t//\n\t\t\tif (pos < 0) {\n\t\t\t\tcount = currentItem;\n\t\t\t\tpos = 0;\n\t\t\t} else if (pos >= itemCount) {\n\t\t\t\tcount = currentItem - itemCount + 1;\n\t\t\t\tpos = itemCount - 1;\n\t\t\t} else if (pos > 0 && fixPos > 0) {\n\t\t\t\tpos--;\n\t\t\t\tcount++;\n\t\t\t} else if (pos < itemCount - 1 && fixPos < 0) {\n\t\t\t\tpos++;\n\t\t\t\tcount--;\n\t\t\t}\n\t\t}\n\n\t\tint offset = scrollingOffset;\n\t\tif (pos != currentItem) {\n\t\t\tsetCurrentItem(pos, false);\n\t\t} else {\n\t\t\tinvalidate();\n\t\t}\n\n\t\t// update offset\n\t\tscrollingOffset = offset - count * itemHeight;\n\t\tif (scrollingOffset > getHeight()) {\n\t\t\tscrollingOffset = scrollingOffset % getHeight() + getHeight();\n\t\t}\n\t}\n\n\t/**\n\t * Scroll the wheel\n\t * @param itemsToScroll items to scroll\n\t * @param time scrolling duration\n\t */\n\tpublic void scroll(int itemsToScroll, int time) {\n\t\tint distance = itemsToScroll * getItemHeight() - scrollingOffset;\n\t\tscroller.scroll(distance, time);\n\t}\n\n\t/**\n\t * Calculates range for wheel items\n\t * @return the items range\n\t */\n\tprivate ItemsRange getItemsRange() {\n\t\tif (getItemHeight() == 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tint first = currentItem;\n\t\tint count = 1;\n\n\t\twhile (count * getItemHeight() < getHeight()) {\n\t\t\tfirst--;\n\t\t\tcount += 2; // top + bottom items\n\t\t}\n\n\t\tif (scrollingOffset != 0) {\n\t\t\tif (scrollingOffset > 0) {\n\t\t\t\tfirst--;\n\t\t\t}\n\t\t\tcount++;\n\n\t\t\t// process empty items above the first or below the second\n\t\t\tint emptyItems = scrollingOffset / getItemHeight();\n\t\t\tfirst -= emptyItems;\n\t\t\tcount += Math.asin(emptyItems);\n\t\t}\n\t\treturn new ItemsRange(first, count);\n\t}\n\n\t/**\n\t * Rebuilds wheel items if necessary. Caches all unused items.\n\t * \n\t * @return true if items are rebuilt\n\t */\n\tprivate boolean rebuildItems() {\n\t\tboolean updated = false;\n\t\tItemsRange range = getItemsRange();\n\t\tif (itemsLayout != null) {\n\t\t\tint first = recycle.recycleItems(itemsLayout, firstItem, range);\n\t\t\tupdated = firstItem != first;\n\t\t\tfirstItem = first;\n\t\t} else {\n\t\t\tcreateItemsLayout();\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (!updated) {\n\t\t\tupdated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount();\n\t\t}\n\n\t\tif (firstItem > range.getFirst() && firstItem <= range.getLast()) {\n\t\t\tfor (int i = firstItem - 1; i >= range.getFirst(); i--) {\n\t\t\t\tif (!addViewItem(i, true)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfirstItem = i;\n\t\t\t}\n\t\t} else {\n\t\t\tfirstItem = range.getFirst();\n\t\t}\n\n\t\tint first = firstItem;\n\t\tfor (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) {\n\t\t\tif (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) {\n\t\t\t\tfirst++;\n\t\t\t}\n\t\t}\n\t\tfirstItem = first;\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Updates view. Rebuilds items and label if necessary, recalculate items sizes.\n\t */\n\tprivate void updateView() {\n\t\tif (rebuildItems()) {\n\t\t\tcalculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);\n\t\t\tlayout(getWidth(), getHeight());\n\t\t}\n\t}\n\n\t/**\n\t * Creates item layouts if necessary\n\t */\n\tprivate void createItemsLayout() {\n\t\tif (itemsLayout == null) {\n\t\t\titemsLayout = new LinearLayout(getContext());\n\t\t\titemsLayout.setOrientation(LinearLayout.VERTICAL);\n\t\t}\n\t}\n\n\t/**\n\t * Builds view for measuring\n\t */\n\tprivate void buildViewForMeasuring() {\n\t\t// clear all items\n\t\tif (itemsLayout != null) {\n\t\t\trecycle.recycleItems(itemsLayout, firstItem, new ItemsRange());\n\t\t} else {\n\t\t\tcreateItemsLayout();\n\t\t}\n\n\t\t// add views\n\t\tint addItems = visibleItems / 2;\n\t\tfor (int i = currentItem + addItems; i >= currentItem - addItems; i--) {\n\t\t\tif (addViewItem(i, true)) {\n\t\t\t\tfirstItem = i;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Adds view for item to items layout\n\t * @param index the item index\n\t * @param first the flag indicates if view should be first\n\t * @return true if corresponding item exists and is added\n\t */\n\tprivate boolean addViewItem(int index, boolean first) {\n\t\tView view = getItemView(index);\n\t\tif (view != null) {\n\t\t\tif (first) {\n\t\t\t\titemsLayout.addView(view, 0);\n\t\t\t} else {\n\t\t\t\titemsLayout.addView(view);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks whether intem index is valid\n\t * @param index the item index\n\t * @return true if item index is not out of bounds or the wheel is cyclic\n\t */\n\tprivate boolean isValidItemIndex(int index) {\n\t\treturn viewAdapter != null && viewAdapter.getItemsCount() > 0 &&\n\t\t\t\t(isCyclic || index >= 0 && index < viewAdapter.getItemsCount());\n\t}\n\n\t/**\n\t * Returns view for specified item\n\t * @param index the item index\n\t * @return item view or empty view if index is out of bounds\n\t */\n\tprivate View getItemView(int index) {\n\t\tif (viewAdapter == null || viewAdapter.getItemsCount() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tint count = viewAdapter.getItemsCount();\n\t\tif (!isValidItemIndex(index)) {\n\t\t\treturn viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout);\n\t\t} else {\n\t\t\twhile (index < 0) {\n\t\t\t\tindex = count + index;\n\t\t\t}\n\t\t}\n\n\t\tindex %= count;\n\t\treturn viewAdapter.getItem(index, recycle.getItem(), itemsLayout);\n\t}\n\n\t/**\n\t * Stops scrolling\n\t */\n\tpublic void stopScrolling() {\n\t\tscroller.stopScrolling();\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AbstractWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.database.DataSetObserver;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Abstract Wheel adapter.\n */\npublic abstract class AbstractWheelAdapter implements WheelViewAdapter {\n    // Observers\n    private List<DataSetObserver> datasetObservers;\n    \n    @Override\n    public View getEmptyItem(View convertView, ViewGroup parent) {\n        return null;\n    }\n\n    @Override\n    public void registerDataSetObserver(DataSetObserver observer) {\n        if (datasetObservers == null) {\n            datasetObservers = new LinkedList<DataSetObserver>();\n        }\n        datasetObservers.add(observer);\n    }\n\n    @Override\n    public void unregisterDataSetObserver(DataSetObserver observer) {\n        if (datasetObservers != null) {\n            datasetObservers.remove(observer);\n        }\n    }\n    \n    /**\n     * Notifies observers about data changing\n     */\n    protected void notifyDataChangedEvent() {\n        if (datasetObservers != null) {\n            for (DataSetObserver observer : datasetObservers) {\n                observer.onChanged();\n            }\n        }\n    }\n    \n    /**\n     * Notifies observers about invalidating data\n     */\n    protected void notifyDataInvalidatedEvent() {\n        if (datasetObservers != null) {\n            for (DataSetObserver observer : datasetObservers) {\n                observer.onInvalidated();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AbstractWheelTextAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\n/**\n * Abstract wheel adapter provides common functionality for adapters.\n */\npublic abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {\n    \n    /** Text view resource. Used as a default view for adapter. */\n    public static final int TEXT_VIEW_ITEM_RESOURCE = -1;\n    \n    /** No resource constant. */\n    protected static final int NO_RESOURCE = 0;\n    \n    /** Default text color */\n    public static final int DEFAULT_TEXT_COLOR = 0xFF585858;\n    \n    /** Default text color */\n    public static final int LABEL_COLOR = 0xFF700070;\n    \n    /** Default text size */\n    public static final int DEFAULT_TEXT_SIZE = 18;\n    \n    // Text settings\n    private int textColor = DEFAULT_TEXT_COLOR;\n    private int textSize = DEFAULT_TEXT_SIZE;\n    \n    // Current context\n    protected Context context;\n    // Layout inflater\n    protected LayoutInflater inflater;\n    \n    // Items resources\n    protected int itemResourceId;\n    protected int itemTextResourceId;\n    \n    // Empty items resources\n    protected int emptyItemResourceId;\n\t\n    /**\n     * Constructor\n     * @param context the current context\n     */\n    protected AbstractWheelTextAdapter(Context context) {\n        this(context, TEXT_VIEW_ITEM_RESOURCE);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views\n     */\n    protected AbstractWheelTextAdapter(Context context, int itemResource) {\n        this(context, itemResource, NO_RESOURCE);\n    }\n    \n    /**\n     * Constructor\n     * @param context the current context\n     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views\n     * @param itemTextResource the resource ID for a text view in the item layout\n     */\n    protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) {\n        this.context = context;\n        itemResourceId = itemResource;\n        itemTextResourceId = itemTextResource;\n        \n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n    }\n    \n    /**\n     * Gets text color\n     * @return the text color\n     */\n    public int getTextColor() {\n        return textColor;\n    }\n    \n    /**\n     * Sets text color\n     * @param textColor the text color to set\n     */\n    public void setTextColor(int textColor) {\n        this.textColor = textColor;\n    }\n    \n    /**\n     * Gets text size\n     * @return the text size\n     */\n    public int getTextSize() {\n        return textSize;\n    }\n    \n    /**\n     * Sets text size\n     * @param textSize the text size to set\n     */\n    public void setTextSize(int textSize) {\n        this.textSize = textSize;\n    }\n    \n    /**\n     * Gets resource Id for items views\n     * @return the item resource Id\n     */\n    public int getItemResource() {\n        return itemResourceId;\n    }\n    \n    /**\n     * Sets resource Id for items views\n     * @param itemResourceId the resource Id to set\n     */\n    public void setItemResource(int itemResourceId) {\n        this.itemResourceId = itemResourceId;\n    }\n    \n    /**\n     * Gets resource Id for text view in item layout \n     * @return the item text resource Id\n     */\n    public int getItemTextResource() {\n        return itemTextResourceId;\n    }\n    \n    /**\n     * Sets resource Id for text view in item layout \n     * @param itemTextResourceId the item text resource Id to set\n     */\n    public void setItemTextResource(int itemTextResourceId) {\n        this.itemTextResourceId = itemTextResourceId;\n    }\n\n    /**\n     * Gets resource Id for empty items views\n     * @return the empty item resource Id\n     */\n    public int getEmptyItemResource() {\n        return emptyItemResourceId;\n    }\n\n    /**\n     * Sets resource Id for empty items views\n     * @param emptyItemResourceId the empty item resource Id to set\n     */\n    public void setEmptyItemResource(int emptyItemResourceId) {\n        this.emptyItemResourceId = emptyItemResourceId;\n    }\n    \n    \n    /**\n     * Returns text for specified item\n     * @param index the item index\n     * @return the text of specified items\n     */\n    protected abstract CharSequence getItemText(int index);\n\n    @Override\n    public View getItem(int index, View convertView, ViewGroup parent) {\n        if (index >= 0 && index < getItemsCount()) {\n            if (convertView == null) {\n                convertView = getView(itemResourceId, parent);\n            }\n            TextView textView = getTextView(convertView, itemTextResourceId);\n            if (textView != null) {\n                CharSequence text = getItemText(index);\n                if (text == null) {\n                    text = \"\";\n                }\n                textView.setText(text);\n    \n                if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {\n                    configureTextView(textView);\n                }\n            }\n            return convertView;\n        }\n    \treturn null;\n    }\n\n    @Override\n    public View getEmptyItem(View convertView, ViewGroup parent) {\n        if (convertView == null) {\n            convertView = getView(emptyItemResourceId, parent);\n        }\n        if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {\n            configureTextView((TextView)convertView);\n        }\n            \n        return convertView;\n\t}\n\n    /**\n     * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.\n     * @param view the text view to be configured\n     */\n    protected void configureTextView(TextView view) {\n        view.setTextColor(textColor);\n        view.setGravity(Gravity.CENTER);\n        view.setTextSize(textSize);\n        view.setEllipsize(TextUtils.TruncateAt.END);\n        view.setLines(1);\n//        view.setCompoundDrawablePadding(20);\n//        view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);\n    }\n    \n    /**\n     * Loads a text view from view\n     * @param view the text view or layout containing it\n     * @param textResource the text resource Id in layout\n     * @return the loaded text view\n     */\n    private TextView getTextView(View view, int textResource) {\n    \tTextView text = null;\n    \ttry {\n            if (textResource == NO_RESOURCE && view instanceof TextView) {\n                text = (TextView) view;\n            } else if (textResource != NO_RESOURCE) {\n                text = (TextView) view.findViewById(textResource);\n            }\n        } catch (ClassCastException e) {\n            Log.e(\"AbstractWheelAdapter\", \"You must supply a resource ID for a TextView\");\n            throw new IllegalStateException(\n                    \"AbstractWheelAdapter requires the resource ID to be a TextView\", e);\n        }\n        \n        return text;\n    }\n    \n    /**\n     * Loads view from resources\n     * @param resource the resource Id\n     * @return the loaded view or null if resource is not set\n     */\n    private View getView(int resource, ViewGroup parent) {\n        switch (resource) {\n        case NO_RESOURCE:\n            return null;\n        case TEXT_VIEW_ITEM_RESOURCE:\n            return new TextView(context);\n        default:\n            return inflater.inflate(resource, parent, false);    \n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AdapterWheel.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.view.wheel.WheelAdapter;\n\n/**\n * Adapter class for old wheel adapter (deprecated WheelAdapter class).\n * \n * @deprecated Will be removed soon\n */\npublic class AdapterWheel extends AbstractWheelTextAdapter {\n\n    // Source adapter\n    private WheelAdapter adapter;\n    \n    /**\n     * Constructor\n     * @param context the current context\n     * @param adapter the source adapter\n     */\n    public AdapterWheel(Context context, WheelAdapter adapter) {\n        super(context);\n        \n        this.adapter = adapter;\n    }\n\n    /**\n     * Gets original adapter\n     * @return the original adapter\n     */\n    public WheelAdapter getAdapter() {\n        return adapter;\n    }\n    \n    @Override\n    public int getItemsCount() {\n        return adapter.getItemsCount();\n    }\n\n    @Override\n    protected CharSequence getItemText(int index) {\n        return adapter.getItem(index);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/ArrayWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.entity.city.BaseAddressModel;\n\nimport java.util.ArrayList;\n\n/**\n * The simple Array wheel adapter\n *\n * @param <T> the element type\n */\npublic class ArrayWheelAdapter<T> extends AbstractWheelTextAdapter {\n\n    // items\n    private ArrayList<T> items;\n\n    /**\n     * Constructor\n     *\n     * @param context the current context\n     * @param items   the items\n     */\n    public ArrayWheelAdapter(Context context, ArrayList<T> items) {\n        super(context);\n\n        //setEmptyItemResource(TEXT_VIEW_ITEM_RESOURCE);\n        this.items = items;\n    }\n\n    @Override\n    public CharSequence getItemText(int index) {\n        if (index >= 0 && index < items.size()) {\n            T item = items.get(index);\n            if (item instanceof BaseAddressModel) {\n                return ((BaseAddressModel) item).name;\n            } else if(item instanceof String) {\n                return item.toString();\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public int getItemsCount() {\n        return items.size();\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/NumericWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\n\n/**\n * Numeric Wheel adapter.\n */\npublic class NumericWheelAdapter extends AbstractWheelTextAdapter {\n    \n    /** The default min value */\n    public static final int DEFAULT_MAX_VALUE = 9;\n\n    /** The default max value */\n    private static final int DEFAULT_MIN_VALUE = 0;\n    \n    // Values\n    private int minValue;\n    private int maxValue;\n    \n    // format\n    private String format;\n    \n    /**\n     * Constructor\n     * @param context the current context\n     */\n    public NumericWheelAdapter(Context context) {\n        this(context, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param minValue the wheel min value\n     * @param maxValue the wheel max value\n     */\n    public NumericWheelAdapter(Context context, int minValue, int maxValue) {\n        this(context, minValue, maxValue, null);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param minValue the wheel min value\n     * @param maxValue the wheel max value\n     * @param format the format string\n     */\n    public NumericWheelAdapter(Context context, int minValue, int maxValue, String format) {\n        super(context);\n        \n        this.minValue = minValue;\n        this.maxValue = maxValue;\n        this.format = format;\n    }\n\n    @Override\n    public CharSequence getItemText(int index) {\n        if (index >= 0 && index < getItemsCount()) {\n            int value = minValue + index;\n            return format != null ? String.format(format, value) : Integer.toString(value);\n        }\n        return null;\n    }\n\n    @Override\n    public int getItemsCount() {\n        return maxValue - minValue + 1;\n    }    \n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/WheelViewAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.database.DataSetObserver;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * Wheel items adapter interface\n */\npublic interface WheelViewAdapter {\n\t/**\n\t * Gets items count\n\t * @return the count of wheel items\n\t */\n\tpublic int getItemsCount();\n\t\n\t/**\n\t * Get a View that displays the data at the specified position in the data set\n\t * \n\t * @param index the item index\n\t * @param convertView the old view to reuse if possible\n\t * @param parent the parent that this view will eventually be attached to\n\t * @return the wheel item View\n\t */\n\tpublic View getItem(int index, View convertView, ViewGroup parent);\n\n\t/**\n\t * Get a View that displays an empty wheel item placed before the first or after\n\t * the last wheel item.\n\t * \n\t * @param convertView the old view to reuse if possible\n     * @param parent the parent that this view will eventually be attached to\n\t * @return the empty item View\n\t */\n\tpublic View getEmptyItem(View convertView, ViewGroup parent);\n\t\n\t/**\n\t * Register an observer that is called when changes happen to the data used by this adapter.\n\t * @param observer the observer to be registered\n\t */\n\tpublic void registerDataSetObserver(DataSetObserver observer);\n\t\n\t/**\n\t * Unregister an observer that has previously been registered\n\t * @param observer the observer to be unregistered\n\t */\n\tvoid unregisterDataSetObserver(DataSetObserver observer);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/anim/dd_mask_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <alpha\n        android:fromAlpha=\"0\"\n        android:toAlpha=\"1\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/anim/dd_mask_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <alpha\n        android:fromAlpha=\"1\"\n        android:toAlpha=\"0\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/anim/dd_menu_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <translate\n        android:fromYDelta=\"-100%p\"\n        android:toYDelta=\"0\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/anim/dd_menu_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <translate\n        android:fromYDelta=\"0\"\n        android:toYDelta=\"-100%p\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/color/txt_blue2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@color/txt_link_blue\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/color/txt_gray2primarydark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/colorPrimaryDark\" android:state_checked=\"true\" />\n    <item android:color=\"@color/txt_gray\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/color/txt_lgray2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@android:color/white\" android:state_checked=\"true\" />\n    <item android:color=\"@color/txt_light_gray\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/color/txt_primary2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@android:color/white\" android:state_checked=\"true\" />\n    <item android:color=\"@color/colorPrimary\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/color/txt_white2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@android:color/white\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/bg_gray2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@color/bg_gray\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/bg_primary2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/colorPrimaryDark\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@color/colorPrimaryDark\" android:state_pressed=\"true\"/>\n    <item android:drawable=\"@color/colorPrimary\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/bg_primarydark_indicator_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/layerlist_primarydark_indicator\" android:state_checked=\"true\" />\n    <item android:drawable=\"@android:color/transparent\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/bg_tran2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@android:color/transparent\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/bg_white2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@android:color/white\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/cirrect_10a_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/bg_position_bar_down\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/cirrect_5a_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/bg_position_bar_up\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/cirrect_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/correct_gray_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/divider_gray\" />\n\n    <solid android:color=\"@android:color/white\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/correct_primary.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/correct_primary2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/correct_primary_light\" android:state_enabled=\"false\" />\n    <item android:drawable=\"@drawable/correct_primary_dark\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@drawable/correct_primary\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/correct_primary_dark.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimaryDark\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/correct_primary_light.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimaryLight\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/correct_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/correct_primary_stroke2solid_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/correct_primary\" android:state_checked=\"true\" />\n    <item android:drawable=\"@drawable/correct_primary_stroke\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/layerlist_primarydark_indicator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:top=\"28dp\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"@color/colorPrimaryDark\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/oval_primary_light_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@color/colorPrimaryLight\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/oval_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@color/colorPrimary\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/shape_bottom_line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:left=\"-1dp\"\n        android:right=\"-1dp\">\n        <shape>\n            <stroke\n                android:width=\"1dp\"\n                android:color=\"@color/divider_gray\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/shape_oval_primary2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/oval_primary_solid\" android:state_checked=\"true\" />\n\n    <item android:drawable=\"@drawable/shape_oval_white_solid\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/shape_oval_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/transparent\"></solid>\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\"></stroke>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/shape_oval_primary_stroke2solid_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/oval_primary_solid\" android:state_checked=\"true\" />\n\n    <item android:drawable=\"@drawable/shape_oval_primary_stroke\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/shape_oval_red_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/holo_red_dark\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/shape_oval_white_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/white\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/shape_top_line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:bottom=\"-2dp\"\n        android:left=\"-2dp\"\n        android:right=\"-2dp\">\n        <shape>\n            <stroke\n                android:width=\"1dp\"\n                android:color=\"@color/divider_gray\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/wheel_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- \n    Android Wheel Control.\n    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html\n   \n    Copyright 2010 Yuri Kanivets\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/drawable/wheel_val.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- \n    Android Wheel Control.\n    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html\n   \n    Copyright 2010 Yuri Kanivets\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- \n\t<gradient\n\t\tandroid:startColor=\"#70222222\"\n\t\tandroid:centerColor=\"#70222222\"\n\t\tandroid:endColor=\"#70EEEEEE\"\n\t\tandroid:angle=\"90\" />\n\t\t -->\n\n\t<stroke android:width=\"1dp\" android:color=\"#C7C7C7\" /> \n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/activity_image_browser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\">\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/vp_image_brower\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </android.support.v4.view.ViewPager>\n\n    <TextView\n        android:id=\"@+id/tv_image_index\"\n        style=\"@style/TextAppearance.AppCompat.Headline\"\n        android:layout_width=\"88dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginTop=\"8dp\"\n        android:gravity=\"center\"\n        android:padding=\"4dp\"\n        android:text=\"1/9\"\n        android:textColor=\"@android:color/white\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/activity_web_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <WebView\n        android:id=\"@+id/webview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </WebView>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/footer_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\"\n    android:padding=\"@dimen/margin_medium\">\n\n    <ProgressBar\n        android:id=\"@+id/pb_footer_progress\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:indeterminateDuration=\"900\" />\n\n    <TextView\n        android:id=\"@+id/tv_footer_progress\"\n        style=\"@style/TextViewCaption\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"没有更多数据\"\n        android:visibility=\"gone\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/formitem_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        android:id=\"@+id/tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"56dp\"\n        android:gravity=\"center_vertical\"\n        android:layout_centerVertical=\"true\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <EditText\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@null\"\n        android:paddingLeft=\"80dp\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/formitem_select.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        android:id=\"@+id/tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"56dp\"\n        android:layout_centerVertical=\"true\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_mid_container\"\n        android:layout_width=\"match_parent\"\n        android:visibility=\"gone\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"80dp\"\n        android:paddingRight=\"@dimen/margin_large\">\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:paddingLeft=\"80dp\"\n        android:paddingRight=\"@dimen/margin_large\" />\n\n    <ImageView\n        android:id=\"@+id/iv_right\"\n        android:layout_width=\"18dp\"\n        android:layout_height=\"18dp\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\" />\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/include_banner_with_indicator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/include_banner_with_indicator\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/banner_height\">\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/vp_banner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/banner_height\">\n    </android.support.v4.view.ViewPager>\n\n    <RadioGroup\n        android:id=\"@+id/rg_indicator\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignBottom=\"@+id/vp_banner\"\n        android:layout_alignRight=\"@+id/vp_banner\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"@dimen/margin_small\"\n        android:layout_marginRight=\"@dimen/margin_medium\"\n        android:orientation=\"horizontal\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/include_ddm_listview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ListView\n        android:id=\"@+id/lv_ddm\"\n        style=\"@style/AbsListViewCommon\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/margin_large\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/include_group_divider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/margin_small\"\n    android:orientation=\"vertical\">\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:background=\"@color/bg_gray\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/include_refresh_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.SwipeRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/srl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n</android.support.v4.widget.SwipeRefreshLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/include_titlebar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/rl_titlebar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48dp\"\n    android:background=\"@color/colorPrimary\"\n    android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/titlebar_iv_left\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:padding=\"13dp\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\"\n        android:textColor=\"@android:color/white\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv\"\n        style=\"@style/TextViewTitle\"\n        android:layout_centerInParent=\"true\"\n        android:gravity=\"center\"\n        android:maxWidth=\"224dp\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"26sp\" />\n\n    <ImageView\n        android:id=\"@+id/titlebar_iv_right\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:padding=\"13dp\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv_right\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\"\n        android:textColor=\"@android:color/white\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/item_default_drop_down.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"32dp\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        style=\"@style/TextViewCaption\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"32dp\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"54dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/item_image_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/banner_height\">\n\n    <ImageView\n        android:id=\"@+id/iv_image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/banner_height\"\n        android:scaleType=\"centerCrop\" />\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"24dp\"\n        android:layout_alignBottom=\"@id/iv_image\"\n        android:background=\"#3000\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_huge\"\n        android:textColor=\"@android:color/white\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/item_image_browser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/iv_image_browser\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitCenter\" />\n\n    <ProgressBar\n        android:id=\"@+id/pb_loading\"\n        style=\"@style/Widget.AppCompat.ProgressBar\"\n        android:layout_width=\"56dp\"\n        android:layout_height=\"56dp\"\n        android:layout_centerInParent=\"true\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/item_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"?listPreferredItemHeightSmall\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <ImageView\n        android:id=\"@+id/iv_left\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\" />\n\n    <TextView\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_small\" />\n\n    <ImageView\n        android:id=\"@+id/iv_red_dot\"\n        android:layout_width=\"8dp\"\n        android:layout_height=\"8dp\"\n        android:layout_gravity=\"top\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:src=\"@drawable/shape_oval_red_solid\"\n        android:visibility=\"gone\" />\n\n    <View\n        android:layout_width=\"0dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\" />\n\n    <TextView\n        android:id=\"@+id/tv_right\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_small\"\n        android:textColor=\"@color/txt_light_gray\"\n        android:visibility=\"gone\" />\n\n    <ImageView\n        android:id=\"@+id/iv_right\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:visibility=\"gone\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/listview_dropdown_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    style=\"@style/ListViewLineDivider\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n</ListView>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/layout/wheel_dialog_address.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"#E9E9E9\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"20dip\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"5dip\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"20dip\"\n            android:text=\"请选择省市区\"\n            android:textColor=\"#000000\"\n            android:textSize=\"20sp\" />\n    </RelativeLayout>\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"30dip\"\n        android:orientation=\"horizontal\">\n\n        <com.boredream.bdcodehelper.view.wheel.WheelView\n            android:id=\"@+id/id_province\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"></com.boredream.bdcodehelper.view.wheel.WheelView>\n\n        <com.boredream.bdcodehelper.view.wheel.WheelView\n            android:id=\"@+id/id_city\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"></com.boredream.bdcodehelper.view.wheel.WheelView>\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/btn_confirm\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dip\"\n        android:gravity=\"center\"\n        android:text=\"确定\"\n        android:textColor=\"#000000\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <declare-styleable name=\"DrawableTextView\">\n        <attr name=\"drawableWidth\" format=\"dimension\" />\n        <attr name=\"drawableHeight\" format=\"dimension\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"DropDownMenu\">\n        <attr name=\"ddunderlineColor\" format=\"color\" />\n        <attr name=\"dddividerColor\" format=\"color\" />\n        <attr name=\"ddtextSelectedColor\" format=\"color\" />\n        <attr name=\"ddtextUnselectedColor\" format=\"color\" />\n        <attr name=\"ddmenuBackgroundColor\" format=\"color\" />\n        <attr name=\"ddmaskColor\" format=\"color\" />\n        <attr name=\"ddmenuTextSize\" format=\"dimension\" />\n        <attr name=\"ddmenuSelectedIcon\" format=\"reference\" />\n        <attr name=\"ddmenuUnselectedIcon\" format=\"reference\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"BottomTabRadioButton\">\n        <attr name=\"hint_mode\" format=\"enum\">\n            <enum name=\"none\" value=\"0\" />\n            <enum name=\"point\" value=\"1\" />\n            <enum name=\"num\" value=\"2\" />\n        </attr>\n        <attr name=\"hint_color\" format=\"color\" />\n        <attr name=\"hint_toppadding\" format=\"dimension\" />\n        <attr name=\"hint_rightpadding\" format=\"dimension\" />\n        <attr name=\"point_radius\" format=\"dimension\" />\n        <attr name=\"num\" format=\"integer\" />\n        <attr name=\"num_radius\" format=\"dimension\" />\n        <attr name=\"num_size\" format=\"dimension\" />\n        <attr name=\"num_color\" format=\"color\" />\n    </declare-styleable>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- basic -->\n    <!-- 主色调 -->\n    <color name=\"colorPrimary\">#8BC34A</color>\n    <color name=\"colorPrimaryDark\">#76A63E</color>\n    <color name=\"colorPrimaryLight\">#E8F3BD</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"colorSecondary\">#ff9900</color>\n    <color name=\"colorSecondaryDark\">#d88200</color>\n    <!-- 主体文字,标题/标签 -->\n    <color name=\"txt_black\">#212121</color>\n    <!-- 内容文字,正文 -->\n    <color name=\"txt_gray\">#808080</color>\n    <!-- 辅助文字,提示 -->\n    <color name=\"txt_light_gray\">#CCCCCC</color>\n    <!-- 背景色 -->\n    <color name=\"bg_gray\">#f1f1f1</color>\n    <!-- 按下灰色 -->\n    <color name=\"bg_gray_pressed\">#e8e8e8</color>\n    <!-- 高亮,红棕色 -->\n    <color name=\"brown\">#d54c1c</color>\n    <!-- 分割线 -->\n    <color name=\"divider_gray\">#cbcbcb</color>\n    <!-- other -->\n    <color name=\"txt_link_blue\">#1ea5ff</color>\n\n    <!-- wheel -->\n    <color name=\"province_line_border\">#C7C7C7</color>\n\n    <!-- drop down menu -->\n    <color name=\"white\">#ffffff</color>\n    <color name=\"gray\">#cccccc</color>\n\n    <color name=\"drop_down_selected\">#8BC34A</color>\n    <color name=\"drop_down_unselected\">#808080</color>\n\n    <color name=\"mask_color\">#88888888</color>\n    <color name=\"check_bg\">#f1f1f1</color>\n    <color name=\"un_press_color\">#8BC34A</color>\n\n    <!-- position bar -->\n    <color name=\"bg_position_bar_up\">#0D8BC34A</color>\n    <color name=\"bg_position_bar_down\">#1A8BC34A</color>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/values/dimens.xml",
    "content": "<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n    <!-- margin -->\n    <dimen name=\"margin_tiny\">4dp</dimen>\n    <dimen name=\"margin_small\">8dp</dimen>\n    <dimen name=\"margin_medium\">16dp</dimen>\n    <dimen name=\"margin_large\">32dp</dimen>\n    <dimen name=\"margin_huge\">64dp</dimen>\n    <dimen name=\"margin_only_txt\">48dp</dimen>\n\n    <!-- txtsize -->\n    <dimen name=\"txtsize_display1\">34sp</dimen>\n    <dimen name=\"txtsize_headline\">24sp</dimen>\n    <dimen name=\"txtsize_title\">20sp</dimen>\n    <dimen name=\"txtsize_subhead\">16sp</dimen>\n    <dimen name=\"txtsize_body\">14sp</dimen>\n    <dimen name=\"txtsize_caption\">12sp</dimen>\n\n    <!-- other size -->\n    <dimen name=\"corner_radius\">2dp</dimen>\n    <dimen name=\"banner_height\">136dp</dimen>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"dialog_positive\">确定</string>\n    <string name=\"dialog_negative\">取消</string>\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP/bdcodehelper/src/main/res/values/styles.xml",
    "content": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <style name=\"AppBaseTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n\n    </style>\n\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowFullscreen\">false</item>\n        <item name=\"android:windowActionBar\">false</item>\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"colorButtonNormal\">@color/colorPrimary</item>\n        <item name=\"colorControlActivated\">@color/colorPrimary</item>\n        <item name=\"android:windowBackground\">@color/bg_gray</item>\n    </style>\n\n    <style name=\"TextViewHeadline\" parent=\"TextAppearance.AppCompat.Headline\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:singleLine\">true</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewTitle\" parent=\"TextAppearance.AppCompat.Title\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:singleLine\">true</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewSubhead\" parent=\"TextAppearance.AppCompat.Subhead\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewBody\" parent=\"TextAppearance.AppCompat.Body1\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewCaption\" parent=\"TextAppearance.AppCompat.Caption\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_light_gray</item>\n    </style>\n\n    <style name=\"EditTextSingleLine\" parent=\"@style/Widget.AppCompat.EditText\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">48dp</item>\n        <item name=\"android:textColorHint\">@color/txt_light_gray</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n        <item name=\"android:textSize\">@dimen/txtsize_subhead</item>\n        <item name=\"android:singleLine\">true</item>\n    </style>\n\n    <style name=\"ButtonPrimary\" parent=\"TextViewSubhead\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:textSize\">20sp</item>\n        <item name=\"android:textColor\">@color/txt_white2gray_sel</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:background\">@drawable/correct_primary2dark_sel</item>\n    </style>\n\n    <style name=\"RadioButtonBottomTab\">\n        <item name=\"android:layout_weight\">1</item>\n        <item name=\"android:layout_width\">0dp</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:button\">@null</item>\n        <item name=\"android:background\">@drawable/bg_white2gray_sel</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:paddingBottom\">@dimen/margin_small</item>\n        <item name=\"android:paddingTop\">@dimen/margin_small</item>\n    </style>\n\n    <style name=\"AbsListViewCommon\" parent=\"Widget.AppCompat.ListView\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:cacheColorHint\">@android:color/transparent</item>\n        <item name=\"android:listSelector\">@android:color/transparent</item>\n        <item name=\"android:divider\">@null</item>\n        <item name=\"android:dividerHeight\">0dp</item>\n        <item name=\"android:scrollbars\">none</item>\n    </style>\n\n    <style name=\"ListViewLineDivider\" parent=\"AbsListViewCommon\">\n        <item name=\"android:divider\">@color/divider_gray</item>\n        <item name=\"android:dividerHeight\">1px</item>\n    </style>\n\n    <style name=\"GridViewImages\" parent=\"AbsListViewCommon\">\n        <item name=\"android:horizontalSpacing\">4dp</item>\n        <item name=\"android:verticalSpacing\">4dp</item>\n    </style>\n\n    <!-- 自定义对话框 -->\n    <style name=\"custom_dialog\" parent=\"Theme.AppCompat.Dialog\">\n        <item name=\"android:windowFrame\">@null</item>\n        <item name=\"android:windowIsFloating\">true</item>\n        <item name=\"android:windowIsTranslucent\">false</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:background\">@android:color/transparent</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n\n    </style>\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.1.2'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n\n// Define versions in a single place\next {\n    // Sdk and tools\n    minSdkVersion = 15\n    targetSdkVersion = 23\n    compileSdkVersion = 23\n    buildToolsVersion = '23.0.3'\n\n    // App dependencies\n    supportLibraryVersion = '23.4.0'\n    guavaVersion = '18.0'\n    junitVersion = '4.12'\n    mockitoVersion = '1.10.19'\n    powerMockito = '1.6.2'\n    hamcrestVersion = '1.3'\n    runnerVersion = '0.4.1'\n    rulesVersion = '0.4.1'\n    espressoVersion = '2.2.1'\n    retrofitVersion = '2.0.0-beta2'\n    okhttploggingVersion = '2.6.0'\n    rxjavaVersion = '1.1.0'\n    rxbindingVersion = '0.2.0'\n    glideVersion = '3.6.1'\n    glideokhttpVersion = '1.3.1'\n    photoviewVersion = '1.2.4'\n}"
  },
  {
    "path": "DesignResCollection_MVP/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Dec 28 10:00:20 PST 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip\n"
  },
  {
    "path": "DesignResCollection_MVP/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "DesignResCollection_MVP/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "DesignResCollection_MVP/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "DesignResCollection_MVP/settings.gradle",
    "content": "include ':app', ':bdcodehelper'\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/README.md",
    "content": "## 使用框架\n\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'com.neenbedankt.android-apt'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.boredream.designrescollection\"\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode 70\n        versionName \"0.7.0\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg'\n        }\n    }\n\n    packagingOptions {\n        exclude 'META-INF/DEPENDENCIES'\n        exclude 'META-INF/LICENSE'\n        exclude 'META-INF/NOTICE'\n    }\n\n    android.applicationVariants.all { variant ->\n        renameAPK(variant, defaultConfig, \"release\")\n    }\n}\n\ndef renameAPK(variant, defaultConfig, buildType) {\n    variant.outputs.each { output ->\n        def applicationName = 'DesignResCollection'\n        def formattedDate = new Date().format('yyyyMMdd')\n        def file = output.packageApplication.outputFile\n        def fileName = applicationName + \"_v\" + defaultConfig.versionName + \"_\" + formattedDate + \"_\" + buildType + \".apk\"\n        output.packageApplication.outputFile = new File(file.parent, fileName)\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(path: ':bdcodehelper')\n\n    // Dependencies for local unit tests\n    testCompile \"junit:junit:$rootProject.ext.junitVersion\"\n    testCompile \"org.mockito:mockito-all:$rootProject.ext.mockitoVersion\"\n    testCompile \"org.hamcrest:hamcrest-all:$rootProject.ext.hamcrestVersion\"\n\n    // Espresso UI Testing\n    androidTestCompile \"com.android.support.test:runner:$rootProject.runnerVersion\"\n    androidTestCompile \"com.android.support.test:rules:$rootProject.rulesVersion\"\n    androidTestCompile \"com.android.support.test.espresso:espresso-core:$rootProject.espressoVersion\"\n    androidTestCompile \"com.android.support.test.espresso:espresso-contrib:$rootProject.espressoVersion\"\n    androidTestCompile \"com.android.support.test.espresso:espresso-intents:$rootProject.espressoVersion\"\n\n    // Resolve conflicts between main and test APK:\n    androidTestCompile \"com.android.support:support-annotations:$rootProject.supportLibraryVersion\"\n    androidTestCompile \"com.android.support:support-v4:$rootProject.supportLibraryVersion\"\n    androidTestCompile \"com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion\"\n\n    // Dagger dependencies\n    apt \"com.google.dagger:dagger-compiler:$rootProject.daggerVersion\"\n    compile \"com.google.dagger:dagger:$rootProject.daggerVersion\"\n    provided 'javax.annotation:javax.annotation-api:1.2'\n\n}\n\nconfigurations {\n    androidTestCompile.exclude group: 'com.android.support', module: 'support-v4'\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/proguard.cfg",
    "content": "######################## 固定部分 ########################\n\n#1.基本指令区\n-optimizationpasses 5\n-dontusemixedcaseclassnames\n-dontskipnonpubliclibraryclasses\n-dontskipnonpubliclibraryclassmembers\n-dontpreverify\n-verbose\n-ignorewarning\n-printmapping proguardMapping.txt\n-optimizations !code/simplification/cast,!field/*,!class/merging/*\n-keepattributes *Annotation*,InnerClasses\n-keepattributes Signature\n-keepattributes SourceFile,LineNumberTable\n\n#2.默认保留区\n-keep public class * extends android.app.Activity\n-keep public class * extends android.app.Application\n-keep public class * extends android.app.Service\n-keep public class * extends android.content.BroadcastReceiver\n-keep public class * extends android.content.ContentProvider\n-keep public class * extends android.app.backup.BackupAgentHelper\n-keep public class * extends android.preference.Preference\n-keep public class * extends android.view.View\n-keep public class com.android.vending.licensing.ILicensingService\n-keep class android.support.** {*;}\n\n-keepclasseswithmembernames class * {\n    native <methods>;\n}\n-keepclassmembers class * extends android.app.Activity{\n    public void *(android.view.View);\n}\n-keepclassmembers enum * {\n    public static **[] values();\n    public static ** valueOf(java.lang.String);\n}\n-keep public class * extends android.view.View{\n    *** get*();\n    void set*(***);\n    public <init>(android.content.Context);\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keepclasseswithmembers class * {\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n-keep class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n-keepclassmembers class * implements java.io.Serializable {\n    static final long serialVersionUID;\n    private static final java.io.ObjectStreamField[] serialPersistentFields;\n    private void writeObject(java.io.ObjectOutputStream);\n    private void readObject(java.io.ObjectInputStream);\n    java.lang.Object writeReplace();\n    java.lang.Object readResolve();\n}\n-keep class **.R$* {\n *;\n}\n-keepclassmembers class * {\n    void *(**On*Event);\n}\n\n#3.webview\n-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n   public *;\n}\n-keepclassmembers class * extends android.webkit.webViewClient {\n    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);\n    public boolean *(android.webkit.WebView, java.lang.String);\n}\n-keepclassmembers class * extends android.webkit.webViewClient {\n    public void *(android.webkit.webView, jav.lang.String);\n}\n\n######################## 非固定部分 ########################\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/androidTest/java/com/boredream/designrescollection/ApplicationTest.java",
    "content": "package com.boredream.designrescollection;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/androidTest/java/com/boredream/designrescollection/idlingres/RxIdlingResource.java",
    "content": "package com.boredream.designrescollection.idlingres;\n\nimport android.support.test.espresso.Espresso;\nimport android.support.test.espresso.IdlingResource;\nimport android.util.Log;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.plugins.RxJavaObservableExecutionHook;\n\npublic class RxIdlingResource extends RxJavaObservableExecutionHook implements IdlingResource {\n\n    private static final String TAG = \"RxIdlingResource\";\n\n    private final AtomicInteger subscriptions = new AtomicInteger(0);\n\n    private static RxIdlingResource INSTANCE;\n\n    private ResourceCallback resourceCallback;\n\n    private RxIdlingResource() {\n        //private\n    }\n\n    public static RxIdlingResource get() {\n        if (INSTANCE == null) {\n            INSTANCE = new RxIdlingResource();\n            Espresso.registerIdlingResources(INSTANCE);\n        }\n        return INSTANCE;\n    }\n\n    /* ======================== */\n    /* IdlingResource Overrides */\n    /* ======================== */\n\n    @Override\n    public String getName() {\n        return TAG;\n    }\n\n    @Override\n    public boolean isIdleNow() {\n        int activeSubscriptionCount = subscriptions.get();\n        return activeSubscriptionCount == 0;\n    }\n\n    @Override\n    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {\n        this.resourceCallback = resourceCallback;\n    }\n\n    /* ======================================= */\n    /* RxJavaObservableExecutionHook Overrides */\n    /* ======================================= */\n\n    @Override\n    public <T> Observable.OnSubscribe<T> onSubscribeStart(Observable<? extends T> observableInstance,\n                                                          final Observable.OnSubscribe<T> onSubscribe) {\n        int activeSubscriptionCount = subscriptions.incrementAndGet();\n        Log.d(TAG, onSubscribe + \" - onSubscribeStart: \" + activeSubscriptionCount);\n\n        return new Observable.OnSubscribe<T>() {\n            @Override\n            public void call(final Subscriber<? super T> subscriber) {\n                onSubscribe.call(new Subscriber<T>() {\n                    @Override\n                    public void onCompleted() {\n                        subscriber.onCompleted();\n                        onFinally(onSubscribe, \"onCompleted\");\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        subscriber.onError(e);\n                        onFinally(onSubscribe, \"onError\");\n                    }\n\n                    @Override\n                    public void onNext(T t) {\n                        subscriber.onNext(t);\n                    }\n                });\n            }\n        };\n    }\n\n    private <T> void onFinally(Observable.OnSubscribe<T> onSubscribe, final String finalizeCaller) {\n        int activeSubscriptionCount = subscriptions.decrementAndGet();\n        Log.d(TAG, onSubscribe + \" - \" + finalizeCaller + \": \" + activeSubscriptionCount);\n\n        if (activeSubscriptionCount == 0) {\n            Log.d(TAG, \"onTransitionToIdle\");\n            resourceCallback.onTransitionToIdle();\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/androidTest/java/com/boredream/designrescollection/ui/login/LoginActivityTest.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport android.content.Intent;\nimport android.support.test.rule.ActivityTestRule;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.idlingres.RxIdlingResource;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport rx.plugins.RxJavaPlugins;\n\nimport static android.support.test.espresso.Espresso.onView;\nimport static android.support.test.espresso.action.ViewActions.click;\nimport static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;\nimport static android.support.test.espresso.action.ViewActions.typeText;\nimport static android.support.test.espresso.assertion.ViewAssertions.matches;\nimport static android.support.test.espresso.matcher.RootMatchers.withDecorView;\nimport static android.support.test.espresso.matcher.ViewMatchers.withId;\nimport static android.support.test.espresso.matcher.ViewMatchers.withText;\nimport static org.hamcrest.core.Is.is;\nimport static org.hamcrest.core.IsNot.not;\n\n@RunWith(AndroidJUnit4.class)\npublic class LoginActivityTest {\n\n\t@Rule\n\tpublic ActivityTestRule<LoginActivity> mActivityRule = new ActivityTestRule<>(LoginActivity.class, true, false);\n\n\tstatic {\n\t\tRxJavaPlugins.getInstance().registerObservableExecutionHook(RxIdlingResource.get());\n\t}\n\n\t@Test\n\tpublic void testLogin_EmptyPassword() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"13913391521\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"密码不能为空\")));\n\t}\n\n\t@Test\n\tpublic void testLogin_EmptyUsername() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"123456\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"用户名不能为空\")));\n\t}\n\n\t@Test\n\tpublic void testLogin_Success() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tintent.putExtra(\"checkLogin\", true);\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"18551681236\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"123456\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tAssert.assertTrue(UserInfoKeeper.getCurrentUser() != null);\n\t}\n\n\t@Test\n\tpublic void testLogin_UserNotExit() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"110110110\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"123456\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"找不到用户\")));\n\t}\n\n\t@Test\n\tpublic void testLogin_PswError() throws Exception {\n\t\tIntent intent = new Intent();\n\t\tmActivityRule.launchActivity(intent);\n\n\t\t// actions\n\t\tonView(withId(R.id.et_username)).perform(typeText(\"18551681236\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.et_password)).perform(typeText(\"110\"), closeSoftKeyboard());\n\t\tonView(withId(R.id.btn_login)).perform(click());\n\n\t\t// assertions\n\t\tonView(withId(android.R.id.message))\n\t\t\t\t.inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n\t\t\t\t.check(matches(withText(\"密码不正确\")));\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/androidTest/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditActivityTest.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport android.app.Activity;\nimport android.app.Instrumentation;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.support.test.espresso.intent.Intents;\nimport android.support.test.rule.ActivityTestRule;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.idlingres.RxIdlingResource;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.hamcrest.core.IsNot;\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport java.util.Random;\n\nimport rx.plugins.RxJavaPlugins;\n\nimport static android.support.test.espresso.Espresso.onView;\nimport static android.support.test.espresso.action.ViewActions.click;\nimport static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;\nimport static android.support.test.espresso.action.ViewActions.typeText;\nimport static android.support.test.espresso.assertion.ViewAssertions.matches;\nimport static android.support.test.espresso.intent.Intents.intending;\nimport static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;\nimport static android.support.test.espresso.matcher.RootMatchers.withDecorView;\nimport static android.support.test.espresso.matcher.ViewMatchers.withId;\nimport static android.support.test.espresso.matcher.ViewMatchers.withText;\nimport static org.hamcrest.core.Is.is;\n\n@RunWith(AndroidJUnit4.class)\npublic class UserInfoEditActivityTest {\n\n    @Rule\n    public ActivityTestRule<UserInfoEditActivity> mActivityRule = new ActivityTestRule<>(UserInfoEditActivity.class, true, true);\n\n    static {\n        User user = new User();\n        user.setObjectId(\"57abf85e2e958a00543737da\");\n        user.setUsername(\"18551681236\");\n        user.setNickname(\"\");\n        user.setSessionToken(\"hh45pryl55lbm6n3l6sfbuywg\");\n        UserInfoKeeper.setCurrentUser(user);\n\n        RxJavaPlugins.getInstance().registerObservableExecutionHook(RxIdlingResource.get());\n    }\n\n    @Test\n    public void testUploadAvatar() throws Exception {\n        Intents.init();\n\n        // Stub the Intent.\n        Instrumentation.ActivityResult resultGallery = createImageGalleryActivityResultStub();\n        intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(resultGallery);\n\n        // actions\n        onView(withId(R.id.ll_avatar)).perform(click());\n        onView(withText(\"相册\"))\n                .inRoot(withDecorView(IsNot.not(is(mActivityRule.getActivity().getWindow().getDecorView()))))\n                .perform(click());\n\n        // assertions\n        Assert.assertTrue(UserInfoKeeper.getCurrentUser().getAvatar() != null);\n    }\n\n    private Instrumentation.ActivityResult createImageGalleryActivityResultStub() {\n        Uri uri = Uri.parse(\"file:///android_asset/test_avatar.jpg\");\n\n        Intent resultData = new Intent();\n        resultData.setData(uri);\n\n        // Create the ActivityResult with the Intent.\n        return new Instrumentation.ActivityResult(Activity.RESULT_OK, resultData);\n    }\n\n    @Test\n    public void testUpdateNickname() throws Exception {\n        String newName = \"boredream\" + new Random().nextInt(10);\n\n        // actions\n        onView(withId(R.id.ll_username)).perform(click());\n        onView(withId(R.id.et_input)).perform(typeText(newName), closeSoftKeyboard());\n        onView(withText(\"保存\")).perform(click());\n\n        // assertions\n        onView(withId(R.id.tv_username)).check(matches(withText(newName)));\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.boredream.designrescollection\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.READ_LOGS\" />\n    <uses-permission android:name=\"android.permission.CALL_PHONE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n\n    <application\n        android:name=\".base.BaseApplication\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".ui.MainActivity\"\n            android:launchMode=\"singleTask\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\".ui.register.RegisterStep1Activity\" />\n        <activity android:name=\".ui.register.RegisterStep2Activity\" />\n        <activity android:name=\".ui.login.LoginActivity\" />\n        <activity android:name=\".ui.SettingActivity\" />\n        <activity android:name=\".ui.AboutActivity\" />\n        <activity android:name=\".ui.userinfoedit.UserInfoEditActivity\" />\n        <activity android:name=\".ui.modifytext.ModifyTextActivity\" />\n        <activity android:name=\".ui.feedback.FeedBackActivity\" />\n        <activity\n            android:name=\".ui.login.Main2Activity\"\n            android:label=\"@string/title_activity_main2\"></activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/adapter/DesignResAdapter.java",
    "content": "package com.boredream.designrescollection.adapter;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.activity.WebViewActivity;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.net.GlideHelper;\n\nimport java.util.ArrayList;\n\npublic class DesignResAdapter extends RecyclerView.Adapter<DesignResAdapter.ViewHolder> {\n\n    private Context context;\n    private ArrayList<DesignRes> datas;\n\n    public DesignResAdapter(Context context, ArrayList<DesignRes> datas) {\n        this.context = context;\n        this.datas = datas;\n    }\n\n    @Override\n    public int getItemCount() {\n        return datas.size();\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        public ImageView iv_image;\n        public TextView tv_name;\n\n        public ViewHolder(View rootView) {\n            super(rootView);\n\n            this.iv_image = (ImageView) rootView.findViewById(R.id.iv_image);\n            this.tv_name = (TextView) rootView.findViewById(R.id.tv_name);\n        }\n\n    }\n\n    @Override\n    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(context).inflate(R.layout.item_design_res, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(ViewHolder holder, int position) {\n        final DesignRes data = datas.get(position);\n\n        GlideHelper.showImage(context, data.getImgUrl(), holder.iv_image);\n        String str = String.format(\"[%s] %s\", data.getSrcTag(), data.getName());\n        holder.tv_name.setText(str);\n\n        holder.itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Intent intent = new Intent(context, WebViewActivity.class);\n                intent.putExtra(WebViewActivity.EXTRA_TITLE, data.getName());\n                intent.putExtra(WebViewActivity.EXTRA_URL, data.getSrcLink());\n                context.startActivity(intent);\n            }\n        });\n    }\n\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/adapter/MoreRecyclerAdapter.java",
    "content": "package com.boredream.designrescollection.adapter;\n\nimport android.content.Intent;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.adapter.SettingRecyclerAdapter;\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.GlideHelper;\nimport com.boredream.designrescollection.ui.login.LoginActivity;\n\nimport java.util.List;\n\n/**\n * 更多选项列表适配器\n * <p>\n * 第一个位置为HEADER类型,对应用户信息<br/>\n * 其他位置为LIST类型,对应选项item\n */\npublic class MoreRecyclerAdapter extends SettingRecyclerAdapter {\n\n    private static final int ITEM_VIEW_TYPE_HEADER = 0;\n\n    private User user;\n\n    public MoreRecyclerAdapter(List<SettingItem> datas, OnItemClickListener listener) {\n        super(datas, listener);\n    }\n\n    @Override\n    public int getItemCount() {\n        // header + 1\n        return datas.size() + 1;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return position == 0 ? ITEM_VIEW_TYPE_HEADER : super.getItemViewType(position);\n    }\n\n    public void setUser(User user) {\n        this.user = user;\n    }\n\n    public static class ViewHolderUserHeader extends RecyclerView.ViewHolder {\n\n        public View include_more_header;\n        public ImageView iv_avatar;\n        public TextView tv_name;\n        // not login\n        public View include_more_no_header;\n        public Button btn_login;\n\n        public ViewHolderUserHeader(final View itemView) {\n            super(itemView);\n\n            include_more_header = itemView.findViewById(R.id.include_more_header);\n            iv_avatar = (ImageView) itemView.findViewById(R.id.iv_avatar);\n            tv_name = (TextView) itemView.findViewById(R.id.tv_name);\n            include_more_no_header = itemView.findViewById(R.id.include_more_no_header);\n            btn_login = (Button) itemView.findViewById(R.id.btn_login);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        if (viewType == ITEM_VIEW_TYPE_HEADER) {\n            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_more_header, parent, false);\n            return new ViewHolderUserHeader(v);\n        } else {\n            return super.onCreateViewHolder(parent, viewType);\n        }\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {\n        int itemViewType = getItemViewType(position);\n        if (itemViewType == ITEM_VIEW_TYPE_HEADER) {\n            // header\n            ViewHolderUserHeader viewHolderHeader = (ViewHolderUserHeader) holder;\n            if (user != null) {\n                // 如果已登录,用户数据非空,则显示用户信息\n                viewHolderHeader.include_more_header.setVisibility(View.VISIBLE);\n                viewHolderHeader.include_more_no_header.setVisibility(View.GONE);\n\n                GlideHelper.showAvatar(holder.itemView.getContext(), user.getAvatar(), viewHolderHeader.iv_avatar);\n                viewHolderHeader.tv_name.setText(user.getNickname());\n\n                viewHolderHeader.itemView.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        if (mOnItemClickListener != null) {\n                            // header使用特殊的position -1\n                            mOnItemClickListener.onItemClick(null, view, -1, -1);\n                        }\n                    }\n                });\n            } else {\n                // 未登录,提供登录按钮,点击进入登录页\n                viewHolderHeader.include_more_header.setVisibility(View.GONE);\n                viewHolderHeader.include_more_no_header.setVisibility(View.VISIBLE);\n\n                viewHolderHeader.btn_login.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        Intent intent = new Intent(view.getContext(), LoginActivity.class);\n                        view.getContext().startActivity(intent);\n                    }\n                });\n            }\n        } else {\n            // setting item\n            // 第一个位置多了个HEADER,所以position差1\n            super.onBindViewHolder(holder, position - 1);\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/base/BaseActivity.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.os.Bundle;\n\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.designrescollection.constants.CommonConstants;\nimport com.boredream.designrescollection.ui.MainActivity;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\nimport rx.functions.Action1;\n\npublic class BaseActivity extends BoreBaseActivity {\n\n    public BaseApplication application;\n    public SharedPreferences sp;\n\n    private boolean couldDoubleBackExit;\n    private boolean doubleBackExitPressedOnce;\n\n    protected boolean isActive;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // 如果是退出应用flag,则直接关闭当前页面,不加载UI\n        boolean exit = getIntent().getBooleanExtra(\"exit\", false);\n        if (exit) {\n            finish();\n            return;\n        }\n\n        application = (BaseApplication) getApplication();\n        sp = getSharedPreferences(CommonConstants.SP_NAME, MODE_PRIVATE);\n    }\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n        isActive = true;\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        isActive = false;\n    }\n\n    /**\n     * 设置是否可以双击返回退出，需要有该功能的页面set true即可\n     *\n     * @param couldDoubleBackExit true-开启双击退出\n     */\n    public void setCouldDoubleBackExit(boolean couldDoubleBackExit) {\n        this.couldDoubleBackExit = couldDoubleBackExit;\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (!couldDoubleBackExit) {\n            // 非双击退出状态，使用原back逻辑\n            super.onBackPressed();\n            return;\n        }\n\n        // 双击返回键关闭程序\n        // 如果两秒重置时间内再次点击返回,则退出程序\n        if (doubleBackExitPressedOnce) {\n            exit();\n            return;\n        }\n\n        doubleBackExitPressedOnce = true;\n        showToast(\"再按一次返回键关闭程序\");\n        Observable.just(null)\n                .delay(2, TimeUnit.SECONDS)\n                .subscribe(new Action1<Object>() {\n                    @Override\n                    public void call(Object o) {\n                        // 延迟两秒后重置标志位为false\n                        doubleBackExitPressedOnce = false;\n                    }\n                });\n    }\n\n    /**\n     * 退出程序\n     */\n    protected void exit() {\n        // 退出程序方法有多种\n        // 这里使用clear + new task的方式清空整个任务栈,只保留新打开的Main页面\n        // 然后Main页面接收到退出的标志位exit=true,finish自己,这样就关闭了全部页面\n        Intent intent = new Intent(this, MainActivity.class);\n        intent.putExtra(\"exit\", true);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);\n        startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/base/BaseApplication.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.app.Application;\n\nimport com.boredream.designrescollection.net.DaggerAppComponent;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.integration.okhttp.OkHttpUrlLoader;\nimport com.bumptech.glide.load.model.GlideUrl;\nimport com.squareup.okhttp.Interceptor;\nimport com.squareup.okhttp.OkHttpClient;\nimport com.squareup.okhttp.Request;\nimport com.squareup.okhttp.Response;\nimport com.squareup.okhttp.logging.HttpLoggingInterceptor;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic class BaseApplication extends Application {\n\n    private static final String APP_ID_NAME = \"X-LC-Id\";\n    private static final String API_KEY_NAME = \"X-LC-Key\";\n    public static final String SESSION_TOKEN_KEY = \"X-LC-Session\";\n\n    private static final String APP_ID_VALUE = \"iaEH7ObIA4sPY8RSs3VCVXBg-gzGzoHsz\";\n    private static final String API_KEY_VALUE = \"dXfhXIVyeWMN2czJkd4ehwzs\";\n\n    private OkHttpClient okHttpClient;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        initOkHttpClient();\n        initGlide();\n    }\n\n    private void initOkHttpClient() {\n        // OkHttpClient\n        okHttpClient = new OkHttpClient();\n\n        // 统一添加的Header\n        okHttpClient.networkInterceptors().add(new Interceptor() {\n            @Override\n            public Response intercept(Chain chain) throws IOException {\n                Request request = chain.request().newBuilder()\n                        .addHeader(\"Content-Type\", \"application/json\")\n                        .addHeader(APP_ID_NAME, APP_ID_VALUE)\n                        .addHeader(API_KEY_NAME, API_KEY_VALUE)\n                        .addHeader(SESSION_TOKEN_KEY, UserInfoKeeper.getToken())\n                        .build();\n                return chain.proceed(request);\n            }\n        });\n\n        // log\n        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();\n        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);\n        okHttpClient.interceptors().add(interceptor);\n    }\n\n    /**\n     * 图片加载框架Glide,使用OkHttp处理网络请求\n     */\n    private void initGlide() {\n        DaggerAppComponent.builder().build().inject(this);\n\n        Glide.get(this).register(GlideUrl.class, InputStream.class,\n                new OkHttpUrlLoader.Factory(okHttpClient));\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/base/BaseEntity.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class BaseEntity extends BoreBaseEntity {\n\n    @Override\n    public boolean equals(Object o) {\n        if (o instanceof BaseEntity) {\n            BaseEntity oEntity = (BaseEntity) o;\n            return this.objectId.equals(oEntity.objectId);\n        }\n        return super.equals(o);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/base/BaseFragment.java",
    "content": "package com.boredream.designrescollection.base;\n\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\npublic abstract class BaseFragment extends Fragment {\n\n    protected String TAG;\n    protected BaseActivity activity;\n    // progressDialog/sp/application 等使用activity.xx 调用\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        TAG = getClass().getSimpleName();\n\n        activity = (BaseActivity) getActivity();\n    }\n\n    protected void intent2Activity(Class<? extends Activity> tarActivity) {\n        Intent intent = new Intent(activity, tarActivity);\n        startActivity(intent);\n    }\n\n    protected void showToast(String msg) {\n        ToastUtils.showToast(activity, msg, Toast.LENGTH_SHORT);\n    }\n\n    protected void showLog(String msg) {\n        Log.i(TAG, msg);\n    }\n\n    protected void showProgressDialog() {\n        activity.showProgressDialog();\n    }\n\n    protected void dismissProgressDialog() {\n        activity.dismissProgressDialog();\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/base/BasePresenter.java",
    "content": "/*\n * Copyright 2016, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.boredream.designrescollection.base;\n\npublic interface BasePresenter {\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/base/BaseView.java",
    "content": "/*\n * Copyright 2016, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.boredream.designrescollection.base;\n\npublic interface BaseView<T> {\n\n    void setPresenter(T presenter);\n\n    boolean isActive();\n\n    void showProgress();\n\n    void dismissProgress();\n\n    void showTip(String message);\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/constants/CommonConstants.java",
    "content": "package com.boredream.designrescollection.constants;\n\n/**\n * 通用常量\n */\npublic class CommonConstants {\n\n    private CommonConstants() {\n    }\n\n    /**\n     * SharedPreferences 名称\n     */\n    public static final String SP_NAME = \"config\";\n\n    /**\n     * 每页加载的数量\n     */\n    public static final int COUNT_OF_PAGE = 20;\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/entity/Comment.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class Comment extends BaseEntity {\n    /**\n     * 所属资源\n     */\n    private DesignRes designRes;\n\n    /**\n     * 发送用户, Pointer or User\n     */\n    private User user;\n\n    /**\n     * 评论内容\n     */\n    private String content;\n\n    public DesignRes getDesignRes() {\n        return designRes;\n    }\n\n    public void setDesignRes(DesignRes designRes) {\n        this.designRes = designRes;\n    }\n\n    public User getUser() {\n        return user;\n    }\n\n    public void setUser(User user) {\n        this.user = user;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/entity/DesignRes.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\n/**\n * 设计资源\n */\npublic class DesignRes extends BaseEntity {\n\n    private String desc;\n    private String srcTag;\n    private String name;\n    private String imgUrl;\n    private String srcLink;\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getSrcTag() {\n        return srcTag;\n    }\n\n    public void setSrcTag(String srcTag) {\n        this.srcTag = srcTag;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getImgUrl() {\n        return imgUrl;\n    }\n\n    public void setImgUrl(String imgUrl) {\n        this.imgUrl = imgUrl;\n    }\n\n    public String getSrcLink() {\n        return srcLink;\n    }\n\n    public void setSrcLink(String srcLink) {\n        this.srcLink = srcLink;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        if (!super.equals(o)) return false;\n\n        DesignRes designRes = (DesignRes) o;\n\n        if (desc != null ? !desc.equals(designRes.desc) : designRes.desc != null) return false;\n        if (srcTag != null ? !srcTag.equals(designRes.srcTag) : designRes.srcTag != null)\n            return false;\n        if (name != null ? !name.equals(designRes.name) : designRes.name != null) return false;\n        if (imgUrl != null ? !imgUrl.equals(designRes.imgUrl) : designRes.imgUrl != null)\n            return false;\n        return srcLink != null ? srcLink.equals(designRes.srcLink) : designRes.srcLink == null;\n\n    }\n\n    @Override\n    public int hashCode() {\n        int result = desc != null ? desc.hashCode() : 0;\n        result = 31 * result + (srcTag != null ? srcTag.hashCode() : 0);\n        result = 31 * result + (name != null ? name.hashCode() : 0);\n        result = 31 * result + (imgUrl != null ? imgUrl.hashCode() : 0);\n        result = 31 * result + (srcLink != null ? srcLink.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/entity/FeedBack.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class FeedBack extends BaseEntity {\n\n    private String content;\n    private String email;\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/entity/User.java",
    "content": "package com.boredream.designrescollection.entity;\n\n\nimport com.boredream.designrescollection.base.BaseEntity;\n\npublic class User extends BaseEntity {\n\n    private String sessionToken;\n\n    private String nickname;\n\n    private String username;\n\n    /**\n     * 验证手机号\n     */\n    private String mobilePhoneNumber;\n\n    /**\n     * 密码\n     */\n    private String password;\n\n    /**\n     * 手机号验证码,发送短信验证时请求使用\n     */\n    private String smsCode;\n\n    /**\n     * 头像图片地址\n     */\n    private String avatar;\n\n    private String company;\n\n    public String getSessionToken() {\n        return sessionToken;\n    }\n\n    public void setSessionToken(String sessionToken) {\n        this.sessionToken = sessionToken;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n\n    public String getAvatar() {\n        return avatar;\n    }\n\n    public void setAvatar(String avatar) {\n        this.avatar = avatar;\n    }\n\n    public String getSmsCode() {\n        return smsCode;\n    }\n\n    public void setSmsCode(String smsCode) {\n        this.smsCode = smsCode;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getMobilePhoneNumber() {\n        return mobilePhoneNumber;\n    }\n\n    public void setMobilePhoneNumber(String mobilePhoneNumber) {\n        this.mobilePhoneNumber = mobilePhoneNumber;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getNickname() {\n        return nickname;\n    }\n\n    public void setNickname(String nickname) {\n        this.nickname = nickname;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/net/ApiModule.java",
    "content": "package com.boredream.designrescollection.net;\n\nimport com.squareup.okhttp.OkHttpClient;\n\nimport javax.inject.Singleton;\n\nimport dagger.Module;\nimport dagger.Provides;\nimport retrofit.GsonConverterFactory;\nimport retrofit.Retrofit;\nimport retrofit.RxJavaCallAdapterFactory;\n\n@Module\npublic class ApiModule {\n\n    // LeanCloud\n    public static final String HOST = \"https://api.leancloud.cn\";\n\n    @Singleton\n    @Provides\n    ApiService provideApiService(OkHttpClient httpClient) {\n        // Retrofit\n        Retrofit retrofit = new Retrofit.Builder()\n                .baseUrl(HOST)\n                .addConverterFactory(GsonConverterFactory.create()) // gson\n                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // rxjava\n                .client(httpClient)\n                .build();\n\n        return retrofit.create(ApiService.class);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/net/ApiService.java",
    "content": "package com.boredream.designrescollection.net;\n\nimport com.boredream.bdcodehelper.entity.AppUpdateInfo;\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.entity.User;\nimport com.squareup.okhttp.RequestBody;\n\nimport java.util.Map;\n\nimport retrofit.http.Body;\nimport retrofit.http.GET;\nimport retrofit.http.POST;\nimport retrofit.http.PUT;\nimport retrofit.http.Path;\nimport retrofit.http.Query;\nimport rx.Observable;\n\npublic interface ApiService {\n    ////////////////////////////// 通用接口 //////////////////////////////\n    // 登录用户\n    @GET(\"/1/login\")\n    Observable<User> login(\n            @Query(\"username\") String username,\n            @Query(\"password\") String password);\n\n    // 注册用户\n    @POST(\"/1/users\")\n    Observable<User> register(\n            @Body User user);\n\n    // 修改用户详情(注意, 提交什么参数修改什么参数)\n    @PUT(\"/1/users/{objectId}\")\n    Observable<BaseEntity> updateUserById(\n            @Path(\"objectId\") String userId,\n            @Body Map<String, Object> updateInfo);\n\n    // 上传图片接口\n    @POST(\"/1/files/{fileName}\")\n    Observable<FileUploadResponse> fileUpload(\n            @Path(\"fileName\") String fileName,\n            @Body RequestBody image);\n\n    // 查询app更新信息\n    @GET(\"/1/classes/AppUpdateInfo\")\n    Observable<ListResponse<AppUpdateInfo>> getAppUpdateInfo();\n\n    // 提交意见反馈\n    @POST(\"/1/classes/FeedBack\")\n    Observable<BaseEntity> addFeedBack(\n            @Body FeedBack feedBack);\n\n\n    ////////////////////////////// 业务接口 //////////////////////////////\n\n    // 查询设计资源\n    @GET(\"/1/classes/DesignRes\")\n    Observable<ListResponse<DesignRes>> getDesignRes(\n            @Query(\"limit\") int perPageCount,\n            @Query(\"skip\") int page);\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/net/AppComponent.java",
    "content": "package com.boredream.designrescollection.net;\n\nimport com.boredream.designrescollection.base.BaseApplication;\nimport com.boredream.designrescollection.utils.PerApplication;\n\nimport javax.inject.Singleton;\n\nimport dagger.Component;\n\n@PerApplication\n@Singleton\n@Component(modules = {ApiModule.class})\npublic interface AppComponent {\n\n    void inject(BaseApplication request);\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/net/GlideHelper.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.content.Context;\nimport android.widget.ImageView;\n\nimport com.boredream.bdcodehelper.net.GlideCircleTransform;\nimport com.boredream.designrescollection.R;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\n\n/**\n * Glide\n */\npublic class GlideHelper {\n\n    public static void showAvatar(Context context, String avatar, ImageView iv) {\n        Glide.with(context)\n                .load(avatar)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .transform(new GlideCircleTransform(context))\n                .crossFade()\n                .into(iv);\n    }\n\n    public static void showImage(Context context, String imageUrl, ImageView iv) {\n        Glide.with(context)\n                .load(imageUrl)\n                .asBitmap()\n                .animate(android.R.anim.fade_in)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n                .into(iv);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/net/SimpleSubscriber.java",
    "content": "package com.boredream.designrescollection.net;\n\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\nimport rx.Subscriber;\n\n/**\n * 通用订阅者,用于统一处理回调\n */\npublic class SimpleSubscriber<T> extends Subscriber<T> {\n\n    private Context context;\n\n    public SimpleSubscriber(Context context) {\n        this.context = context;\n    }\n\n    @Override\n    public void onCompleted() {\n        // sub\n    }\n\n    @Override\n    public void onError(Throwable throwable) {\n        // 统一处理错误回调，显示Toast\n        String errorInfo = ErrorInfoUtils.parseHttpErrorInfo(throwable);\n        ToastUtils.showToast(context, errorInfo);\n    }\n\n    @Override\n    public void onNext(T t) {\n        // sub\n    }\n\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/AboutActivity.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.SpannableString;\nimport android.text.Spanned;\nimport android.text.method.LinkMovementMethod;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\n\npublic class AboutActivity extends BaseActivity {\n\n    private TextView tv_version;\n    private TextView tv_about;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_about);\n        initView();\n    }\n\n    private void initView() {\n        initBackTitle(\"关于我\");\n\n        tv_version = (TextView) findViewById(R.id.tv_version);\n        tv_about = (TextView) findViewById(R.id.tv_about);\n\n        tv_version.setText(\"Version \" + AppUtils.getAppVersionName(this));\n\n        SpannableString ss = getAboutString();\n        tv_about.setMovementMethod(LinkMovementMethod.getInstance());\n        tv_about.setText(ss);\n    }\n\n    private SpannableString getAboutString() {\n        final String githubLink = getString(R.string.github);\n        String format = String.format(getString(R.string.about), githubLink);\n        SpannableString ss = new SpannableString(format);\n        // 网址部分可点击,跳转到网页\n        StringUtils.PrimaryClickableSpan span = new StringUtils.PrimaryClickableSpan(this) {\n            @Override\n            public void onClick(View widget) {\n                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(githubLink));\n                startActivity(intent);\n            }\n        };\n        int start = format.indexOf(githubLink);\n        ss.setSpan(span, start, start + githubLink.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        return ss;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/MainActivity.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\n\nimport com.boredream.bdcodehelper.fragment.FragmentController;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.ApiService;\nimport com.boredream.designrescollection.ui.home.HomeFragment;\nimport com.boredream.designrescollection.utils.UpdateUtils;\n\nimport java.util.ArrayList;\n\nimport javax.inject.Inject;\n\n\npublic class MainActivity extends BaseActivity implements RadioGroup.OnCheckedChangeListener {\n\n    @Inject ApiService service;\n\n    private RadioGroup rg_bottom_tab;\n    private RadioButton rb1;\n    private FragmentController controller;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        initView();\n        initData();\n    }\n\n    private void initView() {\n        setCouldDoubleBackExit(true);\n\n        rg_bottom_tab = (RadioGroup) findViewById(R.id.rg_bottom_tab);\n        rb1 = (RadioButton) findViewById(R.id.rb1);\n\n        rg_bottom_tab.setOnCheckedChangeListener(this);\n    }\n\n    private void initData() {\n        ArrayList<Fragment> fragments = new ArrayList<>();\n        fragments.add(new HomeFragment());\n        fragments.add(new UserFragment());\n\n        controller = new FragmentController(this, R.id.fl_content, fragments);\n\n        // 默认Fragment\n        rb1.setChecked(true);\n        controller.showFragment(0);\n\n        UpdateUtils.checkUpdate(this, service.getAppUpdateInfo(), false);\n    }\n\n    @Override\n    public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {\n        switch (checkedId) {\n            case R.id.rb1:\n                controller.showFragment(0);\n                break;\n            case R.id.rb2:\n                controller.showFragment(1);\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/SettingActivity.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.Button;\n\nimport com.boredream.bdcodehelper.adapter.SettingRecyclerAdapter;\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.ApiService;\nimport com.boredream.designrescollection.ui.feedback.FeedBackActivity;\nimport com.boredream.designrescollection.utils.UpdateUtils;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.inject.Inject;\n\npublic class SettingActivity extends BaseActivity implements View.OnClickListener, AdapterView.OnItemClickListener {\n\n    @Inject ApiService service;\n    private RecyclerView rv_setting;\n    private Button btn_logout;\n\n    private SettingRecyclerAdapter adapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_setting);\n        initView();\n        initData();\n    }\n\n    private void initView() {\n        initBackTitle(\"设置\");\n\n        rv_setting = (RecyclerView) findViewById(R.id.rv_setting);\n        btn_logout = (Button) findViewById(R.id.btn_logout);\n\n        btn_logout.setOnClickListener(this);\n    }\n\n    private void initData() {\n        // 使用列表显示多个选项条\n        List<SettingItem> items = new ArrayList<>();\n\n        items.add(new SettingItem(\n                R.mipmap.ic_cached_grey600_24dp,\n                \"检查更新\",\n                AppUtils.getAppVersionName(this),\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n        items.add(new SettingItem(\n                R.mipmap.ic_announcement_grey600_24dp,\n                \"反馈\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n\n        adapter = new SettingRecyclerAdapter(items, this);\n        rv_setting.setAdapter(adapter);\n\n        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(\n                this, LinearLayoutManager.VERTICAL, false);\n        rv_setting.setLayoutManager(linearLayoutManager);\n        // 每个item之间的分割线\n        rv_setting.addItemDecoration(new DividerItemDecoration(this));\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        switch (position) {\n            case 0:\n                showProgressDialog();\n                // 强制检查更新,并添加额外回调用于处理进度框\n                UpdateUtils.checkUpdate(this, service.getAppUpdateInfo(), true);\n                break;\n            case 1:\n                if(UserInfoKeeper.checkLogin(this)) {\n                    // 一般意见反馈不需要登录，这里模拟下需登录场景的处理方法\n                    intent2Activity(FeedBackActivity.class);\n                }\n                break;\n        }\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_logout:\n                // 登出,清理用户数据同时跳转到主页\n                UserInfoKeeper.logout();\n                intent2Activity(MainActivity.class);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/UserFragment.java",
    "content": "package com.boredream.designrescollection.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\n\nimport com.boredream.bdcodehelper.entity.SettingItem;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\nimport com.boredream.bdcodehelper.view.EmptyItemDecoration;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.adapter.MoreRecyclerAdapter;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.ui.userinfoedit.UserInfoEditActivity;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class UserFragment extends BaseFragment implements AdapterView.OnItemClickListener {\n\n    private RecyclerView rv_user;\n    private MoreRecyclerAdapter adapter;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = View.inflate(activity, R.layout.frag_user, null);\n        initView(view);\n        initData();\n        return view;\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n\n        // 如果未登录进入本页面,然后跳转登录页面成功后返回,此时应该再次更新用户信息\n        adapter.setUser(UserInfoKeeper.getCurrentUser());\n        adapter.notifyDataSetChanged();\n    }\n\n    private void initView(View view) {\n        new TitleBuilder(view).setTitleText(\"更多\");\n\n        rv_user = (RecyclerView) view.findViewById(R.id.rv_user);\n    }\n\n    private void initData() {\n        // more items\n        List<SettingItem> items = new ArrayList<>();\n        items.add(new SettingItem(\n                R.mipmap.ic_info_grey600_24dp,\n                \"关于\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n        items.add(new SettingItem(\n                R.mipmap.ic_settings_grey600_24dp,\n                \"设置\",\n                null,\n                R.mipmap.ic_chevron_right_grey600_24dp\n        ));\n\n        adapter = new MoreRecyclerAdapter(items, this);\n        rv_user.setAdapter(adapter);\n\n        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(\n                activity, LinearLayoutManager.VERTICAL, false);\n        rv_user.setLayoutManager(linearLayoutManager);\n        // 每个item之间的分割线\n        rv_user.addItemDecoration(new DividerItemDecoration(activity));\n        // 每组item之间的分割间隔\n        rv_user.addItemDecoration(new EmptyItemDecoration(\n                new Integer[]{0, 1}, DisplayUtils.dp2px(activity, 16)));\n\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        switch (position) {\n            case -1:\n                // 给特殊的用户信息header位置设为了position=-1的item click事件\n                intent2Activity(UserInfoEditActivity.class);\n                break;\n            case 0:\n                intent2Activity(AboutActivity.class);\n                break;\n            case 1:\n                intent2Activity(SettingActivity.class);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/feedback/FeedBackActivity.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\n\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.EditText;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.ApiService;\n\nimport javax.inject.Inject;\n\npublic class FeedBackActivity extends BaseActivity implements FeedBackContract.View {\n\n    private FeedBackContract.Presenter presenter;\n    private EditText et_content;\n    private EditText et_email;\n    @Inject ApiService service;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_feed_back);\n\n        initView();\n    }\n\n    private void initView() {\n        presenter = new FeedBackPresenter(this, service);\n\n        initBackTitle(\"意见反馈\")\n                .setRightText(\"提交\")\n                .setRightOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        submit();\n                    }\n                });\n\n        et_content = (EditText) findViewById(R.id.et_content);\n        et_email = (EditText) findViewById(R.id.et_email);\n\n    }\n\n    private void submit() {\n        // 开始验证输入内容\n        String content = et_content.getText().toString().trim();\n        String email = et_email.getText().toString().trim();\n\n        presenter.addFeedback(content, email);\n    }\n\n    @Override\n    public void addFeedbackSuccess() {\n        showToast(\"反馈成功\");\n        finish();\n    }\n\n    @Override\n    public void setPresenter(FeedBackContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/feedback/FeedBackContract.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\n\npublic interface FeedBackContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void addFeedbackSuccess();\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void addFeedback(String content, String email);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/feedback/FeedBackPresenter.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.net.ApiService;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class FeedBackPresenter implements FeedBackContract.Presenter {\n\n    private final FeedBackContract.View view;\n    private final ApiService api;\n\n    public FeedBackPresenter(FeedBackContract.View view, ApiService api) {\n        this.view = view;\n        this.api = api;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void addFeedback(String content, String email) {\n        // 开始验证输入内容\n        if (StringUtils.isEmpty(content)) {\n            view.showTip(\"反馈内容不能为空\");\n            return;\n        }\n\n        if (StringUtils.isEmpty(email)) {\n            view.showTip(\"请输入邮箱地址,方便我们对您的意见进行及时回复\");\n            return;\n        }\n\n        view.showProgress();\n\n        // 使用自定义对象存至云平台,作为简易版的反馈意见收集\n        FeedBack fb = new FeedBack();\n        fb.setContent(content);\n        fb.setEmail(email);\n\n        Observable<BaseEntity> observable = ObservableDecorator.decorate(api.addFeedBack(fb));\n        observable.subscribe(new Subscriber<BaseEntity>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.showTip(\"反馈提交失败\");\n            }\n\n            @Override\n            public void onNext(BaseEntity entity) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.addFeedbackSuccess();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/home/HomeContract.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\nimport com.boredream.designrescollection.entity.DesignRes;\n\nimport java.util.List;\n\npublic interface HomeContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void loadListSuccess(int page, List<DesignRes> datas);\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void loadList(int page);\n\n        void pullToLoadList();\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/home/HomeFragment.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\n\nimport android.os.Bundle;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.view.GridSpacingDecorator;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.adapter.DesignResAdapter;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.constants.CommonConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class HomeFragment extends BaseFragment implements HomeContract.View {\n\n    private View view;\n    private SwipeRefreshLayout srl;\n    private RecyclerView rv;\n\n    private HomeContract.Presenter presenter;\n    private int curPage = 1;\n    private ArrayList<DesignRes> datas = new ArrayList<>();\n    private LoadMoreAdapter adapter;\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        view = View.inflate(activity, R.layout.frag_home, null);\n        initView();\n        initData();\n        return view;\n    }\n\n    private void initView() {\n        presenter = new HomePresenter(this);\n        new TitleBuilder(view).setTitleText(getString(R.string.tab1));\n\n        srl = (SwipeRefreshLayout) view.findViewById(R.id.srl);\n        srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {\n            @Override\n            public void onRefresh() {\n                presenter.pullToLoadList();\n            }\n        });\n\n        rv = (RecyclerView) view.findViewById(R.id.rv);\n        rv.addItemDecoration(new GridSpacingDecorator(DisplayUtils.dp2px(activity, 8)));\n        GridLayoutManager gridLayoutManager = new GridLayoutManager(activity, 2);\n        rv.setLayoutManager(gridLayoutManager);\n\n        adapter = new LoadMoreAdapter(rv,\n                new DesignResAdapter(activity, datas),\n                new LoadMoreAdapter.OnLoadMoreListener() {\n                    @Override\n                    public void onLoadMore() {\n                        presenter.loadList(curPage + 1);\n                    }\n                });\n        rv.setAdapter(adapter);\n    }\n\n    private void initData() {\n        presenter.loadList(1);\n    }\n\n    @Override\n    public void loadListSuccess(int page, List<DesignRes> datas) {\n        curPage = page;\n        if (curPage == 1) {\n            this.datas.clear();\n        }\n        this.datas.addAll(datas);\n\n        // 设置是否已加载完全部数据状态\n        adapter.setStatus(datas.size() == CommonConstants.COUNT_OF_PAGE\n                ? LoadMoreAdapter.STATUS_HAVE_MORE : LoadMoreAdapter.STATUS_LOADED_ALL);\n        adapter.notifyDataSetChanged();\n    }\n\n    @Override\n    public void setPresenter(HomeContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isAdded();\n    }\n\n    @Override\n    public void showProgress() {\n        srl.post(new Runnable() {\n            @Override\n            public void run() {\n                srl.setRefreshing(true);\n            }\n        });\n    }\n\n    @Override\n    public void dismissProgress() {\n        srl.setRefreshing(false);\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/home/HomePresenter.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.designrescollection.constants.CommonConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\nimport com.boredream.designrescollection.net.ApiService;\n\nimport java.util.List;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class HomePresenter implements HomeContract.Presenter {\n\n    private final HomeContract.View view;\n    private final ApiService service;\n    public List<DesignRes> datas;\n\n    public HomePresenter(HomeContract.View view, ApiService service) {\n        this.view = view;\n        this.service = service;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void pullToLoadList() {\n        loadData(1);\n    }\n\n    @Override\n    public void loadList(final int page) {\n        if(page == 1) {\n            view.showProgress();\n        }\n\n        loadData(page);\n    }\n\n    private void loadData(final int page) {\n        Observable<ListResponse<DesignRes>> observable = service.getDesignRes(\n                CommonConstants.COUNT_OF_PAGE, (page - 1) * CommonConstants.COUNT_OF_PAGE);\n        ObservableDecorator.decorate(observable).subscribe(\n                new Subscriber<ListResponse<DesignRes>>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        if (!view.isActive()) {\n                            return;\n                        }\n                        view.dismissProgress();\n\n                        String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                        view.showTip(error);\n                    }\n\n                    @Override\n                    public void onNext(ListResponse<DesignRes> response) {\n                        if (!view.isActive()) {\n                            return;\n                        }\n                        view.dismissProgress();\n\n                        datas = response.getResults();\n                        view.loadListSuccess(page, datas);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/login/LoginActivity.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\n\nimport android.os.Bundle;\n\nimport com.boredream.bdcodehelper.utils.ActivityUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\n\nimport javax.inject.Inject;\n\npublic class LoginActivity extends BaseActivity {\n\n    /**\n     * 是否为验证登录,true-登录成功后,直接finish返回到来源页 false-登录成功后跳转到主页\n     */\n    private boolean checkLogin;\n\n    @Inject LoginPresenter presenter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_login);\n\n        initExtras();\n        initView();\n    }\n\n    private void initExtras() {\n        checkLogin = getIntent().getBooleanExtra(\"checkLogin\", false);\n    }\n\n    private void initView() {\n        initBackTitle(\"登录\");\n\n        LoginFragment loginFragment = (LoginFragment) getSupportFragmentManager().findFragmentById(R.id.fl_content);\n        if (loginFragment == null) {\n            loginFragment = LoginFragment.newInstance(checkLogin);\n            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), loginFragment, R.id.fl_content);\n        }\n\n        DaggerLoginComponent.builder()\n                .loginPresenterModule(new LoginPresenterModule(loginFragment))\n                .build()\n                .inject(this);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/login/LoginComponent.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport com.boredream.designrescollection.utils.PerActivity;\n\nimport dagger.Component;\n\n@PerActivity\n@Component(modules = {LoginPresenterModule.class})\npublic interface LoginComponent {\n    void inject(LoginActivity activity);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/login/LoginContract.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\nimport com.boredream.designrescollection.entity.User;\n\n/**\n * This specifies the contract between the view and the presenter.\n */\npublic interface LoginContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void loginSuccess(User user);\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void login(String username, String password);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/login/LoginFragment.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseFragment;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.ui.MainActivity;\nimport com.boredream.designrescollection.ui.register.RegisterStep1Activity;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\npublic class LoginFragment extends BaseFragment implements LoginContract.View, View.OnClickListener {\n\n    private static final String ARGUMENT_CHECK_LOGIN = \"checkLogin\";\n    private boolean checkLogin;\n\n    private LoginContract.Presenter presenter;\n\n    private EditText et_username;\n    private EditText et_password;\n    private TextView tv_forget_psw;\n    private Button btn_login;\n    private LinearLayout ll_regist;\n\n    public static LoginFragment newInstance(boolean checkLogin) {\n        Bundle arguments = new Bundle();\n        arguments.putBoolean(ARGUMENT_CHECK_LOGIN, checkLogin);\n        LoginFragment fragment = new LoginFragment();\n        fragment.setArguments(arguments);\n        return fragment;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View view = View.inflate(activity, R.layout.frag_login, null);\n        initExtras();\n        initView(view);\n        return view;\n    }\n\n    private void initExtras() {\n        checkLogin = getArguments().getBoolean(ARGUMENT_CHECK_LOGIN);\n    }\n\n    private void initView(View view) {\n        et_username = (EditText) view.findViewById(R.id.et_username);\n        et_password = (EditText) view.findViewById(R.id.et_password);\n        tv_forget_psw = (TextView) view.findViewById(R.id.tv_forget_psw);\n        btn_login = (Button) view.findViewById(R.id.btn_login);\n        ll_regist = (LinearLayout) view.findViewById(R.id.ll_regist);\n\n        tv_forget_psw.setOnClickListener(this);\n        btn_login.setOnClickListener(this);\n        ll_regist.setOnClickListener(this);\n    }\n\n    @Override\n    public void onClick(View v) {\n        Intent intent = new Intent(activity, RegisterStep1Activity.class);\n        switch (v.getId()) {\n            case R.id.btn_login:\n                String username = et_username.getText().toString().trim();\n                String password = et_password.getText().toString().trim();\n                presenter.login(username, password);\n                break;\n            case R.id.tv_forget_psw:\n                intent.putExtra(\"type\", 1);\n                startActivity(intent);\n                break;\n            case R.id.ll_regist:\n                intent.putExtra(\"type\", 0);\n                startActivity(intent);\n                break;\n        }\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void loginSuccess(User user) {\n        dismissProgressDialog();\n\n        UserInfoKeeper.setCurrentUser(user);\n\n        if (checkLogin) {\n            activity.finish();\n        } else {\n            intent2Activity(MainActivity.class);\n        }\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n\n    @Override\n    public boolean isActive() {\n        return isAdded();\n    }\n\n    @Override\n    public void setPresenter(LoginContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/login/LoginPresenter.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.ApiService;\n\nimport javax.inject.Inject;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class LoginPresenter implements LoginContract.Presenter {\n\n    private final LoginContract.View view;\n    private final ApiService service;\n\n    @Inject\n    public LoginPresenter(LoginContract.View view, ApiService service) {\n        this.view = view;\n        this.service = service;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void login(String username, String password) {\n        if (StringUtils.isEmpty(username)) {\n            view.showTip(\"用户名不能为空\");\n            return;\n        }\n\n        if (StringUtils.isEmpty(password)) {\n            view.showTip(\"密码不能为空\");\n            return;\n        }\n\n        view.showProgress();\n\n        Observable<User> observable = service.login(username, password);\n        ObservableDecorator.decorate(observable).subscribe(new Subscriber<User>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                view.showTip(error);\n            }\n\n            @Override\n            public void onNext(User user) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.loginSuccess(user);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/login/LoginPresenterModule.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport dagger.Module;\nimport dagger.Provides;\n\n@Module\npublic class LoginPresenterModule {\n\n    private final LoginContract.View mView;\n\n    public LoginPresenterModule(LoginContract.View view) {\n        mView = view;\n    }\n\n    @Provides\n    LoginContract.View provideLoginContractView() {\n        return mView;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/modifytext/ModifyTextActivity.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.EditText;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\n\n/**\n * 修改文字内容输入框页面\n */\npublic class ModifyTextActivity extends BaseActivity implements ModifyTextContract.View {\n\n    public static final String EXTRA_TITLE = \"title\";\n    public static final String EXTRA_OLD_STRING = \"oldString\";\n\n    public static final String RESULT_IS_MODIFY = \"isModify\";\n    public static final String RESULT_NEW_STRING = \"newString\";\n\n    private String title;\n    private String oldString;\n\n    private ModifyTextContract.Presenter presenter;\n    private EditText et_input;\n\n    public static void start(Activity context, int requestCode, String title, String oldString) {\n        Intent intent = new Intent(context, ModifyTextActivity.class);\n        intent.putExtra(ModifyTextActivity.EXTRA_TITLE, title);\n        intent.putExtra(ModifyTextActivity.EXTRA_OLD_STRING, oldString);\n        context.startActivityForResult(intent, requestCode);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_input);\n\n        initExtras();\n        initView();\n        initData();\n    }\n\n    private void initExtras() {\n        Intent intent = getIntent();\n        title = intent.getStringExtra(EXTRA_TITLE);\n        oldString = intent.getStringExtra(EXTRA_OLD_STRING);\n    }\n\n    private void initView() {\n        presenter = new ModifyTextPresenter(this);\n\n        initBackTitle(title + \"修改\")\n                .setRightText(\"保存\")\n                .setRightOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        submit();\n                    }\n                });\n        et_input = (EditText) findViewById(R.id.et_input);\n    }\n\n    private void initData() {\n        if (oldString != null) {\n            et_input.setText(oldString);\n        }\n    }\n\n    private void submit() {\n        String str = et_input.getText().toString().trim();\n        presenter.modifyText(title, oldString, str);\n    }\n\n    @Override\n    public void modifyTextSuccess(boolean isModify, String newString) {\n        Intent intent = new Intent();\n        intent.putExtra(RESULT_NEW_STRING, newString);\n        intent.putExtra(RESULT_IS_MODIFY, isModify);\n        setResult(RESULT_OK, intent);\n        finish();\n    }\n\n    @Override\n    public void setPresenter(ModifyTextContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n\n    }\n\n    @Override\n    public void dismissProgress() {\n\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/modifytext/ModifyTextContract.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\n\npublic interface ModifyTextContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void modifyTextSuccess(boolean isModify, String newString);\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void modifyText(String title, String oldString, String modifyString);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/modifytext/ModifyTextPresenter.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport com.boredream.bdcodehelper.utils.StringUtils;\n\npublic class ModifyTextPresenter implements ModifyTextContract.Presenter {\n\n    private final ModifyTextContract.View view;\n\n    public ModifyTextPresenter(ModifyTextContract.View view) {\n        this.view = view;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void modifyText(String title, String oldString, String modifyString) {\n        if (StringUtils.isEmpty(modifyString)) {\n            view.showTip(title + \"不能为空\");\n            return;\n        }\n\n        // 旧文字为空或旧文字和新文字不相等，视为已修改\n        boolean isModify = oldString == null || !oldString.equals(modifyString);\n        view.modifyTextSuccess(isModify, modifyString);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterContract.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\nimport com.boredream.designrescollection.entity.User;\n\npublic class RegisterContract {\n    interface View extends BaseView<Presenter> {\n\n        void requestSmsSuccess(String phone, String password);\n\n        void registerSuccess(User user);\n    }\n\n    interface Presenter extends BasePresenter {\n\n        void requestSms(String phone, String password);\n\n        void register(String phone, String password, String code);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterPresenter.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.ApiService;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class RegisterPresenter implements RegisterContract.Presenter {\n\n    private RegisterContract.View view;\n    private ApiService service;\n\n    public RegisterPresenter(RegisterContract.View view, ApiService service) {\n        this.view = view;\n        this.service = service;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void requestSms(final String phone, final String password) {\n        if (StringUtils.isEmpty(phone)) {\n            view.showTip(\"请输入用户名\");\n            return;\n        }\n\n        if (StringUtils.isEmpty(password) || password.length() < 6) {\n            view.showTip(\"请设置登录密码，不少于6位\");\n            return;\n        }\n\n        view.showProgress();\n\n        // FIXME 模拟获取短信接口\n        Observable<String> observable = Observable.just(\"发送验证码咯~\");\n        ObservableDecorator.decorate(observable).subscribe(new Subscriber<String>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                view.showTip(error);\n            }\n\n            @Override\n            public void onNext(String string) {\n                if (!view.isActive()) {\n                    return;\n                }\n                view.dismissProgress();\n\n                view.requestSmsSuccess(phone, password);\n            }\n        });\n    }\n\n    @Override\n    public void register(String phone, String password, String code) {\n        if (StringUtils.isEmpty(code)) {\n            view.showTip(\"请输入验证码\");\n            return;\n        }\n\n        view.showProgress();\n\n        // 注册接口\n        User user = new User();\n        user.setMobilePhoneNumber(phone);\n        user.setUsername(phone);\n        user.setPassword(password);\n        user.setSmsCode(code);\n        Observable<User> observable = service.register(user);\n        ObservableDecorator.decorate(observable).subscribe(new Subscriber<User>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        if (!view.isActive()) {\n                            return;\n                        }\n\n                        view.dismissProgress();\n\n                        String error = ErrorInfoUtils.parseHttpErrorInfo(e);\n                        view.showTip(error);\n                    }\n\n                    @Override\n                    public void onNext(User user) {\n                        UserInfoKeeper.setCurrentUser(user);\n\n                        if (!view.isActive()) {\n                            return;\n                        }\n\n                        view.dismissProgress();\n\n                        view.registerSuccess(user);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterStep1Activity.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\n\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.ApiService;\n\nimport javax.inject.Inject;\n\n/**\n * 注册页面步骤一\n */\npublic class RegisterStep1Activity extends BaseActivity implements View.OnClickListener, RegisterContract.View {\n\n    private RegisterContract.Presenter presenter;\n    @Inject ApiService service;\n\n    private EditText et_username;\n    private EditText et_password;\n    private Button btn_next;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_register_step1);\n\n        initView();\n    }\n\n    private void initView() {\n        presenter = new RegisterPresenter(this, service);\n        initBackTitle(\"注册\");\n\n        et_username = (EditText) findViewById(R.id.et_username);\n        et_password = (EditText) findViewById(R.id.et_password);\n        btn_next = (Button) findViewById(R.id.btn_next);\n\n        btn_next.setOnClickListener(this);\n    }\n\n    private void next() {\n        String phone = et_username.getText().toString().trim();\n        String password = et_password.getText().toString().trim();\n\n        presenter.requestSms(phone, password);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_next:\n                next();\n                break;\n        }\n    }\n\n    @Override\n    public void requestSmsSuccess(String phone, String password) {\n        // 短信验证码发送成功后,跳转到短信验证页,同时传递所需数据\n        Intent intent = new Intent(this, RegisterStep2Activity.class);\n        intent.putExtra(\"phone\", phone);\n        intent.putExtra(\"password\", password);\n        startActivity(intent);\n    }\n\n    @Override\n    public void registerSuccess(User user) {\n        // do nothing\n    }\n\n    @Override\n    public void setPresenter(RegisterContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/register/RegisterStep2Activity.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\n\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.CountDownTimer;\nimport android.support.v7.app.AlertDialog;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\n\nimport com.boredream.bdcodehelper.utils.DateUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.ApiService;\nimport com.boredream.designrescollection.ui.MainActivity;\n\nimport javax.inject.Inject;\n\n/**\n * 注册页面步骤二\n */\npublic class RegisterStep2Activity extends BaseActivity implements View.OnClickListener, RegisterContract.View {\n\n    // 总倒计时60秒\n    private static final long TOTCAL_TIME = 60 * DateUtils.ONE_SECOND_MILLIONS;\n    // 每次减少1秒\n    private static final long COUNT_DOWN_INTERVAL = DateUtils.ONE_SECOND_MILLIONS;\n\n    private RegisterContract.Presenter presenter;\n    @Inject ApiService service;\n\n    private EditText et_verification_code;\n    private Button btn_code_info;\n    private Button btn_next;\n\n    private String phone;\n    private String password;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_register_step2);\n\n        initExtras();\n        initView();\n        initData();\n    }\n\n    private void initExtras() {\n        Intent intent = getIntent();\n        phone = intent.getStringExtra(\"phone\");\n        password = intent.getStringExtra(\"password\");\n    }\n\n    private void initView() {\n        presenter = new RegisterPresenter(this, service);\n        initBackTitle(\"手机号验证\");\n\n        et_verification_code = (EditText) findViewById(R.id.et_verification_code);\n        btn_code_info = (Button) findViewById(R.id.btn_code_info);\n        btn_next = (Button) findViewById(R.id.btn_next);\n\n        btn_code_info.setOnClickListener(this);\n        btn_next.setOnClickListener(this);\n    }\n\n    private void initData() {\n        startCountDown();\n    }\n\n    /**\n     * 开始倒计时\n     */\n    private void startCountDown() {\n        showToast(\"短信验证码发送成功\");\n\n        btn_code_info.setText(\"60秒\");\n        btn_code_info.setEnabled(false);\n\n        // 倒计时开始,共60秒,每次减少1秒\n        CountDownTimer timer = new CountDownTimer(TOTCAL_TIME, COUNT_DOWN_INTERVAL) {\n            @Override\n            public void onTick(long l) {\n                // 重新获取(60)\n                String restTime = (int) (l / COUNT_DOWN_INTERVAL) + \"秒\";\n                btn_code_info.setText(restTime);\n            }\n\n            @Override\n            public void onFinish() {\n                // 倒计时结束,重置按钮\n                btn_code_info.setText(\"重新获取\");\n                btn_code_info.setEnabled(true);\n            }\n        };\n        timer.start();\n    }\n\n    /**\n     * 根据类型提交注册或重置密码接口\n     */\n    private void submit() {\n        String code = et_verification_code.getText().toString().trim();\n        presenter.register(phone, password, code);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_code_info:\n                presenter.requestSms(phone, password);\n                break;\n            case R.id.btn_next:\n                submit();\n                break;\n        }\n    }\n\n    @Override\n    public void requestSmsSuccess(String phone, String password) {\n        startCountDown();\n    }\n\n    @Override\n    public void registerSuccess(User user) {\n        // 注册成功提示框,提醒用户完善资料\n        new AlertDialog.Builder(this)\n                .setMessage(\"注册成功，你可以在个人详情中修改或完善用户信息。\")\n                .setPositiveButton(\"确定\", null)\n                .setOnDismissListener(new DialogInterface.OnDismissListener() {\n                    @Override\n                    public void onDismiss(DialogInterface dialog) {\n                        // 确定或者返回键关闭对话框都走此\n                        intent2Activity(MainActivity.class);\n                    }\n                })\n                .setCancelable(false) // cancelable设为false,防止用户点击返回键关闭对话框停留在当前页面\n                .show();\n    }\n\n    @Override\n    public void setPresenter(RegisterContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditActivity.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ImageUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.ApiService;\nimport com.boredream.designrescollection.net.GlideHelper;\nimport com.boredream.designrescollection.ui.modifytext.ModifyTextActivity;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport javax.inject.Inject;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class UserInfoEditActivity extends BaseActivity implements View.OnClickListener, UserInfoEditContract.View {\n\n    private static final int REQUEST_CODE_MODIFY_NICKNAME = 110;\n\n    private UserInfoEditContract.Presenter presenter;\n    @Inject ApiService service;\n\n    private ImageView iv_avatar;\n    private LinearLayout ll_avatar;\n    private TextView tv_username;\n    private LinearLayout ll_username;\n\n    private User currentUser;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_user_info_edit);\n\n        initView();\n        initData();\n    }\n\n    private void initData() {\n        currentUser = UserInfoKeeper.getCurrentUser();\n        GlideHelper.showAvatar(this, currentUser.getAvatar(), iv_avatar);\n        tv_username.setText(currentUser.getNickname());\n    }\n\n    private void initView() {\n        presenter = new UserInfoEditPresenter(this, service, UserInfoKeeper.getCurrentUser());\n\n        initBackTitle(\"修改个人资料\");\n\n        iv_avatar = (ImageView) findViewById(R.id.iv_avatar);\n        ll_avatar = (LinearLayout) findViewById(R.id.ll_avatar);\n        tv_username = (TextView) findViewById(R.id.tv_username);\n        ll_username = (LinearLayout) findViewById(R.id.ll_username);\n\n        ll_avatar.setOnClickListener(this);\n        ll_username.setOnClickListener(this);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.ll_avatar:\n                ImageUtils.showImagePickDialog(this);\n                break;\n            case R.id.ll_username:\n                ModifyTextActivity.start(this, REQUEST_CODE_MODIFY_NICKNAME,\n                        \"昵称\", currentUser.getNickname());\n                break;\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n\n        Uri uri;\n        switch (requestCode) {\n            case ImageUtils.REQUEST_CODE_FROM_ALBUM:\n                // 从相册选择\n                uri = data.getData();\n                compressAndUpload(uri);\n                break;\n            case ImageUtils.REQUEST_CODE_FROM_CAMERA:\n                // 相机拍照\n                uri = ImageUtils.imageUriFromCamera;\n                compressAndUpload(uri);\n                break;\n            case REQUEST_CODE_MODIFY_NICKNAME:\n                boolean isModify = data.getBooleanExtra(ModifyTextActivity.RESULT_IS_MODIFY, true);\n                if (!isModify) {\n                    // 未修改，不做任何操作\n                    return;\n                }\n                presenter.updateNickname(data.getStringExtra(ModifyTextActivity.RESULT_NEW_STRING));\n                break;\n        }\n    }\n\n    private void compressAndUpload(final Uri uri) {\n        showProgress();\n\n        Observable<byte[]> observable = ImageUtils.compressImage(this, uri, iv_avatar.getWidth(), iv_avatar.getHeight());\n        ObservableDecorator.decorate(observable)\n                .subscribe(new Subscriber<byte[]>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onError(Throwable e) {\n                        showToast(e.getMessage());\n                        dismissProgress();\n                    }\n\n                    @Override\n                    public void onNext(byte[] bytes) {\n                        presenter.uploadAvatar(bytes);\n                    }\n                });\n    }\n\n    @Override\n    public void uploadUserInfoSuccess() {\n        initData();\n    }\n\n    @Override\n    public void setPresenter(UserInfoEditContract.Presenter presenter) {\n        this.presenter = presenter;\n    }\n\n    @Override\n    public boolean isActive() {\n        return isActive;\n    }\n\n    @Override\n    public void showProgress() {\n        showProgressDialog();\n    }\n\n    @Override\n    public void dismissProgress() {\n        dismissProgressDialog();\n    }\n\n    @Override\n    public void showTip(String message) {\n        showToast(message);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditContract.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport com.boredream.designrescollection.base.BasePresenter;\nimport com.boredream.designrescollection.base.BaseView;\n\npublic interface UserInfoEditContract {\n\n    interface View extends BaseView<Presenter> {\n\n        void uploadUserInfoSuccess();\n\n    }\n\n    interface Presenter extends BasePresenter {\n\n        /**\n         * 上传用户头像\n         */\n        void uploadAvatar(byte[] bytes);\n\n        /**\n         * 修改昵称\n         */\n        void updateNickname(String nickname);\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditPresenter.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.ErrorInfoUtils;\nimport com.boredream.bdcodehelper.utils.StringUtils;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.ApiService;\nimport com.squareup.okhttp.MediaType;\nimport com.squareup.okhttp.RequestBody;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport rx.Observable;\nimport rx.Subscriber;\n\npublic class UserInfoEditPresenter implements UserInfoEditContract.Presenter {\n\n    private final UserInfoEditContract.View view;\n    private final ApiService service;\n    private final User user;\n\n    public UserInfoEditPresenter(UserInfoEditContract.View view,\n                                 ApiService service,\n                                 User user) {\n        this.view = view;\n        this.service = service;\n        this.user = user;\n        this.view.setPresenter(this);\n    }\n\n    @Override\n    public void uploadAvatar(byte[] bytes) {\n        // 第一步,上传头像文件到服务器\n        String filename = \"image_\" + System.currentTimeMillis() + \".jpg\";\n        RequestBody requestBody = RequestBody.create(MediaType.parse(\"image/jpeg\"), bytes);\n        Observable<FileUploadResponse> observable = service.fileUpload(filename, requestBody);\n        ObservableDecorator.decorate(observable).subscribe(\n                new Subscriber<FileUploadResponse>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onNext(FileUploadResponse fileUploadResponse) {\n                        // 第二步,将上传图片返回的url地址更新至用户对象中\n                        updateUserAvatar(/*HttpRequest.FILE_HOST + */fileUploadResponse.getUrl());\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        view.dismissProgress();\n                    }\n                });\n    }\n\n    /**\n     * 更新用户头像\n     *\n     * @param avatarUrl 头像图片地址\n     */\n    public void updateUserAvatar(final String avatarUrl) {\n        Map<String, Object> updateMap = new HashMap<>();\n        updateMap.put(\"avatar\", avatarUrl);\n\n        Observable<BaseEntity> observable = service.updateUserById(\n                user.getObjectId(), updateMap);\n        ObservableDecorator.decorate(observable)\n                .subscribe(new Subscriber<BaseEntity>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onNext(BaseEntity entity) {\n                        view.dismissProgress();\n\n                        // 成功后更新当前用户的头像数据\n                        user.setAvatar(avatarUrl);\n\n                        view.uploadUserInfoSuccess();\n\n                        view.showTip(\"上传修改头像成功\");\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        view.dismissProgress();\n\n                        view.showTip(\"上传修改头像失败\");\n                    }\n                });\n    }\n\n    @Override\n    public void updateNickname(final String nickname) {\n        // validate\n        if (StringUtils.isEmpty(nickname)) {\n            view.showTip(\"昵称不能为空\");\n            return;\n        }\n\n        view.showProgress();\n\n        Map<String, Object> updateMap = new HashMap<>();\n        updateMap.put(\"nickname\", nickname);\n        Observable<BaseEntity> observable = service.updateUserById(user.getObjectId(), updateMap);\n        ObservableDecorator.decorate(observable)\n                .subscribe(new Subscriber<BaseEntity>() {\n                    @Override\n                    public void onCompleted() {\n\n                    }\n\n                    @Override\n                    public void onNext(BaseEntity entity) {\n                        view.dismissProgress();\n\n                        // 修改成功后更新当前用户的昵称\n                        user.setNickname(nickname);\n\n                        view.showTip(\"昵称修改成功\");\n                        view.uploadUserInfoSuccess();\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        view.dismissProgress();\n\n                        String error = ErrorInfoUtils.parseHttpErrorInfo(throwable);\n                        view.showTip(error);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/utils/PerActivity.java",
    "content": "package com.boredream.designrescollection.utils;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport javax.inject.Scope;\n\n@Documented\n@Scope\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface PerActivity {\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/utils/PerApplication.java",
    "content": "package com.boredream.designrescollection.utils;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport javax.inject.Scope;\n\n@Documented\n@Scope\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface PerApplication {\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/utils/UpdateUtils.java",
    "content": "package com.boredream.designrescollection.utils;\n\n\nimport android.app.Activity;\nimport android.app.DownloadManager;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.support.annotation.NonNull;\nimport android.support.v7.app.AlertDialog;\n\nimport com.boredream.bdcodehelper.entity.AppUpdateInfo;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.DialogUtils;\nimport com.boredream.bdcodehelper.utils.NetUtils;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\nimport com.boredream.designrescollection.R;\nimport com.boredream.designrescollection.base.BaseActivity;\nimport com.boredream.designrescollection.net.SimpleSubscriber;\n\nimport java.util.ArrayList;\nimport java.util.Locale;\n\nimport rx.Observable;\n\n/**\n * 检查更新工具类\n * <p>\n * 可以注册下载完成广播，在其中进行提示跳转安装等行为\n * <p>\n * <li>注册广播</li>\n * <pre>\n *      context.registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));\n * </pre>\n * <p>\n * <li>使用广播</li>\n * <pre>\n *      String action = intent.getAction();\n *      if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {\n *          long enqueueId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);\n *          Uri uri = UpdateUtils.getDownloadUriById(context, enqueueId);\n *          // do something\n *      }\n * </pre>\n * </p>\n */\npublic class UpdateUtils {\n\n    public static final int DOWNLOAD_STATUS_NEED_LOAD = 1;\n    public static final int DOWNLOAD_STATUS_RUNNING = 2;\n    public static final int DOWNLOAD_STATUS_LOADED = 3;\n\n    /**\n     * 检测版本更新\n     *\n     * @param context\n     * @param isForceCheck 是否强制检测更新\n     *                     true强制 - 无论什么网络环境都会提示更新\n     *                     false非强制 - WiFi情况下才提示更新\n     */\n    public static void checkUpdate(final BaseActivity context,\n                                   Observable<ListResponse<AppUpdateInfo>> observable,\n                                   final boolean isForceCheck) {\n        if (!NetUtils.isConnected(context)) {\n            // 无网络时\n            if (isForceCheck) {\n                // 手动强制检测更新时，提示文字\n                ToastUtils.showToast(context, \"请检查网络连接\");\n            } else {\n                // 非强制不做操作\n            }\n            return;\n        }\n\n        // 开始检测更新\n\n        if (isForceCheck) {\n            // 强制更新时，才提示进度框\n            context.showProgressDialog();\n        }\n\n        ObservableDecorator.decorate(observable).subscribe(\n                new SimpleSubscriber<ListResponse<AppUpdateInfo>>(context) {\n                    @Override\n                    public void onError(Throwable throwable) {\n                        if (isForceCheck) {\n                            // 强制更新时，才提示错误\n                            super.onError(throwable);\n                        }\n                        context.dismissProgressDialog();\n                    }\n\n                    @Override\n                    public void onNext(ListResponse<AppUpdateInfo> response) {\n                        context.dismissProgressDialog();\n\n                        ArrayList<AppUpdateInfo> results = response.getResults();\n                        if (results.size() == 0) {\n                            if (isForceCheck) {\n                                ToastUtils.showToast(context, \"当前已经是最新版本\");\n                            }\n                        }\n\n\n                        AppUpdateInfo newestUpdateInfo = results.get(0);\n                        for (AppUpdateInfo updateInfo : results) {\n                            if (updateInfo.getVersion() > newestUpdateInfo.getVersion()) {\n                                // 取最大版本号的作为最新版本\n                                newestUpdateInfo = updateInfo;\n                            }\n                        }\n\n                        if (newestUpdateInfo.getVersion() <= AppUtils.getAppVersionCode(context)) {\n                            if (isForceCheck) {\n                                ToastUtils.showToast(context, \"当前已经是最新版本\");\n                            }\n                        } else {\n                            showUpdateConfirmDialog(context, newestUpdateInfo);\n                        }\n                    }\n                }\n        );\n    }\n\n    /**\n     * 无Wifi状态确认更新对话框\n     */\n    private static void showNoWifiConfirmDialog(final BaseActivity context, final AppUpdateInfo updateInfo) {\n        DialogUtils.showCommonDialog(context, \"没有wifi连接，是否继续选择更新？\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        startDownload(context, updateInfo);\n                    }\n                });\n    }\n\n    /**\n     * 显示更新对话框,包含版本相关信息\n     */\n    private static void showUpdateConfirmDialog(final BaseActivity context, final AppUpdateInfo updateInfo) {\n        String content = String.format(Locale.CHINESE,\n                context.getResources().getString(R.string.update_info),\n                updateInfo.getVersionName(),\n                updateInfo.getUpdateInfo() == null ? \"无\" : updateInfo.getUpdateInfo());\n\n        new AlertDialog.Builder(context)\n                .setTitle(\"发现新版本\")\n                .setMessage(content)\n                .setPositiveButton(\"立即更新\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        if (NetUtils.isWifi(context)) {\n                            startDownload(context, updateInfo);\n                        } else {\n                            showNoWifiConfirmDialog(context, updateInfo);\n                        }\n                    }\n                })\n                .setNegativeButton(\"以后再说\", null)\n                .show();\n    }\n\n    /**\n     * 开始下载\n     *\n     * @param context\n     * @param updateInfo\n     */\n    private static void startDownload(BaseActivity context, AppUpdateInfo updateInfo) {\n        int status = getDownloadStatus(context, updateInfo);\n        if (status != DOWNLOAD_STATUS_NEED_LOAD) {\n            // 不用下载则无需下列操作\n            return;\n        }\n\n        ToastUtils.showToast(context, \"开始下载安装包...\");\n\n        // parse url\n        Uri mUri = Uri.parse(updateInfo.getFileUrl());\n\n        // create request\n        DownloadManager.Request r = new DownloadManager.Request(mUri);\n\n        // set request property\n        String apkName = getDownloadApkName(context, updateInfo);\n        r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);\n        r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);\n\n        // create manager\n        DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);\n\n        // key code, set mine type\n        r.setMimeType(\"application/vnd.android.package-archive\");\n\n        // add to queue\n        dm.enqueue(r);\n    }\n\n    @NonNull\n    private static String getDownloadApkName(BaseActivity context, AppUpdateInfo updateInfo) {\n        return context.getString(R.string.app_name) + \"_\" + updateInfo.getVersionName() + \".apk\";\n    }\n\n    /**\n     * 判断当前版本文件下载状态\n     *\n     * @param context\n     * @param updateInfo\n     * @return\n     */\n    private static int getDownloadStatus(BaseActivity context, AppUpdateInfo updateInfo) {\n        DownloadManager.Query query = new DownloadManager.Query();\n        DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);\n        Cursor c = dm.query(query);\n\n        if (!c.moveToFirst()) {\n            // 无下载内容\n            return DOWNLOAD_STATUS_NEED_LOAD;\n        }\n\n        do {\n            int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));\n            String title = c.getString(c.getColumnIndex(DownloadManager.COLUMN_TITLE));\n            String apkName = getDownloadApkName(context, updateInfo);\n            if (title.equals(apkName)) {\n                // 如果下载列表中文件是当前版本应用，则继续判断下载状态\n                if (status == DownloadManager.STATUS_SUCCESSFUL) {\n                    // 如果已经下载，返回状态，同时直接提示安装\n                    String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));\n                    AppUtils.promptInstall(context, Uri.parse(uri));\n                    return DOWNLOAD_STATUS_LOADED;\n                } else if (status == DownloadManager.STATUS_RUNNING\n                        || status == DownloadManager.STATUS_PAUSED\n                        || status == DownloadManager.STATUS_PENDING) {\n                    return DOWNLOAD_STATUS_RUNNING;\n                } else {\n                    // 失败也视为可以再次下载\n                    return DOWNLOAD_STATUS_NEED_LOAD;\n                }\n            }\n        } while (c.moveToNext());\n\n        return DOWNLOAD_STATUS_NEED_LOAD;\n    }\n\n    /**\n     * 根据下载队列id获取下载Uri\n     *\n     * @param enqueueId\n     * @return null-获取不到\n     */\n    public static Uri getDownloadUriById(Context context, long enqueueId) {\n        DownloadManager.Query query = new DownloadManager.Query();\n        query.setFilterById(enqueueId);\n        DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);\n        Cursor c = dm.query(query);\n        if (c.moveToFirst()) {\n            int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);\n            if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {\n                String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));\n                return Uri.parse(uri);\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/java/com/boredream/designrescollection/utils/UserInfoKeeper.java",
    "content": "package com.boredream.designrescollection.utils;\n\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.ui.login.LoginActivity;\n\n/**\n * 用户信息保存工具\n */\npublic class UserInfoKeeper {\n\n    private static User currentUser;\n\n    /**\n     * 获取当前登录用户\n     */\n    public static User getCurrentUser() {\n        return currentUser;\n    }\n\n    /**\n     * 保存设置当前登录用户\n     */\n    public static void setCurrentUser(User user) {\n        currentUser = user;\n    }\n\n    /**\n     * 清空当前登录用户\n     */\n    public static void clearCurrentUser() {\n        currentUser = null;\n    }\n\n    public static String getToken() {\n        // 统一Header配置时用的token,没有的话要用空字符串,不能为null\n        String token = \"\";\n        if (currentUser != null && currentUser.getSessionToken() != null) {\n            token = currentUser.getSessionToken();\n        }\n        return token;\n    }\n\n    /**\n     * 登出\n     */\n    public static void logout() {\n        clearCurrentUser();\n    }\n\n    /**\n     * 检测登录状态\n     *\n     * @return true-已登录 false-未登录,会自动跳转至登录页\n     */\n    public static boolean checkLogin(Context context) {\n        if (currentUser == null) {\n            Intent intent = new Intent(context, LoginActivity.class);\n            intent.putExtra(\"checkLogin\", true);\n            context.startActivity(intent);\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/anim/loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <rotate\n        android:duration=\"500\"\n        android:fromDegrees=\"0\"\n        android:pivotX=\"50%\"\n        android:pivotY=\"50%\"\n        android:repeatCount=\"-1\"\n        android:toDegrees=\"359\" />\n</set>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/color/txt_blue2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@color/txt_link_blue\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/drawable/ic_fav_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_favorite_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_favorite_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/drawable/ic_home_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_home_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_home_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/drawable/ic_more_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_timer_auto_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_timer_auto_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/drawable/ic_search_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_search_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_search_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/drawable/ic_settings_grey2black_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/ic_settings_black_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@mipmap/ic_settings_grey600_24dp\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/drawable/oval_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@mipmap/bg_pull_to_refresh\" />\n\n    <item>\n        <rotate\n            android:drawable=\"@mipmap/ic_loading\"\n            android:fromDegrees=\"0\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n            android:toDegrees=\"360\" />\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center_horizontal\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <ImageView\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@mipmap/ic_launcher\" />\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:text=\"@string/app_name\" />\n\n        <TextView\n            android:id=\"@+id/tv_version\"\n            style=\"@style/TextViewCaption\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_tiny\"\n            android:text=\"Version 1.0.0\" />\n\n        <TextView\n            android:id=\"@+id/tv_about\"\n            style=\"@style/TextViewBody\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:gravity=\"center\"\n            android:text=\"@string/about\"\n            android:textColor=\"@color/txt_gray\" />\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_feed_back.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/white\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/margin_medium\">\n\n        <EditText\n            android:id=\"@+id/et_content\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"top\"\n            android:hint=\"请输入您的意见反馈\"\n            android:maxLines=\"10\"\n            android:minLines=\"3\"\n            android:padding=\"@dimen/margin_medium\" />\n\n        <EditText\n            android:id=\"@+id/et_email\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"请输入您的邮箱\" />\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <TextView\n        style=\"@style/TextViewSubhead\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:text=\"名字不得超过12个字符\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <EditText\n        android:id=\"@+id/et_input\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"48dp\"\n        android:layout_margin=\"@dimen/margin_medium\"\n        android:maxLength=\"12\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <FrameLayout\n        android:id=\"@+id/fl_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </FrameLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:id=\"@+id/fl_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\">\n    </FrameLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <include layout=\"@layout/include_bottom_tab\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_regist.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <EditText\n            android:id=\"@+id/et_username\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入手机号\"\n            android:inputType=\"number\"\n            android:maxEms=\"11\" />\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"设置登录密码，不少于6位\"\n            android:inputType=\"textPassword\" />\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_register_step1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <EditText\n            android:id=\"@+id/et_username\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入手机号\"\n            android:inputType=\"number\"\n            android:maxEms=\"11\" />\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:layout_marginTop=\"@dimen/margin_small\"\n            android:hint=\"设置登录密码，不少于6位\"\n            android:inputType=\"textPassword\" />\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_register_step2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/activity_vertical_margin\">\n\n        <TextView\n            style=\"@style/TextViewBody\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"你会收到一条带验证码的短信，请输入验证码：\"\n            android:textColor=\"@color/txt_gray\" />\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\">\n\n            <EditText\n                android:id=\"@+id/et_verification_code\"\n                style=\"@style/EditTextSingleLine\"\n                android:hint=\"请输入验证码\"\n                android:inputType=\"number\"\n                android:maxEms=\"10\" />\n\n            <Button\n                android:id=\"@+id/btn_code_info\"\n                style=\"@style/TextViewBody\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:background=\"@null\"\n                android:text=\"60秒\"\n                android:textColor=\"@color/txt_blue2gray_sel\" />\n        </RelativeLayout>\n\n        <Button\n            android:id=\"@+id/btn_next\"\n            style=\"@style/ButtonPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/margin_large\"\n            android:text=\"下一步\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv_setting\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:layout_weight=\"1\"></android.support.v7.widget.RecyclerView>\n\n    <Button\n        android:id=\"@+id/btn_logout\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/margin_large\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_medium\"\n        android:text=\"退出登录\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/activity_user_info_edit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_avatar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"72dp\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:background=\"@drawable/bg_white2gray_sel\"\n        android:clickable=\"true\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\">\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"头像\" />\n\n        <ImageView\n            android:id=\"@+id/iv_avatar\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@mipmap/ic_launcher\" />\n\n        <ImageView\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_username\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:background=\"@drawable/bg_white2gray_sel\"\n        android:clickable=\"true\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\">\n\n        <TextView\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"昵称\" />\n\n        <TextView\n            android:id=\"@+id/tv_username\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"boredream\"\n            android:textColor=\"@color/txt_gray\" />\n\n        <ImageView\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/frag_home.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <include layout=\"@layout/include_refresh_list\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/frag_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"@dimen/activity_vertical_margin\">\n\n    <EditText\n        android:id=\"@+id/et_username\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"48dp\"\n        android:hint=\"请输入手机号\"\n        android:inputType=\"number\"\n        android:maxEms=\"11\" />\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"@dimen/margin_small\">\n\n        <EditText\n            android:id=\"@+id/et_password\"\n            style=\"@style/EditTextSingleLine\"\n            android:layout_height=\"48dp\"\n            android:hint=\"请输入密码\"\n            android:inputType=\"textPassword\" />\n\n        <TextView\n            android:id=\"@+id/tv_forget_psw\"\n            style=\"@style/TextViewBody\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:clickable=\"true\"\n            android:padding=\"@dimen/margin_small\"\n            android:text=\"忘记密码?\"\n            android:textColor=\"@color/colorPrimary\" />\n    </RelativeLayout>\n\n    <Button\n        android:id=\"@+id/btn_login\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"@dimen/margin_large\"\n        android:text=\"登录\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_regist\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/margin_medium\"\n        android:clickable=\"true\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            style=\"@style/TextViewBody\"\n            android:text=\"还没有账号?  赶紧\"\n            android:textColor=\"@color/txt_light_gray\" />\n\n        <TextView\n            style=\"@style/TextViewBody\"\n            android:text=\"注册\"\n            android:textColor=\"@color/colorPrimary\" />\n\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/frag_user.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv_user\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginTop=\"@dimen/margin_medium\">\n    </android.support.v7.widget.RecyclerView>\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/include_bottom_tab.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RadioGroup xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/rg_bottom_tab\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:background=\"@android:color/white\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\">\n\n    <com.boredream.bdcodehelper.view.DrawableRadioButton\n        android:id=\"@+id/rb1\"\n        style=\"@style/RadioButtonBottomTab\"\n        android:drawableTop=\"@drawable/ic_home_grey2black_sel\"\n        app:drawableHeight=\"40dp\"\n        app:drawableWidth=\"40dp\" />\n\n    <com.boredream.bdcodehelper.view.DrawableRadioButton\n        android:id=\"@+id/rb2\"\n        style=\"@style/RadioButtonBottomTab\"\n        android:drawableTop=\"@drawable/ic_more_grey2black_sel\"\n        app:drawableHeight=\"40dp\"\n        app:drawableWidth=\"40dp\" />\n</RadioGroup>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/include_more_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"96dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <ImageView\n        android:id=\"@+id/iv_avatar\"\n        android:layout_width=\"68dp\"\n        android:layout_height=\"68dp\"\n        android:scaleType=\"centerCrop\" />\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"68dp\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/tv_name\"\n            style=\"@style/TextViewSubhead\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n\n    </LinearLayout>\n\n    <ImageView\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:src=\"@mipmap/ic_chevron_right_grey600_24dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/include_more_no_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"96dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center\"\n    android:orientation=\"vertical\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"尚未登录，无法进行收藏等操作。\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <Button\n        android:id=\"@+id/btn_login\"\n        style=\"@style/ButtonPrimary\"\n        android:layout_width=\"120dp\"\n        android:layout_height=\"40dp\"\n        android:layout_marginTop=\"@dimen/margin_small\"\n        android:text=\"立即登录\" />\n\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/item_design_res.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"vertical\">\n\n    <ImageView\n        android:id=\"@+id/iv_image\"\n        android:layout_width=\"172dp\"\n        android:layout_height=\"172dp\"\n        android:scaleType=\"centerCrop\" />\n\n    <TextView\n        android:id=\"@+id/tv_name\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"@dimen/margin_tiny\"\n        android:lines=\"2\" />\n\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/layout/item_more_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <include\n        android:id=\"@+id/include_more_header\"\n        layout=\"@layout/include_more_header\" />\n\n    <include\n        android:id=\"@+id/include_more_no_header\"\n        layout=\"@layout/include_more_no_header\" />\n\n</FrameLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/menu/menu_main2.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\"com.boredream.designrescollection.ui.login.Main2Activity\">\n    <item\n        android:id=\"@+id/action_settings\"\n        android:orderInCategory=\"100\"\n        android:showAsAction=\"never\"\n        android:title=\"@string/action_settings\" />\n</menu>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">DesignResCollection</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"tab1\">首页</string>\n    <string name=\"tab2\">搜索</string>\n    <string name=\"tab3\">收藏</string>\n    <string name=\"tab4\">我</string>\n    <string name=\"about\">\n        使用LeanCloud的Restful API作为后端支持\\n\n        使用LeanCloud的定时云代码，自动按时爬取数据并保存至LeanCloud中\\n\n        使用Retrofit2.0 + RxJava 实现网络请求部分\\n\n        使用Glide实现图片部分\\n\n        \\n\n        开源项目, 地址为\\n\n        %1$s\\n\n        \\n\n        欢迎follow我以及star项目\\n\n        有任何应用问题可以在反馈中提出\\n\n        对于项目代码有任何疑问,也可以在github项目中提issue\n    </string>\n    <string name=\"github\">https://github.com/boredream/DesignResCollection</string>\n    <string name=\"update_info\">\n        最新版本：%1$s\n        \\n\\n更新内容：\\n%2$s\n    </string>\n    <string name=\"title_activity_main2\">Main2Activity</string>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/values/styles.xml",
    "content": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/test/java/com/boredream/designrescollection/net/HttpRequestTest.java",
    "content": "package com.boredream.designrescollection.net;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.entity.User;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport rx.Subscriber;\n\npublic class HttpRequestTest {\n\n    @Before\n    public void setUp() {\n        BoreConstants.isUnitTest = true;\n    }\n\n    @Test\n    public void test() {\n        HttpRequest.getInstance().login(\"18551681236\", \"123456\").subscribe(new Subscriber<User>() {\n            @Override\n            public void onCompleted() {\n\n            }\n\n            @Override\n            public void onError(Throwable e) {\n                System.out.println(e.toString());\n            }\n\n            @Override\n            public void onNext(User user) {\n                System.out.println(user.toString());\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/test/java/com/boredream/designrescollection/ui/feedback/FeedBackPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.feedback;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.FeedBack;\nimport com.boredream.designrescollection.net.HttpRequest;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport rx.Observable;\n\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n/**\n * 提交反馈很少有失败情况，所以使用mock模拟接口部分手动返回错误结果，以验证对应场景\n * 同时也提供真实接口的presenter，用于测试真实数据\n */\npublic class FeedBackPresenterTest {\n\n    // 用于测试真实接口返回数据\n    private FeedBackPresenter presenter;\n\n    // 用于测试模拟接口返回数据\n    private FeedBackPresenter mockPresenter;\n\n    @Mock\n    private FeedBackContract.View view;\n\n    @Mock\n    private HttpRequest.ApiService api;\n\n    @Before\n    public void setupMocksAndView() {\n        // 使用Mock标签等需要先init初始化一下\n        MockitoAnnotations.initMocks(this);\n\n        // 当view调用isActive方法时，就返回true表示UI已激活。方便测试接口返回数据后测试view的方法\n        when(view.isActive()).thenReturn(true);\n\n        // 设置单元测试标识\n        BoreConstants.isUnitTest = true;\n\n        // 用真实接口创建反馈Presenter\n        presenter = new FeedBackPresenter(view, HttpRequest.getInstance().service);\n        // 用mock模拟接口创建反馈Presenter\n        mockPresenter = new FeedBackPresenter(view, api);\n    }\n\n    @Test\n    public void testAddFeedback_Success() throws Exception {\n        // 真实数据，调用实际接口\n        String content = \"这个App真是好！\";\n        String email = \"110@qq.com\";\n        presenter.addFeedback(content, email);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).addFeedbackSuccess();\n    }\n\n    @Test\n    public void testAddFeedback_Mock_Success() throws Exception {\n        // 模拟数据，当api调用addFeedBack接口传入任意值时，就返回成功的基本数据BaseEntity\n        when(api.addFeedBack(any(FeedBack.class))).thenReturn(Observable.just(new BaseEntity()));\n\n        String content = \"这个App真是棒！\";\n        String email = \"119@qq.com\";\n        mockPresenter.addFeedback(content, email);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).addFeedbackSuccess();\n    }\n\n    @Test\n    public void testAddFeedback_Mock_Error() throws Exception {\n        // 模拟数据，当api调用addFeedBack接口传入任意值时，就抛出错误error\n        when(api.addFeedBack(any(FeedBack.class))).thenReturn(Observable.<BaseEntity>error(new Exception(\"孙贼你说谁辣鸡呢？\")));\n\n        String content = \"这个App真是辣鸡！\";\n        String email = \"120@qq.com\";\n        mockPresenter.addFeedback(content, email);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).showTip(\"反馈提交失败\");\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/test/java/com/boredream/designrescollection/ui/home/HomePresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.home;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.entity.DesignRes;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport java.util.Collections;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class HomePresenterTest {\n\n    private HomePresenter presenter;\n\n    @Mock\n    private HomeContract.View view;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        presenter = new HomePresenter(view);\n    }\n\n    @Test\n    public void testPullToLoadList() throws Exception {\n        presenter.pullToLoadList();\n\n        verify(view).dismissProgress();\n        verify(view).loadListSuccess(1, presenter.datas);\n        Assert.assertTrue(presenter.datas.size() > 0);\n    }\n\n    @Test\n    public void testLoadList() throws Exception {\n        presenter.loadList(1);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).loadListSuccess(1, presenter.datas);\n        Assert.assertTrue(presenter.datas.size() > 0);\n    }\n\n    @Test\n    public void testLoadList_overPage() throws Exception {\n        presenter.loadList(999);\n\n        verify(view).dismissProgress();\n        verify(view).loadListSuccess(999, Collections.<DesignRes>emptyList());\n        Assert.assertFalse(presenter.datas.size() > 0);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/test/java/com/boredream/designrescollection/ui/login/LoginPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.login;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n/**\n * 接口部分使用真实数据，只进行了view的mock测试，验证各种数据返回后的view的处理是否符合预期\n */\npublic class LoginPresenterTest {\n\n    private LoginPresenter presenter;\n\n    @Mock\n    private LoginContract.View view;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        // 设置标识，用于区分处理Observer的线程等情况\n        BoreConstants.isUnitTest = true;\n\n        presenter = new LoginPresenter(view, HttpRequest.getInstance());\n    }\n\n    @Test\n    public void testLogin_EmptyPassword() throws Exception {\n        presenter.login(\"13913391521\", \"\");\n\n        verify(view).showTip(\"密码不能为空\");\n    }\n\n    @Test\n    public void testLogin_EmptyUsername() throws Exception {\n        presenter.login(null, \"123456\");\n\n        verify(view).showTip(\"用户名不能为空\");\n    }\n\n    @Test\n    public void testLogin_Success() throws Exception {\n        String phone = \"18551681236\";\n        presenter.login(phone, \"123456\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).loginSuccess(UserInfoKeeper.getCurrentUser());\n        Assert.assertEquals(UserInfoKeeper.getCurrentUser().getUsername(), phone);\n    }\n\n    @Test\n    public void testLogin_UserNotExit() throws Exception {\n        String phone = \"110110110\";\n        presenter.login(phone, \"123456\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).showTip(\"找不到用户\");\n    }\n\n    @Test\n    public void testLogin_PswError() throws Exception {\n        String phone = \"18551681236\";\n        presenter.login(phone, \"110119120\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).showTip(\"密码不正确\");\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/test/java/com/boredream/designrescollection/ui/modifytext/ModifyTextPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.modifytext;\n\nimport com.boredream.bdcodehelper.BoreConstants;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class ModifyTextPresenterTest {\n\n    @Mock\n    private ModifyTextContract.View view;\n\n    private ModifyTextPresenter presenter;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        presenter = new ModifyTextPresenter(view);\n    }\n\n    @Test\n    public void testModifyText_Empty1() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = null;\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).showTip(\"昵称不能为空\");\n    }\n\n    @Test\n    public void testModifyText_Empty2() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = \"\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).showTip(\"昵称不能为空\");\n    }\n\n    @Test\n    public void testModifyText_NoModify() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = \"aaa\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(false, \"aaa\");\n    }\n\n    @Test\n    public void testModifyText_Success1() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"aaa\";\n        String modifyString = \"bbb\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(true, \"bbb\");\n    }\n\n    @Test\n    public void testModifyText_Success2() throws Exception {\n        String title = \"昵称\";\n        String oldString = null;\n        String modifyString = \"bbb\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(true, \"bbb\");\n    }\n\n    @Test\n    public void testModifyText_Success3() throws Exception {\n        String title = \"昵称\";\n        String oldString = \"\";\n        String modifyString = \"bbb\";\n        presenter.modifyText(title, oldString, modifyString);\n\n        verify(view).modifyTextSuccess(true, \"bbb\");\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/test/java/com/boredream/designrescollection/ui/register/RegisterPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.register;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.designrescollection.utils.UserInfoKeeper;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class RegisterPresenterTest {\n\n    @Mock\n    private RegisterContract.View view;\n\n    private RegisterPresenter presenter;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        presenter = new RegisterPresenter(view);\n    }\n\n    @Test\n    public void testRequestSms() throws Exception {\n        // 模拟发送短信，无需测试\n        String phone = \"13913391235\";\n        String password = \"123456\";\n        presenter.requestSms(phone, password);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).requestSmsSuccess(phone, password);\n    }\n\n    @Test\n    public void testRegister() throws Exception {\n        String phone = \"13913391238\";\n        String password = \"123456\";\n        String code = \"1234\";\n        presenter.register(phone, password, code);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).registerSuccess(UserInfoKeeper.getCurrentUser());\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/app/src/test/java/com/boredream/designrescollection/ui/userinfoedit/UserInfoEditPresenterTest.java",
    "content": "package com.boredream.designrescollection.ui.userinfoedit;\n\nimport com.boredream.bdcodehelper.BoreConstants;\nimport com.boredream.bdcodehelper.entity.FileUploadResponse;\nimport com.boredream.designrescollection.base.BaseEntity;\nimport com.boredream.designrescollection.entity.User;\nimport com.boredream.designrescollection.net.HttpRequest;\nimport com.squareup.okhttp.MediaType;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport rx.Observable;\n\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Matchers.anyMap;\nimport static org.mockito.Matchers.anyString;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\npublic class UserInfoEditPresenterTest {\n\n    @Mock\n    private UserInfoEditContract.View view;\n\n    @Mock\n    private HttpRequest httpRequest;\n\n    private UserInfoEditPresenter presenter;\n\n    @Before\n    public void setupMocksAndView() {\n        // Mockito has a very convenient way to inject mocks by using the @Mock annotation. To\n        // inject the mocks in the test the initMocks method needs to be called.\n        MockitoAnnotations.initMocks(this);\n\n        // The presenter wont't update the view unless it's active.\n        when(view.isActive()).thenReturn(true);\n\n        BoreConstants.isUnitTest = true;\n\n        User user = new User();\n        user.setObjectId(\"123456\");\n        presenter = new UserInfoEditPresenter(view, httpRequest, user);\n    }\n\n    @Test\n    public void testFileUpload() throws Exception {\n        FileUploadResponse response = new FileUploadResponse();\n        response.setFilename(\"image\");\n        response.setUrl(\"www.baidu.com\");\n\n        when(httpRequest.fileUpload(any(byte[].class), anyString(), any(MediaType.class)))\n                .thenReturn(Observable.just(response));\n\n        // 如果不加updateUserById的when处理，由于httpRequest的是mock的对象，updateUserById方法会毫无反应\n        // 但是updateUserById是ApiService方法，加空指针报错。\n        // 因为虽然mock了httpRequest对象，但是没mock该对象中的service变量的对象\n        when(httpRequest.service.updateUserById(anyString(), anyMap()))\n                .thenReturn(Observable.just(new BaseEntity()));\n\n        byte[] image = new byte[1024];\n        presenter.uploadAvatar(image);\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).uploadUserInfoSuccess();\n    }\n\n    @Test\n    public void testUpdateNickname() throws Exception {\n        // 无法使用由于httpRequest.service，只能创建一个httpRequest方法使用之\n        when(httpRequest.updateNickname(anyString(), anyString()))\n                .thenReturn(Observable.just(new BaseEntity()));\n\n        presenter.updateNickname(\"new name~~\");\n\n        verify(view).showProgress();\n        verify(view).dismissProgress();\n        verify(view).uploadUserInfoSuccess();\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/README.md",
    "content": "# BDCodeHelper 代码助手\nCode Helper Model for android develper (Android Studio)  \n代码为Android Studio 的 Model，不是完整App应用。需要主项目依赖导入作为辅助开发工具。\n\n---\n# 功能介绍\nModel封装了应用中常用的功能，包括\n####adapter包\n* **LoadMoreAdapter** 加载更多适配器，用于包装普通RecyclerView.Adapter增添一个加载更多功能。适用于所有LayoutManager。  \n装饰器设计模式。无需自定义控件，无需写一大堆监听代码，包装即用~   \n感谢[飞飞大神](https://github.com/jeffreyhappy)的贡献，我在他代码基础上做了简单修改。\n\n* **SettingRecyclerAdapter** 设置选项列表适配器  。\nItem通用样式为：左侧图标、中间文字、右侧文字、右侧图标。  \n使用数据类SettingItem，不同字段对应不同控件，图片资源为-1或者字符为null时，对应位置控件不显示。\n\n####fragment包\n* **FragmentController** fragment切换控制器。  \n初始化时直接add全部fragment, 然后利用show和hide进行切换控制。\n\n####utils包\n大部分常用工具类，比较特殊的单独介绍下\n* **TitleBuilder** 标题栏构造器。\n使用构造器模式设置标题栏，结合layout中的include_titlebar.xml一起使用，先在布局中include引入标题栏布局，  \n再于Activity或Fragment中使用TitleBuilder设置标题栏内容，标题栏格式为：标题文字、左右各自是文字/图片按钮。\n\n####views包\n封装了一些有用的自定义控件\n* **BottomTabRadioButton** 底部导航栏选项卡RadioButton\n利用onDraw绘制红色圆点、带数字的红色圆圈，提供各种自定义attrs属性可以对红点的颜色、数字大小、数字颜色等进行配置。\n感谢[程序媛大神燕姐](https://github.com/xiaoxuyan)的贡献，我在他代码基础上做了简单修改。\n\n\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.ext.compileSdkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n\n        versionCode 1\n        versionName \"1.0\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\n// App dependencies\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n\n    // Android support\n    compile \"com.android.support:appcompat-v7:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:cardview-v7:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:design:$rootProject.supportLibraryVersion\"\n    compile \"com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion\"\n\n    // Retrofit\n    compile \"com.squareup.retrofit:retrofit:$rootProject.retrofitVersion\"\n    compile \"com.squareup.retrofit:converter-gson:$rootProject.retrofitVersion\"\n    compile \"com.squareup.retrofit:adapter-rxjava:$rootProject.retrofitVersion\"\n    compile \"com.squareup.okhttp:logging-interceptor:$rootProject.okhttploggingVersion\"\n\n    // RxJava\n    compile \"io.reactivex:rxandroid:$rootProject.rxjavaVersion\"\n    compile \"com.jakewharton.rxbinding:rxbinding:$rootProject.rxbindingVersion\"\n\n    // Glide\n    compile \"com.github.bumptech.glide:glide:$rootProject.glideVersion\"\n    compile \"com.github.bumptech.glide:okhttp-integration:$rootProject.glideokhttpVersion\"\n\n    // Others\n    compile \"com.commit451:PhotoView:$rootProject.photoviewVersion\"\n    compile \"com.github.promeg:tinypinyin:1.0.0\"\n    compile \"org.greenrobot:eventbus:3.0.0\"\n\n\n\n    /////////////////   put test in main project below   //////////////////\n//    // Dependencies for local unit tests\n//    testCompile \"junit:junit:$rootProject.ext.junitVersion\"\n//    testCompile \"org.mockito:mockito-all:$rootProject.ext.mockitoVersion\"\n//    testCompile \"org.hamcrest:hamcrest-all:$rootProject.ext.hamcrestVersion\"\n//\n//    // Espresso UI Testing\n//    androidTestCompile \"com.android.support.test:runner:$rootProject.runnerVersion\"\n//    androidTestCompile \"com.android.support.test:rules:$rootProject.rulesVersion\"\n//    androidTestCompile \"com.android.support.test.espresso:espresso-core:$rootProject.espressoVersion\"\n//    androidTestCompile \"com.android.support.test.espresso:espresso-contrib:$rootProject.espressoVersion\"\n//    androidTestCompile \"com.android.support.test.espresso:espresso-intents:$rootProject.espressoVersion\"\n//\n//    // Resolve conflicts between main and test APK:\n//    androidTestCompile \"com.android.support:support-annotations:$rootProject.supportLibraryVersion\"\n//    androidTestCompile \"com.android.support:support-v4:$rootProject.supportLibraryVersion\"\n//    androidTestCompile \"com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion\"\n\n}\n\n// copy to rootProject build.gradle\n//// Define versions in a single place\n//ext {\n//    // Sdk and tools\n//    minSdkVersion = 15\n//    targetSdkVersion = 23\n//    compileSdkVersion = 23\n//    buildToolsVersion = '23.0.3'\n//\n//    // App dependencies\n//    supportLibraryVersion = '23.4.0'\n//    guavaVersion = '18.0'\n//    junitVersion = '4.12'\n//    mockitoVersion = '1.10.19'\n//    powerMockito = '1.6.2'\n//    hamcrestVersion = '1.3'\n//    runnerVersion = '0.4.1'\n//    rulesVersion = '0.4.1'\n//    espressoVersion = '2.2.1'\n//    retrofitVersion = '2.0.0-beta2'\n//    okhttploggingVersion = '2.6.0'\n//    rxjavaVersion = '1.1.0'\n//    rxbindingVersion = '0.2.0'\n//    glideVersion = '3.6.1'\n//    glideokhttpVersion = '1.3.1'\n//    photoviewVersion = '1.2.4'\n//}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\adt-bundle-windows-x86_64-20140702\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.boredream.bdcodehelper\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:supportsRtl=\"true\">\n\n        <activity android:name=\".activity.ImageBrowserActivity\" />\n        <activity android:name=\".activity.WebViewActivity\" />\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/BoreConstants.java",
    "content": "package com.boredream.bdcodehelper;\n\npublic class BoreConstants {\n    private BoreConstants() {\n    }\n\n    public static boolean isUnitTest = false;\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/activity/ImageBrowserActivity.java",
    "content": "package com.boredream.bdcodehelper.activity;\n\n\nimport android.os.Bundle;\nimport android.support.v4.view.ViewPager;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.ImageBrowserAdapter;\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\n\nimport java.util.ArrayList;\n\npublic class ImageBrowserActivity extends BoreBaseActivity {\n\n    private ViewPager vp_image_brower;\n    private TextView tv_image_index;\n\n    private int position;\n    private ImageBrowserAdapter adapter;\n    private ArrayList<? extends ImageUrlInterface> images;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_image_browser);\n\n        initData();\n        initView();\n        setData();\n    }\n\n    private void initData() {\n        images = (ArrayList<ImageUrlInterface>) getIntent().getSerializableExtra(\"images\");\n        position = getIntent().getIntExtra(\"position\", 0);\n    }\n\n    private void initView() {\n        vp_image_brower = (ViewPager) findViewById(R.id.vp_image_brower);\n        tv_image_index = (TextView) findViewById(R.id.tv_image_index);\n    }\n\n    private void setData() {\n        adapter = new ImageBrowserAdapter(this, images);\n        vp_image_brower.setAdapter(adapter);\n\n        final int size = images.size();\n//        int initPosition = Integer.MAX_VALUE / 2 / size * size + position;\n        int initPosition = position;\n\n        if (size > 1) {\n            tv_image_index.setVisibility(View.VISIBLE);\n            tv_image_index.setText((position + 1) + \"/\" + size);\n        } else {\n            tv_image_index.setVisibility(View.GONE);\n        }\n\n        vp_image_brower.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n\n            @Override\n            public void onPageSelected(int arg0) {\n                int index = arg0 % size;\n                tv_image_index.setText((index + 1) + \"/\" + size);\n            }\n\n            @Override\n            public void onPageScrolled(int arg0, float arg1, int arg2) {\n\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int arg0) {\n\n            }\n        });\n\n        vp_image_brower.setCurrentItem(initPosition);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/activity/WebViewActivity.java",
    "content": "package com.boredream.bdcodehelper.activity;\n\nimport android.annotation.SuppressLint;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.webkit.WebSettings;\nimport android.webkit.WebView;\nimport android.webkit.WebViewClient;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.base.BoreBaseActivity;\nimport com.boredream.bdcodehelper.utils.AppUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\n\npublic class WebViewActivity extends BoreBaseActivity {\n\n    public static final String EXTRA_TITLE = \"title\";\n    public static final String EXTRA_URL = \"url\";\n\n    private WebView webview;\n    private String title;\n    private TitleBuilder titleBuilder;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_web_view);\n\n        title = getIntent().getStringExtra(EXTRA_TITLE);\n        String url = getIntent().getStringExtra(EXTRA_URL);\n\n        initView();\n\n        showProgressDialog();\n        webview.loadUrl(url);\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\")\n    private void initView() {\n        titleBuilder = initBackTitle(title);\n        titleBuilder.getRootView().setOnLongClickListener(new View.OnLongClickListener() {\n            @Override\n            public boolean onLongClick(View v) {\n                String url = webview.getUrl();\n                if(!TextUtils.isEmpty(url)) {\n                    AppUtils.copy2clipboard(WebViewActivity.this, url);\n                    showToast(\"网址已经复制到剪贴板\");\n                }\n                return false;\n            }\n        });\n\n        webview = (WebView) findViewById(R.id.webview);\n        webview.setWebViewClient(new MyWebClient());\n\n        WebSettings settings = webview.getSettings();\n        settings.setJavaScriptEnabled(true);\n        settings.setSupportZoom(false);\n        settings.setBuiltInZoomControls(false);\n        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);\n    }\n\n    private class MyWebClient extends WebViewClient {\n\n        @Override\n        public void onPageStarted(WebView view, String url, Bitmap favicon) {\n            super.onPageStarted(view, url, favicon);\n        }\n\n        @Override\n        public void onPageFinished(WebView view, String url) {\n            super.onPageFinished(view, url);\n            titleBuilder.setTitleText(view.getTitle());\n            dismissProgressDialog();\n        }\n\n        public boolean shouldOverrideUrlLoading(WebView view, String url) {\n            webview.loadUrl(url);\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/BannerPagerAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.support.v4.view.PagerAdapter;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.activity.ImageBrowserActivity;\nimport com.boredream.bdcodehelper.activity.WebViewActivity;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\n\nimport java.util.ArrayList;\n\npublic class BannerPagerAdapter extends PagerAdapter {\n\n    private Context context;\n    private ArrayList<? extends ImageUrlInterface> images;\n\n    public BannerPagerAdapter(Context context, ArrayList<? extends ImageUrlInterface> images) {\n        this.context = context;\n        this.images = images;\n    }\n\n    @Override\n    public int getCount() {\n        if (images.size() > 1) {\n            return Integer.MAX_VALUE;\n        }\n        return images.size();\n    }\n\n    @Override\n    public boolean isViewFromObject(View arg0, Object arg1) {\n        return arg0 == arg1;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        container.removeView((View) object);\n    }\n\n    @Override\n    public Object instantiateItem(ViewGroup container, final int position) {\n        final ImageUrlInterface image = images.get(position % images.size());\n\n        View view = View.inflate(context, R.layout.item_image_banner, null);\n        TextView tv_title = (TextView) view.findViewById(R.id.tv_title);\n        final ImageView iv = (ImageView) view.findViewById(R.id.iv_image);\n\n        String title = image.getImageTitle();\n        if (TextUtils.isEmpty(title)) {\n            tv_title.setVisibility(View.GONE);\n        } else {\n            tv_title.setVisibility(View.VISIBLE);\n            tv_title.setText(title);\n        }\n\n        final String url = image.getImageUrl();\n        Glide.with(context)\n                .load(url)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n//                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n//                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .centerCrop()\n                .crossFade()\n                .into(iv);\n\n        iv.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (!TextUtils.isEmpty(image.getImageLink())) {\n//                    Intent intent = new Intent();\n//                    intent.setAction(Intent.ACTION_VIEW);\n//                    Uri url = Uri.parse(link);\n//                    intent.setData(url);\n//                    context.startActivity(intent);\n                    Intent intent = new Intent(context, WebViewActivity.class);\n                    intent.putExtra(\"title\", image.getImageTitle());\n                    intent.putExtra(\"url\", image.getImageLink());\n                    context.startActivity(intent);\n                } else {\n                    Intent intent = new Intent(context, ImageBrowserActivity.class);\n                    intent.putExtra(\"images\", images);\n                    intent.putExtra(\"position\", position);\n                    context.startActivity(intent);\n                }\n            }\n        });\n\n        container.addView(view);\n        return view;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/ImageBrowserAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.app.Activity;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.PagerAdapter;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.engine.DiskCacheStrategy;\nimport com.bumptech.glide.load.resource.drawable.GlideDrawable;\nimport com.bumptech.glide.request.animation.GlideAnimation;\nimport com.bumptech.glide.request.target.SimpleTarget;\n\nimport java.util.List;\n\nimport uk.co.senab.photoview.PhotoViewAttacher;\n\npublic class ImageBrowserAdapter extends PagerAdapter {\n\n    private Activity context;\n    private List<? extends ImageUrlInterface> picUrls;\n\n    public ImageBrowserAdapter(Activity context, List<? extends ImageUrlInterface> picUrls) {\n        this.context = context;\n        this.picUrls = picUrls;\n    }\n\n    @Override\n    public int getCount() {\n        if (picUrls.size() > 1) {\n            return Integer.MAX_VALUE;\n        }\n        return picUrls.size();\n    }\n\n    @Override\n    public boolean isViewFromObject(View view, Object object) {\n        return view == object;\n    }\n\n    @Override\n    public View instantiateItem(final ViewGroup container, int position) {\n        final View rootView = View.inflate(context, R.layout.item_image_browser, null);\n\n        int index = position % picUrls.size();\n        final ProgressBar pb_loading = (ProgressBar) rootView.findViewById(R.id.pb_loading);\n        final ImageView iv_image_browser = (ImageView) rootView.findViewById(R.id.iv_image_browser);\n        final PhotoViewAttacher pva = new PhotoViewAttacher(iv_image_browser);\n        String url = picUrls.get(index).getImageUrl();\n\n        Glide.with(context)\n                .load(url)\n                .diskCacheStrategy(DiskCacheStrategy.ALL)\n//                .placeholder(R.mipmap.ic_account_circle_grey600_24dp)\n//                .error(R.mipmap.ic_account_circle_grey600_24dp)\n                .centerCrop()\n                .crossFade()\n                .into(new SimpleTarget<GlideDrawable>() {\n\n                    @Override\n                    public void onLoadFailed(Exception e, Drawable errorDrawable) {\n                        super.onLoadFailed(e, errorDrawable);\n                        pb_loading.setVisibility(View.GONE);\n                        iv_image_browser.setVisibility(View.VISIBLE);\n                    }\n\n                    @Override\n                    public void onLoadStarted(Drawable placeholder) {\n                        super.onLoadStarted(placeholder);\n                        pb_loading.setVisibility(View.VISIBLE);\n                        iv_image_browser.setVisibility(View.GONE);\n                    }\n\n                    @Override\n                    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {\n                        pb_loading.setVisibility(View.GONE);\n                        iv_image_browser.setVisibility(View.VISIBLE);\n\n                        iv_image_browser.setImageDrawable(resource);\n                        pva.update();\n                    }\n                });\n\n        pva.setOnPhotoTapListener(new PhotoViewAttacher.OnPhotoTapListener() {\n            @Override\n            public void onPhotoTap(View view, float x, float y) {\n                context.onBackPressed();\n            }\n        });\n\n        container.addView(rootView);\n        return rootView;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        container.removeView((View) object);\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/ListDropDownAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.util.List;\n\npublic class ListDropDownAdapter extends BaseAdapter {\n\n    private Context context;\n    private List<String> list;\n    private int checkItemPosition = 0;\n\n    public void setCheckItem(int position) {\n        checkItemPosition = position;\n        notifyDataSetChanged();\n    }\n\n    public ListDropDownAdapter(Context context, List<String> list) {\n        this.context = context;\n        this.list = list;\n    }\n\n    @Override\n    public int getCount() {\n        return list.size();\n    }\n\n    @Override\n    public Object getItem(int position) {\n        return null;\n    }\n\n    @Override\n    public long getItemId(int position) {\n        return position;\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n        ViewHolder viewHolder;\n        if (convertView != null) {\n            viewHolder = (ViewHolder) convertView.getTag();\n        } else {\n            convertView = LayoutInflater.from(context).inflate(R.layout.item_default_drop_down, null);\n            viewHolder = new ViewHolder(convertView);\n            convertView.setTag(viewHolder);\n        }\n        fillValue(position, viewHolder);\n        return convertView;\n    }\n\n    private void fillValue(int position, ViewHolder viewHolder) {\n        viewHolder.tv_title.setText(list.get(position));\n        if (checkItemPosition != -1) {\n            if (checkItemPosition == position) {\n                viewHolder.tv_title.setTextColor(context.getResources().getColor(R.color.drop_down_selected));\n                viewHolder.tv_title.setBackgroundResource(R.color.check_bg);\n            } else {\n                viewHolder.tv_title.setTextColor(context.getResources().getColor(R.color.drop_down_unselected));\n                viewHolder.tv_title.setBackgroundResource(R.color.white);\n            }\n        }\n    }\n\n    static class ViewHolder {\n        TextView tv_title;\n\n        ViewHolder(View view) {\n            tv_title = (TextView) view.findViewById(R.id.tv_title);\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/LoadMoreAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\nimport android.graphics.drawable.Drawable;\nimport android.support.v7.widget.GridLayoutManager;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 加载更多装饰适配器,用于包装普通RecyclerView.Adapter增添一个加载更多功能\n */\npublic class LoadMoreAdapter extends RecyclerView.Adapter {\n\n    /**\n     * 下拉状态 - 无内容。footer位置不做任何显示\n     */\n    public static final int STATUS_NONE = 0;\n\n    /**\n     * 下拉状态 - 有更多。footer位置有progressbar进度框\n     */\n    public static final int STATUS_HAVE_MORE = 1;\n\n    /**\n     * 下拉状态 - 已经加载全部数据。footer位置显示文字\n     */\n    public static final int STATUS_LOADED_ALL = 2;\n\n    /**\n     * 当前状态, 默认为 STATUS_NONE\n     */\n    private int status = STATUS_NONE;\n\n    private int ITEM_VIEW_TYPE_FOOTER = 0x10002;\n\n    /**\n     * 正在加载更多中\n     */\n    private boolean isLoadingMore = false;\n\n    private RecyclerView mRecyclerView;\n    private RecyclerView.Adapter mAdapter;\n    private OnLoadMoreListener mOnLoadMoreListener;\n    private Drawable mLoadMoreProgressDrawable;\n\n    public LoadMoreAdapter(RecyclerView recyclerView,\n                           RecyclerView.Adapter adapter,\n                           OnLoadMoreListener onLoadMoreListener) {\n        // 不设置加载更多progressbar的drawable,使用默认的样式\n        this(recyclerView, adapter, onLoadMoreListener, null);\n    }\n\n    public LoadMoreAdapter(RecyclerView recyclerView,\n                           RecyclerView.Adapter adapter,\n                           OnLoadMoreListener onLoadMoreListener,\n                           Drawable loadMoreProgressDrawable) {\n        mRecyclerView = recyclerView;\n        mAdapter = adapter;\n        mOnLoadMoreListener = onLoadMoreListener;\n        mLoadMoreProgressDrawable = loadMoreProgressDrawable;\n        setScrollListener();\n    }\n\n    public RecyclerView.Adapter getSrcAdapter() {\n        return mAdapter;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        isLoadingMore = false;\n        this.status = status;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        if (position == mAdapter.getItemCount()) {\n            // 最后一个位置是FOOTER\n            return ITEM_VIEW_TYPE_FOOTER;\n        } else {\n            return mAdapter.getItemViewType(position);\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        // 原adapter数量上+1,多了个footer\n        return mAdapter.getItemCount() + 1;\n    }\n\n    public class LoadMoreViewHolder extends RecyclerView.ViewHolder {\n\n        public ProgressBar pb_footer_progress;\n        public TextView tv_footer_progress;\n\n        public LoadMoreViewHolder(View itemView) {\n            super(itemView);\n\n            pb_footer_progress = (ProgressBar) itemView.findViewById(R.id.pb_footer_progress);\n            tv_footer_progress = (TextView) itemView.findViewById(R.id.tv_footer_progress);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        if (viewType == ITEM_VIEW_TYPE_FOOTER) {\n            LayoutInflater inflater = LayoutInflater.from(parent.getContext());\n            View loadMore = inflater.inflate(R.layout.footer_progress, parent, false);\n            LoadMoreViewHolder holder = new LoadMoreViewHolder(loadMore);\n            return holder;\n        } else {\n            return mAdapter.onCreateViewHolder(parent, viewType);\n        }\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {\n        if (holder instanceof LoadMoreViewHolder) {\n            handleFooter((LoadMoreViewHolder) holder);\n        } else {\n            mAdapter.onBindViewHolder(holder, position);\n        }\n    }\n\n    /**\n     * 处理footer的view显示\n     */\n    private void handleFooter(final LoadMoreViewHolder holder) {\n        if (mLoadMoreProgressDrawable != null) {\n            // 设置自定义进度框样式\n            holder.pb_footer_progress.setIndeterminateDrawable(mLoadMoreProgressDrawable);\n        }\n\n        // 设置item占满屏幕宽度, 网格列表类型使用\n        RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager();\n        if (layoutManager instanceof StaggeredGridLayoutManager) {\n            StaggeredGridLayoutManager.LayoutParams layoutParams =\n                    (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();\n            layoutParams.setFullSpan(true);\n        } else if (layoutManager instanceof GridLayoutManager) {\n            final GridLayoutManager manager = (GridLayoutManager) layoutManager;\n            manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {\n                @Override\n                public int getSpanSize(int position) {\n                    int spanSize = 1;\n                    if (getItemViewType(position) == ITEM_VIEW_TYPE_FOOTER) {\n                        spanSize = manager.getSpanCount();\n                    }\n                    return spanSize;\n                }\n            });\n        }\n\n        // 根据不同状态显示footer样式\n        switch (status) {\n            case STATUS_HAVE_MORE:\n                holder.itemView.setVisibility(View.VISIBLE);\n\n                holder.tv_footer_progress.setVisibility(View.GONE);\n                holder.pb_footer_progress.setVisibility(View.VISIBLE);\n                break;\n            case STATUS_LOADED_ALL:\n                holder.itemView.setVisibility(View.VISIBLE);\n\n                holder.tv_footer_progress.setVisibility(View.VISIBLE);\n                holder.pb_footer_progress.setVisibility(View.GONE);\n                break;\n            case STATUS_NONE:\n            default:\n                holder.itemView.setVisibility(View.GONE);\n                break;\n        }\n    }\n\n    /**\n     * 设置滚动监听, 判断当列表滚动到底部时, 触发加载更多回调\n     */\n    private void setScrollListener() {\n        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {\n            @Override\n            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {\n                RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();\n                if (layoutManager instanceof StaggeredGridLayoutManager) {\n                    StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;\n                    int pastVisibleItems = -1;\n                    int visibleItemCount = staggeredGridLayoutManager.getChildCount();\n                    int totalItemCount = staggeredGridLayoutManager.getItemCount();\n                    int[] firstVisibleItems = null;\n                    firstVisibleItems = staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);\n                    if (firstVisibleItems != null && firstVisibleItems.length > 0) {\n                        pastVisibleItems = firstVisibleItems[0];\n                    }\n\n                    if (visibleItemCount + pastVisibleItems >= totalItemCount) {\n                        triggerLoadMore();\n                    }\n                } else if (layoutManager instanceof LinearLayoutManager) {\n                    // GridLayoutManager 是 LinearLayoutManager 的子类, 也符合这个条件\n                    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;\n                    int visibleItemCount = linearLayoutManager.getChildCount();\n                    int totalItemCount = linearLayoutManager.getItemCount();\n                    int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();\n\n                    if (visibleItemCount + firstVisibleItemPosition >= totalItemCount) {\n                        triggerLoadMore();\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * 触发加载更多回调\n     */\n    private synchronized void triggerLoadMore() {\n        // 如果是正在加载更多中,不再重复触发\n        if (isLoadingMore) {\n            return;\n        }\n\n        // 如果状态不是STATUS_HAVE_MORE则不触发\n        if (status != STATUS_HAVE_MORE) {\n            return;\n        }\n\n        isLoadingMore = true;\n        mOnLoadMoreListener.onLoadMore();\n        onLoadMore();\n    }\n\n    protected void onLoadMore() {\n        // sub\n    }\n\n    public interface OnLoadMoreListener {\n        void onLoadMore();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/adapter/SettingRecyclerAdapter.java",
    "content": "package com.boredream.bdcodehelper.adapter;\n\n\nimport android.support.v7.widget.RecyclerView;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.SettingItem;\n\nimport java.util.List;\n\n/**\n * 设置选项列表适配器\n * <p>\n * Item通用样式为：左侧图标、中间文字、右侧文字、右侧图标。\n */\npublic class SettingRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {\n\n    private static final int ITEM_VIEW_TYPE_SETTING_ITEM = 0x10001;\n\n    protected List<SettingItem> datas;\n    protected AdapterView.OnItemClickListener mOnItemClickListener;\n\n    public SettingRecyclerAdapter(List<SettingItem> datas, AdapterView.OnItemClickListener listener) {\n        this.datas = datas;\n        mOnItemClickListener = listener;\n    }\n\n    @Override\n    public int getItemCount() {\n        return datas.size();\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return ITEM_VIEW_TYPE_SETTING_ITEM;\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n\n        public ImageView iv_left;\n        public TextView tv_mid;\n        public TextView tv_right;\n        public ImageView iv_right;\n\n        public ViewHolder(final View itemView) {\n            super(itemView);\n\n            iv_left = (ImageView) itemView.findViewById(R.id.iv_left);\n            tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n            tv_right = (TextView) itemView.findViewById(R.id.tv_right);\n            iv_right = (ImageView) itemView.findViewById(R.id.iv_right);\n        }\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_setting, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {\n        ViewHolder settingViewHolder = (ViewHolder) holder;\n        holder.itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                if (mOnItemClickListener != null) {\n                    mOnItemClickListener.onItemClick(null, view, position, -1);\n                }\n            }\n        });\n        SettingItem data = datas.get(position);\n\n        settingViewHolder.iv_left.setImageResource(data.leftImgRes);\n        if (!TextUtils.isEmpty(data.rightText)) {\n            settingViewHolder.tv_right.setVisibility(View.VISIBLE);\n            settingViewHolder.tv_right.setText(data.rightText);\n        } else {\n            settingViewHolder.tv_right.setVisibility(View.GONE);\n        }\n        settingViewHolder.tv_mid.setText(data.midText);\n\n        if (data.rightImage != -1) {\n            settingViewHolder.iv_right.setVisibility(View.VISIBLE);\n            settingViewHolder.iv_right.setImageResource(data.rightImage);\n        } else {\n            settingViewHolder.iv_right.setVisibility(View.GONE);\n        }\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/base/BoreBaseActivity.java",
    "content": "package com.boredream.bdcodehelper.base;\n\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.utils.DialogUtils;\nimport com.boredream.bdcodehelper.utils.TitleBuilder;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\npublic class BoreBaseActivity extends AppCompatActivity {\n\n    protected String TAG;\n    private Dialog progressDialog;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        init();\n    }\n\n    private void init() {\n        TAG = getClass().getSimpleName();\n        progressDialog = DialogUtils.createProgressDialog(this);\n    }\n\n    /**\n     * 左侧有返回键的标题栏\n     * <p>如果在此基础上还要加其他内容,比如右侧有文字按钮,可以获取该方法返回值继续设置其他内容\n     *\n     * @param title 标题\n     */\n    protected TitleBuilder initBackTitle(String title) {\n        return new TitleBuilder(this)\n                .setTitleText(title)\n                .setLeftImage(R.mipmap.ic_back)\n                .setLeftOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View v) {\n                        finish();\n                    }\n                });\n    }\n\n    /**\n     * 跳转页面,无extra简易型\n     *\n     * @param tarActivity 目标页面\n     */\n    public void intent2Activity(Class<? extends Activity> tarActivity) {\n        Intent intent = new Intent(this, tarActivity);\n        startActivity(intent);\n    }\n\n    public void showToast(String msg) {\n        ToastUtils.showToast(this, msg, Toast.LENGTH_SHORT);\n    }\n\n    public void showLog(String msg) {\n        Log.i(TAG, msg);\n    }\n\n    public void showProgressDialog() {\n        progressDialog.show();\n    }\n\n    public void dismissProgressDialog() {\n        progressDialog.dismiss();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/base/BoreBaseEntity.java",
    "content": "package com.boredream.bdcodehelper.base;\n\n\nimport com.boredream.bdcodehelper.entity.Pointer;\n\n/**\n * 数据实体基类\n * <p>\n * 之所以继承Pointer对象,是因为接口用法的限制,具体可以参考Bmob/LeanCloud/Parse的相关文档<br/>\n * 这样的接口可以让对象在提交创建和获取的时候都更加方便<br/>\n * 提交时只要添加Pointer的type和className等所需字段即可,获取时基本不用做任何额外处理\n */\npublic class BoreBaseEntity extends Pointer {\n\n    // 添加新数据时,返回为objectId + createdAt\n    // 更新数据时,返回为updateAt\n\n    private String createdAt;\n    private String updatedAt;\n\n    public String getCreatedAt() {\n        return createdAt;\n    }\n\n    public void setCreatedAt(String createdAt) {\n        this.createdAt = createdAt;\n    }\n\n    public String getUpdatedAt() {\n        return updatedAt;\n    }\n\n    public void setUpdatedAt(String updatedAt) {\n        this.updatedAt = updatedAt;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (o instanceof BoreBaseEntity) {\n            BoreBaseEntity oEntity = (BoreBaseEntity) o;\n            return this.objectId.equals(oEntity.objectId);\n        }\n        return super.equals(o);\n    }\n\n    @Override\n    public String toString() {\n        return \"BaseEntity{\" +\n                \"objectId='\" + objectId + '\\'' +\n                \", createdAt='\" + createdAt + '\\'' +\n                \", updatedAt='\" + updatedAt + '\\'' +\n                '}';\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/db/AddressData.java",
    "content": "package com.boredream.bdcodehelper.db;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\n\nimport com.boredream.bdcodehelper.entity.city.CityModel;\nimport com.github.promeg.pinyinhelper.Pinyin;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\n\npublic class AddressData {\n    public static ArrayList<String> mProvinceDatas = new ArrayList<>();\n    public static HashMap<String, ArrayList<CityModel>> mCitisDatasMap = new HashMap<>();\n    public static ArrayList<CityModel> allCities = new ArrayList<>();\n    public static CityModel currentCity;\n\n    public static void init(final Context context) {\n        new Thread() {\n            @Override\n            public void run() {\n                // 初始化，只需要调用一次\n                AssetsDatabaseManager.initManager(context);\n                // 获取管理对象，因为数据库需要通过管理对象才能够获取\n                AssetsDatabaseManager adm = AssetsDatabaseManager.getManager();\n                // 通过管理对象获取数据库\n                SQLiteDatabase sql = adm.getDatabase(\"city\");\n\n                // city\n                Cursor cursorCity = sql.rawQuery(\"select *,* from T_City, T_Province where T_City.ProID = T_Province.ProSort\", null);\n                if (!cursorCity.moveToFirst()) {\n                    return;\n                }\n                do {\n                    String province = cursorCity.getString(cursorCity.getColumnIndex(\"ProName\"));\n\n                    CityModel city = new CityModel();\n                    city.province = province;\n                    city.id = cursorCity.getString(cursorCity.getColumnIndex(\"CitySort\"));\n                    city.name = cursorCity.getString(cursorCity.getColumnIndex(\"CityName\"));\n\n                    if(!city.name.endsWith(\"市\")) {\n                        continue;\n                    }\n\n                    city.name = city.name.substring(0, city.name.length() - 1);\n\n                    StringBuilder sbLetter = new StringBuilder();\n                    for(char c : city.name.toCharArray()) {\n                        String letter;\n                        if(c == '长') {\n                            letter = \"CHANG\";\n                        } else if(c == '重'){\n                            letter = \"CHONG\";\n                        } else if(c == '厦'){\n                            letter = \"XIA\";\n                        } else {\n                            letter = Pinyin.toPinyin(c);\n                        }\n                        sbLetter.append(letter);\n                    }\n                    city.letter = sbLetter.toString();\n\n                    allCities.add(city);\n\n                    if(!mProvinceDatas.contains(province)) {\n                        mProvinceDatas.add(province);\n                    }\n\n                    ArrayList<CityModel> cities = mCitisDatasMap.get(province);\n                    if(cities == null) {\n                        cities = new ArrayList<>();\n                        cities.add(city);\n                        mCitisDatasMap.put(province, cities);\n                    } else {\n                        cities.add(city);\n                    }\n\n                    // 默认城市\n                    if(city.name.equals(\"上海\")) {\n                        currentCity = city;\n                    }\n\n                } while (cursorCity.moveToNext());\n\n                Collections.sort(allCities, new Comparator<CityModel>() {\n                    @Override\n                    public int compare(CityModel cityModel, CityModel t1) {\n                        return cityModel.letter.compareTo(t1.letter);\n                    }\n                });\n            }\n        }.start();\n\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/db/AssetsDatabaseManager.java",
    "content": "package com.boredream.bdcodehelper.db;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.AssetManager;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * This is a Assets Database Manager\n * Use it, you can use a assets database file in you application\n * It will copy the database file to \"/data/data/[your application package name]/database\" when you first time you use it\n * Then you can get a SQLiteDatabase object by the assets database file\n *\n * How to use:\n * 1. Initialize AssetsDatabaseManager\n * 2. Get AssetsDatabaseManager\n * 3. Get a SQLiteDatabase object through database file\n * 4. Use this database object\n *\n * Using example:\n * AssetsDatabaseManager.initManager(getApplication()); // this method is only need call one time\n * AssetsDatabaseManager mg = AssetsDatabaseManager.getManager();   // get a AssetsDatabaseManager object\n * SQLiteDatabase db1 = mg.getDatabase(\"db1.db\");   // get SQLiteDatabase object, db1.db is a file in assets folder\n * db1.???  // every operate by you want\n * Of cause, you can use AssetsDatabaseManager.getManager().getDatabase(\"xx\") to get a database when you need use a database\n */\npublic class AssetsDatabaseManager {\n    private static String tag = \"AssetsDatabase\"; // for LogCat\n    private static String databasepath = \"/data/data/%s/database\"; // %s is packageName\n\n\n    // A mapping from assets database file to SQLiteDatabase object\n    private Map<String, SQLiteDatabase> databases = new HashMap<String, SQLiteDatabase>();\n\n    // Context of application\n    private Context context = null;\n\n    // Singleton Pattern\n    private static AssetsDatabaseManager mInstance = null;\n\n    /**\n     * Initialize AssetsDatabaseManager\n     * @param context, context of application\n     */\n    public static void initManager(Context context){\n        if(mInstance == null){\n            mInstance = new AssetsDatabaseManager(context);\n        }\n    }\n\n    /**\n     * Get a AssetsDatabaseManager object\n     * @return, if success return a AssetsDatabaseManager object, else return null\n     */\n    public static AssetsDatabaseManager getManager(){\n        return mInstance;\n    }\n\n    private AssetsDatabaseManager(Context context){\n        this.context = context;\n    }\n\n    /**\n     * Get a assets database, if this database is opened this method is only return a copy of the opened database\n     * @param dbfile, the assets file which will be opened for a database\n     * @return, if success it return a SQLiteDatabase object else return null\n     */\n    public SQLiteDatabase getDatabase(String dbfile) {\n        if(databases.get(dbfile) != null){\n            Log.i(tag, String.format(\"Return a database copy of %s\", dbfile));\n            return (SQLiteDatabase) databases.get(dbfile);\n        }\n        if(context==null)\n            return null;\n\n        Log.i(tag, String.format(\"Create database %s\", dbfile));\n        String spath = getDatabaseFilepath();\n        String sfile = getDatabaseFile(dbfile);\n\n        File file = new File(sfile);\n        SharedPreferences dbs = context.getSharedPreferences(AssetsDatabaseManager.class.toString(), 0);\n        boolean flag = dbs.getBoolean(dbfile, false); // Get Database file flag, if true means this database file was copied and valid\n        if(!flag || !file.exists()){\n            file = new File(spath);\n            if(!file.exists() && !file.mkdirs()){\n                Log.i(tag, \"Create \\\"\"+spath+\"\\\" fail!\");\n                return null;\n            }\n            if(!copyAssetsToFilesystem(dbfile, sfile)){\n                Log.i(tag, String.format(\"Copy %s to %s fail!\", dbfile, sfile));\n                return null;\n            }\n\n            dbs.edit().putBoolean(dbfile, true).commit();\n        }\n\n        SQLiteDatabase db = SQLiteDatabase.openDatabase(sfile, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);\n        if(db != null){\n            databases.put(dbfile, db);\n        }\n        return db;\n    }\n\n    private String getDatabaseFilepath(){\n        return String.format(databasepath, context.getApplicationInfo().packageName);\n    }\n\n    private String getDatabaseFile(String dbfile){\n        return getDatabaseFilepath()+\"/\"+dbfile;\n    }\n\n    private boolean copyAssetsToFilesystem(String assetsSrc, String des){\n        Log.i(tag, \"Copy \"+assetsSrc+\" to \"+des);\n        InputStream istream = null;\n        OutputStream ostream = null;\n        try{\n            AssetManager am = context.getAssets();\n            istream = am.open(assetsSrc);\n            ostream = new FileOutputStream(des);\n            byte[] buffer = new byte[1024];\n            int length;\n            while ((length = istream.read(buffer))>0){\n                ostream.write(buffer, 0, length);\n            }\n            istream.close();\n            ostream.close();\n        }\n        catch(Exception e){\n            e.printStackTrace();\n            try{\n                if(istream!=null)\n                    istream.close();\n                if(ostream!=null)\n                    ostream.close();\n            }\n            catch(Exception ee){\n                ee.printStackTrace();\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Close assets database\n     * @param dbfile, the assets file which will be closed soon\n     * @return, the status of this operating\n     */\n    public boolean closeDatabase(String dbfile){\n        if(databases.get(dbfile) != null){\n            SQLiteDatabase db = (SQLiteDatabase) databases.get(dbfile);\n            db.close();\n            databases.remove(dbfile);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Close all assets database\n     */\n    static public void closeAllDatabase(){\n        Log.i(tag, \"closeAllDatabase\");\n        if(mInstance != null){\n            for(int i=0; i<mInstance.databases.size(); ++i){\n                if(mInstance.databases.get(i)!=null){\n                    mInstance.databases.get(i).close();\n                }\n            }\n            mInstance.databases.clear();\n        }\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/AppUpdateInfo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class AppUpdateInfo extends BoreBaseEntity {\n    private int version;\n    private String versionName;\n    private String fileUrl;\n    private String updateInfo;\n\n    public int getVersion() {\n        return version;\n    }\n\n    public void setVersion(int version) {\n        this.version = version;\n    }\n\n    public String getVersionName() {\n        return versionName;\n    }\n\n    public void setVersionName(String versionName) {\n        this.versionName = versionName;\n    }\n\n    public String getFileUrl() {\n        return fileUrl;\n    }\n\n    public void setFileUrl(String fileUrl) {\n        this.fileUrl = fileUrl;\n    }\n\n    public String getUpdateInfo() {\n        return updateInfo;\n    }\n\n    public void setUpdateInfo(String updateInfo) {\n        this.updateInfo = updateInfo;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ErrorResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class ErrorResponse {\n\n    private int code;\n    private String error;\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public void setError(String error) {\n        this.error = error;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getError() {\n        return error;\n    }\n\n    @Override\n    public String toString() {\n        return \"ErrorResponse{\" +\n                \"code=\" + code +\n                \", error='\" + error + '\\'' +\n                '}';\n    }\n}\n\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FileInfo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.base.BoreBaseEntity;\n\npublic class FileInfo extends BoreBaseEntity {\n    private String cdn;\n    private String fiilename;\n    private String url;\n\n    public String getCdn() {\n        return cdn;\n    }\n\n    public void setCdn(String cdn) {\n        this.cdn = cdn;\n    }\n\n    public String getFiilename() {\n        return fiilename;\n    }\n\n    public void setFiilename(String fiilename) {\n        this.fiilename = fiilename;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FileUploadResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class FileUploadResponse {\n    private String filename;\n    private String group;\n    private String url;\n\n    public void setFilename(String filename) {\n        this.filename = filename;\n    }\n\n    public void setGroup(String group) {\n        this.group = group;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getFilename() {\n        return filename;\n    }\n\n    public String getGroup() {\n        return group;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if(o instanceof FileUploadResponse) {\n            return this.url.equals(((FileUploadResponse)o).url);\n        }\n        return super.equals(o);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/FormItem.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport android.text.InputType;\n\npublic class FormItem {\n\n    public static final int TYPE_INPUT = 0;\n    public static final int TYPE_SELECT = 1;\n\n    /**\n     * 类型，0-输入，1-选择\n     */\n    public int type;\n\n    /**\n     * 左侧文字\n     */\n    public String leftText;\n\n    /**\n     * 中间文字，hint使用\n     */\n    public String midText;\n\n    /**\n     * 输入框类型\n     */\n    public int inputType;\n\n    /**\n     * 右侧图片id\n     */\n    public int rightImg;\n\n    public FormItem() {\n\n    }\n\n    public static FormItem getInputItem(String leftText, String hint) {\n        return getInputItem(leftText, hint, InputType.TYPE_CLASS_TEXT);\n    }\n\n    public static FormItem getInputItem(String leftText, String hint, int inputType) {\n        FormItem formItem = new FormItem();\n        formItem.type = TYPE_INPUT;\n        formItem.leftText = leftText;\n        formItem.midText = hint;\n        formItem.inputType = inputType;\n        return formItem;\n    }\n\n    public static FormItem getSelectItem(String leftText, int rightImg) {\n        FormItem formItem = new FormItem();\n        formItem.type = TYPE_SELECT;\n        formItem.leftText = leftText;\n        formItem.rightImg = rightImg;\n        return formItem;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ImageUrlInterface.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.io.Serializable;\n\npublic interface ImageUrlInterface extends Serializable {\n    String getImageUrl();\n    String getImageTitle();\n    String getImageLink();\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/ListResponse.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.util.ArrayList;\n\npublic class ListResponse<T> {\n    private ArrayList<T> results;\n\n    public ArrayList<T> getResults() {\n        return results;\n    }\n\n    public void setResults(ArrayList<T> results) {\n        this.results = results;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/PageIndex.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\n\nimport java.util.List;\n\n/**\n * 页数索引, 多页加载时使用\n */\npublic class PageIndex {\n\n    /**\n     * 起始页\n     */\n    private int startPage;\n\n    /**\n     * 请求加载的新页数\n     */\n    private int newPage;\n\n    /**\n     * 当前已加载的页数\n     */\n    private int currentPage;\n\n    /**\n     * 每页加载的数量\n     */\n    private int countPerPage;\n\n    public int getStartPage() {\n        return startPage;\n    }\n\n    /**\n     * 页数索引\n     *\n     * @param startPage 起始页, 通常是 0 或 1\n     */\n    public PageIndex(int startPage, int countPerPage) {\n        this.startPage = startPage;\n        this.countPerPage = countPerPage;\n        init();\n    }\n\n    /**\n     * 重置初始化\n     */\n    public void init() {\n        this.currentPage = startPage;\n    }\n\n    /**\n     * 新页数数据获取成功, 将当前页数更新未新页数\n     */\n    private void success() {\n        currentPage = newPage;\n    }\n\n    /**\n     * 起始页\n     *\n     * @return 起始页\n     */\n    public int toStartPage() {\n        newPage = startPage;\n        return newPage;\n    }\n\n    /**\n     * 下一页\n     *\n     * @return 当前页+1作为下一页\n     */\n    public int toNextPage() {\n        newPage = currentPage + 1;\n        return newPage;\n    }\n\n    /**\n     * 数据获取成功, 设置返回结果\n     *\n     * @param adapter\n     * @param currentList 当前已有数据\n     * @param newList     请求获取的新数据\n     * @param <T>\n     */\n    public <T> void setResponse(LoadMoreAdapter adapter, List<T> currentList, List<T> newList) {\n        // 更新当前页数\n        success();\n\n        // 如果当前页为起始页, 则清空数据\n        if (currentPage == startPage) {\n            currentList.clear();\n        }\n\n        if (newList == null) {\n            return;\n        }\n\n        // 添加数据\n        currentList.addAll(newList);\n\n        // 设置是否已加载完全部数据状态\n        adapter.setStatus(newList.size() == countPerPage\n                ? LoadMoreAdapter.STATUS_HAVE_MORE : LoadMoreAdapter.STATUS_LOADED_ALL);\n\n        // 更新UI\n        adapter.notifyDataSetChanged();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Pointer.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport com.google.gson.Gson;\n\nimport java.io.Serializable;\n\npublic class Pointer implements Serializable {\n    public static final String TYPE = \"Pointer\";\n\n    protected String __type;\n    protected String className;\n    protected String objectId;\n\n    public Pointer() {\n    }\n\n    public Pointer(String className, String objectId) {\n        this.__type = TYPE;\n        this.setClassName(className);\n        this.setObjectId(objectId);\n    }\n\n    public String get__type() {\n        return __type;\n    }\n\n    public void set__type(String __type) {\n        this.__type = __type;\n    }\n\n    public String getClassName() {\n        return this.className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n\n    public String getObjectId() {\n        return this.objectId;\n    }\n\n    public void setObjectId(String objectId) {\n        this.objectId = objectId;\n    }\n\n    /**\n     * 将Pointer转换为所需对象\n     *\n     * @param clazz 转换目标类型\n     * @return 转换后的对象, 转换失败时为null\n     */\n    public <T> T parseToObject(Class<T> clazz) {\n        T t = null;\n        Gson gson = new Gson();\n        try {\n            // 原Pointer对象转为json, 如果用include查询的话, Pointer中除了className还会包含目标对象的数据\n            String json = gson.toJson(this);\n            // 转为目标对象, 多余的className正好通过转换过滤掉\n\n            t = gson.fromJson(json, clazz);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return t;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Relation.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Relation implements Serializable {\n    private String __op = \"AddRelation\";\n    private List<Pointer> objects = new ArrayList();\n\n    public Relation(Pointer pointer) {\n        this.objects.add(pointer);\n    }\n\n    public Relation() {\n    }\n\n    public void add(Pointer pointer) {\n        this.objects.add(pointer);\n    }\n\n    public void remove(Pointer pointer) {\n        this.__op = \"RemoveRelation\";\n        this.objects.add(pointer);\n    }\n\n    public String get__op() {\n        return this.__op;\n    }\n\n    public List<Pointer> getObjects() {\n        return this.objects;\n    }\n\n    public void setObjects(List<Pointer> objects) {\n        this.objects = objects;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/RelationTo.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class RelationTo {\n    public static final String OP_RELATEDTO = \"$relatedTo\";\n\n    private String key;\n    private Pointer object;\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public Pointer getObject() {\n        return object;\n    }\n\n    public void setObject(Pointer object) {\n        this.object = object;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/SettingItem.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\n/**\n * 更多item信息\n */\npublic class SettingItem {\n\n    /**\n     * 左侧图片\n     */\n    public int leftImgRes;\n\n    /**\n     * 中间文字\n     */\n    public String midText;\n\n    /**\n     * 右侧文字\n     */\n    public String rightText;\n\n    /**\n     * 右侧图片\n     */\n    public int rightImage;\n\n    public SettingItem() {\n\n    }\n\n    public SettingItem(int leftImgRes, String midText, String rightText, int rightImage) {\n        this.leftImgRes = leftImgRes;\n        this.midText = midText;\n        this.rightText = rightText;\n        this.rightImage = rightImage;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/UpdatePswRequest.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\npublic class UpdatePswRequest {\n    private String oldPassword;\n    private String newPassword;\n\n    public String getOldPassword() {\n        return oldPassword;\n    }\n\n    public void setOldPassword(String oldPassword) {\n        this.oldPassword = oldPassword;\n    }\n\n    public String getNewPassword() {\n        return newPassword;\n    }\n\n    public void setNewPassword(String newPassword) {\n        this.newPassword = newPassword;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/Where.java",
    "content": "package com.boredream.bdcodehelper.entity;\n\nimport java.util.Map;\n\npublic class Where {\n    public static final String OP_INQUERY = \"$inQuery\";\n\n    private Map<String, String> where;\n    private String className;\n\n    public Map<String, String> getWhere() {\n        return where;\n    }\n\n    public void setWhere(Map<String, String> where) {\n        this.where = where;\n    }\n\n    public String getClassName() {\n        return className;\n    }\n\n    public void setClassName(String className) {\n        this.className = className;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/city/BaseAddressModel.java",
    "content": "package com.boredream.bdcodehelper.entity.city;\n\nimport java.io.Serializable;\n\npublic class BaseAddressModel implements Serializable {\n    public String id;\n    public String name;\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/entity/city/CityModel.java",
    "content": "package com.boredream.bdcodehelper.entity.city;\n\npublic class CityModel extends BaseAddressModel {\n\tpublic String province;\n\tpublic String letter;\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif(o instanceof CityModel) {\n\t\t\treturn ((CityModel)o).id.equals(this.id);\n\t\t}\n\t\treturn super.equals(o);\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/fragment/FragmentController.java",
    "content": "package com.boredream.bdcodehelper.fragment;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v7.app.AppCompatActivity;\n\nimport java.util.ArrayList;\n\n/**\n * fragment切换控制器, 初始化时直接add全部fragment, 然后利用show和hide进行切换控制\n */\npublic class FragmentController {\n\n    private int containerId;\n    private FragmentManager fm;\n    private ArrayList<Fragment> fragments;\n\n    public FragmentController(AppCompatActivity activity, int containerId, ArrayList<Fragment> fragments) {\n        this.containerId = containerId;\n        this.fragments = fragments;\n        this.fm = activity.getSupportFragmentManager();\n        initFragment();\n    }\n\n    public void initFragment() {\n        FragmentTransaction ft = fm.beginTransaction();\n        for (int i = 0; i < fragments.size(); i++) {\n            ft.add(containerId, fragments.get(i), String.valueOf(i));\n        }\n        ft.commit();\n    }\n\n    public void showFragment(int position) {\n        hideFragments();\n        Fragment fragment = fragments.get(position);\n        FragmentTransaction ft = fm.beginTransaction();\n        ft.show(fragment);\n        ft.commit();\n    }\n\n    public void hideFragments() {\n        FragmentTransaction ft = fm.beginTransaction();\n        for (Fragment fragment : fragments) {\n            if (fragment != null) {\n                ft.hide(fragment);\n            }\n        }\n        ft.commit();\n    }\n\n    public Fragment getFragment(int position) {\n        return fragments.get(position);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/ErrorConstants.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ErrorConstants {\n    public static Map<Integer, String> errors;\n\n    static {\n        errors = new HashMap<>();\n        errors.put(9001, \"Application Id为空，请初始化.\");\n        errors.put(9002, \"解析返回数据出错\");\n        errors.put(9003, \"上传文件出错\");\n        errors.put(9004, \"文件上传失败\");\n        errors.put(9005, \"批量操作只支持最多50条\");\n        errors.put(9006, \"objectId为空\");\n        errors.put(9007, \"文件大小超过10M\");\n        errors.put(9008, \"上传文件不存在\");\n        errors.put(9009, \"没有缓存数据\");\n        errors.put(9010, \"网络超时\");\n        errors.put(9011, \"BmobUser类不支持批量操作\");\n        errors.put(9012, \"上下文为空\");\n        errors.put(9013, \"BmobObject（数据表名称）格式不正确\");\n        errors.put(9014, \"第三方账号授权失败\");\n        errors.put(9015, \"其他错误均返回此code\");\n        errors.put(9016, \"无网络连接，请检查您的手机网络.\");\n        errors.put(9017, \"与第三方登录有关的错误，具体请看对应的错误描述\");\n        errors.put(9018, \"参数不能为空\");\n        errors.put(9019, \"格式不正确：手机号码、邮箱地址、验证码\");\n\n        errors.put(401, \"用户登陆信息失效\");\n        errors.put(500, \"服务器忙，请稍后再试\");\n\n        errors.put(101, \"用户名或密码不正确\");\n        errors.put(102, \"格式不正确\");\n        errors.put(103, \"查询单个对象或更新对象时必须提供objectId 或 非法的 class 名称，class 名称是大小写敏感的，并且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线.\");\n        errors.put(104, \"关联的class名称不存在\");\n        errors.put(105, \"字段名是大小写敏感的，且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线 或 字段名是\");\n        errors.put(106, \"不是一个正确的指针类型\");\n        errors.put(107, \"数据格式不正确\");\n        errors.put(108, \"用户名和密码是必需的\");\n        errors.put(109, \"登录信息是必需的，如邮箱和密码时缺少其中一个提示此信息\");\n        errors.put(111, \"传入的字段值与字段类型不匹配\");\n        errors.put(112, \"请求的值必须是数组\");\n        errors.put(113, \"请求数组中每个元素应该是一个像这样子的json对象\");\n        errors.put(114, \"请求数组大于50\");\n        errors.put(117, \"纬度范围在[-90, 90] 或 经度范围在[-180, 180]\");\n        errors.put(120, \"要使用此功能，请在\");\n        errors.put(131, \"不正确的deviceToken\");\n        errors.put(132, \"不正确的installationId\");\n        errors.put(133, \"不正确的deviceType\");\n        errors.put(134, \"deviceToken已经存在\");\n        errors.put(135, \"installationId已经存在\");\n        errors.put(136, \"只读属性不能修改 或 android设备不需要设置deviceToken\");\n        errors.put(138, \"表是只读的\");\n        errors.put(139, \"角色名称是大小写敏感的，并且必须以英文字母开头，有效的字符仅限在英文字母、数字、空格、横线以及下划线。\");\n        errors.put(141, \"缺失推送需要的data参数\");\n        errors.put(142, \"时间格式应该如下： 2013-12-04 00:51:13\");\n        errors.put(143, \"必须是一个数字\");\n        errors.put(144, \"不能是之前的时间\");\n        errors.put(145, \"文件大小错误\");\n        errors.put(146, \"文件名错误\");\n        errors.put(147, \"文件分页上传偏移量错误\");\n        errors.put(148, \"文件上下文错误\");\n        errors.put(149, \"空文件\");\n        errors.put(150, \"文件上传错误\");\n        errors.put(151, \"文件删除错误\");\n        errors.put(160, \"图片错误\");\n        errors.put(161, \"图片模式错误\");\n        errors.put(162, \"图片宽度错误\");\n        errors.put(163, \"图片高度错误\");\n        errors.put(164, \"图片长边错误\");\n        errors.put(165, \"图片短边错误\");\n        errors.put(201, \"缺失数据\");\n        errors.put(202, \"用户名已经存在\");\n        errors.put(203, \"邮箱已经存在\");\n        errors.put(204, \"必须提供一个邮箱地址\");\n        errors.put(205, \"没有找到此邮件的用户\");\n        errors.put(206, \"登录用户才能修改自己的信息。RestAPI的Http Header中没有提供sessionToken的正确值，不能修改或删除用户\");\n        errors.put(207, \"验证码错误\");\n        errors.put(208, \"authData不正确\");\n        errors.put(209, \"该手机号码已经存在\");\n        errors.put(210, \"密码不正确\");\n        errors.put(211, \"找不到用户\");\n        errors.put(301, \"验证错误详细提示，如邮箱格式不正确\");\n        errors.put(302, \"Bmob后台设置了应用设置值， 如'不允许SDK创建表 '\");\n        errors.put(310, \"云端逻辑运行错误的详细信息\");\n        errors.put(311, \"云端逻辑名称是大小写敏感的，且必须以英文字母开头，有效的字符仅限在英文字母、数字以及下划线。\");\n        errors.put(401, \"唯一键不能存在重复的值\");\n        errors.put(402, \"查询的wher语句长度大于具体多少个字节\");\n        errors.put(601, \"不正确的BQL查询语句\");\n        errors.put(1002, \"该应用能创建的表数已达到限制\");\n        errors.put(1003, \"该表的行数已达到限制\");\n        errors.put(1004, \"该表的列数已达到限制\");\n        errors.put(1005, \"每月api请求数量已达到限制\");\n        errors.put(1006, \"该应用能创建定时任务数已达到限制\");\n        errors.put(1007, \"该应用能创建云端逻辑数已达到限制\");\n        errors.put(1500, \"你上传的文件大小已超出限制\");\n\n        errors.put(10010, \"该手机号发送短信达到限制(对于一个应用来说，一天给同一手机号发送短信不能超过10条，一小时给同一手机号发送短信不能超过5条，一分钟给同一手机号发送短信不能超过1条)\");\n        errors.put(10011, \"该账户无可用的发送短信条数\");\n        errors.put(10012, \"身份信息必须审核通过才能使用该功能\");\n        errors.put(10013, \"非法短信内容\");\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/GlideCircleTransform.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapShader;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\n\nimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;\nimport com.bumptech.glide.load.resource.bitmap.BitmapTransformation;\n\npublic class GlideCircleTransform extends BitmapTransformation {\n    public GlideCircleTransform(Context context) {\n        super(context);\n    }\n\n    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {\n        return circleCrop(pool, toTransform);\n    }\n\n    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {\n        if (source == null) return null;\n        int size = Math.min(source.getWidth(), source.getHeight());\n        int x = (source.getWidth() - size) / 2;\n        int y = (source.getHeight() - size) / 2;\n        // TODO this could be acquired from the pool too\n        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);\n        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);\n        if (result == null) {\n            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);\n        }\n        Canvas canvas = new Canvas(result);\n        Paint paint = new Paint();\n        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));\n        paint.setAntiAlias(true);\n        float r = size / 2f;\n        canvas.drawCircle(r, r, r, paint);\n        return result;\n    }\n\n    @Override\n    public String getId() {\n        return getClass().getName();\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/MultiPageRequest.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport rx.Observable;\n\npublic abstract class MultiPageRequest<T> {\n\n    public abstract Observable<T> request(int page);\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/ObservableDecorator.java",
    "content": "package com.boredream.bdcodehelper.net;\n\nimport com.boredream.bdcodehelper.BoreConstants;\n\nimport java.util.concurrent.TimeUnit;\n\nimport rx.Observable;\nimport rx.android.schedulers.AndroidSchedulers;\nimport rx.schedulers.Schedulers;\n\n/**\n * 观察者装饰器\n */\npublic class ObservableDecorator {\n\n    public static <T> Observable<T> decorate(Observable<T> observable) {\n        Observable<T> newObservable;\n        if(BoreConstants.isUnitTest) {\n            newObservable = observable.subscribeOn(Schedulers.immediate())\n                    .observeOn(Schedulers.immediate());\n        } else {\n            newObservable = observable.subscribeOn(Schedulers.newThread())\n                    .observeOn(AndroidSchedulers.mainThread())\n                    .delay(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread()); // FIXME 模拟延迟,用于观察加载框等效果\n        }\n        return newObservable;\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/net/RoundedCornersTransformation.java",
    "content": "package com.boredream.bdcodehelper.net;\n\n/**\n * Copyright (C) 2015 Wasabeef\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapShader;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.Transformation;\nimport com.bumptech.glide.load.engine.Resource;\nimport com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;\nimport com.bumptech.glide.load.resource.bitmap.BitmapResource;\n\npublic class RoundedCornersTransformation implements Transformation<Bitmap> {\n\n  public enum CornerType {\n    ALL,\n    TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,\n    TOP, BOTTOM, LEFT, RIGHT,\n    OTHER_TOP_LEFT, OTHER_TOP_RIGHT, OTHER_BOTTOM_LEFT, OTHER_BOTTOM_RIGHT,\n    DIAGONAL_FROM_TOP_LEFT, DIAGONAL_FROM_TOP_RIGHT\n  }\n\n  private BitmapPool mBitmapPool;\n  private int mRadius;\n  private int mDiameter;\n  private int mMargin;\n  private CornerType mCornerType;\n\n  public RoundedCornersTransformation(Context context, int radius, int margin) {\n    this(context, radius, margin, CornerType.ALL);\n  }\n\n  public RoundedCornersTransformation(BitmapPool pool, int radius, int margin) {\n    this(pool, radius, margin, CornerType.ALL);\n  }\n\n  public RoundedCornersTransformation(Context context, int radius, int margin,\n      CornerType cornerType) {\n    this(Glide.get(context).getBitmapPool(), radius, margin, cornerType);\n  }\n\n  public RoundedCornersTransformation(BitmapPool pool, int radius, int margin,\n      CornerType cornerType) {\n    mBitmapPool = pool;\n    mRadius = radius;\n    mDiameter = mRadius * 2;\n    mMargin = margin;\n    mCornerType = cornerType;\n  }\n\n  @Override\n  public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {\n    Bitmap source = resource.get();\n\n    int width = source.getWidth();\n    int height = source.getHeight();\n\n    Bitmap bitmap = mBitmapPool.get(width, height, Bitmap.Config.ARGB_8888);\n    if (bitmap == null) {\n      bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n    }\n\n    Canvas canvas = new Canvas(bitmap);\n    Paint paint = new Paint();\n    paint.setAntiAlias(true);\n    paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));\n    drawRoundRect(canvas, paint, width, height);\n    return BitmapResource.obtain(bitmap, mBitmapPool);\n  }\n\n  private void drawRoundRect(Canvas canvas, Paint paint, float width, float height) {\n    float right = width - mMargin;\n    float bottom = height - mMargin;\n\n    switch (mCornerType) {\n      case ALL:\n        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);\n        break;\n      case TOP_LEFT:\n        drawTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case TOP_RIGHT:\n        drawTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM_LEFT:\n        drawBottomLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM_RIGHT:\n        drawBottomRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case TOP:\n        drawTopRoundRect(canvas, paint, right, bottom);\n        break;\n      case BOTTOM:\n        drawBottomRoundRect(canvas, paint, right, bottom);\n        break;\n      case LEFT:\n        drawLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case RIGHT:\n        drawRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_TOP_LEFT:\n        drawOtherTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_TOP_RIGHT:\n        drawOtherTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_BOTTOM_LEFT:\n        drawOtherBottomLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case OTHER_BOTTOM_RIGHT:\n        drawOtherBottomRightRoundRect(canvas, paint, right, bottom);\n        break;\n      case DIAGONAL_FROM_TOP_LEFT:\n        drawDiagonalFromTopLeftRoundRect(canvas, paint, right, bottom);\n        break;\n      case DIAGONAL_FROM_TOP_RIGHT:\n        drawDiagonalFromTopRightRoundRect(canvas, paint, right, bottom);\n        break;\n      default:\n        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);\n        break;\n    }\n  }\n\n  private void drawTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, mMargin + mRadius, bottom), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n    canvas.drawRect(new RectF(right - mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom - mRadius), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawBottomRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n    canvas.drawRect(new RectF(right - mRadius, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawTopRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawBottomRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);\n  }\n\n  private void drawRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);\n  }\n\n  private void drawOtherTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);\n  }\n\n  private void drawOtherTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawOtherBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mRadius, bottom), paint);\n  }\n\n  private void drawOtherBottomRightRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,\n        paint);\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,\n        paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  private void drawDiagonalFromTopLeftRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),\n        mRadius, mRadius, paint);\n    canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,\n        mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mDiameter, bottom), paint);\n    canvas.drawRect(new RectF(mMargin + mDiameter, mMargin, right, bottom - mRadius), paint);\n  }\n\n  private void drawDiagonalFromTopRightRoundRect(Canvas canvas, Paint paint, float right,\n      float bottom) {\n    canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,\n        mRadius, paint);\n    canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),\n        mRadius, mRadius, paint);\n    canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);\n    canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);\n  }\n\n  @Override public String getId() {\n    return \"RoundedTransformation(radius=\" + mRadius + \", margin=\" + mMargin + \", diameter=\"\n        + mDiameter + \", cornerType=\" + mCornerType.name() + \")\";\n  }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/FormItemsPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.entity.FormItem;\nimport com.boredream.bdcodehelper.utils.ToastUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class FormItemsPresent {\n\n    public interface OnSelectItemClickListener {\n        void onSelectItemClick(String leftText);\n    }\n\n    private Context context;\n    private LinearLayout ll_container;\n    private List<FormItem> items;\n\n    public FormItemsPresent(LinearLayout ll_container) {\n        this.context = ll_container.getContext();\n        this.ll_container = ll_container;\n    }\n\n    public void load(List<FormItem> items, Integer[] emptyIndexs,\n                     final OnSelectItemClickListener listener) {\n        this.items = items;\n        List<Integer> emptyIndexList = Arrays.asList(emptyIndexs);\n\n        for (int i = 0; i < items.size(); i++) {\n            final FormItem formItem = items.get(i);\n\n            // item\n            View itemView;\n            if (formItem.type == FormItem.TYPE_INPUT) {\n                // input\n                itemView = View.inflate(context, R.layout.formitem_input, null);\n                EditText tv_mid = (EditText) itemView.findViewById(R.id.tv_mid);\n                tv_mid.setInputType(formItem.inputType);\n                tv_mid.setHint(formItem.midText);\n            } else {\n                // select\n                itemView = View.inflate(context, R.layout.formitem_select, null);\n\n                ImageView iv_right = (ImageView) itemView.findViewById(R.id.iv_right);\n                if (formItem.rightImg != -1) {\n                    iv_right.setImageResource(formItem.rightImg);\n                }\n\n                itemView.setOnClickListener(new View.OnClickListener() {\n                    @Override\n                    public void onClick(View view) {\n                        if (listener != null) {\n                            listener.onSelectItemClick(formItem.leftText);\n                        }\n                    }\n                });\n            }\n            TextView tv_left = (TextView) itemView.findViewById(R.id.tv_left);\n            tv_left.setText(formItem.leftText);\n            itemView.setTag(formItem.leftText);\n            ll_container.addView(itemView);\n\n            // divider\n            View dividerView;\n            if (emptyIndexList.contains(i)) {\n                dividerView = View.inflate(context, R.layout.include_group_divider, null);\n            } else {\n                dividerView = new View(context);\n                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(\n                        LinearLayout.LayoutParams.MATCH_PARENT, 1);\n                dividerView.setLayoutParams(params);\n                dividerView.setBackgroundResource(R.color.divider_gray);\n            }\n            ll_container.addView(dividerView);\n        }\n    }\n\n    public ViewGroup getItemView(String leftText) {\n        ViewGroup itemView = (ViewGroup) ll_container.findViewWithTag(leftText);\n        return itemView;\n    }\n\n    public String getString(String leftText) {\n        ViewGroup itemView = getItemView(leftText);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        return tv_mid.getText().toString().trim();\n    }\n\n    public LinearLayout showMidContainer(String leftText) {\n        ViewGroup itemView = getItemView(leftText);\n        LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        ll_mid_container.setVisibility(View.VISIBLE);\n        tv_mid.setVisibility(View.GONE);\n        return ll_mid_container;\n    }\n\n    public TextView showMidText(String leftText, String midText) {\n        ViewGroup itemView = getItemView(leftText);\n        LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n        TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n        ll_mid_container.setVisibility(View.GONE);\n        tv_mid.setVisibility(View.VISIBLE);\n        tv_mid.setText(midText);\n        return tv_mid;\n    }\n\n    public boolean validate() {\n        for (FormItem item : items) {\n            ViewGroup itemView = getItemView(item.leftText);\n            if (item.type == FormItem.TYPE_INPUT) {\n                // input\n                EditText tv_mid = (EditText) itemView.findViewById(R.id.tv_mid);\n                if (TextUtils.isEmpty(tv_mid.getText().toString().trim())) {\n                    ToastUtils.showToast(context, tv_mid.getHint());\n                    return false;\n                }\n            } else {\n                // select\n                TextView tv_mid = (TextView) itemView.findViewById(R.id.tv_mid);\n                LinearLayout ll_mid_container = (LinearLayout) itemView.findViewById(R.id.ll_mid_container);\n                if (tv_mid.getVisibility() == View.VISIBLE) {\n                    if (TextUtils.isEmpty(tv_mid.getText().toString().trim())) {\n                        ToastUtils.showToast(context, \"请选择\" + item.leftText);\n                        return false;\n                    }\n                } else {\n                    if (ll_mid_container.getChildCount() == 0) {\n                        ToastUtils.showToast(context, \"请选择\" + item.leftText);\n                        return false;\n                    }\n                }\n            }\n        }\n        return true;\n\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/GroupEtEmptyCheckPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.widget.EditText;\n\npublic class GroupEtEmptyCheckPresent {\n\n    private EditText[] ets;\n\n    public interface OnEtEmptyListener {\n        void onEtEmpty(boolean hasOneEmpty);\n    }\n\n    public GroupEtEmptyCheckPresent(EditText... ets) {\n        this.ets = ets;\n    }\n\n    public void check(final OnEtEmptyListener listener) {\n        for(EditText et : ets) {\n            et.addTextChangedListener(new TextWatcher() {\n                @Override\n                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {\n\n                }\n\n                @Override\n                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {\n                    checkAllEt(listener, ets);\n                }\n\n                @Override\n                public void afterTextChanged(Editable editable) {\n\n                }\n            });\n        }\n    }\n\n    private void checkAllEt(OnEtEmptyListener listener, EditText[] ets) {\n        boolean hasEmpty = false;\n\n        for(EditText et : ets) {\n            String s = et.getText().toString().trim();\n            if(TextUtils.isEmpty(s)) {\n                hasEmpty = true;\n                break;\n            }\n         }\n\n        listener.onEtEmpty(hasEmpty);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/ImageBannerPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.content.Context;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.CountDownTimer;\nimport android.support.v4.view.ViewPager;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.widget.RadioButton;\nimport android.widget.RadioGroup;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.BannerPagerAdapter;\nimport com.boredream.bdcodehelper.entity.ImageUrlInterface;\nimport com.boredream.bdcodehelper.utils.DisplayUtils;\n\nimport java.util.ArrayList;\n\npublic class ImageBannerPresent {\n\n    private static final int AUTO_SCROLL_GAP_TIME = 4000;\n    private static final int STATE_STOP = 0;\n    private static final int STATE_AUTO_SCROLLING = 1;\n    private int currentState;\n\n    private Context context;\n    private final CountDownTimer countDownTimer;\n\n    private ArrayList<? extends ImageUrlInterface> images;\n    private ViewPager vp_banner;\n\n    private RadioGroup rg_indicator;\n    private BannerPagerAdapter adapter;\n\n    public ImageBannerPresent(Context context, View include_banner_with_indicator) {\n        this.context = context;\n\n        vp_banner = (ViewPager) include_banner_with_indicator.findViewById(R.id.vp_banner);\n        rg_indicator = (RadioGroup) include_banner_with_indicator.findViewById(R.id.rg_indicator);\n\n        vp_banner.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\n            @Override\n            public void onPageScrollStateChanged(int state) {\n                // FIXME\n//                if (state == ViewPager.SCROLL_STATE_DRAGGING) {\n//                    stopAutoScroll();\n//                } else {\n//                    startAutoScroll();\n//                }\n            }\n        });\n\n        countDownTimer = new CountDownTimer(\n                Long.MAX_VALUE, AUTO_SCROLL_GAP_TIME) {\n            @Override\n            public void onTick(long l) {\n                vp_banner.setCurrentItem(vp_banner.getCurrentItem() + 1);\n            }\n\n            @Override\n            public void onFinish() {\n\n            }\n        };\n    }\n\n    public void load(ArrayList<? extends ImageUrlInterface> images) {\n        this.images = images;\n\n        adapter = new BannerPagerAdapter(context, images);\n        vp_banner.setAdapter(adapter);\n\n        setIndicator();\n        startAutoScroll();\n    }\n\n    public void startAutoScroll() {\n        if (currentState == STATE_AUTO_SCROLLING) {\n            return;\n        }\n\n        currentState = STATE_AUTO_SCROLLING;\n        countDownTimer.start();\n    }\n\n    public void stopAutoScroll() {\n        currentState = STATE_STOP;\n        countDownTimer.cancel();\n    }\n\n    private void setIndicator() {\n        if (images.size() <= 1) {\n            rg_indicator.setVisibility(View.GONE);\n            return;\n        }\n\n        rg_indicator.setVisibility(View.VISIBLE);\n\n        vp_banner.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n            @Override\n            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {\n\n            }\n\n            @Override\n            public void onPageSelected(int position) {\n                if (rg_indicator.getChildCount() > 1) {\n                    ((RadioButton) rg_indicator.getChildAt(position % images.size())).setChecked(true);\n                }\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int state) {\n\n            }\n        });\n\n        rg_indicator.removeAllViews();\n        for (int i = 0; i < images.size(); i++) {\n            RadioButton rb = new RadioButton(context);\n            RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(\n                    DisplayUtils.dp2px(context, 8), DisplayUtils.dp2px(context, 8));\n            if (i > 0) {\n                params.setMargins(DisplayUtils.dp2px(context, 8), 0, 0, 0);\n            }\n            rb.setLayoutParams(params);\n            rb.setButtonDrawable(new ColorDrawable());\n            rb.setBackgroundResource(R.drawable.shape_oval_primary2white_sel);\n            rb.setOnTouchListener(new View.OnTouchListener() {\n                @Override\n                public boolean onTouch(View view, MotionEvent motionEvent) {\n                    // do nothing\n                    return true;\n                }\n            });\n            rg_indicator.addView(rb);\n        }\n\n        ((RadioButton) rg_indicator.getChildAt(0)).setChecked(true);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/ImageBrowserPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.app.Activity;\nimport android.support.v4.view.ViewPager;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.adapter.ImageBrowserAdapter;\n\nimport java.util.ArrayList;\n\npublic class ImageBrowserPresent {\n    private Activity activity;\n    private ViewPager vp_image_brower;\n    private TextView tv_image_index;\n\n    private int position;\n    private ImageBrowserAdapter adapter;\n    private ArrayList<String> images;\n\n    public ImageBrowserPresent(Activity activity, ImageBrowserAdapter adapter,\n                               ViewPager vp_image_brower, TextView tv_image_index) {\n        this.activity = activity;\n        this.adapter = adapter;\n        this.vp_image_brower = vp_image_brower;\n        this.tv_image_index = tv_image_index;\n    }\n\n    public void init() {\n        initData();\n        setData();\n    }\n\n    private void initData() {\n        images = (ArrayList<String>) activity.getIntent().getSerializableExtra(\"images\");\n        position = activity.getIntent().getIntExtra(\"position\", 0);\n    }\n\n    private void setData() {\n        vp_image_brower.setAdapter(adapter);\n\n        final int size = images.size();\n        int initPosition = position;\n\n        if (size > 1) {\n            tv_image_index.setVisibility(View.VISIBLE);\n            tv_image_index.setText((position + 1) + \"/\" + size);\n        } else {\n            tv_image_index.setVisibility(View.GONE);\n        }\n\n        vp_image_brower.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {\n\n            @Override\n            public void onPageSelected(int arg0) {\n                int index = arg0 % size;\n                tv_image_index.setText((index + 1) + \"/\" + size);\n            }\n\n            @Override\n            public void onPageScrolled(int arg0, float arg1, int arg2) {\n\n            }\n\n            @Override\n            public void onPageScrollStateChanged(int arg0) {\n\n            }\n        });\n\n        vp_image_brower.setCurrentItem(initPosition);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/present/MultiPageLoadPresent.java",
    "content": "package com.boredream.bdcodehelper.present;\n\nimport android.app.Activity;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.view.View;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.adapter.LoadMoreAdapter;\nimport com.boredream.bdcodehelper.entity.ListResponse;\nimport com.boredream.bdcodehelper.entity.PageIndex;\nimport com.boredream.bdcodehelper.net.MultiPageRequest;\nimport com.boredream.bdcodehelper.net.ObservableDecorator;\nimport com.boredream.bdcodehelper.view.DividerItemDecoration;\n\nimport java.util.ArrayList;\n\nimport rx.Observable;\nimport rx.Subscriber;\nimport rx.Subscription;\n\npublic class MultiPageLoadPresent {\n\n    private Activity activity;\n    private LoadMoreAdapter loadMoreAdapter;\n\n    private SwipeRefreshLayout srl;\n    private RecyclerView rv;\n    private RecyclerView.ItemDecoration itemDecoration;\n\n    public RecyclerView getRv() {\n        return rv;\n    }\n\n    public MultiPageLoadPresent(Activity activity, View include_refresh_list, PageIndex pageIndex) {\n        this.activity = activity;\n        this.srl = (SwipeRefreshLayout) include_refresh_list;\n        this.pageIndex = pageIndex;\n        initView();\n    }\n\n    private void initView() {\n        srl.setColorSchemeColors(activity.getResources().getColor(R.color.colorPrimary));\n        rv = (RecyclerView) srl.findViewById(R.id.rv);\n\n        LinearLayoutManager layoutManager = new LinearLayoutManager(\n                activity, StaggeredGridLayoutManager.VERTICAL, false);\n        rv.setLayoutManager(layoutManager);\n        itemDecoration = new DividerItemDecoration(activity);\n        rv.addItemDecoration(itemDecoration);\n    }\n\n    public void setItemDecoration(RecyclerView.ItemDecoration itemDecoration) {\n        rv.removeItemDecoration(this.itemDecoration);\n        this.itemDecoration = itemDecoration;\n        if (this.itemDecoration != null) {\n            rv.addItemDecoration(this.itemDecoration);\n        }\n    }\n\n    private ArrayList datas;\n    private PageIndex pageIndex;\n    private MultiPageRequest request;\n    private Subscriber subscriber;\n\n    public void setDatas(ArrayList datas) {\n        this.datas = datas;\n        rv.post(new Runnable() {\n            @Override\n            public void run() {\n                loadMoreAdapter.notifyDataSetChanged();\n            }\n        });\n    }\n\n    public <T> Subscription load(RecyclerView.Adapter adapter,\n                                 ArrayList datas,\n                                 MultiPageRequest<T> request,\n                                 Subscriber<T> subscriber) {\n        this.datas = datas;\n        this.request = request;\n        this.subscriber = subscriber;\n\n        loadMoreAdapter = new LoadMoreAdapter(rv, adapter,\n                new LoadMoreAdapter.OnLoadMoreListener() {\n                    @Override\n                    public void onLoadMore() {\n                        // 列表拉到底部时,加载下一页\n                        loadData(pageIndex.toNextPage());\n                    }\n                });\n        rv.setAdapter(loadMoreAdapter);\n        srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {\n            @Override\n            public void onRefresh() {\n                // 下拉刷新时,重新加载起始页\n                loadData(pageIndex.toStartPage());\n            }\n        });\n\n        return loadData(this.pageIndex.toStartPage());\n    }\n\n    public void setStatus(int status) {\n        if(loadMoreAdapter != null) {\n            loadMoreAdapter.setStatus(status);\n        }\n    }\n\n    public void notifyDataSetChanged() {\n        if(loadMoreAdapter != null) {\n            loadMoreAdapter.notifyDataSetChanged();\n        }\n    }\n\n    public void initPage() {\n        pageIndex.init();\n    }\n\n    public boolean isRefreshing() {\n        return srl.isRefreshing();\n    }\n\n    public void setRefreshing(final boolean refreshing) {\n        srl.post(new Runnable() {\n            @Override\n            public void run() {\n                srl.setRefreshing(refreshing);\n            }\n        });\n    }\n\n    /**\n     * 加载列表\n     *\n     * @param page 页数\n     */\n    private Subscription loadData(final int page) {\n        Observable observable = this.request.request(page);\n        return ObservableDecorator.decorate(observable).subscribe(\n                new Subscriber<ListResponse>() {\n                    @Override\n                    public void onNext(ListResponse response) {\n                        if (subscriber != null) {\n                            subscriber.onNext(response);\n                        }\n                        setRefreshing(false);\n\n                        // 加载成功后更新数据\n                        pageIndex.setResponse(loadMoreAdapter, datas, response.getResults());\n                    }\n\n                    @Override\n                    public void onCompleted() {\n                        if (subscriber != null) {\n                            subscriber.onCompleted();\n                        }\n                    }\n\n                    @Override\n                    public void onError(Throwable throwable) {\n                        if (subscriber != null) {\n                            subscriber.onError(throwable);\n                        }\n                        setRefreshing(false);\n                    }\n                });\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ActivityUtils.java",
    "content": "/*\n * Copyright 2016, The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.utils;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\n\n/**\n * This provides methods to help Activities load their UI.\n */\npublic class ActivityUtils {\n\n    /**\n     * The {@code fragment} is added to the container view with id {@code frameId}. The operation is\n     * performed by the {@code fragmentManager}.\n     */\n    public static void addFragmentToActivity(FragmentManager fragmentManager,\n                                             Fragment fragment, int frameId) {\n        FragmentTransaction transaction = fragmentManager.beginTransaction();\n        transaction.add(frameId, fragment);\n        transaction.commit();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/AppUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.telephony.TelephonyManager;\nimport android.util.Log;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\n\nimport java.io.File;\n\npublic class AppUtils {\n\n    /**\n     * 获取版本名称\n     */\n    public static String getAppVersionName(Context context) {\n        String versionName = \"\";\n        try {\n            // ---get the package info---\n            PackageManager pm = context.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);\n            versionName = pi.versionName;\n            if (versionName == null || versionName.length() <= 0) {\n                return \"\";\n            }\n        } catch (Exception e) {\n            Log.e(\"VersionInfo\", \"Exception\", e);\n        }\n        return versionName;\n    }\n\n    /**\n     * 获取版本号\n     */\n    public static int getAppVersionCode(Context context) {\n        int versioncode = -1;\n        try {\n            // ---get the package info---\n            PackageManager pm = context.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);\n            versioncode = pi.versionCode;\n        } catch (Exception e) {\n            Log.e(\"VersionInfo\", \"Exception\", e);\n        }\n        return versioncode;\n    }\n\n    public static String getIMEI(Context context) {\n        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);\n        return tm.getDeviceId();\n    }\n\n    /**\n     * 显示软键盘\n     */\n    public static void openSoftInput(EditText et) {\n        InputMethodManager inputMethodManager = (InputMethodManager) et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.showSoftInput(et, InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    /**\n     * 隐藏软键盘\n     */\n    public static void hideSoftInput(EditText et) {\n        InputMethodManager inputMethodManager = (InputMethodManager) et.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.hideSoftInputFromWindow(et.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);\n    }\n\n    /**\n     * 获取SD卡路径\n     *\n     * @return 如果sd卡不存在则返回null\n     */\n    public static File getSDPath() {\n        File sdDir = null;\n        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);   //判断sd卡是否存在\n        if (sdCardExist) {\n            sdDir = Environment.getExternalStorageDirectory();//获取跟目录\n        }\n        return sdDir;\n    }\n\n    /**\n     * 安装文件\n     *\n     * @param data\n     */\n    public static void promptInstall(Context context, Uri data) {\n        Intent promptInstall = new Intent(Intent.ACTION_VIEW)\n                .setDataAndType(data, \"application/vnd.android.package-archive\");\n        // FLAG_ACTIVITY_NEW_TASK 可以保证安装成功时可以正常打开 app\n        promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(promptInstall);\n    }\n\n    public static void copy2clipboard(Context context, String text){\n        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);\n        ClipData clip = ClipData.newPlainText(\"clip\", text);\n        cm.setPrimaryClip(clip);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DateUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.text.TextUtils;\nimport android.text.format.DateFormat;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * 日期时间工具类\n */\npublic class DateUtils {\n\n    public static final long ONE_SECOND_MILLIONS = 1000;\n    public static final long ONE_MINUTE_MILLIONS = 60 * ONE_SECOND_MILLIONS;\n    public static final long ONE_HOUR_MILLIONS = 60 * ONE_MINUTE_MILLIONS;\n    public static final long ONE_DAY_MILLIONS = 24 * ONE_HOUR_MILLIONS;\n    public static final int DAY_OF_YEAR = 365;\n\n    // 日期格式为 2016-02-03 17:04:58\n    public static final String PATTERN_DATE = \"yyyy年MM月dd日\";\n    public static final String PATTERN_TIME = \"HH:mm:ss\";\n    public static final String PATTERN_SPLIT = \" \";\n    public static final String PATTERN = PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME;\n\n    public static String getShortTime(String dateStr) {\n        String str;\n\n        Date date = str2date(dateStr);\n        Date curDate = new Date();\n\n        long durTime = curDate.getTime() - date.getTime();\n        int dayDiff = calculateDayDiff(date, curDate);\n\n        if (durTime <= 10 * ONE_MINUTE_MILLIONS) {\n            str = \"刚刚\";\n        } else if (durTime < ONE_HOUR_MILLIONS) {\n            str = durTime / ONE_MINUTE_MILLIONS + \"分钟前\";\n        } else if (dayDiff == 0) {\n            str = durTime / ONE_HOUR_MILLIONS + \"小时前\";\n        } else if (dayDiff == -1) {\n            str = \"昨天\" + DateFormat.format(\"HH:mm\", date);\n        } else if (isSameYear(date, curDate) && dayDiff < -1) {\n            str = DateFormat.format(\"MM-dd\", date).toString();\n        } else {\n            str = DateFormat.format(\"yyyy-MM\", date).toString();\n        }\n\n        return str;\n    }\n\n    /**\n     * 获取日期 PATTERN_DATE 部分\n     */\n    public static String getDate(String date) {\n        if (TextUtils.isEmpty(date) || !date.contains(PATTERN_SPLIT)) {\n            return \"\";\n        }\n        return date.split(PATTERN_SPLIT)[0];\n    }\n\n    /**\n     * 原有日期上累加月\n     *\n     * @return 累加后的日期 PATTERN_DATE 部分\n     */\n    public static String addMonth(String date, int moonCount) {\n        //如果date为空 就用当前时间\n        if (TextUtils.isEmpty(date)) {\n            SimpleDateFormat df = new SimpleDateFormat(PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME);\n            date = df.format(new Date());\n        }\n        Calendar calendar = str2calendar(date);\n        calendar.add(Calendar.MONTH, moonCount);\n        return getDate(calendar2str(calendar));\n    }\n\n    /**\n     * 计算天数差\n     */\n    public static int calculateDayDiff(Date targetTime, Date compareTime) {\n        boolean sameYear = isSameYear(targetTime, compareTime);\n        if (sameYear) {\n            return calculateDayDiffOfSameYear(targetTime, compareTime);\n        } else {\n            int dayDiff = 0;\n\n            // 累计年数差的整年天数\n            int yearDiff = calculateYearDiff(targetTime, compareTime);\n            dayDiff += yearDiff * DAY_OF_YEAR;\n\n            // 累计同一年内的天数\n            dayDiff += calculateDayDiffOfSameYear(targetTime, compareTime);\n\n            return dayDiff;\n        }\n    }\n\n    /**\n     * 计算同一年内的天数差\n     */\n    public static int calculateDayDiffOfSameYear(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return 0;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarDayOfYear = tarCalendar.get(Calendar.DAY_OF_YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comDayOfYear = compareCalendar.get(Calendar.DAY_OF_YEAR);\n\n        return tarDayOfYear - comDayOfYear;\n    }\n\n    /**\n     * 计算年数差\n     */\n    public static int calculateYearDiff(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return 0;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n\n        return tarYear - comYear;\n    }\n\n    /**\n     * 计算月数差\n     *\n     * @param targetTime\n     * @param compareTime\n     * @return\n     */\n    public static int calculateMonthDiff(String targetTime, String compareTime) {\n        return calculateMonthDiff(str2date(targetTime, PATTERN_DATE),\n                str2date(compareTime, PATTERN_DATE));\n    }\n\n    /**\n     * 计算月数差\n     *\n     * @param targetTime\n     * @param compareTime\n     * @return\n     */\n    public static int calculateMonthDiff(Date targetTime, Date compareTime) {\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n        int tarMonth = tarCalendar.get(Calendar.MONTH);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n        int comMonth = compareCalendar.get(Calendar.MONTH);\n        return ((tarYear - comYear) * 12 + tarMonth - comMonth);\n\n    }\n\n    /**\n     * 是否为同一年\n     */\n    public static boolean isSameYear(Date targetTime, Date compareTime) {\n        if (targetTime == null || compareTime == null) {\n            return false;\n        }\n\n        Calendar tarCalendar = Calendar.getInstance();\n        tarCalendar.setTime(targetTime);\n        int tarYear = tarCalendar.get(Calendar.YEAR);\n\n        Calendar compareCalendar = Calendar.getInstance();\n        compareCalendar.setTime(compareTime);\n        int comYear = compareCalendar.get(Calendar.YEAR);\n\n        return tarYear == comYear;\n    }\n\n    public static Date str2date(String str, String format) {\n        Date date = null;\n        try {\n            if (str != null) {\n                SimpleDateFormat sdf = new SimpleDateFormat(format);\n                date = sdf.parse(str);\n            }\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        return date;\n    }\n\n    public static Date str2date(String str) {\n        return str2date(str, PATTERN);\n    }\n\n    public static String date2str(Date date) {\n        return date2str(date, PATTERN);\n    }\n\n    public static String date2str(Date date, String format) {\n        SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.CHINA);\n        return sdf.format(date);\n    }\n\n    public static Calendar str2calendar(String str) {\n        Calendar calendar = null;\n        Date date = str2date(str);\n        if (date != null) {\n            calendar = Calendar.getInstance();\n            calendar.setTime(date);\n        }\n        return calendar;\n    }\n\n\n    public static Calendar str2calendar(String str, String format) {\n        Calendar calendar = null;\n        Date date = str2date(str, format);\n        if (date != null) {\n            calendar = Calendar.getInstance();\n            calendar.setTime(date);\n        }\n        return calendar;\n    }\n\n    public static String calendar2str(Calendar calendar) {\n        return date2str(calendar.getTime());\n    }\n\n    public static String calendar2str(Calendar calendar, String format) {\n        return date2str(calendar.getTime(), format);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DialogUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.support.v7.app.AlertDialog;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 对话框工具类, 提供常用对话框显示, 使用support.v7包内的AlertDialog样式\n */\npublic class DialogUtils {\n\n    public static Dialog createProgressDialog(Context context) {\n        return createProgressDialog(context, true);\n    }\n\n    public static Dialog createProgressDialog(Context context, boolean needCancle) {\n        ProgressDialog dialog = new ProgressDialog(context);\n        dialog.setMessage(\"Loading ...\");\n        dialog.setCancelable(needCancle);\n        dialog.setCanceledOnTouchOutside(false);\n        return dialog;\n    }\n\n    public static Dialog showCommonDialog(Context context, String message,\n                                          DialogInterface.OnClickListener listener) {\n        return new AlertDialog.Builder(context)\n                .setMessage(message)\n                .setPositiveButton(context.getString(R.string.dialog_positive), listener)\n                .setNegativeButton(context.getString(R.string.dialog_negative), null)\n                .show();\n    }\n\n    public static Dialog showConfirmDialog(Context context, String message,\n                                           DialogInterface.OnClickListener listener) {\n        return new AlertDialog.Builder(context)\n                .setMessage(message)\n                .setPositiveButton(context.getString(R.string.dialog_positive), listener)\n                .show();\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/DisplayUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.util.DisplayMetrics;\n\npublic class DisplayUtils {\n\t/**\n\t * 将px值转换为dp值\n\t */\n\tpublic static int px2dp(Context context, float pxValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().density;\n\t\treturn (int) (pxValue / scale + 0.5f);\n\t}\n\n\t/**\n\t * 将dp值转换为px值\n\t */\n\tpublic static int dp2px(Context context, float dpValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().density;\n\t\treturn (int) (dpValue * scale + 0.5f);\n\t}\n\n\t/**\n\t * 将px值转换为sp值\n\t */\n\tpublic static int px2sp(Context context, float pxValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().scaledDensity;\n\t\treturn (int) (pxValue / scale + 0.5f);\n\t}\n\n\t/**\n\t * 将sp值转换为px值\n\t */\n\tpublic static int sp2px(Context context, float dpValue) {\n\t\tfinal float scale = context.getResources().getDisplayMetrics().scaledDensity;\n\t\treturn (int) (dpValue * scale + 0.5f);\n\t}\n\n\t/**\n\t * 获取屏幕宽度\n\t */\n\tpublic static int getScreenWidthPixels(Activity context) {\n\t\tDisplayMetrics metric = new DisplayMetrics();\n\t\tcontext.getWindowManager().getDefaultDisplay().getMetrics(metric);\n\t\treturn metric.widthPixels;\n\t}\n\n\t/**\n\t * 获取屏幕高度\n\t */\n\tpublic static int getScreenHeightPixels(Activity context) {\n\t\tDisplayMetrics metric = new DisplayMetrics();\n\t\tcontext.getWindowManager().getDefaultDisplay().getMetrics(metric);\n\t\treturn metric.heightPixels;\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ErrorInfoUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport com.boredream.bdcodehelper.entity.ErrorResponse;\nimport com.boredream.bdcodehelper.net.ErrorConstants;\nimport com.google.gson.Gson;\nimport com.squareup.okhttp.MediaType;\nimport com.squareup.okhttp.ResponseBody;\n\nimport java.net.UnknownHostException;\n\nimport retrofit.HttpException;\n\npublic class ErrorInfoUtils {\n\n    /**\n     * 解析服务器错误信息\n     */\n    public static String parseHttpErrorInfo(Throwable throwable) {\n        String errorInfo = throwable.getMessage();\n\n        if (throwable instanceof HttpException) {\n            // 如果是Retrofit的Http错误,则转换类型,获取信息\n            HttpException exception = (HttpException) throwable;\n            ResponseBody responseBody = exception.response().errorBody();\n            MediaType type = responseBody.contentType();\n\n            // 如果是application/json类型数据,则解析返回内容\n            if (type.type().equals(\"application\") && type.subtype().equals(\"json\")) {\n                try {\n                    // 这里的返回内容是Bmob/AVOS/Parse等RestFul API文档中的错误代码和错误信息对象\n                    ErrorResponse errorResponse = new Gson().fromJson(\n                            responseBody.string(), ErrorResponse.class);\n\n                    errorInfo = getLocalErrorInfo(errorResponse);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        } else {\n            if (throwable instanceof UnknownHostException) {\n                errorInfo = \"无法连接到服务器\";\n            }\n        }\n\n        return errorInfo;\n    }\n\n    /**\n     * 获取本地预设错误信息\n     */\n    private static String getLocalErrorInfo(ErrorResponse error) {\n        String s = ErrorConstants.errors.get(error.getCode());\n        if (StringUtils.isEmpty(s)) {\n            return error.getError();\n        } else {\n            return s;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ImageUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.provider.DocumentsContract;\nimport android.provider.MediaStore;\nimport android.support.v7.app.AlertDialog;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.request.FutureTarget;\n\nimport rx.Observable;\nimport rx.functions.Func1;\n\n/**\n * 图片工具类\n */\npublic class ImageUtils {\n\n    /**\n     * 拍照\n     */\n    public static final int REQUEST_CODE_FROM_CAMERA = 1 << 10;\n\n    /**\n     * 相册\n     */\n    public static final int REQUEST_CODE_FROM_ALBUM = 1 << 12;\n\n    /**\n     * 裁剪\n     */\n    public static final int REQUEST_CODE_CROP_IMAGE = 1 << 14;\n\n    /**\n     * 存放拍照图片的uri地址\n     */\n    public static Uri imageUriFromCamera;\n\n    /**\n     * 存放裁剪图片的uri地址\n     */\n    public static Uri cropImageUri;\n\n    /**\n     * 显示获取照片不同方式对话框\n     */\n    public static void showImagePickDialog(final Activity activity) {\n        showImagePickDialog(activity, 0);\n    }\n\n    /**\n     * 显示获取照片不同方式对话框\n     */\n    public static void showImagePickDialog(final Activity activity, final int addRequest) {\n        String title = \"选择获取图片方式\";\n        String[] items = new String[]{\"拍照\", \"相册\"};\n        new AlertDialog.Builder(activity)\n                .setTitle(title)\n                .setItems(items, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                        switch (which) {\n                            case 0:\n                                pickImageFromCamera(activity, addRequest);\n                                break;\n                            case 1:\n                                pickImageFromAlbum(activity, addRequest);\n                                break;\n                            default:\n                                break;\n                        }\n                    }\n                })\n                .setNegativeButton(\"取消\", null)\n                .show();\n    }\n\n    /**\n     * 打开相机拍照获取图片\n     */\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public static void pickImageFromCamera(final Activity activity, int addRequest) {\n        // 先生成一个uri地址用于存放拍照获取的图片\n        imageUriFromCamera = createImageUri(activity);\n\n        Intent intent = new Intent();\n        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUriFromCamera);\n        activity.startActivityForResult(intent, REQUEST_CODE_FROM_CAMERA + addRequest);\n    }\n\n    /**\n     * 打开相机拍照获取图片\n     */\n    public static void pickImageFromCamera(final Activity activity) {\n        pickImageFromCamera(activity, 0);\n    }\n\n    /**\n     * 打开本地相册选取图片\n     */\n    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)\n    public static void pickImageFromAlbum(final Activity activity, int addRequest) {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_GET_CONTENT);\n        intent.setType(\"image/*\");\n        activity.startActivityForResult(intent, REQUEST_CODE_FROM_ALBUM + addRequest);\n    }\n\n    /**\n     * 打开本地相册选取图片\n     */\n    public static void pickImageFromAlbum(final Activity activity) {\n        pickImageFromAlbum(activity, 0);\n    }\n\n    /**\n     * 亚索图片\n     *\n     * @param context\n     * @param uri     图片uri\n     * @param reqW    上传图片需要压缩的宽度\n     * @param reqH    上传图片需要压缩的高度\n     * @return 上传成功回调\n     */\n    public static Observable<byte[]> compressImage(final Context context,\n                                                   Uri uri,\n                                                   final int reqW,\n                                                   final int reqH) {\n        // 先从本地获取图片,利用Glide压缩图片后获取byte[]\n        return Observable.just(uri)\n                .flatMap(new Func1<Uri, Observable<byte[]>>() {\n                    @Override\n                    public Observable<byte[]> call(Uri uri) {\n                        // 在work线程中，同步压缩图片，然后Observable返回\n                        // 即将Glide的回调封装成RxJava的Observable\n                        FutureTarget<byte[]> future = Glide.with(context)\n                                .load(uri)\n                                .asBitmap()\n                                .toBytes()\n                                .into(reqW, reqH);\n\n                        byte[] bytes;\n                        try {\n                            bytes = future.get();\n                        } catch (Exception e) {\n                            // 获取失败时，抛出runtime异常\n                            // 该异常会被Subscriber捕捉，进onError\n                            throw new RuntimeException(e);\n                        }\n                        return Observable.just(bytes);\n                    }\n                });\n    }\n\n    /**\n     * 图片裁剪\n     */\n    public static void cropImage(Activity activity, Uri srcUri) {\n        cropImageUri = createImageUri(activity);\n\n        Intent intent = new Intent(\"com.android.camera.action.CROP\");\n        intent.setDataAndType(srcUri, \"image/*\");\n        intent.putExtra(\"crop\", \"true\");\n\n        ////////////////////////////////////////////////////////////////\n        // 1.宽高和比例都不设置时,裁剪框可以自行调整(比例和大小都可以随意调整)\n        ////////////////////////////////////////////////////////////////\n        // 2.只设置裁剪框宽高比(aspect)后,裁剪框比例固定不可调整,只能调整大小\n        /////////////////////////////////\n        // 3.裁剪后生成图片宽高(output)的设置和裁剪框无关,只决定最终生成图片大小\n        ////////////////////////////////////////////////////////////////\n        // 4.裁剪框宽高比例(aspect)可以和裁剪后生成图片比例(output)不同,此时,\n        //\t会以裁剪框的宽为准,按照裁剪宽高比例生成一个图片,该图和框选部分可能不同,\n        //  不同的情况可能是截取框选的一部分,也可能超出框选部分,向下延伸补足\n        ////////////////////////////////////////////////////////////////\n\n        // aspectX aspectY 是裁剪框宽高的比例\n        intent.putExtra(\"aspectX\", 1);\n        intent.putExtra(\"aspectY\", 1);\n        // outputX outputY 是裁剪后生成图片的宽高\n//\t\tintent.putExtra(\"outputX\", 300);\n//\t\tintent.putExtra(\"outputY\", 100);\n\n        // return-data为true时,会直接返回bitmap数据,但是大图裁剪时会出现OOM,推荐下面为false时的方式\n        // return-data为false时,不会返回bitmap,但需要指定一个MediaStore.EXTRA_OUTPUT保存图片uri\n        intent.putExtra(\"return-data\", false);\n        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);\n\n        activity.startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE);\n    }\n\n    /**\n     * 创建一条图片uri,用于保存拍照后的照片\n     */\n    private static Uri createImageUri(Context context) {\n        String name = \"boreImg\" + System.currentTimeMillis();\n        ContentValues values = new ContentValues();\n        values.put(MediaStore.Images.Media.TITLE, name);\n        values.put(MediaStore.Images.Media.DISPLAY_NAME, name + \".jpeg\");\n        values.put(MediaStore.Images.Media.MIME_TYPE, \"image/jpeg\");\n        Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);\n        return uri;\n    }\n\n    /**\n     * 删除一条图片\n     */\n    public static void deleteImageUri(Context context, Uri uri) {\n        context.getContentResolver().delete(uri, null, null);\n    }\n\n    /**\n     * 用第三方应用app打开图片\n     */\n    public static void openImageByOtherApp(Context context, Uri imageUri) {\n        Intent intent = new Intent();\n        intent.setAction(Intent.ACTION_VIEW);\n        intent.setDataAndType(imageUri, \"image/*\");\n        context.startActivity(intent);\n    }\n\n    /**\n     * 根据Uri获取图片绝对路径，解决Android4.4以上版本Uri转换\n     */\n    public static String getImageAbsolutePath19(Context context, Uri imageUri) {\n        if (context == null || imageUri == null)\n            return null;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT\n                && DocumentsContract.isDocumentUri(context, imageUri)) {\n            if (isExternalStorageDocument(imageUri)) {\n                String docId = DocumentsContract.getDocumentId(imageUri);\n                String[] split = docId.split(\":\");\n                String type = split[0];\n                if (\"primary\".equalsIgnoreCase(type)) {\n                    return Environment.getExternalStorageDirectory() + \"/\" + split[1];\n                }\n            } else if (isDownloadsDocument(imageUri)) {\n                String id = DocumentsContract.getDocumentId(imageUri);\n                Uri contentUri = ContentUris.withAppendedId(Uri.parse(\"content://downloads/public_downloads\"), Long.valueOf(id));\n                return getDataColumn(context, contentUri, null, null);\n            } else if (isMediaDocument(imageUri)) {\n                String docId = DocumentsContract.getDocumentId(imageUri);\n                String[] split = docId.split(\":\");\n                String type = split[0];\n                Uri contentUri = null;\n                if (\"image\".equals(type)) {\n                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;\n                } else if (\"video\".equals(type)) {\n                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;\n                } else if (\"audio\".equals(type)) {\n                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;\n                }\n                String selection = MediaStore.Images.Media._ID + \"=?\";\n                String[] selectionArgs = new String[]{split[1]};\n                return getDataColumn(context, contentUri, selection, selectionArgs);\n            }\n        }\n\n        // MediaStore (and general)\n        if (\"content\".equalsIgnoreCase(imageUri.getScheme())) {\n            // Return the remote address\n            if (isGooglePhotosUri(imageUri))\n                return imageUri.getLastPathSegment();\n            return getDataColumn(context, imageUri, null, null);\n        }\n        // File\n        else if (\"file\".equalsIgnoreCase(imageUri.getScheme())) {\n            return imageUri.getPath();\n        }\n        return null;\n    }\n\n    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {\n        Cursor cursor = null;\n        String column = MediaStore.Images.Media.DATA;\n        String[] projection = {column};\n        try {\n            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);\n            if (cursor != null && cursor.moveToFirst()) {\n                int index = cursor.getColumnIndexOrThrow(column);\n                return cursor.getString(index);\n            }\n        } finally {\n            if (cursor != null)\n                cursor.close();\n        }\n        return null;\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is ExternalStorageProvider.\n     */\n    private static boolean isExternalStorageDocument(Uri uri) {\n        return \"com.android.externalstorage.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is DownloadsProvider.\n     */\n    private static boolean isDownloadsDocument(Uri uri) {\n        return \"com.android.providers.downloads.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is MediaProvider.\n     */\n    private static boolean isMediaDocument(Uri uri) {\n        return \"com.android.providers.media.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is Google Photos.\n     */\n    private static boolean isGooglePhotosUri(Uri uri) {\n        return \"com.google.android.apps.photos.content\".equals(uri.getAuthority());\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/LogUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.util.Log;\n\npublic class LogUtils {\n\n    public static void showLog(String log) {\n        showLog(\"DDD\", log);\n    }\n\n    public static void showLog(String tag, String log) {\n        Log.i(tag, log);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/NetUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\n\npublic class NetUtils {\n\n    private NetUtils() {\n        /* cannot be instantiated */\n        throw new UnsupportedOperationException(\"cannot be instantiated\");\n    }\n\n    /**\n     * 判断网络是否连接\n     */\n    public static boolean isConnected(Context context) {\n        ConnectivityManager cm = (ConnectivityManager)\n                context.getSystemService(Context.CONNECTIVITY_SERVICE);\n\n        if (null == cm) {\n            return false;\n        }\n\n        NetworkInfo info = cm.getActiveNetworkInfo();\n        if (null != info && info.isConnected()) {\n            if (info.getState() == NetworkInfo.State.CONNECTED) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 判断是否是wifi连接\n     */\n    public static boolean isWifi(Context context) {\n        ConnectivityManager cm = (ConnectivityManager)\n                context.getSystemService(Context.CONNECTIVITY_SERVICE);\n\n        if (null == cm) {\n            return false;\n        }\n\n        NetworkInfo info = cm.getActiveNetworkInfo();\n        if (null != info) {\n            if (info.getType() == ConnectivityManager.TYPE_WIFI) {\n                return true;\n            }\n        }\n        return false;\n\n    }\n\n    /**\n     * 打开网络设置界面\n     */\n    public static void openSetting(Activity activity, int requestCode) {\n        Intent intent = new Intent(\"/\");\n        ComponentName cm = new ComponentName(\"com.android.settings\",\n                \"com.android.settings.WirelessSettings\");\n        intent.setComponent(cm);\n        intent.setAction(Intent.ACTION_VIEW);\n        activity.startActivityForResult(intent, requestCode);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/StringUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.Context;\nimport android.text.TextPaint;\nimport android.text.style.ClickableSpan;\nimport android.view.View;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.text.DecimalFormat;\n\npublic class StringUtils {\n\n    public static boolean isEmpty(CharSequence str) {\n        return str == null || str.length() == 0;\n    }\n\n    public static String getMoney(float cost) {\n        DecimalFormat decimalFormat = new DecimalFormat(\"0.00\");\n        return \"￥\" + decimalFormat.format(cost);\n    }\n\n    public static class PrimaryClickableSpan extends ClickableSpan {\n\n        private Context context;\n\n        public PrimaryClickableSpan(Context context) {\n            this.context = context;\n        }\n\n        @Override\n        public void onClick(View widget) {\n            // do nothing\n        }\n\n        @Override\n        public void updateDrawState(TextPaint ds) {\n            ds.setColor(context.getResources().getColor(R.color.colorPrimary));\n            ds.setUnderlineText(false);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/TitleBuilder.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n/**\n * 标题栏构造器,使用方法 new TitleBuilder().setMethod().setMethod()......\n * <p/>\n * 统一格式为标题文字,左右各自是文字/图片按钮\n * 按钮都默认不显示,只有在你调用setLeftText时才会显示左侧按钮文字,图片同理\n * 图片或文字的点击事件都用Left/RightOnClickListener\n */\npublic class TitleBuilder {\n\n    private View rootView;\n    private TextView tvTitle;\n    private ImageView ivLeft;\n    private ImageView ivRight;\n    private TextView tvLeft;\n    private TextView tvRight;\n\n    public View getRootView() {\n        return rootView;\n    }\n\n    public TextView getTvTitle() {\n        return tvTitle;\n    }\n\n    public ImageView getIvLeft() {\n        return ivLeft;\n    }\n\n    public ImageView getIvRight() {\n        return ivRight;\n    }\n\n    public TextView getTvLeft() {\n        return tvLeft;\n    }\n\n    public TextView getTvRight() {\n        return tvRight;\n    }\n\n    /**\n     * Activity中使用这个构造方法\n     */\n    public TitleBuilder(Activity context) {\n        rootView = context.findViewById(R.id.rl_titlebar);\n        if (rootView == null) {\n            return;\n        }\n        tvTitle = (TextView) rootView.findViewById(R.id.titlebar_tv);\n        ivLeft = (ImageView) rootView.findViewById(R.id.titlebar_iv_left);\n        ivRight = (ImageView) rootView.findViewById(R.id.titlebar_iv_right);\n        tvLeft = (TextView) rootView.findViewById(R.id.titlebar_tv_left);\n        tvRight = (TextView) rootView.findViewById(R.id.titlebar_tv_right);\n    }\n\n    /**\n     * Fragment中使用这个构造方法\n     */\n    public TitleBuilder(View context) {\n        rootView = context.findViewById(R.id.rl_titlebar);\n        if (rootView == null) {\n            return;\n        }\n        tvTitle = (TextView) rootView.findViewById(R.id.titlebar_tv);\n        ivLeft = (ImageView) rootView.findViewById(R.id.titlebar_iv_left);\n        ivRight = (ImageView) rootView.findViewById(R.id.titlebar_iv_right);\n        tvLeft = (TextView) rootView.findViewById(R.id.titlebar_tv_left);\n        tvRight = (TextView) rootView.findViewById(R.id.titlebar_tv_right);\n    }\n\n    // title\n    public TitleBuilder setTitleBgRes(int resid) {\n        rootView.setBackgroundResource(resid);\n        return this;\n    }\n\n    public TitleBuilder setTitleText(String text) {\n        tvTitle.setVisibility(TextUtils.isEmpty(text) ? View.GONE\n                : View.VISIBLE);\n        tvTitle.setText(text);\n        return this;\n    }\n\n    // left\n    public TitleBuilder setLeftImage(int resId) {\n        ivLeft.setVisibility(resId > 0 ? View.VISIBLE : View.GONE);\n        ivLeft.setImageResource(resId);\n        return this;\n    }\n\n    public TitleBuilder setLeftText(String text) {\n        tvLeft.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);\n        tvLeft.setText(text);\n        return this;\n    }\n\n    public TitleBuilder setLeftOnClickListener(OnClickListener listener) {\n        if (ivLeft.getVisibility() == View.VISIBLE) {\n            ivLeft.setOnClickListener(listener);\n        } else if (tvLeft.getVisibility() == View.VISIBLE) {\n            tvLeft.setOnClickListener(listener);\n        }\n        return this;\n    }\n\n    // right\n    public TitleBuilder setRightImage(int resId) {\n        ivRight.setVisibility(resId > 0 ? View.VISIBLE : View.GONE);\n        ivRight.setImageResource(resId);\n        return this;\n    }\n\n    public TitleBuilder setRightText(String text) {\n        tvRight.setVisibility(TextUtils.isEmpty(text) ? View.GONE\n                : View.VISIBLE);\n        tvRight.setText(text);\n        return this;\n    }\n\n    public TitleBuilder setRightTextColor(Context context, int resId) {\n        tvRight.setTextColor(context.getResources().getColor(resId));\n        return this;\n    }\n\n    public TitleBuilder setTitleTextColor(Context context, int resId) {\n        tvTitle.setTextColor(context.getResources().getColor(resId));\n        return this;\n    }\n\n\n    public TitleBuilder setRightOnClickListener(OnClickListener listener) {\n        if (ivRight.getVisibility() == View.VISIBLE) {\n            ivRight.setOnClickListener(listener);\n        } else if (tvRight.getVisibility() == View.VISIBLE) {\n            tvRight.setOnClickListener(listener);\n        }\n        return this;\n    }\n\n    public View build() {\n        return rootView;\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ToastUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\npublic class ToastUtils {\n\n    private static Toast mToast;\n\n    /**\n     * 非阻塞试显示Toast,防止出现连续点击Toast时的显示问题\n     */\n    public static void showToast(Context context, CharSequence text, int duration) {\n        if (mToast == null) {\n            mToast = Toast.makeText(context, text, duration);\n        } else {\n            mToast.setText(text);\n            mToast.setDuration(duration);\n        }\n        mToast.show();\n    }\n\n    public static void showToast(Context context, CharSequence text) {\n        showToast(context, text, Toast.LENGTH_SHORT);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/utils/ViewUtils.java",
    "content": "package com.boredream.bdcodehelper.utils;\n\npublic class ViewUtils {\n\n//    public static void setIndicator(Context context, final int size,\n//                                    final ViewPager vp_banner, final RadioGroup rg_indicator) {\n//        // 无图片和只有一张时不要indicator\n//        if (size <= 1) {\n//            rg_indicator.setVisibility(View.GONE);\n//            return;\n//        }\n//        rg_indicator.setVisibility(View.VISIBLE);\n//\n//        vp_banner.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {\n//\n//            @Override\n//            public void onPageSelected(int position) {\n//                // ViewPager和RadioGroup联动\n//                if (rg_indicator.getChildCount() > 1) {\n//                    ((RadioButton) rg_indicator.getChildAt(position % size)).setChecked(true);\n//                }\n//            }\n//        });\n//\n//        // 根据图片数量添加RadioButton\n//        rg_indicator.removeAllViews();\n//        for (int i = 0; i < size; i++) {\n//            RadioButton rb = new RadioButton(context);\n//            // TODO 圆形大小\n//            RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(\n//                    DisplayUtils.dp2px(context, 8), DisplayUtils.dp2px(context, 8));\n//            if (i > 0) {\n//                params.setMargins(DisplayUtils.dp2px(context, 8), 0, 0, 0);\n//            }\n//            rb.setLayoutParams(params);\n//            rb.setButtonDrawable(new ColorDrawable());\n//            rb.setBackgroundResource(R.drawable.shape_oval_yellow_stroke2solid_sel);\n//            rb.setOnTouchListener(new View.OnTouchListener() {\n//                @Override\n//                public boolean onTouch(View view, MotionEvent motionEvent) {\n//                    // 圆不可点击选择\n//                    return true;\n//                }\n//            });\n//            rg_indicator.addView(rb);\n//        }\n//\n//        // 默认选中第一个\n//        if (rg_indicator.getChildCount() > 0) {\n//            ((RadioButton) rg_indicator.getChildAt(0)).setChecked(true);\n//        }\n//    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/AddressWheelDialog.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.view.View;\nimport android.widget.Button;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.db.AddressData;\nimport com.boredream.bdcodehelper.entity.city.CityModel;\nimport com.boredream.bdcodehelper.view.wheel.OnWheelChangedListener;\nimport com.boredream.bdcodehelper.view.wheel.WheelView;\nimport com.boredream.bdcodehelper.view.wheel.adapters.ArrayWheelAdapter;\n\nimport java.util.ArrayList;\n\npublic class AddressWheelDialog extends Dialog implements OnWheelChangedListener {\n\n    private String mCurrentProvice;\n    private CityModel mCurrentCity;\n\n    private WheelView mViewProvince;\n    private WheelView mViewCity;\n    private Button mBtnConfirm;\n\n    public AddressWheelDialog(Context context) {\n        super(context);\n\n        initViews();\n        initData();\n    }\n\n    private void initViews() {\n        setContentView(R.layout.wheel_dialog_address);\n\n        mViewProvince = (WheelView) findViewById(R.id.id_province);\n        mViewCity = (WheelView) findViewById(R.id.id_city);\n        mBtnConfirm = (Button) findViewById(R.id.btn_confirm);\n\n        mViewProvince.addChangingListener(this);\n        mViewCity.addChangingListener(this);\n        mBtnConfirm.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                if(onAddressSelectListener != null) {\n                    CityModel address = new CityModel();\n                    onAddressSelectListener.onAddressSelected(address);\n                }\n            }\n        });\n    }\n\n    private void initData() {\n        mViewProvince.setViewAdapter(new ArrayWheelAdapter<>(getContext(), AddressData.mProvinceDatas));\n        mViewProvince.setVisibleItems(7);\n        mViewCity.setVisibleItems(7);\n        updateCities();\n    }\n\n    @Override\n    public void onChanged(WheelView wheel, int oldValue, int newValue) {\n        if (wheel == mViewProvince) {\n            updateCities();\n        }\n    }\n\n    private void updateCities() {\n        int pCurrent = mViewProvince.getCurrentItem();\n        mCurrentProvice = AddressData.mProvinceDatas.get(pCurrent);\n        ArrayList<CityModel> cities = AddressData.mCitisDatasMap.get(mCurrentProvice);\n        if (cities == null) {\n            cities = new ArrayList<>();\n        }\n        mViewCity.setViewAdapter(new ArrayWheelAdapter<>(getContext(), cities));\n        mViewCity.setCurrentItem(0);\n    }\n\n    private OnAddressSelectListener onAddressSelectListener;\n\n    public void setOnAddressSelectListener(OnAddressSelectListener onAddressSelectListener) {\n        this.onAddressSelectListener = onAddressSelectListener;\n    }\n\n    public interface OnAddressSelectListener {\n        void onAddressSelected(CityModel address);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/BottomTabRadioButton.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.os.Build;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.widget.RadioButton;\n\nimport com.boredream.bdcodehelper.R;\n\npublic class BottomTabRadioButton extends RadioButton {\n\n    /**\n     * 提示模式 - 无提示\n     */\n    private static final int MODE_NONE = 0;\n\n    /**\n     * 提示模式 - 红点提示\n     */\n    private static final int MODE_POINT = 1;\n\n    /**\n     * 提示模式 - 数字提示\n     */\n    private static final int MODE_NUM = 2;\n\n    /**\n     * 默认红点默认半径\n     */\n    private static final float DEFAULT_POINT_RADIUS = 4; //dp\n\n    /**\n     * 默认数字圆圈半径\n     */\n    private static final float DEFAULT_NUM_RADIUS = 8; //dp\n\n    /**\n     * 默认数字文字大小\n     */\n    private static final float DEFAULT_NUM_SIZE = 10; //sp\n\n    private Paint hintPaint;\n    private Paint textPaint;\n    private Rect textRect = new Rect();\n\n    /**\n     * 提示模式\n     */\n    private int hint_mode;\n\n    /**\n     * 圆填充色\n     */\n    private int hint_color;\n\n    /**\n     * 据顶部距离\n     */\n    private int hint_toppadding;\n\n    /**\n     * 据右侧距离\n     */\n    private int hint_rightpadding;\n\n    /**\n     * 圆点半径\n     */\n    private int point_radius;\n\n    /**\n     * 数字\n     */\n    private int num;\n\n    /**\n     * 数字圆圈半径\n     */\n    private int num_radius;\n\n    /**\n     * 数字文字大小\n     */\n    private int num_size;\n\n    /**\n     * 数字文字颜色\n     */\n    private int num_color;\n\n    public int getHint_mode() {\n        return hint_mode;\n    }\n\n    public void setHint_mode(int hint_mode) {\n        this.hint_mode = hint_mode;\n        invalidate();\n    }\n\n    public int getHint_color() {\n        return hint_color;\n    }\n\n    public void setHint_color(int hint_color) {\n        this.hint_color = hint_color;\n        invalidate();\n    }\n\n    public int getHint_toppadding() {\n        return hint_toppadding;\n    }\n\n    public void setHint_toppadding(int hint_toppadding) {\n        this.hint_toppadding = hint_toppadding;\n        invalidate();\n    }\n\n    public int getHint_rightpadding() {\n        return hint_rightpadding;\n    }\n\n    public void setHint_rightpadding(int hint_rightpadding) {\n        this.hint_rightpadding = hint_rightpadding;\n        invalidate();\n    }\n\n    public int getPoint_radius() {\n        return point_radius;\n    }\n\n    public void setPoint_radius(int point_radius) {\n        this.point_radius = point_radius;\n        invalidate();\n    }\n\n    public int getNum() {\n        return num;\n    }\n\n    public void setNum(int num) {\n        this.num = num;\n        invalidate();\n    }\n\n    public int getNum_radius() {\n        return num_radius;\n    }\n\n    public void setNum_radius(int num_radius) {\n        this.num_radius = num_radius;\n        invalidate();\n    }\n\n    public int getNum_size() {\n        return num_size;\n    }\n\n    public void setNum_size(int num_size) {\n        this.num_size = num_size;\n        invalidate();\n    }\n\n    public int getNum_color() {\n        return num_color;\n    }\n\n    public void setNum_color(int num_color) {\n        this.num_color = num_color;\n        invalidate();\n    }\n\n    public BottomTabRadioButton(Context context) {\n        super(context);\n    }\n\n    public BottomTabRadioButton(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView(attrs);\n    }\n\n    public BottomTabRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView(attrs);\n    }\n\n    @TargetApi(Build.VERSION_CODES.LOLLIPOP)\n    public BottomTabRadioButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        initView(attrs);\n    }\n\n    private void initView(AttributeSet attrs) {\n        Context context = getContext();\n        DisplayMetrics metrics = context.getResources().getDisplayMetrics();\n\n        // 根据attrs获取属性\n        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BottomTabRadioButton);\n\n        hint_mode = ta.getInt(R.styleable.BottomTabRadioButton_hint_mode,\n                MODE_NONE);\n        hint_color = ta.getColor(R.styleable.BottomTabRadioButton_hint_color,\n                Color.RED);\n\n        hint_toppadding = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_hint_toppadding,\n                0);\n        hint_rightpadding = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_hint_rightpadding,\n                0);\n\n        float defaultPointRadius = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_POINT_RADIUS, metrics);\n        point_radius = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_point_radius,\n                (int) (defaultPointRadius + 0.5f));\n\n        num = ta.getInt(R.styleable.BottomTabRadioButton_num,\n                -1);\n        float defaultNumRadius = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_DIP, DEFAULT_NUM_RADIUS, metrics);\n        num_radius = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_radius,\n                (int) (defaultNumRadius + 0.5f));\n        float defaultNumSize = TypedValue.applyDimension(\n                TypedValue.COMPLEX_UNIT_SP, DEFAULT_NUM_SIZE, metrics);\n        num_size = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_size,\n                (int) (defaultNumSize + 0.5f));\n        num_color = ta.getDimensionPixelSize(R.styleable.BottomTabRadioButton_num_color,\n                Color.WHITE);\n\n        ta.recycle();\n\n        // 初始化背景圆画笔\n        hintPaint = new Paint();\n        hintPaint.setAntiAlias(true);\n        hintPaint.setStyle(Paint.Style.FILL);\n        hintPaint.setColor(hint_color);\n\n        // 初始化数字文字画笔\n        textPaint = new Paint();\n        textPaint.setAntiAlias(true);\n        textPaint.setColor(num_color);\n        textPaint.setTextSize(num_size);\n        textPaint.setFakeBoldText(true);\n        textPaint.setTextAlign(Paint.Align.CENTER);\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        if (hint_mode == MODE_POINT) { // 如果是圆点模式\n            // 直接画一个圆点\n            float width = getWidth();\n            float centerX = width - hint_rightpadding - point_radius;\n            float centerY = hint_toppadding + point_radius;\n\n            canvas.drawCircle(centerX, centerY, point_radius, hintPaint);\n        } else if (hint_mode == MODE_NUM) { // 如果是数字模式\n            // 1.画一个背景圆\n            float width = getWidth();\n            float centerX = width - hint_rightpadding - num_radius;\n            float centerY = hint_toppadding + num_radius;\n\n            canvas.drawCircle(centerX, centerY, num_radius, hintPaint);\n\n            // 2.画数字\n            if (num >= 0) {\n                String numStr = String.valueOf(num);\n\n                if (num >= 100) {\n                    // 如果超过100使用\"...\"\n                    numStr = \"...\";\n                }\n                textPaint.getTextBounds(numStr, 0, numStr.length(), textRect);\n                float textCenterY = centerY + textRect.bottom - textRect.top / 2;\n                canvas.drawText(numStr, centerX, textCenterY, textPaint);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/CheckableLinearLayout.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.Checkable;\nimport android.widget.LinearLayout;\n\n/**\n * This is a simple wrapper for {@link LinearLayout} that implements the {@link Checkable}\n * interface by keeping an internal 'checked' state flag.\n * <p>\n * This can be used as the root view for a custom list item layout for\n * {@link android.widget.AbsListView} elements with a\n * {@link android.widget.AbsListView#setChoiceMode(int) choiceMode} set.\n */\npublic class CheckableLinearLayout extends LinearLayout implements Checkable {\n    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};\n\n    private boolean mChecked = false;\n\n    public CheckableLinearLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public boolean isChecked() {\n        return mChecked;\n    }\n\n    public void setChecked(boolean b) {\n        if (b != mChecked) {\n            mChecked = b;\n            refreshDrawableState();\n        }\n    }\n\n    public void toggle() {\n        setChecked(!mChecked);\n    }\n\n    @Override\n    public int[] onCreateDrawableState(int extraSpace) {\n        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);\n        if (isChecked()) {\n            mergeDrawableStates(drawableState, CHECKED_STATE_SET);\n        }\n        return drawableState;\n    }\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DividerItemDecoration.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class DividerItemDecoration extends RecyclerView.ItemDecoration {\n\n    private static final int[] ATTRS = new int[]{\n            android.R.attr.listDivider\n    };\n\n    private List<Integer> ignorePositionList;\n\n    private Drawable mDivider;\n\n    public DividerItemDecoration(Context context) {\n        final TypedArray a = context.obtainStyledAttributes(ATTRS);\n        mDivider = a.getDrawable(0);\n        a.recycle();\n    }\n\n    /**\n     * 忽略分割线的position,即该位置不添加\n     */\n    public void setIgnorePositions(Integer[] ignorePositions) {\n        ignorePositionList = Arrays.asList(ignorePositions);\n    }\n\n    @Override\n    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {\n        drawVertical(c, parent);\n    }\n\n    public void drawVertical(Canvas c, RecyclerView parent) {\n        final int left = parent.getPaddingLeft();\n        final int right = parent.getWidth() - parent.getPaddingRight();\n\n        final int childCount = parent.getChildCount();\n        for (int i = 0; i < childCount; i++) {\n            if (ignorePositionList != null && ignorePositionList.contains(i)) {\n                continue;\n            }\n\n            final View child = parent.getChildAt(i);\n            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child\n                    .getLayoutParams();\n            final int top = child.getBottom() + params.bottomMargin +\n                    Math.round(ViewCompat.getTranslationY(child));\n//            final int bottom = top + mDivider.getIntrinsicHeight();\n            final int bottom = top + 1;\n            mDivider.setBounds(left, top, right, bottom);\n            mDivider.draw(c);\n        }\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n//        outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());\n        outRect.set(0, 0, 0, 1);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DrawableRadioButton.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.widget.RadioButton;\n\nimport com.boredream.bdcodehelper.R;\n\n\npublic class DrawableRadioButton extends RadioButton {\n\n    private int widthPx;\n    private int heightPx;\n\n    public DrawableRadioButton(Context context) {\n        super(context);\n    }\n\n    public DrawableRadioButton(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        initView(context, attrs);\n    }\n\n    public DrawableRadioButton(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        initView(context, attrs);\n    }\n\n    private void initView(Context context, AttributeSet attrs) {\n        TypedArray ta = context.obtainStyledAttributes(attrs,\n                R.styleable.DrawableTextView);\n\n        widthPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableWidth, -1);\n        heightPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableHeight, -1);\n\n        // 左右上下四个图片\n        Drawable[] drawables = getCompoundDrawables();\n\n        setDrawables(drawables);\n\n        ta.recycle();\n    }\n\n    /**\n     * 左上右下四个图片,只会取一个方向图片使用\n     */\n    public void setDrawables(Drawable[] drawables) {\n        // 左右上下四个图片\n        Drawable drawable = null;\n        // 如果其中一个方向有图片,获取之\n        for (int i = 0; i < drawables.length; i++) {\n            if (drawables[i] != null) {\n                drawable = drawables[i];\n                break;\n            }\n        }\n\n        // 设置宽高\n        if (drawable != null && widthPx != -1 && heightPx != -1) {\n            drawable.setBounds(0, 0, widthPx, heightPx);\n        }\n\n        // 将图片放回到TextView中\n        setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DrawableTextView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n\npublic class DrawableTextView extends TextView {\n\n    private final int widthPx;\n    private final int heightPx;\n\n    public DrawableTextView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        TypedArray ta = context.obtainStyledAttributes(attrs,\n                R.styleable.DrawableTextView);\n\n        widthPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableWidth, -1);\n        heightPx = ta.getDimensionPixelSize(\n                R.styleable.DrawableTextView_drawableHeight, -1);\n\n        // 左右上下四个图片\n        Drawable[] drawables = getCompoundDrawables();\n\n        setDrawables(drawables);\n\n        ta.recycle();\n    }\n\n    /**\n     * 左上右下四个图片,只会取一个方向图片使用\n     */\n    public void setDrawables(Drawable[] drawables) {\n        // 左右上下四个图片\n        Drawable drawable = null;\n        // 如果其中一个方向有图片,获取之\n        for (int i = 0; i < drawables.length; i++) {\n            if (drawables[i] != null) {\n                drawable = drawables[i];\n                break;\n            }\n        }\n\n        // 设置宽高\n        if (drawable != null && widthPx != -1 && heightPx != -1) {\n            drawable.setBounds(0, 0, widthPx, heightPx);\n        }\n\n        // 将图片放回到TextView中\n        setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);\n    }\n\n    public DrawableTextView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public DrawableTextView(Context context) {\n        this(context, null);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/DropDownMenu.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.animation.AnimationUtils;\nimport android.widget.FrameLayout;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\nimport java.util.List;\n\npublic class DropDownMenu extends LinearLayout {\n\n    //顶部菜单布局\n    private LinearLayout tabMenuView;\n    //底部容器，包含popupMenuViews，maskView\n    private FrameLayout containerView;\n    //弹出菜单父布局\n    private FrameLayout popupMenuViews;\n    //遮罩半透明View，点击可关闭DropDownMenu\n    private View maskView;\n    //tabMenuView里面选中的tab位置，-1表示未选中\n    private int current_tab_position = -1;\n\n    //分割线颜色\n    private int dividerColor = getResources().getColor(R.color.divider_gray);\n    //tab选中颜色\n    private int textSelectedColor = getResources().getColor(R.color.colorPrimary);\n    //tab未选中颜色\n    private int textUnselectedColor = getResources().getColor(R.color.txt_black);\n    //遮罩颜色\n    private int maskColor = 0x88888888;\n    //tab字体大小\n    private int menuTextSize = 12;\n\n    //tab选中图标\n    private int menuSelectedIcon;\n    //tab未选中图标\n    private int menuUnselectedIcon;\n\n\n    public DropDownMenu(Context context) {\n        super(context, null);\n    }\n\n    public DropDownMenu(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    @TargetApi(Build.VERSION_CODES.HONEYCOMB)\n    public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        setOrientation(VERTICAL);\n\n        //为DropDownMenu添加自定义属性\n        int menuBackgroundColor = 0xffffffff;\n        int underlineColor = 0xffcccccc;\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DropDownMenu);\n        underlineColor = a.getColor(R.styleable.DropDownMenu_ddunderlineColor, underlineColor);\n        dividerColor = a.getColor(R.styleable.DropDownMenu_dddividerColor, dividerColor);\n        textSelectedColor = a.getColor(R.styleable.DropDownMenu_ddtextSelectedColor, textSelectedColor);\n        textUnselectedColor = a.getColor(R.styleable.DropDownMenu_ddtextUnselectedColor, textUnselectedColor);\n        menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_ddmenuBackgroundColor, menuBackgroundColor);\n        maskColor = a.getColor(R.styleable.DropDownMenu_ddmaskColor, maskColor);\n        menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_ddmenuTextSize, menuTextSize);\n        menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuSelectedIcon, menuSelectedIcon);\n        menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuUnselectedIcon, menuUnselectedIcon);\n        a.recycle();\n\n        //初始化tabMenuView并添加到tabMenuView\n        tabMenuView = new LinearLayout(context);\n        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n        tabMenuView.setOrientation(HORIZONTAL);\n        tabMenuView.setBackgroundColor(menuBackgroundColor);\n        tabMenuView.setLayoutParams(params);\n        addView(tabMenuView, 0);\n\n        //为tabMenuView添加下划线\n        View underLine = new View(getContext());\n        underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpTpPx(1.0f)));\n        underLine.setBackgroundColor(underlineColor);\n        addView(underLine, 1);\n\n        //初始化containerView并将其添加到DropDownMenu\n        containerView = new FrameLayout(context);\n        containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));\n        addView(containerView, 2);\n\n    }\n\n    /**\n     * 初始化DropDownMenu\n     *\n     * @param tabTexts\n     * @param popupViews\n     * @param contentView\n     */\n    public void setDropDownMenu(List<String> tabTexts, List<View> popupViews, View contentView) {\n        if (tabTexts.size() != popupViews.size()) {\n            throw new IllegalArgumentException(\"params not match, tabTexts.size() should be equal popupViews.size()\");\n        }\n\n        for (int i = 0; i < tabTexts.size(); i++) {\n            addTab(tabTexts, i);\n        }\n\n        containerView.addView(contentView, 0);\n\n        maskView = new View(getContext());\n        maskView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));\n        maskView.setBackgroundColor(maskColor);\n        maskView.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                closeMenu();\n            }\n        });\n        containerView.addView(maskView, 1);\n        maskView.setVisibility(GONE);\n\n        popupMenuViews = new FrameLayout(getContext());\n        popupMenuViews.setVisibility(GONE);\n        containerView.addView(popupMenuViews, 2);\n\n        for (int i = 0; i < popupViews.size(); i++) {\n            popupViews.get(i).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n            popupMenuViews.addView(popupViews.get(i), i);\n        }\n\n    }\n\n    private void addTab(List<String> tabTexts, int i) {\n        final TextView tab = new TextView(getContext());\n        tab.setSingleLine();\n        tab.setEllipsize(TextUtils.TruncateAt.END);\n        tab.setGravity(Gravity.CENTER);\n        tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, menuTextSize);\n        tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));\n        tab.setTextColor(textUnselectedColor);\n        tab.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(menuUnselectedIcon), null);\n        tab.setText(tabTexts.get(i));\n        tab.setPadding(dpTpPx(48), dpTpPx(8), dpTpPx(48), dpTpPx(8));\n        //添加点击事件\n        tab.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                switchMenu(tab);\n            }\n        });\n        tabMenuView.addView(tab);\n        //添加分割线\n        if (i < tabTexts.size() - 1) {\n            View view = new View(getContext());\n            LayoutParams params = new LayoutParams(\n                    dpTpPx(0.5f), ViewGroup.LayoutParams.MATCH_PARENT);\n            params.setMargins(0, dpTpPx(4), 0, dpTpPx(4));\n            view.setLayoutParams(params);\n            view.setBackgroundColor(dividerColor);\n            tabMenuView.addView(view);\n        }\n    }\n\n    /**\n     * 改变tab文字\n     *\n     * @param text\n     */\n    public void setTabText(String text) {\n        if (current_tab_position != -1) {\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setText(text);\n        }\n    }\n\n    public void setTabClickable(boolean clickable) {\n        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {\n            tabMenuView.getChildAt(i).setClickable(clickable);\n        }\n    }\n\n    /**\n     * 关闭菜单\n     */\n    public void closeMenu() {\n        if (current_tab_position != -1) {\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setTextColor(textUnselectedColor);\n            ((TextView) tabMenuView.getChildAt(current_tab_position)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                    getResources().getDrawable(menuUnselectedIcon), null);\n            popupMenuViews.setVisibility(View.GONE);\n            popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_out));\n            maskView.setVisibility(GONE);\n            maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_out));\n            current_tab_position = -1;\n        }\n\n    }\n\n    /**\n     * DropDownMenu是否处于可见状态\n     *\n     * @return\n     */\n    public boolean isShowing() {\n        return current_tab_position != -1;\n    }\n\n    /**\n     * 切换菜单\n     *\n     * @param target\n     */\n    private void switchMenu(View target) {\n        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {\n            if (target == tabMenuView.getChildAt(i)) {\n                if (current_tab_position == i) {\n                    closeMenu();\n                } else {\n                    if (current_tab_position == -1) {\n                        popupMenuViews.setVisibility(View.VISIBLE);\n                        popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_in));\n                        maskView.setVisibility(VISIBLE);\n                        maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_in));\n                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);\n                    } else {\n                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);\n                    }\n                    current_tab_position = i;\n                    ((TextView) tabMenuView.getChildAt(i)).setTextColor(textSelectedColor);\n                    ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                            getResources().getDrawable(menuSelectedIcon), null);\n                }\n            } else {\n                ((TextView) tabMenuView.getChildAt(i)).setTextColor(textUnselectedColor);\n                ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,\n                        getResources().getDrawable(menuUnselectedIcon), null);\n                popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);\n            }\n        }\n    }\n\n    public int dpTpPx(float value) {\n        DisplayMetrics dm = getResources().getDisplayMetrics();\n        return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm) + 0.5);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/EmptyItemDecoration.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.graphics.Rect;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npublic class EmptyItemDecoration extends RecyclerView.ItemDecoration {\n\n    /**\n     * decoration添加的位置,为空时所有item都添加\n     */\n    private List<Integer> dividerPositionList;\n    private int height;\n\n    public EmptyItemDecoration(int height) {\n        this.height = height;\n    }\n\n    public EmptyItemDecoration(Integer[] dividerPositions, int height) {\n        this.dividerPositionList = Arrays.asList(dividerPositions);\n        this.height = height;\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n        int position = parent.getChildAdapterPosition(view);\n        if (dividerPositionList == null || dividerPositionList.contains(position)) {\n            outRect.set(0, 0, 0, height);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/GridSpacingDecorator.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.graphics.Rect;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\n\npublic class GridSpacingDecorator extends RecyclerView.ItemDecoration {\n\n    private int space;\n\n    public GridSpacingDecorator(int space) {\n        this.space = space;\n    }\n\n    @Override\n    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {\n        outRect.left = space / 2;\n        outRect.right = space / 2;\n        outRect.bottom = space;\n        if (parent.getChildAdapterPosition(view) <= 1) {\n            outRect.top = space;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/PinnedSectionListView.java",
    "content": "package com.boredream.bdcodehelper.view;\n/*\n * Copyright (C) 2013 Sergej Shafarenka, halfbit.de\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file kt in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.content.Context;\nimport android.database.DataSetObserver;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.PointF;\nimport android.graphics.Rect;\nimport android.graphics.drawable.GradientDrawable;\nimport android.graphics.drawable.GradientDrawable.Orientation;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.SoundEffectConstants;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.widget.AbsListView;\nimport android.widget.HeaderViewListAdapter;\nimport android.widget.ListAdapter;\nimport android.widget.ListView;\nimport android.widget.SectionIndexer;\n\nimport com.boredream.bdcodehelper.BuildConfig;\n\n/**\n * ListView, which is capable to pin section views at its top while the rest is still scrolled.\n */\npublic class PinnedSectionListView extends ListView {\n\n\n    //-- inner classes\n\n\t/** List adapter to be implemented for being used with PinnedSectionListView adapter. */\n\tpublic static interface PinnedSectionListAdapter extends ListAdapter {\n\t\t/** This method shall return 'true' if views of given type has to be pinned. */\n\t\tboolean isItemViewTypePinned(int viewType);\n\t}\n\n\t/** Wrapper class for pinned section view and its position in the list. */\n\tstatic class PinnedSection {\n\t\tpublic View view;\n\t\tpublic int position;\n\t\tpublic long id;\n\t}\n\n\t//-- class fields\n\n    // fields used for handling touch events\n    private final Rect mTouchRect = new Rect();\n    private final PointF mTouchPoint = new PointF();\n    private int mTouchSlop;\n    private View mTouchTarget;\n    private MotionEvent mDownEvent;\n\n    // fields used for drawing shadow under a pinned section\n    private GradientDrawable mShadowDrawable;\n    private int mSectionsDistanceY;\n    private int mShadowHeight;\n\n    /** Delegating listener, can be null. */\n    OnScrollListener mDelegateOnScrollListener;\n\n    /** Shadow for being recycled, can be null. */\n    PinnedSection mRecycleSection;\n\n    /** shadow instance with a pinned view, can be null. */\n    PinnedSection mPinnedSection;\n\n    /** Pinned view Y-translation. We use it to stick pinned view to the next section. */\n    int mTranslateY;\n\n\t/** Scroll listener which does the magic */\n\tprivate final OnScrollListener mOnScrollListener = new OnScrollListener() {\n\n\t\t// boredream-view which need to hide\n\t\tprivate View hideView;\n\n\t\t@Override public void onScrollStateChanged(AbsListView view, int scrollState) {\n\t\t\tif (mDelegateOnScrollListener != null) { // delegate\n\t\t\t\tmDelegateOnScrollListener.onScrollStateChanged(view, scrollState);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {\n\n            if (mDelegateOnScrollListener != null) { // delegate\n                mDelegateOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);\n            }\n\n            // get expected adapter or fail fast\n            ListAdapter adapter = getAdapter();\n            if (adapter == null || visibleItemCount == 0) return; // nothing to do\n\n            final boolean isFirstVisibleItemSection =\n                    isItemViewTypePinned(adapter, adapter.getItemViewType(firstVisibleItem));\n\n            if (isFirstVisibleItemSection) {\n                View sectionView = getChildAt(0);\n                if (sectionView.getTop() == getPaddingTop()) { // view sticks to the top, no need for pinned shadow\n                    destroyPinnedShadow();\n                \t// boredream-re show pinned item of list\n                \tif(hideView != null && hideView.getVisibility() == View.INVISIBLE) {\n                \t\thideView.setVisibility(View.VISIBLE);\n                \t}\n                } else { // section doesn't stick to the top, make sure we have a pinned shadow\n                    ensureShadowForPosition(firstVisibleItem, firstVisibleItem, visibleItemCount);\n                    \n                    // boredream-hide pinned item of list\n                    if(mPinnedSection != null\n                    \t\t&& firstVisibleItem == mPinnedSection.position\n                    \t\t&& sectionView.getTop() < 0) {\n                    \thideView = sectionView;\n                    \tsectionView.setVisibility(View.INVISIBLE);\n                    }\n                }\n            } else { // section is not at the first visible position\n            \t// boredream-re show pinned item of list\n            \tif(hideView != null && hideView.getVisibility() == View.INVISIBLE) {\n            \t\thideView.setVisibility(View.VISIBLE);\n            \t}\n            \t\n                int sectionPosition = findCurrentSectionPosition(firstVisibleItem);\n                if (sectionPosition > -1) { // we have section position\n                    ensureShadowForPosition(sectionPosition, firstVisibleItem, visibleItemCount);\n                } else { // there is no section for the first visible item, destroy shadow\n                    destroyPinnedShadow();\n                }\n            }\n\t\t};\n\n\t};\n\n\t/** Default change observer. */\n    private final DataSetObserver mDataSetObserver = new DataSetObserver() {\n        @Override public void onChanged() {\n            recreatePinnedShadow();\n        };\n        @Override public void onInvalidated() {\n            recreatePinnedShadow();\n        }\n    };\n\n\t//-- constructors\n\n    public PinnedSectionListView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView();\n    }\n\n    public PinnedSectionListView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        initView();\n    }\n\n    private void initView() {\n        setOnScrollListener(mOnScrollListener);\n        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();\n        initShadow(true);\n    }\n\n    //-- public API methods\n\n    public void setShadowVisible(boolean visible) {\n        initShadow(visible);\n        if (mPinnedSection != null) {\n            View v = mPinnedSection.view;\n            invalidate(v.getLeft(), v.getTop(), v.getRight(), v.getBottom() + mShadowHeight);\n        }\n    }\n\n    //-- pinned section drawing methods\n\n    public void initShadow(boolean visible) {\n        if (visible) {\n            if (mShadowDrawable == null) {\n                mShadowDrawable = new GradientDrawable(Orientation.TOP_BOTTOM,\n                        new int[] { Color.parseColor(\"#ffa0a0a0\"), Color.parseColor(\"#50a0a0a0\"), Color.parseColor(\"#00a0a0a0\")});\n                mShadowHeight = (int) (8 * getResources().getDisplayMetrics().density);\n            }\n        } else {\n            if (mShadowDrawable != null) {\n                mShadowDrawable = null;\n                mShadowHeight = 0;\n            }\n        }\n    }\n\n\t/** Create shadow wrapper with a pinned view for a view at given position */\n\tvoid createPinnedShadow(int position) {\n\n\t\t// try to recycle shadow\n\t\tPinnedSection pinnedShadow = mRecycleSection;\n\t\tmRecycleSection = null;\n\n\t\t// create new shadow, if needed\n\t\tif (pinnedShadow == null) pinnedShadow = new PinnedSection();\n\t\t// request new view using recycled view, if such\n\t\tView pinnedView = getAdapter().getView(position, pinnedShadow.view, PinnedSectionListView.this);\n\n\t\t// read layout parameters\n\t\tLayoutParams layoutParams = (LayoutParams) pinnedView.getLayoutParams();\n\t\tif (layoutParams == null) {\n//\t\t    layoutParams = (LayoutParams) generateDefaultLayoutParams();\n\t\t\t// boredream-fix bug\n\t\t\tlayoutParams = (LayoutParams) new LayoutParams(\n\t                LayoutParams.MATCH_PARENT,\n\t                LayoutParams.WRAP_CONTENT, 0);\n\t\t    pinnedView.setLayoutParams(layoutParams);\n\t\t}\n\n\t\tint heightMode = MeasureSpec.getMode(layoutParams.height);\n\t\tint heightSize = MeasureSpec.getSize(layoutParams.height);\n\n\t\tif (heightMode == MeasureSpec.UNSPECIFIED) heightMode = MeasureSpec.EXACTLY;\n\n\t\tint maxHeight = getHeight() - getListPaddingTop() - getListPaddingBottom();\n\t\tif (heightSize > maxHeight) heightSize = maxHeight;\n\n\t\t// measure & layout\n\t\tint ws = MeasureSpec.makeMeasureSpec(getWidth() - getListPaddingLeft() - getListPaddingRight(), MeasureSpec.EXACTLY);\n\t\tint hs = MeasureSpec.makeMeasureSpec(heightSize, heightMode);\n\t\tpinnedView.measure(ws, hs);\n\t\tpinnedView.layout(0, 0, pinnedView.getMeasuredWidth(), pinnedView.getMeasuredHeight());\n\t\tmTranslateY = 0;\n\n\t\t// initialize pinned shadow\n\t\tpinnedShadow.view = pinnedView;\n\t\tpinnedShadow.position = position;\n\t\tpinnedShadow.id = getAdapter().getItemId(position);\n\n\t\t// store pinned shadow\n\t\tmPinnedSection = pinnedShadow;\n\t}\n\n\t/** Destroy shadow wrapper for currently pinned view */\n\tvoid destroyPinnedShadow() {\n\t    if (mPinnedSection != null) {\n\t        // keep shadow for being recycled later\n\t        mRecycleSection = mPinnedSection;\n\t        mPinnedSection = null;\n\t    }\n\t}\n\n\t/** Makes sure we have an actual pinned shadow for given position. */\n    void ensureShadowForPosition(int sectionPosition, int firstVisibleItem, int visibleItemCount) {\n        if (visibleItemCount < 2) { // no need for creating shadow at all, we have a single visible item\n            destroyPinnedShadow();\n            return;\n        }\n\n        if (mPinnedSection != null\n                && mPinnedSection.position != sectionPosition) { // invalidate shadow, if required\n            destroyPinnedShadow();\n        }\n\n        if (mPinnedSection == null) { // create shadow, if empty\n            createPinnedShadow(sectionPosition);\n        }\n\n        // align shadow according to next section position, if needed\n        int nextPosition = sectionPosition + 1;\n        if (nextPosition < getCount()) {\n            int nextSectionPosition = findFirstVisibleSectionPosition(nextPosition,\n                    visibleItemCount - (nextPosition - firstVisibleItem));\n            if (nextSectionPosition > -1) {\n                View nextSectionView = getChildAt(nextSectionPosition - firstVisibleItem);\n                final int bottom = mPinnedSection.view.getBottom() + getPaddingTop();\n                mSectionsDistanceY = nextSectionView.getTop() - bottom;\n                if (mSectionsDistanceY < 0) {\n                    // next section overlaps pinned shadow, move it up\n                    mTranslateY = mSectionsDistanceY;\n                } else {\n                    // next section does not overlap with pinned, stick to top\n                    mTranslateY = 0;\n                }\n            } else {\n                // no other sections are visible, stick to top\n                mTranslateY = 0;\n                mSectionsDistanceY = Integer.MAX_VALUE;\n            }\n        }\n\n    }\n\n\tint findFirstVisibleSectionPosition(int firstVisibleItem, int visibleItemCount) {\n\t\tListAdapter adapter = getAdapter();\n\n        int adapterDataCount = adapter.getCount();\n        if (getLastVisiblePosition() >= adapterDataCount) return -1; // dataset has changed, no candidate\n\n        if (firstVisibleItem+visibleItemCount >= adapterDataCount){//added to prevent index Outofbound (in case)\n            visibleItemCount = adapterDataCount-firstVisibleItem;\n        }\n\n\t\tfor (int childIndex = 0; childIndex < visibleItemCount; childIndex++) {\n\t\t\tint position = firstVisibleItem + childIndex;\n\t\t\tint viewType = adapter.getItemViewType(position);\n\t\t\tif (isItemViewTypePinned(adapter, viewType)) return position;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tint findCurrentSectionPosition(int fromPosition) {\n\t\tListAdapter adapter = getAdapter();\n\n\t\tif (fromPosition >= adapter.getCount()) return -1; // dataset has changed, no candidate\n\t\t\n\t\tif (adapter instanceof SectionIndexer) {\n\t\t\t// try fast way by asking section indexer\n\t\t\tSectionIndexer indexer = (SectionIndexer) adapter;\n\t\t\tint sectionPosition = indexer.getSectionForPosition(fromPosition);\n\t\t\tint itemPosition = indexer.getPositionForSection(sectionPosition);\n\t\t\tint typeView = adapter.getItemViewType(itemPosition);\n\t\t\tif (isItemViewTypePinned(adapter, typeView)) {\n\t\t\t\treturn itemPosition;\n\t\t\t} // else, no luck\n\t\t}\n\n\t\t// try slow way by looking through to the next section item above\n\t\tfor (int position=fromPosition; position>=0; position--) {\n\t\t\tint viewType = adapter.getItemViewType(position);\n\t\t\tif (isItemViewTypePinned(adapter, viewType)) return position;\n\t\t}\n\t\treturn -1; // no candidate found\n\t}\n\n\tvoid recreatePinnedShadow() {\n\t    destroyPinnedShadow();\n        ListAdapter adapter = getAdapter();\n        if (adapter != null && adapter.getCount() > 0) {\n            int firstVisiblePosition = getFirstVisiblePosition();\n            int sectionPosition = findCurrentSectionPosition(firstVisiblePosition);\n            if (sectionPosition == -1) return; // no views to pin, exit\n            ensureShadowForPosition(sectionPosition,\n                    firstVisiblePosition, getLastVisiblePosition() - firstVisiblePosition);\n        }\n\t}\n\n\t@Override\n\tpublic void setOnScrollListener(OnScrollListener listener) {\n\t\tif (listener == mOnScrollListener) {\n\t\t\tsuper.setOnScrollListener(listener);\n\t\t} else {\n\t\t\tmDelegateOnScrollListener = listener;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onRestoreInstanceState(Parcelable state) {\n\t\tsuper.onRestoreInstanceState(state);\n\t\tpost(new Runnable() {\n\t\t\t@Override public void run() { // restore pinned view after configuration change\n\t\t\t    recreatePinnedShadow();\n\t\t\t}\n\t\t});\n\t}\n\n\t@Override\n\tpublic void setAdapter(ListAdapter adapter) {\n\n\t    // assert adapter in debug mode\n\t\tif (BuildConfig.DEBUG && adapter != null) {\n\t\t\tif (!(adapter instanceof PinnedSectionListAdapter))\n\t\t\t\tthrow new IllegalArgumentException(\"Does your adapter implement PinnedSectionListAdapter?\");\n\t\t\tif (adapter.getViewTypeCount() < 2)\n\t\t\t\tthrow new IllegalArgumentException(\"Does your adapter handle at least two types\" +\n\t\t\t\t\t\t\" of views in getViewTypeCount() method: items and sections?\");\n\t\t}\n\n\t\t// unregister observer at old adapter and register on new one\n\t\tListAdapter oldAdapter = getAdapter();\n\t\tif (oldAdapter != null) oldAdapter.unregisterDataSetObserver(mDataSetObserver);\n\t\tif (adapter != null) adapter.registerDataSetObserver(mDataSetObserver);\n\n\t\t// destroy pinned shadow, if new adapter is not same as old one\n\t\tif (oldAdapter != adapter) destroyPinnedShadow();\n\n\t\tsuper.setAdapter(adapter);\n\t}\n\n\t@Override\n\tprotected void onLayout(boolean changed, int l, int t, int r, int b) {\n\t    super.onLayout(changed, l, t, r, b);\n        if (mPinnedSection != null) {\n            int parentWidth = r - l - getPaddingLeft() - getPaddingRight();\n            int shadowWidth = mPinnedSection.view.getWidth();\n            if (parentWidth != shadowWidth) {\n                recreatePinnedShadow();\n            }\n        }\n\t}\n\n\t@Override\n\tprotected void dispatchDraw(Canvas canvas) {\n\t\tsuper.dispatchDraw(canvas);\n\n\t\tif (mPinnedSection != null) {\n\n\t\t\t// prepare variables\n\t\t\tint pLeft = getListPaddingLeft();\n\t\t\tint pTop = getListPaddingTop();\n\t\t\tView view = mPinnedSection.view;\n\n\t\t\t// draw child\n\t\t\tcanvas.save();\n\n\t\t\tint clipHeight = view.getHeight() +\n\t\t\t        (mShadowDrawable == null ? 0 : Math.min(mShadowHeight, mSectionsDistanceY));\n\t\t\tcanvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);\n\n\t\t\tcanvas.translate(pLeft, pTop + mTranslateY);\n\t\t\tdrawChild(canvas, mPinnedSection.view, getDrawingTime());\n\n\t\t\tif (mShadowDrawable != null && mSectionsDistanceY > 0) {\n\t\t\t    mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),\n\t\t\t            mPinnedSection.view.getBottom(),\n\t\t\t            mPinnedSection.view.getRight(),\n\t\t\t            mPinnedSection.view.getBottom() + mShadowHeight);\n\t\t\t    mShadowDrawable.draw(canvas);\n\t\t\t}\n\n\t\t\tcanvas.restore();\n\t\t}\n\t}\n\n\t//-- touch handling methods\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent ev) {\n\n        final float x = ev.getX();\n        final float y = ev.getY();\n        final int action = ev.getAction();\n\n        if (action == MotionEvent.ACTION_DOWN\n                && mTouchTarget == null\n                && mPinnedSection != null\n                && isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target\n\n            // user touched pinned view\n            mTouchTarget = mPinnedSection.view;\n            mTouchPoint.x = x;\n            mTouchPoint.y = y;\n\n            // copy down event for eventually be used later\n            mDownEvent = MotionEvent.obtain(ev);\n        }\n\n        if (mTouchTarget != null) {\n            if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view\n                mTouchTarget.dispatchTouchEvent(ev);\n            }\n\n            if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view\n                super.dispatchTouchEvent(ev);\n                performPinnedItemClick();\n                clearTouchTarget();\n\n            } else if (action == MotionEvent.ACTION_CANCEL) { // cancel\n                clearTouchTarget();\n\n            } else if (action == MotionEvent.ACTION_MOVE) {\n                if (Math.abs(y - mTouchPoint.y) > mTouchSlop) {\n\n                    // cancel sequence on touch target\n                    MotionEvent event = MotionEvent.obtain(ev);\n                    event.setAction(MotionEvent.ACTION_CANCEL);\n                    mTouchTarget.dispatchTouchEvent(event);\n                    event.recycle();\n\n                    // provide correct sequence to super class for further handling\n                    super.dispatchTouchEvent(mDownEvent);\n                    super.dispatchTouchEvent(ev);\n                    clearTouchTarget();\n\n                }\n            }\n\n            return true;\n        }\n\n        // call super if this was not our pinned view\n        return super.dispatchTouchEvent(ev);\n    }\n\n    private boolean isPinnedViewTouched(View view, float x, float y) {\n        view.getHitRect(mTouchRect);\n\n        // by taping top or bottom padding, the list performs on click on a border item.\n        // we don't add top padding here to keep behavior consistent.\n        mTouchRect.top += mTranslateY;\n\n        mTouchRect.bottom += mTranslateY + getPaddingTop();\n        mTouchRect.left += getPaddingLeft();\n        mTouchRect.right -= getPaddingRight();\n        return mTouchRect.contains((int)x, (int)y);\n    }\n\n    private void clearTouchTarget() {\n        mTouchTarget = null;\n        if (mDownEvent != null) {\n            mDownEvent.recycle();\n            mDownEvent = null;\n        }\n    }\n\n    private boolean performPinnedItemClick() {\n        if (mPinnedSection == null) return false;\n\n        OnItemClickListener listener = getOnItemClickListener();\n        if (listener != null && getAdapter().isEnabled(mPinnedSection.position)) {\n            View view =  mPinnedSection.view;\n            playSoundEffect(SoundEffectConstants.CLICK);\n            if (view != null) {\n                view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);\n            }\n            listener.onItemClick(this, view, mPinnedSection.position, mPinnedSection.id);\n            return true;\n        }\n        return false;\n    }\n\n    public static boolean isItemViewTypePinned(ListAdapter adapter, int viewType) {\n        if (adapter instanceof HeaderViewListAdapter) {\n            adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();\n        }\n        return ((PinnedSectionListAdapter) adapter).isItemViewTypePinned(viewType);\n    }\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/PositionBar.java",
    "content": "package com.boredream.bdcodehelper.view;\n\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport com.boredream.bdcodehelper.R;\n\n@SuppressLint(\"ClickableViewAccessibility\")\npublic class PositionBar extends LinearLayout {\n\n\tprivate String[] mItems = { \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\",\n\t\t\t\"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\",\n\t\t\t\"V\", \"W\", \"X\", \"Y\", \"Z\" };\n\n\tprivate OnPositionChangedListener listener;\n\n\tpublic void setOnPositionChangedListener(OnPositionChangedListener listener) {\n\t\tthis.listener = listener;\n\t}\n\n\tpublic PositionBar(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t\t\n\t\tsetOrientation(VERTICAL);\n\t\tsetBackgroundResource(R.drawable.cirrect_5a_primary_solid);\n\t}\n\t\n\tpublic void setItems(String[] items) {\n\t\tmItems = items;\n\t\tfor (CharSequence s : mItems) {\n\t\t\tTextView t = new TextView(getContext());\n\t\t\tt.setText(s);\n\t\t\tt.setTextSize(10);\n\t\t\tLayoutParams params = new LayoutParams(\n\t\t\t\t\tViewGroup.LayoutParams.WRAP_CONTENT, 0);\n\t\t\tparams.weight = 1;\n\t\t\tt.setLayoutParams(params);\n\t\t\tt.setTextColor(getResources().getColor(R.color.txt_black));\n\t\t\taddView(t);\n\t\t}\n\t}\n\n\tpublic String[] getItems() {\n\t\treturn mItems;\n\t}\n\n\tpublic PositionBar(Context context) {\n\t\tthis(context, null);\n\t}\n\n\t@Override\n\tpublic boolean onTouchEvent(MotionEvent ev) {\n\t\tfinal int action = ev.getAction();\n\t\tTextView child = null;\n\n\t\tswitch (action & MotionEvent.ACTION_MASK) {\n\t\tcase MotionEvent.ACTION_DOWN:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_10a_primary_solid);\n\t\t\tchild = findChildByLocation(ev.getX(), ev.getY());\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(child==null?\"\":child.getText().toString());\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MotionEvent.ACTION_MOVE:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_10a_primary_solid);\n\t\t\tchild = findChildByLocation(ev.getX(), ev.getY());\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(child==null?\"\":child.getText().toString());\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MotionEvent.ACTION_UP:\n\t\t\tsetBackgroundResource(R.drawable.cirrect_5a_primary_solid);\n\t\t\tif (listener != null) {\n\t\t\t\tlistener.onPositionSelected(\"\");\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate TextView findChildByLocation(float x, float y) {\n\t\tTextView child = null;\n\t\tint mContentTop = getChildAt(0).getTop();\n\t\tint mContentBottom = getChildAt(getChildCount() - 1).getBottom();\n\t\tint defSize = (mContentBottom - mContentTop) / mItems.length;\n\n\t\tint index = (int) ((y - mContentTop) / defSize);\n\t\tif (index >= 0 && index < mItems.length\n\t\t\t\t&& x >= 0 && x <= getWidth()) {\n\t\t\tchild = (TextView) getChildAt(index);\n\t\t}\n\t\treturn child;\n\t}\n\n\tpublic interface OnPositionChangedListener {\n\t\tvoid onPositionSelected(String key);\n\t}\n\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightGridView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.GridView;\n\npublic class WrapHeightGridView extends GridView {\n\n    public WrapHeightGridView(Context context) {\n        super(context);\n    }\n\n    public WrapHeightGridView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public WrapHeightGridView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int heightSpec = MeasureSpec.makeMeasureSpec(\n                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);\n\n        super.onMeasure(widthMeasureSpec, heightSpec);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightLinearLayoutManager.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * 用作wrap_content的RecyclerView\n */\npublic class WrapHeightLinearLayoutManager extends LinearLayoutManager {\n\n    public WrapHeightLinearLayoutManager(Context context, int orientation, boolean reverseLayout)    {\n        super(context, orientation, reverseLayout);\n    }\n\n    private int[] mMeasuredDimension = new int[2];\n\n    @Override\n    public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,\n                          int widthSpec, int heightSpec) {\n        final int widthMode = View.MeasureSpec.getMode(widthSpec);\n        final int heightMode = View.MeasureSpec.getMode(heightSpec);\n        final int widthSize = View.MeasureSpec.getSize(widthSpec);\n        final int heightSize = View.MeasureSpec.getSize(heightSpec);\n        int width = 0;\n        int height = 0;\n        for (int i = 0; i < getItemCount(); i++) {\n            measureScrapChild(recycler, i,\n                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),\n                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),\n                    mMeasuredDimension);\n\n            if (getOrientation() == HORIZONTAL) {\n                width = width + mMeasuredDimension[0];\n                if (i == 0) {\n                    height = mMeasuredDimension[1];\n                }\n            } else {\n                height = height + mMeasuredDimension[1];\n                if (i == 0) {\n                    width = mMeasuredDimension[0];\n                }\n            }\n        }\n        switch (widthMode) {\n            case View.MeasureSpec.EXACTLY:\n                width = widthSize;\n            case View.MeasureSpec.AT_MOST:\n            case View.MeasureSpec.UNSPECIFIED:\n        }\n\n        switch (heightMode) {\n            case View.MeasureSpec.EXACTLY:\n                height = heightSize;\n            case View.MeasureSpec.AT_MOST:\n            case View.MeasureSpec.UNSPECIFIED:\n        }\n\n        setMeasuredDimension(width, height);\n    }\n\n    private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,\n                                   int heightSpec, int[] measuredDimension) {\n        View view = recycler.getViewForPosition(position);\n        if (view != null) {\n            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();\n            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,\n                    getPaddingLeft() + getPaddingRight(), p.width);\n            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,\n                    getPaddingTop() + getPaddingBottom(), p.height);\n            view.measure(childWidthSpec, childHeightSpec);\n            measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;\n            measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;\n            recycler.recycleView(view);\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/WrapHeightListView.java",
    "content": "package com.boredream.bdcodehelper.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.ListView;\n\npublic class WrapHeightListView extends ListView {\n\n    public WrapHeightListView(Context context) {\n        super(context);\n    }\n\n    public WrapHeightListView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public WrapHeightListView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\n        int heightSpec = MeasureSpec.makeMeasureSpec(\n                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);\n\n        super.onMeasure(widthMeasureSpec, heightSpec);\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/ItemsRange.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Range for visible items.\n */\npublic class ItemsRange {\n\t// First item number\n\tprivate int first;\n\t\n\t// Items count\n\tprivate int count;\n\n\t/**\n\t * Default constructor. Creates an empty range\n\t */\n    public ItemsRange() {\n        this(0, 0);\n    }\n    \n\t/**\n\t * Constructor\n\t * @param first the number of first item\n\t * @param count the count of items\n\t */\n\tpublic ItemsRange(int first, int count) {\n\t\tthis.first = first;\n\t\tthis.count = count;\n\t}\n\t\n\t/**\n\t * Gets number of  first item\n\t * @return the number of the first item\n\t */\n\tpublic int getFirst() {\n\t\treturn first;\n\t}\n\t\n\t/**\n\t * Gets number of last item\n\t * @return the number of last item\n\t */\n\tpublic int getLast() {\n\t\treturn getFirst() + getCount() - 1;\n\t}\n\t\n\t/**\n\t * Get items count\n\t * @return the count of items\n\t */\n\tpublic int getCount() {\n\t\treturn count;\n\t}\n\t\n\t/**\n\t * Tests whether item is contained by range\n\t * @param index the item number\n\t * @return true if item is contained\n\t */\n\tpublic boolean contains(int index) {\n\t\treturn index >= getFirst() && index <= getLast();\n\t}\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelChangedListener.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel changed listener interface.\n * <p>The onChanged() method is called whenever current wheel positions is changed:\n * <li> New Wheel position is set\n * <li> Wheel view is scrolled\n */\npublic interface OnWheelChangedListener {\n\t/**\n\t * Callback method to be invoked when current item changed\n\t * @param wheel the wheel view whose state has changed\n\t * @param oldValue the old value of current item\n\t * @param newValue the new value of current item\n\t */\n\tvoid onChanged(WheelView wheel, int oldValue, int newValue);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelClickedListener.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel clicked listener interface.\n * <p>The onItemClicked() method is called whenever a wheel item is clicked\n * <li> New Wheel position is set\n * <li> Wheel view is scrolled\n */\npublic interface OnWheelClickedListener {\n    /**\n     * Callback method to be invoked when current item clicked\n     * @param wheel the wheel view\n     * @param itemIndex the index of clicked item\n     */\n    void onItemClicked(WheelView wheel, int itemIndex);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/OnWheelScrollListener.java",
    "content": "/*\n *  Copyright 2010 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel scrolled listener interface.\n */\npublic interface OnWheelScrollListener {\n\t/**\n\t * Callback method to be invoked when scrolling started.\n\t * @param wheel the wheel view whose state has changed.\n\t */\n\tvoid onScrollingStarted(WheelView wheel);\n\t\n\t/**\n\t * Callback method to be invoked when scrolling ended.\n\t * @param wheel the wheel view whose state has changed.\n\t */\n\tvoid onScrollingFinished(WheelView wheel);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelAdapter.java",
    "content": "/*\n *  Copyright 2010 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\n/**\n * Wheel adapter interface\n * \n * @deprecated Use WheelViewAdapter\n */\npublic interface WheelAdapter {\n\t/**\n\t * Gets items count\n\t * @return the count of wheel items\n\t */\n\tpublic int getItemsCount();\n\t\n\t/**\n\t * Gets a wheel item by index.\n\t * \n\t * @param index the item index\n\t * @return the wheel item text or null\n\t */\n\tpublic String getItem(int index);\n\t\n\t/**\n\t * Gets maximum item length. It is used to determine the wheel width. \n\t * If -1 is returned there will be used the default wheel width.\n\t * \n\t * @return the maximum item length or -1\n\t */\n\tpublic int getMaximumLength();\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelRecycle.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.view.View;\nimport android.widget.LinearLayout;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Recycle stores wheel items to reuse. \n */\npublic class WheelRecycle {\n\t// Cached items\n\tprivate List<View> items;\n\t\n\t// Cached empty items\n\tprivate List<View> emptyItems;\n\t\n\t// Wheel view\n\tprivate WheelView wheel;\n\t\n\t/**\n\t * Constructor\n\t * @param wheel the wheel view\n\t */\n\tpublic WheelRecycle(WheelView wheel) {\n\t\tthis.wheel = wheel;\n\t}\n\n\t/**\n\t * Recycles items from specified layout.\n\t * There are saved only items not included to specified range.\n\t * All the cached items are removed from original layout.\n\t * \n\t * @param layout the layout containing items to be cached\n\t * @param firstItem the number of first item in layout\n\t * @param range the range of current wheel items \n\t * @return the new value of first item number\n\t */\n\tpublic int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) {\n\t\tint index = firstItem;\n\t\tfor (int i = 0; i < layout.getChildCount();) {\n\t\t\tif (!range.contains(index)) {\n\t\t\t\trecycleView(layout.getChildAt(i), index);\n\t\t\t\tlayout.removeViewAt(i);\n\t\t\t\tif (i == 0) { // first item\n\t\t\t\t\tfirstItem++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ti++; // go to next item\n\t\t\t}\n\t\t\tindex++;\n\t\t}\n\t\treturn firstItem;\n\t}\n\t\n\t/**\n\t * Gets item view\n\t * @return the cached view\n\t */\n\tpublic View getItem() {\n\t\treturn getCachedView(items);\n\t}\n\n\t/**\n\t * Gets empty item view\n\t * @return the cached empty view\n\t */\n\tpublic View getEmptyItem() {\n\t\treturn getCachedView(emptyItems);\n\t}\n\t\n\t/**\n\t * Clears all views \n\t */\n\tpublic void clearAll() {\n\t\tif (items != null) {\n\t\t\titems.clear();\n\t\t}\n\t\tif (emptyItems != null) {\n\t\t\temptyItems.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Adds view to specified cache. Creates a cache list if it is null.\n\t * @param view the view to be cached\n\t * @param cache the cache list\n\t * @return the cache list\n\t */\n\tprivate List<View> addView(View view, List<View> cache) {\n\t\tif (cache == null) {\n\t\t\tcache = new LinkedList<View>();\n\t\t}\n\t\t\n\t\tcache.add(view);\n\t\treturn cache;\n\t}\n\n\t/**\n\t * Adds view to cache. Determines view type (item view or empty one) by index.\n\t * @param view the view to be cached\n\t * @param index the index of view\n\t */\n\tprivate void recycleView(View view, int index) {\n\t\tint count = wheel.getViewAdapter().getItemsCount();\n\n\t\tif ((index < 0 || index >= count) && !wheel.isCyclic()) {\n\t\t\t// empty view\n\t\t\temptyItems = addView(view, emptyItems);\n\t\t} else {\n\t\t\twhile (index < 0) {\n\t\t\t\tindex = count + index;\n\t\t\t}\n\t\t\tindex %= count;\n\t\t\titems = addView(view, items);\n\t\t}\n\t}\n\t\n\t/**\n\t * Gets view from specified cache.\n\t * @param cache the cache\n\t * @return the first view from cache.\n\t */\n\tprivate View getCachedView(List<View> cache) {\n\t\tif (cache != null && cache.size() > 0) {\n\t\t\tView view = cache.get(0);\n\t\t\tcache.remove(0);\n\t\t\treturn view;\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelScroller.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n *  \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\nimport android.view.GestureDetector.SimpleOnGestureListener;\nimport android.view.animation.Interpolator;\nimport android.widget.Scroller;\n\n/**\n * Scroller class handles scrolling events and updates the \n */\npublic class WheelScroller {\n    /**\n     * Scrolling listener interface\n     */\n    public interface ScrollingListener {\n        /**\n         * Scrolling callback called when scrolling is performed.\n         * @param distance the distance to scroll\n         */\n        void onScroll(int distance);\n\n        /**\n         * Starting callback called when scrolling is started\n         */\n        void onStarted();\n        \n        /**\n         * Finishing callback called after justifying\n         */\n        void onFinished();\n        \n        /**\n         * Justifying callback called to justify a view when scrolling is ended\n         */\n        void onJustify();\n    }\n    \n    /** Scrolling duration */\n    private static final int SCROLLING_DURATION = 400;\n\n    /** Minimum delta for scrolling */\n    public static final int MIN_DELTA_FOR_SCROLLING = 1;\n\n    // Listener\n    private ScrollingListener listener;\n    \n    // Context\n    private Context context;\n    \n    // Scrolling\n    private GestureDetector gestureDetector;\n    private Scroller scroller;\n    private int lastScrollY;\n    private float lastTouchedY;\n    private boolean isScrollingPerformed;\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param listener the scrolling listener\n     */\n    public WheelScroller(Context context, ScrollingListener listener) {\n        gestureDetector = new GestureDetector(context, gestureListener);\n        gestureDetector.setIsLongpressEnabled(false);\n        \n        scroller = new Scroller(context);\n\n        this.listener = listener;\n        this.context = context;\n    }\n    \n    /**\n     * Set the the specified scrolling interpolator\n     * @param interpolator the interpolator\n     */\n    public void setInterpolator(Interpolator interpolator) {\n        scroller.forceFinished(true);\n        scroller = new Scroller(context, interpolator);\n    }\n    \n    /**\n     * Scroll the wheel\n     * @param distance the scrolling distance\n     * @param time the scrolling duration\n     */\n    public void scroll(int distance, int time) {\n        scroller.forceFinished(true);\n\n        lastScrollY = 0;\n        \n        scroller.startScroll(0, 0, 0, distance, time != 0 ? time : SCROLLING_DURATION);\n        setNextMessage(MESSAGE_SCROLL);\n        \n        startScrolling();\n    }\n   \n    /**\n     * Stops scrolling\n     */\n    public void stopScrolling() {\n        scroller.forceFinished(true);\n    }\n    \n    /**\n     * Handles Touch event \n     * @param event the motion event\n     * @return\n     */\n    public boolean onTouchEvent(MotionEvent event) {\n        switch (event.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n                lastTouchedY = event.getY();\n                scroller.forceFinished(true);\n                clearMessages();\n                break;\n    \n            case MotionEvent.ACTION_MOVE:\n                // perform scrolling\n                int distanceY = (int)(event.getY() - lastTouchedY);\n                if (distanceY != 0) {\n                    startScrolling();\n                    listener.onScroll(distanceY);\n                    lastTouchedY = event.getY();\n                }\n                break;\n        }\n        \n        if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {\n            justify();\n        }\n\n        return true;\n    }\n    \n    // gesture listener\n    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {\n        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {\n            // Do scrolling in onTouchEvent() since onScroll() are not call immediately\n            //  when user touch and move the wheel\n            return true;\n        }\n        \n        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {\n            lastScrollY = 0;\n            final int maxY = 0x7FFFFFFF;\n            final int minY = -maxY;\n            scroller.fling(0, lastScrollY, 0, (int) -velocityY, 0, 0, minY, maxY);\n            setNextMessage(MESSAGE_SCROLL);\n            return true;\n        }\n    };\n\n    // Messages\n    private final int MESSAGE_SCROLL = 0;\n    private final int MESSAGE_JUSTIFY = 1;\n    \n    /**\n     * Set next message to queue. Clears queue before.\n     * \n     * @param message the message to set\n     */\n    private void setNextMessage(int message) {\n        clearMessages();\n        animationHandler.sendEmptyMessage(message);\n    }\n\n    /**\n     * Clears messages from queue\n     */\n    private void clearMessages() {\n        animationHandler.removeMessages(MESSAGE_SCROLL);\n        animationHandler.removeMessages(MESSAGE_JUSTIFY);\n    }\n    \n    // animation handler\n    private Handler animationHandler = new Handler() {\n        public void handleMessage(Message msg) {\n            scroller.computeScrollOffset();\n            int currY = scroller.getCurrY();\n            int delta = lastScrollY - currY;\n            lastScrollY = currY;\n            if (delta != 0) {\n                listener.onScroll(delta);\n            }\n            \n            // scrolling is not finished when it comes to final Y\n            // so, finish it manually \n            if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {\n                currY = scroller.getFinalY();\n                scroller.forceFinished(true);\n            }\n            if (!scroller.isFinished()) {\n                animationHandler.sendEmptyMessage(msg.what);\n            } else if (msg.what == MESSAGE_SCROLL) {\n                justify();\n            } else {\n                finishScrolling();\n            }\n        }\n    };\n    \n    /**\n     * Justifies wheel\n     */\n    private void justify() {\n        listener.onJustify();\n        setNextMessage(MESSAGE_JUSTIFY);\n    }\n\n    /**\n     * Starts scrolling\n     */\n    private void startScrolling() {\n        if (!isScrollingPerformed) {\n            isScrollingPerformed = true;\n            listener.onStarted();\n        }\n    }\n\n    /**\n     * Finishes scrolling\n     */\n    void finishScrolling() {\n        if (isScrollingPerformed) {\n            listener.onFinished();\n            isScrollingPerformed = false;\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/WheelView.java",
    "content": "/*\n *  Android Wheel Control.\n *  https://code.google.com/p/android-wheel/\n * \n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel;\n\nimport android.content.Context;\nimport android.database.DataSetObserver;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.GradientDrawable;\nimport android.graphics.drawable.GradientDrawable.Orientation;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup.LayoutParams;\nimport android.view.animation.Interpolator;\nimport android.widget.LinearLayout;\n\nimport com.boredream.bdcodehelper.R;\nimport com.boredream.bdcodehelper.view.wheel.adapters.WheelViewAdapter;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Numeric wheel view.\n * \n * @author Yuri Kanivets\n */\npublic class WheelView extends View {\n\n\t/** Top and bottom shadows colors */\n\t/*/ Modified by wulianghuan 2014-11-25\n\tprivate int[] SHADOWS_COLORS = new int[] { 0xFF111111,\n\t\t\t0x00AAAAAA, 0x00AAAAAA };\n\t//*/\n\tprivate int[] SHADOWS_COLORS = new int[] { 0xefE9E9E9,\n\t\t\t0xcfE9E9E9, 0x3fE9E9E9 };\n\n\t/** Top and bottom items offset (to hide that) */\n\tprivate static final int ITEM_OFFSET_PERCENT = 0;\n\n\t/** Left and right padding value */\n\tprivate static final int PADDING = 10;\n\n\t/** Default count of visible items */\n\tprivate static final int DEF_VISIBLE_ITEMS = 5;\n\n\t// Wheel Values\n\tprivate int currentItem = 0;\n\n\t// Count of visible items\n\tprivate int visibleItems = DEF_VISIBLE_ITEMS;\n\n\t// Item height\n\tprivate int itemHeight = 0;\n\n\t// Center Line\n\tprivate Drawable centerDrawable;\n\n\t// Wheel drawables\n\tprivate int wheelBackground = R.drawable.wheel_bg;\n\tprivate int wheelForeground = R.drawable.wheel_val;\n\n\t// Shadows drawables\n\tprivate GradientDrawable topShadow;\n\tprivate GradientDrawable bottomShadow;\n\n\t// Draw Shadows\n\tprivate boolean drawShadows = true;\n\n\t// Scrolling\n\tprivate WheelScroller scroller;\n\tprivate boolean isScrollingPerformed;\n\tprivate int scrollingOffset;\n\n\t// Cyclic\n\tboolean isCyclic = false;\n\n\t// Items layout\n\tprivate LinearLayout itemsLayout;\n\n\t// The number of first item in layout\n\tprivate int firstItem;\n\n\t// View adapter\n\tprivate WheelViewAdapter viewAdapter;\n\n\t// Recycle\n\tprivate WheelRecycle recycle = new WheelRecycle(this);\n\n\t// Listeners\n\tprivate List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>();\n\tprivate List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>();\n\tprivate List<OnWheelClickedListener> clickingListeners = new LinkedList<OnWheelClickedListener>();\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context, AttributeSet attrs, int defStyle) {\n\t\tsuper(context, attrs, defStyle);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context, AttributeSet attrs) {\n\t\tsuper(context, attrs);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Constructor\n\t */\n\tpublic WheelView(Context context) {\n\t\tsuper(context);\n\t\tinitData(context);\n\t}\n\n\t/**\n\t * Initializes class data\n\t * @param context the context\n\t */\n\tprivate void initData(Context context) {\n\t\tscroller = new WheelScroller(getContext(), scrollingListener);\n\t}\n\n\t// Scrolling listener\n\tWheelScroller.ScrollingListener scrollingListener = new WheelScroller.ScrollingListener() {\n\t\t@Override\n\t\tpublic void onStarted() {\n\t\t\tisScrollingPerformed = true;\n\t\t\tnotifyScrollingListenersAboutStart();\n\t\t}\n\n\t\t@Override\n\t\tpublic void onScroll(int distance) {\n\t\t\tdoScroll(distance);\n\n\t\t\tint height = getHeight();\n\t\t\tif (scrollingOffset > height) {\n\t\t\t\tscrollingOffset = height;\n\t\t\t\tscroller.stopScrolling();\n\t\t\t} else if (scrollingOffset < -height) {\n\t\t\t\tscrollingOffset = -height;\n\t\t\t\tscroller.stopScrolling();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void onFinished() {\n\t\t\tif (isScrollingPerformed) {\n\t\t\t\tnotifyScrollingListenersAboutEnd();\n\t\t\t\tisScrollingPerformed = false;\n\t\t\t}\n\n\t\t\tscrollingOffset = 0;\n\t\t\tinvalidate();\n\t\t}\n\n\t\t@Override\n\t\tpublic void onJustify() {\n\t\t\tif (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) {\n\t\t\t\tscroller.scroll(scrollingOffset, 0);\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * Set the the specified scrolling interpolator\n\t * @param interpolator the interpolator\n\t */\n\tpublic void setInterpolator(Interpolator interpolator) {\n\t\tscroller.setInterpolator(interpolator);\n\t}\n\n\t/**\n\t * Gets count of visible items\n\t * \n\t * @return the count of visible items\n\t */\n\tpublic int getVisibleItems() {\n\t\treturn visibleItems;\n\t}\n\n\t/**\n\t * Sets the desired count of visible items.\n\t * Actual amount of visible items depends on wheel layout parameters.\n\t * To apply changes and rebuild view call measure().\n\t * \n\t * @param count the desired count for visible items\n\t */\n\tpublic void setVisibleItems(int count) {\n\t\tvisibleItems = count;\n\t}\n\n\t/**\n\t * Gets view adapter\n\t * @return the view adapter\n\t */\n\tpublic WheelViewAdapter getViewAdapter() {\n\t\treturn viewAdapter;\n\t}\n\n\t// Adapter listener\n\tprivate DataSetObserver dataObserver = new DataSetObserver() {\n\t\t@Override\n\t\tpublic void onChanged() {\n\t\t\tinvalidateWheel(false);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onInvalidated() {\n\t\t\tinvalidateWheel(true);\n\t\t}\n\t};\n\n\t/**\n\t * Sets view adapter. Usually new adapters contain different views, so\n\t * it needs to rebuild view by calling measure().\n\t * \n\t * @param viewAdapter the view adapter\n\t */\n\tpublic void setViewAdapter(WheelViewAdapter viewAdapter) {\n\t\tif (this.viewAdapter != null) {\n\t\t\tthis.viewAdapter.unregisterDataSetObserver(dataObserver);\n\t\t}\n\t\tthis.viewAdapter = viewAdapter;\n\t\tif (this.viewAdapter != null) {\n\t\t\tthis.viewAdapter.registerDataSetObserver(dataObserver);\n\t\t}\n\n\t\tinvalidateWheel(true);\n\t}\n\n\t/**\n\t * Adds wheel changing listener\n\t * @param listener the listener\n\t */\n\tpublic void addChangingListener(OnWheelChangedListener listener) {\n\t\tchangingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel changing listener\n\t * @param listener the listener\n\t */\n\tpublic void removeChangingListener(OnWheelChangedListener listener) {\n\t\tchangingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies changing listeners\n\t * @param oldValue the old wheel value\n\t * @param newValue the new wheel value\n\t */\n\tprotected void notifyChangingListeners(int oldValue, int newValue) {\n\t\tfor (OnWheelChangedListener listener : changingListeners) {\n\t\t\tlistener.onChanged(this, oldValue, newValue);\n\t\t}\n\t}\n\n\t/**\n\t * Adds wheel scrolling listener\n\t * @param listener the listener\n\t */\n\tpublic void addScrollingListener(OnWheelScrollListener listener) {\n\t\tscrollingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel scrolling listener\n\t * @param listener the listener\n\t */\n\tpublic void removeScrollingListener(OnWheelScrollListener listener) {\n\t\tscrollingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies listeners about starting scrolling\n\t */\n\tprotected void notifyScrollingListenersAboutStart() {\n\t\tfor (OnWheelScrollListener listener : scrollingListeners) {\n\t\t\tlistener.onScrollingStarted(this);\n\t\t}\n\t}\n\n\t/**\n\t * Notifies listeners about ending scrolling\n\t */\n\tprotected void notifyScrollingListenersAboutEnd() {\n\t\tfor (OnWheelScrollListener listener : scrollingListeners) {\n\t\t\tlistener.onScrollingFinished(this);\n\t\t}\n\t}\n\n\t/**\n\t * Adds wheel clicking listener\n\t * @param listener the listener\n\t */\n\tpublic void addClickingListener(OnWheelClickedListener listener) {\n\t\tclickingListeners.add(listener);\n\t}\n\n\t/**\n\t * Removes wheel clicking listener\n\t * @param listener the listener\n\t */\n\tpublic void removeClickingListener(OnWheelClickedListener listener) {\n\t\tclickingListeners.remove(listener);\n\t}\n\n\t/**\n\t * Notifies listeners about clicking\n\t */\n\tprotected void notifyClickListenersAboutClick(int item) {\n\t\tfor (OnWheelClickedListener listener : clickingListeners) {\n\t\t\tlistener.onItemClicked(this, item);\n\t\t}\n\t}\n\n\t/**\n\t * Gets current value\n\t * \n\t * @return the current value\n\t */\n\tpublic int getCurrentItem() {\n\t\treturn currentItem;\n\t}\n\n\t/**\n\t * Sets the current item. Does nothing when index is wrong.\n\t * \n\t * @param index the item index\n\t * @param animated the animation flag\n\t */\n\tpublic void setCurrentItem(int index, boolean animated) {\n\t\tif (viewAdapter == null || viewAdapter.getItemsCount() == 0) {\n\t\t\treturn; // throw?\n\t\t}\n\n\t\tint itemCount = viewAdapter.getItemsCount();\n\t\tif (index < 0 || index >= itemCount) {\n\t\t\tif (isCyclic) {\n\t\t\t\twhile (index < 0) {\n\t\t\t\t\tindex += itemCount;\n\t\t\t\t}\n\t\t\t\tindex %= itemCount;\n\t\t\t} else{\n\t\t\t\treturn; // throw?\n\t\t\t}\n\t\t}\n\t\tif (index != currentItem) {\n\t\t\tif (animated) {\n\t\t\t\tint itemsToScroll = index - currentItem;\n\t\t\t\tif (isCyclic) {\n\t\t\t\t\tint scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem);\n\t\t\t\t\tif (scroll < Math.abs(itemsToScroll)) {\n\t\t\t\t\t\titemsToScroll = itemsToScroll < 0 ? scroll : -scroll;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscroll(itemsToScroll, 0);\n\t\t\t} else {\n\t\t\t\tscrollingOffset = 0;\n\n\t\t\t\tint old = currentItem;\n\t\t\t\tcurrentItem = index;\n\n\t\t\t\tnotifyChangingListeners(old, currentItem);\n\n\t\t\t\tinvalidate();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Sets the current item w/o animation. Does nothing when index is wrong.\n\t * \n\t * @param index the item index\n\t */\n\tpublic void setCurrentItem(int index) {\n\t\tsetCurrentItem(index, false);\n\t}\n\n\t/**\n\t * Tests if wheel is cyclic. That means before the 1st item there is shown the last one\n\t * @return true if wheel is cyclic\n\t */\n\tpublic boolean isCyclic() {\n\t\treturn isCyclic;\n\t}\n\n\t/**\n\t * Set wheel cyclic flag\n\t * @param isCyclic the flag to set\n\t */\n\tpublic void setCyclic(boolean isCyclic) {\n\t\tthis.isCyclic = isCyclic;\n\t\tinvalidateWheel(false);\n\t}\n\n\t/**\n\t * Determine whether shadows are drawn\n\t * @return true is shadows are drawn\n\t */\n\tpublic boolean drawShadows() {\n\t\treturn drawShadows;\n\t}\n\n\t/**\n\t * Set whether shadows should be drawn\n\t * @param drawShadows flag as true or false\n\t */\n\tpublic void setDrawShadows(boolean drawShadows) {\n\t\tthis.drawShadows = drawShadows;\n\t}\n\n\t/**\n\t * Set the shadow gradient color\n\t * @param start\n\t * @param middle\n\t * @param end\n\t */\n\tpublic void setShadowColor(int start, int middle, int end) {\n\t\tSHADOWS_COLORS = new int[] {start, middle, end};\n\t}\n\n\t/**\n\t * Sets the drawable for the wheel background\n\t * @param resource\n\t */\n\tpublic void setWheelBackground(int resource) {\n\t\twheelBackground = resource;\n\t\tsetBackgroundResource(wheelBackground);\n\t}\n\n\t/**\n\t * Sets the drawable for the wheel foreground\n\t * @param resource\n\t */\n\tpublic void setWheelForeground(int resource) {\n\t\twheelForeground = resource;\n\t\tcenterDrawable = getContext().getResources().getDrawable(wheelForeground);\n\t}\n\n\t/**\n\t * Invalidates wheel\n\t * @param clearCaches if true then cached views will be clear\n\t */\n\tpublic void invalidateWheel(boolean clearCaches) {\n\t\tif (clearCaches) {\n\t\t\trecycle.clearAll();\n\t\t\tif (itemsLayout != null) {\n\t\t\t\titemsLayout.removeAllViews();\n\t\t\t}\n\t\t\tscrollingOffset = 0;\n\t\t} else if (itemsLayout != null) {\n\t\t\t// cache all items\n\t\t\trecycle.recycleItems(itemsLayout, firstItem, new ItemsRange());\n\t\t}\n\n\t\tinvalidate();\n\t}\n\n\t/**\n\t * Initializes resources\n\t */\n\tprivate void initResourcesIfNecessary() {\n\t\tif (centerDrawable == null) {\n\t\t\tcenterDrawable = getContext().getResources().getDrawable(wheelForeground);\n\t\t}\n\n\t\tif (topShadow == null) {\n\t\t\ttopShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);\n\t\t}\n\n\t\tif (bottomShadow == null) {\n\t\t\tbottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);\n\t\t}\n\n\t\tsetBackgroundResource(wheelBackground);\n\t}\n\n\t/**\n\t * Calculates desired height for layout\n\t * \n\t * @param layout\n\t *            the source layout\n\t * @return the desired layout height\n\t */\n\tprivate int getDesiredHeight(LinearLayout layout) {\n\t\tif (layout != null && layout.getChildAt(0) != null) {\n\t\t\titemHeight = layout.getChildAt(0).getMeasuredHeight();\n\t\t}\n\n\t\tint desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50;\n\n\t\treturn Math.max(desired, getSuggestedMinimumHeight());\n\t}\n\n\t/**\n\t * Returns height of wheel item\n\t * @return the item height\n\t */\n\tprivate int getItemHeight() {\n\t\tif (itemHeight != 0) {\n\t\t\treturn itemHeight;\n\t\t}\n\n\t\tif (itemsLayout != null && itemsLayout.getChildAt(0) != null) {\n\t\t\titemHeight = itemsLayout.getChildAt(0).getHeight();\n\t\t\treturn itemHeight;\n\t\t}\n\n\t\treturn getHeight() / visibleItems;\n\t}\n\n\t/**\n\t * Calculates control width and creates text layouts\n\t * @param widthSize the input layout width\n\t * @param mode the layout mode\n\t * @return the calculated control width\n\t */\n\tprivate int calculateLayoutWidth(int widthSize, int mode) {\n\t\tinitResourcesIfNecessary();\n\n\t\t// TODO: make it static\n\t\titemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));\n\t\titemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED),\n\t\t\t\tMeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));\n\t\tint width = itemsLayout.getMeasuredWidth();\n\n\t\tif (mode == MeasureSpec.EXACTLY) {\n\t\t\twidth = widthSize;\n\t\t} else {\n\t\t\twidth += 2 * PADDING;\n\n\t\t\t// Check against our minimum width\n\t\t\twidth = Math.max(width, getSuggestedMinimumWidth());\n\n\t\t\tif (mode == MeasureSpec.AT_MOST && widthSize < width) {\n\t\t\t\twidth = widthSize;\n\t\t\t}\n\t\t}\n\n\t\titemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY),\n\t\t\t\tMeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));\n\n\t\treturn width;\n\t}\n\n\t@Override\n\tprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n\t\tint widthMode = MeasureSpec.getMode(widthMeasureSpec);\n\t\tint heightMode = MeasureSpec.getMode(heightMeasureSpec);\n\t\tint widthSize = MeasureSpec.getSize(widthMeasureSpec);\n\t\tint heightSize = MeasureSpec.getSize(heightMeasureSpec);\n\n\t\tbuildViewForMeasuring();\n\n\t\tint width = calculateLayoutWidth(widthSize, widthMode);\n\n\t\tint height;\n\t\tif (heightMode == MeasureSpec.EXACTLY) {\n\t\t\theight = heightSize;\n\t\t} else {\n\t\t\theight = getDesiredHeight(itemsLayout);\n\n\t\t\tif (heightMode == MeasureSpec.AT_MOST) {\n\t\t\t\theight = Math.min(height, heightSize);\n\t\t\t}\n\t\t}\n\n\t\tsetMeasuredDimension(width, height);\n\t}\n\n\t@Override\n\tprotected void onLayout(boolean changed, int l, int t, int r, int b) {\n\t\tlayout(r - l, b - t);\n\t}\n\n\t/**\n\t * Sets layouts width and height\n\t * @param width the layout width\n\t * @param height the layout height\n\t */\n\tprivate void layout(int width, int height) {\n\t\tint itemsWidth = width - 2 * PADDING;\n\n\t\titemsLayout.layout(0, 0, itemsWidth, height);\n\t}\n\n\t@Override\n\tprotected void onDraw(Canvas canvas) {\n\t\tsuper.onDraw(canvas);\n\n\t\tif (viewAdapter != null && viewAdapter.getItemsCount() > 0) {\n\t\t\tupdateView();\n\n\t\t\tdrawItems(canvas);\n\t\t\tdrawCenterRect(canvas);\n\t\t}\n\n\t\tif (drawShadows) drawShadows(canvas);\n\t}\n\n\t/**\n\t * Draws shadows on top and bottom of control\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawShadows(Canvas canvas) {\n\t\t/*/ Modified by wulianghuan 2014-11-25\n\t\tint height = (int)(1.5 * getItemHeight());\n\t\t//*/\n\t\tint height = (int)(3 * getItemHeight());\n\t\t//*/\n\t\ttopShadow.setBounds(0, 0, getWidth(), height);\n\t\ttopShadow.draw(canvas);\n\n\t\tbottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());\n\t\tbottomShadow.draw(canvas);\n\t}\n\n\t/**\n\t * Draws items\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawItems(Canvas canvas) {\n\t\tcanvas.save();\n\n\t\tint top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2;\n\t\tcanvas.translate(PADDING, - top + scrollingOffset);\n\n\t\titemsLayout.draw(canvas);\n\n\t\tcanvas.restore();\n\t}\n\n\t/**\n\t * Draws rect for current value\n\t * @param canvas the canvas for drawing\n\t */\n\tprivate void drawCenterRect(Canvas canvas) {\n\t\tint center = getHeight() / 2;\n\t\tint offset = (int) (getItemHeight() / 2 * 1.2);\n\t\t/*/ Remarked by wulianghuan 2014-11-27  使用自己的画线，而不是描边\n\t\tRect rect = new Rect(left, top, right, bottom)\n\t\tcenterDrawable.setBounds(bounds)\n\t\tcenterDrawable.setBounds(0, center - offset, getWidth(), center + offset);\n\t\tcenterDrawable.draw(canvas);\n\t\t//*/\n\t\tPaint paint = new Paint();\n\t\tpaint.setColor(getResources().getColor(R.color.province_line_border));\n\t\t// 设置线宽\n\t\tpaint.setStrokeWidth((float) 3);\n\t\t// 绘制上边直线\n\t\tcanvas.drawLine(0, center - offset, getWidth(), center - offset, paint);\n\t\t// 绘制下边直线\n\t\tcanvas.drawLine(0, center + offset, getWidth(), center + offset, paint);\n\t\t//*/\n\t}\n\n\t@Override\n\tpublic boolean onTouchEvent(MotionEvent event) {\n\t\tif (!isEnabled() || getViewAdapter() == null) {\n\t\t\treturn true;\n\t\t}\n\n\t\tswitch (event.getAction()) {\n\t\t\tcase MotionEvent.ACTION_MOVE:\n\t\t\t\tif (getParent() != null) {\n\t\t\t\t\tgetParent().requestDisallowInterceptTouchEvent(true);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase MotionEvent.ACTION_UP:\n\t\t\t\tif (!isScrollingPerformed) {\n\t\t\t\t\tint distance = (int) event.getY() - getHeight() / 2;\n\t\t\t\t\tif (distance > 0) {\n\t\t\t\t\t\tdistance += getItemHeight() / 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdistance -= getItemHeight() / 2;\n\t\t\t\t\t}\n\t\t\t\t\tint items = distance / getItemHeight();\n\t\t\t\t\tif (items != 0 && isValidItemIndex(currentItem + items)) {\n\t\t\t\t\t\tnotifyClickListenersAboutClick(currentItem + items);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn scroller.onTouchEvent(event);\n\t}\n\n\t/**\n\t * Scrolls the wheel\n\t * @param delta the scrolling value\n\t */\n\tprivate void doScroll(int delta) {\n\t\tscrollingOffset += delta;\n\n\t\tint itemHeight = getItemHeight();\n\t\tint count = scrollingOffset / itemHeight;\n\n\t\tint pos = currentItem - count;\n\t\tint itemCount = viewAdapter.getItemsCount();\n\n\t\tint fixPos = scrollingOffset % itemHeight;\n\t\tif (Math.abs(fixPos) <= itemHeight / 2) {\n\t\t\tfixPos = 0;\n\t\t}\n\t\tif (isCyclic && itemCount > 0) {\n\t\t\tif (fixPos > 0) {\n\t\t\t\tpos--;\n\t\t\t\tcount++;\n\t\t\t} else if (fixPos < 0) {\n\t\t\t\tpos++;\n\t\t\t\tcount--;\n\t\t\t}\n\t\t\t// fix position by rotating\n\t\t\twhile (pos < 0) {\n\t\t\t\tpos += itemCount;\n\t\t\t}\n\t\t\tpos %= itemCount;\n\t\t} else {\n\t\t\t//\n\t\t\tif (pos < 0) {\n\t\t\t\tcount = currentItem;\n\t\t\t\tpos = 0;\n\t\t\t} else if (pos >= itemCount) {\n\t\t\t\tcount = currentItem - itemCount + 1;\n\t\t\t\tpos = itemCount - 1;\n\t\t\t} else if (pos > 0 && fixPos > 0) {\n\t\t\t\tpos--;\n\t\t\t\tcount++;\n\t\t\t} else if (pos < itemCount - 1 && fixPos < 0) {\n\t\t\t\tpos++;\n\t\t\t\tcount--;\n\t\t\t}\n\t\t}\n\n\t\tint offset = scrollingOffset;\n\t\tif (pos != currentItem) {\n\t\t\tsetCurrentItem(pos, false);\n\t\t} else {\n\t\t\tinvalidate();\n\t\t}\n\n\t\t// update offset\n\t\tscrollingOffset = offset - count * itemHeight;\n\t\tif (scrollingOffset > getHeight()) {\n\t\t\tscrollingOffset = scrollingOffset % getHeight() + getHeight();\n\t\t}\n\t}\n\n\t/**\n\t * Scroll the wheel\n\t * @param itemsToScroll items to scroll\n\t * @param time scrolling duration\n\t */\n\tpublic void scroll(int itemsToScroll, int time) {\n\t\tint distance = itemsToScroll * getItemHeight() - scrollingOffset;\n\t\tscroller.scroll(distance, time);\n\t}\n\n\t/**\n\t * Calculates range for wheel items\n\t * @return the items range\n\t */\n\tprivate ItemsRange getItemsRange() {\n\t\tif (getItemHeight() == 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tint first = currentItem;\n\t\tint count = 1;\n\n\t\twhile (count * getItemHeight() < getHeight()) {\n\t\t\tfirst--;\n\t\t\tcount += 2; // top + bottom items\n\t\t}\n\n\t\tif (scrollingOffset != 0) {\n\t\t\tif (scrollingOffset > 0) {\n\t\t\t\tfirst--;\n\t\t\t}\n\t\t\tcount++;\n\n\t\t\t// process empty items above the first or below the second\n\t\t\tint emptyItems = scrollingOffset / getItemHeight();\n\t\t\tfirst -= emptyItems;\n\t\t\tcount += Math.asin(emptyItems);\n\t\t}\n\t\treturn new ItemsRange(first, count);\n\t}\n\n\t/**\n\t * Rebuilds wheel items if necessary. Caches all unused items.\n\t * \n\t * @return true if items are rebuilt\n\t */\n\tprivate boolean rebuildItems() {\n\t\tboolean updated = false;\n\t\tItemsRange range = getItemsRange();\n\t\tif (itemsLayout != null) {\n\t\t\tint first = recycle.recycleItems(itemsLayout, firstItem, range);\n\t\t\tupdated = firstItem != first;\n\t\t\tfirstItem = first;\n\t\t} else {\n\t\t\tcreateItemsLayout();\n\t\t\tupdated = true;\n\t\t}\n\n\t\tif (!updated) {\n\t\t\tupdated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount();\n\t\t}\n\n\t\tif (firstItem > range.getFirst() && firstItem <= range.getLast()) {\n\t\t\tfor (int i = firstItem - 1; i >= range.getFirst(); i--) {\n\t\t\t\tif (!addViewItem(i, true)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfirstItem = i;\n\t\t\t}\n\t\t} else {\n\t\t\tfirstItem = range.getFirst();\n\t\t}\n\n\t\tint first = firstItem;\n\t\tfor (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) {\n\t\t\tif (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) {\n\t\t\t\tfirst++;\n\t\t\t}\n\t\t}\n\t\tfirstItem = first;\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Updates view. Rebuilds items and label if necessary, recalculate items sizes.\n\t */\n\tprivate void updateView() {\n\t\tif (rebuildItems()) {\n\t\t\tcalculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);\n\t\t\tlayout(getWidth(), getHeight());\n\t\t}\n\t}\n\n\t/**\n\t * Creates item layouts if necessary\n\t */\n\tprivate void createItemsLayout() {\n\t\tif (itemsLayout == null) {\n\t\t\titemsLayout = new LinearLayout(getContext());\n\t\t\titemsLayout.setOrientation(LinearLayout.VERTICAL);\n\t\t}\n\t}\n\n\t/**\n\t * Builds view for measuring\n\t */\n\tprivate void buildViewForMeasuring() {\n\t\t// clear all items\n\t\tif (itemsLayout != null) {\n\t\t\trecycle.recycleItems(itemsLayout, firstItem, new ItemsRange());\n\t\t} else {\n\t\t\tcreateItemsLayout();\n\t\t}\n\n\t\t// add views\n\t\tint addItems = visibleItems / 2;\n\t\tfor (int i = currentItem + addItems; i >= currentItem - addItems; i--) {\n\t\t\tif (addViewItem(i, true)) {\n\t\t\t\tfirstItem = i;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Adds view for item to items layout\n\t * @param index the item index\n\t * @param first the flag indicates if view should be first\n\t * @return true if corresponding item exists and is added\n\t */\n\tprivate boolean addViewItem(int index, boolean first) {\n\t\tView view = getItemView(index);\n\t\tif (view != null) {\n\t\t\tif (first) {\n\t\t\t\titemsLayout.addView(view, 0);\n\t\t\t} else {\n\t\t\t\titemsLayout.addView(view);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Checks whether intem index is valid\n\t * @param index the item index\n\t * @return true if item index is not out of bounds or the wheel is cyclic\n\t */\n\tprivate boolean isValidItemIndex(int index) {\n\t\treturn viewAdapter != null && viewAdapter.getItemsCount() > 0 &&\n\t\t\t\t(isCyclic || index >= 0 && index < viewAdapter.getItemsCount());\n\t}\n\n\t/**\n\t * Returns view for specified item\n\t * @param index the item index\n\t * @return item view or empty view if index is out of bounds\n\t */\n\tprivate View getItemView(int index) {\n\t\tif (viewAdapter == null || viewAdapter.getItemsCount() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tint count = viewAdapter.getItemsCount();\n\t\tif (!isValidItemIndex(index)) {\n\t\t\treturn viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout);\n\t\t} else {\n\t\t\twhile (index < 0) {\n\t\t\t\tindex = count + index;\n\t\t\t}\n\t\t}\n\n\t\tindex %= count;\n\t\treturn viewAdapter.getItem(index, recycle.getItem(), itemsLayout);\n\t}\n\n\t/**\n\t * Stops scrolling\n\t */\n\tpublic void stopScrolling() {\n\t\tscroller.stopScrolling();\n\t}\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AbstractWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.database.DataSetObserver;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Abstract Wheel adapter.\n */\npublic abstract class AbstractWheelAdapter implements WheelViewAdapter {\n    // Observers\n    private List<DataSetObserver> datasetObservers;\n    \n    @Override\n    public View getEmptyItem(View convertView, ViewGroup parent) {\n        return null;\n    }\n\n    @Override\n    public void registerDataSetObserver(DataSetObserver observer) {\n        if (datasetObservers == null) {\n            datasetObservers = new LinkedList<DataSetObserver>();\n        }\n        datasetObservers.add(observer);\n    }\n\n    @Override\n    public void unregisterDataSetObserver(DataSetObserver observer) {\n        if (datasetObservers != null) {\n            datasetObservers.remove(observer);\n        }\n    }\n    \n    /**\n     * Notifies observers about data changing\n     */\n    protected void notifyDataChangedEvent() {\n        if (datasetObservers != null) {\n            for (DataSetObserver observer : datasetObservers) {\n                observer.onChanged();\n            }\n        }\n    }\n    \n    /**\n     * Notifies observers about invalidating data\n     */\n    protected void notifyDataInvalidatedEvent() {\n        if (datasetObservers != null) {\n            for (DataSetObserver observer : datasetObservers) {\n                observer.onInvalidated();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AbstractWheelTextAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\n/**\n * Abstract wheel adapter provides common functionality for adapters.\n */\npublic abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {\n    \n    /** Text view resource. Used as a default view for adapter. */\n    public static final int TEXT_VIEW_ITEM_RESOURCE = -1;\n    \n    /** No resource constant. */\n    protected static final int NO_RESOURCE = 0;\n    \n    /** Default text color */\n    public static final int DEFAULT_TEXT_COLOR = 0xFF585858;\n    \n    /** Default text color */\n    public static final int LABEL_COLOR = 0xFF700070;\n    \n    /** Default text size */\n    public static final int DEFAULT_TEXT_SIZE = 18;\n    \n    // Text settings\n    private int textColor = DEFAULT_TEXT_COLOR;\n    private int textSize = DEFAULT_TEXT_SIZE;\n    \n    // Current context\n    protected Context context;\n    // Layout inflater\n    protected LayoutInflater inflater;\n    \n    // Items resources\n    protected int itemResourceId;\n    protected int itemTextResourceId;\n    \n    // Empty items resources\n    protected int emptyItemResourceId;\n\t\n    /**\n     * Constructor\n     * @param context the current context\n     */\n    protected AbstractWheelTextAdapter(Context context) {\n        this(context, TEXT_VIEW_ITEM_RESOURCE);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views\n     */\n    protected AbstractWheelTextAdapter(Context context, int itemResource) {\n        this(context, itemResource, NO_RESOURCE);\n    }\n    \n    /**\n     * Constructor\n     * @param context the current context\n     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views\n     * @param itemTextResource the resource ID for a text view in the item layout\n     */\n    protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) {\n        this.context = context;\n        itemResourceId = itemResource;\n        itemTextResourceId = itemTextResource;\n        \n        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);\n    }\n    \n    /**\n     * Gets text color\n     * @return the text color\n     */\n    public int getTextColor() {\n        return textColor;\n    }\n    \n    /**\n     * Sets text color\n     * @param textColor the text color to set\n     */\n    public void setTextColor(int textColor) {\n        this.textColor = textColor;\n    }\n    \n    /**\n     * Gets text size\n     * @return the text size\n     */\n    public int getTextSize() {\n        return textSize;\n    }\n    \n    /**\n     * Sets text size\n     * @param textSize the text size to set\n     */\n    public void setTextSize(int textSize) {\n        this.textSize = textSize;\n    }\n    \n    /**\n     * Gets resource Id for items views\n     * @return the item resource Id\n     */\n    public int getItemResource() {\n        return itemResourceId;\n    }\n    \n    /**\n     * Sets resource Id for items views\n     * @param itemResourceId the resource Id to set\n     */\n    public void setItemResource(int itemResourceId) {\n        this.itemResourceId = itemResourceId;\n    }\n    \n    /**\n     * Gets resource Id for text view in item layout \n     * @return the item text resource Id\n     */\n    public int getItemTextResource() {\n        return itemTextResourceId;\n    }\n    \n    /**\n     * Sets resource Id for text view in item layout \n     * @param itemTextResourceId the item text resource Id to set\n     */\n    public void setItemTextResource(int itemTextResourceId) {\n        this.itemTextResourceId = itemTextResourceId;\n    }\n\n    /**\n     * Gets resource Id for empty items views\n     * @return the empty item resource Id\n     */\n    public int getEmptyItemResource() {\n        return emptyItemResourceId;\n    }\n\n    /**\n     * Sets resource Id for empty items views\n     * @param emptyItemResourceId the empty item resource Id to set\n     */\n    public void setEmptyItemResource(int emptyItemResourceId) {\n        this.emptyItemResourceId = emptyItemResourceId;\n    }\n    \n    \n    /**\n     * Returns text for specified item\n     * @param index the item index\n     * @return the text of specified items\n     */\n    protected abstract CharSequence getItemText(int index);\n\n    @Override\n    public View getItem(int index, View convertView, ViewGroup parent) {\n        if (index >= 0 && index < getItemsCount()) {\n            if (convertView == null) {\n                convertView = getView(itemResourceId, parent);\n            }\n            TextView textView = getTextView(convertView, itemTextResourceId);\n            if (textView != null) {\n                CharSequence text = getItemText(index);\n                if (text == null) {\n                    text = \"\";\n                }\n                textView.setText(text);\n    \n                if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {\n                    configureTextView(textView);\n                }\n            }\n            return convertView;\n        }\n    \treturn null;\n    }\n\n    @Override\n    public View getEmptyItem(View convertView, ViewGroup parent) {\n        if (convertView == null) {\n            convertView = getView(emptyItemResourceId, parent);\n        }\n        if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {\n            configureTextView((TextView)convertView);\n        }\n            \n        return convertView;\n\t}\n\n    /**\n     * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.\n     * @param view the text view to be configured\n     */\n    protected void configureTextView(TextView view) {\n        view.setTextColor(textColor);\n        view.setGravity(Gravity.CENTER);\n        view.setTextSize(textSize);\n        view.setEllipsize(TextUtils.TruncateAt.END);\n        view.setLines(1);\n//        view.setCompoundDrawablePadding(20);\n//        view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);\n    }\n    \n    /**\n     * Loads a text view from view\n     * @param view the text view or layout containing it\n     * @param textResource the text resource Id in layout\n     * @return the loaded text view\n     */\n    private TextView getTextView(View view, int textResource) {\n    \tTextView text = null;\n    \ttry {\n            if (textResource == NO_RESOURCE && view instanceof TextView) {\n                text = (TextView) view;\n            } else if (textResource != NO_RESOURCE) {\n                text = (TextView) view.findViewById(textResource);\n            }\n        } catch (ClassCastException e) {\n            Log.e(\"AbstractWheelAdapter\", \"You must supply a resource ID for a TextView\");\n            throw new IllegalStateException(\n                    \"AbstractWheelAdapter requires the resource ID to be a TextView\", e);\n        }\n        \n        return text;\n    }\n    \n    /**\n     * Loads view from resources\n     * @param resource the resource Id\n     * @return the loaded view or null if resource is not set\n     */\n    private View getView(int resource, ViewGroup parent) {\n        switch (resource) {\n        case NO_RESOURCE:\n            return null;\n        case TEXT_VIEW_ITEM_RESOURCE:\n            return new TextView(context);\n        default:\n            return inflater.inflate(resource, parent, false);    \n        }\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/AdapterWheel.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.view.wheel.WheelAdapter;\n\n/**\n * Adapter class for old wheel adapter (deprecated WheelAdapter class).\n * \n * @deprecated Will be removed soon\n */\npublic class AdapterWheel extends AbstractWheelTextAdapter {\n\n    // Source adapter\n    private WheelAdapter adapter;\n    \n    /**\n     * Constructor\n     * @param context the current context\n     * @param adapter the source adapter\n     */\n    public AdapterWheel(Context context, WheelAdapter adapter) {\n        super(context);\n        \n        this.adapter = adapter;\n    }\n\n    /**\n     * Gets original adapter\n     * @return the original adapter\n     */\n    public WheelAdapter getAdapter() {\n        return adapter;\n    }\n    \n    @Override\n    public int getItemsCount() {\n        return adapter.getItemsCount();\n    }\n\n    @Override\n    protected CharSequence getItemText(int index) {\n        return adapter.getItem(index);\n    }\n\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/ArrayWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\n\nimport com.boredream.bdcodehelper.entity.city.BaseAddressModel;\n\nimport java.util.ArrayList;\n\n/**\n * The simple Array wheel adapter\n *\n * @param <T> the element type\n */\npublic class ArrayWheelAdapter<T> extends AbstractWheelTextAdapter {\n\n    // items\n    private ArrayList<T> items;\n\n    /**\n     * Constructor\n     *\n     * @param context the current context\n     * @param items   the items\n     */\n    public ArrayWheelAdapter(Context context, ArrayList<T> items) {\n        super(context);\n\n        //setEmptyItemResource(TEXT_VIEW_ITEM_RESOURCE);\n        this.items = items;\n    }\n\n    @Override\n    public CharSequence getItemText(int index) {\n        if (index >= 0 && index < items.size()) {\n            T item = items.get(index);\n            if (item instanceof BaseAddressModel) {\n                return ((BaseAddressModel) item).name;\n            } else if(item instanceof String) {\n                return item.toString();\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public int getItemsCount() {\n        return items.size();\n    }\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/NumericWheelAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.content.Context;\n\n/**\n * Numeric Wheel adapter.\n */\npublic class NumericWheelAdapter extends AbstractWheelTextAdapter {\n    \n    /** The default min value */\n    public static final int DEFAULT_MAX_VALUE = 9;\n\n    /** The default max value */\n    private static final int DEFAULT_MIN_VALUE = 0;\n    \n    // Values\n    private int minValue;\n    private int maxValue;\n    \n    // format\n    private String format;\n    \n    /**\n     * Constructor\n     * @param context the current context\n     */\n    public NumericWheelAdapter(Context context) {\n        this(context, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param minValue the wheel min value\n     * @param maxValue the wheel max value\n     */\n    public NumericWheelAdapter(Context context, int minValue, int maxValue) {\n        this(context, minValue, maxValue, null);\n    }\n\n    /**\n     * Constructor\n     * @param context the current context\n     * @param minValue the wheel min value\n     * @param maxValue the wheel max value\n     * @param format the format string\n     */\n    public NumericWheelAdapter(Context context, int minValue, int maxValue, String format) {\n        super(context);\n        \n        this.minValue = minValue;\n        this.maxValue = maxValue;\n        this.format = format;\n    }\n\n    @Override\n    public CharSequence getItemText(int index) {\n        if (index >= 0 && index < getItemsCount()) {\n            int value = minValue + index;\n            return format != null ? String.format(format, value) : Integer.toString(value);\n        }\n        return null;\n    }\n\n    @Override\n    public int getItemsCount() {\n        return maxValue - minValue + 1;\n    }    \n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/java/com/boredream/bdcodehelper/view/wheel/adapters/WheelViewAdapter.java",
    "content": "/*\n *  Copyright 2011 Yuri Kanivets\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.boredream.bdcodehelper.view.wheel.adapters;\n\nimport android.database.DataSetObserver;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * Wheel items adapter interface\n */\npublic interface WheelViewAdapter {\n\t/**\n\t * Gets items count\n\t * @return the count of wheel items\n\t */\n\tpublic int getItemsCount();\n\t\n\t/**\n\t * Get a View that displays the data at the specified position in the data set\n\t * \n\t * @param index the item index\n\t * @param convertView the old view to reuse if possible\n\t * @param parent the parent that this view will eventually be attached to\n\t * @return the wheel item View\n\t */\n\tpublic View getItem(int index, View convertView, ViewGroup parent);\n\n\t/**\n\t * Get a View that displays an empty wheel item placed before the first or after\n\t * the last wheel item.\n\t * \n\t * @param convertView the old view to reuse if possible\n     * @param parent the parent that this view will eventually be attached to\n\t * @return the empty item View\n\t */\n\tpublic View getEmptyItem(View convertView, ViewGroup parent);\n\t\n\t/**\n\t * Register an observer that is called when changes happen to the data used by this adapter.\n\t * @param observer the observer to be registered\n\t */\n\tpublic void registerDataSetObserver(DataSetObserver observer);\n\t\n\t/**\n\t * Unregister an observer that has previously been registered\n\t * @param observer the observer to be unregistered\n\t */\n\tvoid unregisterDataSetObserver(DataSetObserver observer);\n}\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/anim/dd_mask_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <alpha\n        android:fromAlpha=\"0\"\n        android:toAlpha=\"1\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/anim/dd_mask_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <alpha\n        android:fromAlpha=\"1\"\n        android:toAlpha=\"0\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/anim/dd_menu_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <translate\n        android:fromYDelta=\"-100%p\"\n        android:toYDelta=\"0\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/anim/dd_menu_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:duration=\"250\">\n    <translate\n        android:fromYDelta=\"0\"\n        android:toYDelta=\"-100%p\"/>\n\n</set>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/color/txt_blue2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@color/txt_link_blue\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/color/txt_gray2primarydark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/colorPrimaryDark\" android:state_checked=\"true\" />\n    <item android:color=\"@color/txt_gray\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/color/txt_lgray2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@android:color/white\" android:state_checked=\"true\" />\n    <item android:color=\"@color/txt_light_gray\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/color/txt_primary2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@android:color/white\" android:state_checked=\"true\" />\n    <item android:color=\"@color/colorPrimary\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/color/txt_white2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"@color/txt_gray\" android:state_enabled=\"false\" />\n    <item android:color=\"@android:color/white\" />\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/bg_gray2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@color/bg_gray\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/bg_primary2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/colorPrimaryDark\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@color/colorPrimaryDark\" android:state_pressed=\"true\"/>\n    <item android:drawable=\"@color/colorPrimary\"/>\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/bg_primarydark_indicator_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/layerlist_primarydark_indicator\" android:state_checked=\"true\" />\n    <item android:drawable=\"@android:color/transparent\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/bg_tran2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@android:color/transparent\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/bg_white2gray_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_checked=\"true\" />\n    <item android:drawable=\"@color/bg_gray_pressed\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@android:color/white\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/cirrect_10a_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/bg_position_bar_down\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/cirrect_5a_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/bg_position_bar_up\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/cirrect_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"99dp\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/correct_gray_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/divider_gray\" />\n\n    <solid android:color=\"@android:color/white\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/correct_primary.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/correct_primary2dark_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/correct_primary_light\" android:state_enabled=\"false\" />\n    <item android:drawable=\"@drawable/correct_primary_dark\" android:state_pressed=\"true\" />\n    <item android:drawable=\"@drawable/correct_primary\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/correct_primary_dark.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimaryDark\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/correct_primary_light.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <solid android:color=\"@color/colorPrimaryLight\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/correct_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\" />\n\n    <corners android:radius=\"@dimen/corner_radius\" />\n\n</shape>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/correct_primary_stroke2solid_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/correct_primary\" android:state_checked=\"true\" />\n    <item android:drawable=\"@drawable/correct_primary_stroke\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/layerlist_primarydark_indicator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:top=\"28dp\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"@color/colorPrimaryDark\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/oval_primary_light_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@color/colorPrimaryLight\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/oval_primary_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@color/colorPrimary\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/shape_bottom_line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:left=\"-1dp\"\n        android:right=\"-1dp\">\n        <shape>\n            <stroke\n                android:width=\"1dp\"\n                android:color=\"@color/divider_gray\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/shape_oval_primary2white_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/oval_primary_solid\" android:state_checked=\"true\" />\n\n    <item android:drawable=\"@drawable/shape_oval_white_solid\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/shape_oval_primary_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/transparent\"></solid>\n\n    <stroke\n        android:width=\"1dp\"\n        android:color=\"@color/colorPrimary\"></stroke>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/shape_oval_primary_stroke2solid_sel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/oval_primary_solid\" android:state_checked=\"true\" />\n\n    <item android:drawable=\"@drawable/shape_oval_primary_stroke\" />\n\n</selector>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/shape_oval_red_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/holo_red_dark\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/shape_oval_white_solid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid android:color=\"@android:color/white\"></solid>\n\n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/shape_top_line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:bottom=\"-2dp\"\n        android:left=\"-2dp\"\n        android:right=\"-2dp\">\n        <shape>\n            <stroke\n                android:width=\"1dp\"\n                android:color=\"@color/divider_gray\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/wheel_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- \n    Android Wheel Control.\n    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html\n   \n    Copyright 2010 Yuri Kanivets\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\t\n</layer-list>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/drawable/wheel_val.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- \n    Android Wheel Control.\n    http://android-devblog.blogspot.com/2010/05/wheel-ui-contol.html\n   \n    Copyright 2010 Yuri Kanivets\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <!-- \n\t<gradient\n\t\tandroid:startColor=\"#70222222\"\n\t\tandroid:centerColor=\"#70222222\"\n\t\tandroid:endColor=\"#70EEEEEE\"\n\t\tandroid:angle=\"90\" />\n\t\t -->\n\n\t<stroke android:width=\"1dp\" android:color=\"#C7C7C7\" /> \n</shape>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/activity_image_browser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\">\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/vp_image_brower\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </android.support.v4.view.ViewPager>\n\n    <TextView\n        android:id=\"@+id/tv_image_index\"\n        style=\"@style/TextAppearance.AppCompat.Headline\"\n        android:layout_width=\"88dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginTop=\"8dp\"\n        android:gravity=\"center\"\n        android:padding=\"4dp\"\n        android:text=\"1/9\"\n        android:textColor=\"@android:color/white\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/activity_web_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <include layout=\"@layout/include_titlebar\" />\n\n    <WebView\n        android:id=\"@+id/webview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </WebView>\n\n</LinearLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/footer_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\"\n    android:padding=\"@dimen/margin_medium\">\n\n    <ProgressBar\n        android:id=\"@+id/pb_footer_progress\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:indeterminateDuration=\"900\" />\n\n    <TextView\n        android:id=\"@+id/tv_footer_progress\"\n        style=\"@style/TextViewCaption\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"没有更多数据\"\n        android:visibility=\"gone\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/formitem_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        android:id=\"@+id/tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"56dp\"\n        android:gravity=\"center_vertical\"\n        android:layout_centerVertical=\"true\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <EditText\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/EditTextSingleLine\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@null\"\n        android:paddingLeft=\"80dp\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/formitem_select.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <TextView\n        android:id=\"@+id/tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"56dp\"\n        android:layout_centerVertical=\"true\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"@color/txt_gray\" />\n\n    <LinearLayout\n        android:id=\"@+id/ll_mid_container\"\n        android:layout_width=\"match_parent\"\n        android:visibility=\"gone\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"80dp\"\n        android:paddingRight=\"@dimen/margin_large\">\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:paddingLeft=\"80dp\"\n        android:paddingRight=\"@dimen/margin_large\" />\n\n    <ImageView\n        android:id=\"@+id/iv_right\"\n        android:layout_width=\"18dp\"\n        android:layout_height=\"18dp\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\" />\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/include_banner_with_indicator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/include_banner_with_indicator\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/banner_height\">\n\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/vp_banner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/banner_height\">\n    </android.support.v4.view.ViewPager>\n\n    <RadioGroup\n        android:id=\"@+id/rg_indicator\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignBottom=\"@+id/vp_banner\"\n        android:layout_alignRight=\"@+id/vp_banner\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"@dimen/margin_small\"\n        android:layout_marginRight=\"@dimen/margin_medium\"\n        android:orientation=\"horizontal\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/include_ddm_listview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ListView\n        android:id=\"@+id/lv_ddm\"\n        style=\"@style/AbsListViewCommon\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/margin_large\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/include_group_divider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/margin_small\"\n    android:orientation=\"vertical\">\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:background=\"@color/bg_gray\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1px\"\n        android:background=\"@color/divider_gray\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/include_refresh_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.SwipeRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/srl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n</android.support.v4.widget.SwipeRefreshLayout>\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/include_titlebar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/rl_titlebar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48dp\"\n    android:background=\"@color/colorPrimary\"\n    android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/titlebar_iv_left\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:padding=\"13dp\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv_left\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\"\n        android:textColor=\"@android:color/white\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv\"\n        style=\"@style/TextViewTitle\"\n        android:layout_centerInParent=\"true\"\n        android:gravity=\"center\"\n        android:maxWidth=\"224dp\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"26sp\" />\n\n    <ImageView\n        android:id=\"@+id/titlebar_iv_right\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:padding=\"13dp\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/titlebar_tv_right\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:background=\"@drawable/bg_primary2dark_sel\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_medium\"\n        android:textColor=\"@android:color/white\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/item_default_drop_down.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"32dp\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        style=\"@style/TextViewCaption\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"32dp\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"54dp\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/item_image_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/banner_height\">\n\n    <ImageView\n        android:id=\"@+id/iv_image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/banner_height\"\n        android:scaleType=\"centerCrop\" />\n\n    <TextView\n        android:id=\"@+id/tv_title\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"24dp\"\n        android:layout_alignBottom=\"@id/iv_image\"\n        android:background=\"#3000\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"@dimen/margin_medium\"\n        android:paddingRight=\"@dimen/margin_huge\"\n        android:textColor=\"@android:color/white\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/item_image_browser.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/iv_image_browser\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitCenter\" />\n\n    <ProgressBar\n        android:id=\"@+id/pb_loading\"\n        style=\"@style/Widget.AppCompat.ProgressBar\"\n        android:layout_width=\"56dp\"\n        android:layout_height=\"56dp\"\n        android:layout_centerInParent=\"true\"\n        android:visibility=\"gone\" />\n\n</RelativeLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/item_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"?listPreferredItemHeightSmall\"\n    android:background=\"@drawable/bg_white2gray_sel\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingLeft=\"@dimen/margin_medium\"\n    android:paddingRight=\"@dimen/margin_medium\">\n\n    <ImageView\n        android:id=\"@+id/iv_left\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\" />\n\n    <TextView\n        android:id=\"@+id/tv_mid\"\n        style=\"@style/TextViewSubhead\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_small\" />\n\n    <ImageView\n        android:id=\"@+id/iv_red_dot\"\n        android:layout_width=\"8dp\"\n        android:layout_height=\"8dp\"\n        android:layout_gravity=\"top\"\n        android:layout_marginTop=\"@dimen/margin_medium\"\n        android:src=\"@drawable/shape_oval_red_solid\"\n        android:visibility=\"gone\" />\n\n    <View\n        android:layout_width=\"0dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\" />\n\n    <TextView\n        android:id=\"@+id/tv_right\"\n        style=\"@style/TextViewBody\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"@dimen/margin_medium\"\n        android:layout_marginRight=\"@dimen/margin_small\"\n        android:textColor=\"@color/txt_light_gray\"\n        android:visibility=\"gone\" />\n\n    <ImageView\n        android:id=\"@+id/iv_right\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:visibility=\"gone\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/listview_dropdown_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ListView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    style=\"@style/ListViewLineDivider\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n</ListView>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/layout/wheel_dialog_address.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"#E9E9E9\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"20dip\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"5dip\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"20dip\"\n            android:text=\"请选择省市区\"\n            android:textColor=\"#000000\"\n            android:textSize=\"20sp\" />\n    </RelativeLayout>\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"30dip\"\n        android:orientation=\"horizontal\">\n\n        <com.boredream.bdcodehelper.view.wheel.WheelView\n            android:id=\"@+id/id_province\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"></com.boredream.bdcodehelper.view.wheel.WheelView>\n\n        <com.boredream.bdcodehelper.view.wheel.WheelView\n            android:id=\"@+id/id_city\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"></com.boredream.bdcodehelper.view.wheel.WheelView>\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/btn_confirm\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dip\"\n        android:gravity=\"center\"\n        android:text=\"确定\"\n        android:textColor=\"#000000\" />\n\n</LinearLayout>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <declare-styleable name=\"DrawableTextView\">\n        <attr name=\"drawableWidth\" format=\"dimension\" />\n        <attr name=\"drawableHeight\" format=\"dimension\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"DropDownMenu\">\n        <attr name=\"ddunderlineColor\" format=\"color\" />\n        <attr name=\"dddividerColor\" format=\"color\" />\n        <attr name=\"ddtextSelectedColor\" format=\"color\" />\n        <attr name=\"ddtextUnselectedColor\" format=\"color\" />\n        <attr name=\"ddmenuBackgroundColor\" format=\"color\" />\n        <attr name=\"ddmaskColor\" format=\"color\" />\n        <attr name=\"ddmenuTextSize\" format=\"dimension\" />\n        <attr name=\"ddmenuSelectedIcon\" format=\"reference\" />\n        <attr name=\"ddmenuUnselectedIcon\" format=\"reference\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"BottomTabRadioButton\">\n        <attr name=\"hint_mode\" format=\"enum\">\n            <enum name=\"none\" value=\"0\" />\n            <enum name=\"point\" value=\"1\" />\n            <enum name=\"num\" value=\"2\" />\n        </attr>\n        <attr name=\"hint_color\" format=\"color\" />\n        <attr name=\"hint_toppadding\" format=\"dimension\" />\n        <attr name=\"hint_rightpadding\" format=\"dimension\" />\n        <attr name=\"point_radius\" format=\"dimension\" />\n        <attr name=\"num\" format=\"integer\" />\n        <attr name=\"num_radius\" format=\"dimension\" />\n        <attr name=\"num_size\" format=\"dimension\" />\n        <attr name=\"num_color\" format=\"color\" />\n    </declare-styleable>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- basic -->\n    <!-- 主色调 -->\n    <color name=\"colorPrimary\">#8BC34A</color>\n    <color name=\"colorPrimaryDark\">#76A63E</color>\n    <color name=\"colorPrimaryLight\">#E8F3BD</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"colorSecondary\">#ff9900</color>\n    <color name=\"colorSecondaryDark\">#d88200</color>\n    <!-- 主体文字,标题/标签 -->\n    <color name=\"txt_black\">#212121</color>\n    <!-- 内容文字,正文 -->\n    <color name=\"txt_gray\">#808080</color>\n    <!-- 辅助文字,提示 -->\n    <color name=\"txt_light_gray\">#CCCCCC</color>\n    <!-- 背景色 -->\n    <color name=\"bg_gray\">#f1f1f1</color>\n    <!-- 按下灰色 -->\n    <color name=\"bg_gray_pressed\">#e8e8e8</color>\n    <!-- 高亮,红棕色 -->\n    <color name=\"brown\">#d54c1c</color>\n    <!-- 分割线 -->\n    <color name=\"divider_gray\">#cbcbcb</color>\n    <!-- other -->\n    <color name=\"txt_link_blue\">#1ea5ff</color>\n\n    <!-- wheel -->\n    <color name=\"province_line_border\">#C7C7C7</color>\n\n    <!-- drop down menu -->\n    <color name=\"white\">#ffffff</color>\n    <color name=\"gray\">#cccccc</color>\n\n    <color name=\"drop_down_selected\">#8BC34A</color>\n    <color name=\"drop_down_unselected\">#808080</color>\n\n    <color name=\"mask_color\">#88888888</color>\n    <color name=\"check_bg\">#f1f1f1</color>\n    <color name=\"un_press_color\">#8BC34A</color>\n\n    <!-- position bar -->\n    <color name=\"bg_position_bar_up\">#0D8BC34A</color>\n    <color name=\"bg_position_bar_down\">#1A8BC34A</color>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/values/dimens.xml",
    "content": "<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n    <!-- margin -->\n    <dimen name=\"margin_tiny\">4dp</dimen>\n    <dimen name=\"margin_small\">8dp</dimen>\n    <dimen name=\"margin_medium\">16dp</dimen>\n    <dimen name=\"margin_large\">32dp</dimen>\n    <dimen name=\"margin_huge\">64dp</dimen>\n    <dimen name=\"margin_only_txt\">48dp</dimen>\n\n    <!-- txtsize -->\n    <dimen name=\"txtsize_display1\">34sp</dimen>\n    <dimen name=\"txtsize_headline\">24sp</dimen>\n    <dimen name=\"txtsize_title\">20sp</dimen>\n    <dimen name=\"txtsize_subhead\">16sp</dimen>\n    <dimen name=\"txtsize_body\">14sp</dimen>\n    <dimen name=\"txtsize_caption\">12sp</dimen>\n\n    <!-- other size -->\n    <dimen name=\"corner_radius\">2dp</dimen>\n    <dimen name=\"banner_height\">136dp</dimen>\n\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"dialog_positive\">确定</string>\n    <string name=\"dialog_negative\">取消</string>\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/bdcodehelper/src/main/res/values/styles.xml",
    "content": "<resources xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <style name=\"AppBaseTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n\n    </style>\n\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowFullscreen\">false</item>\n        <item name=\"android:windowActionBar\">false</item>\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"colorButtonNormal\">@color/colorPrimary</item>\n        <item name=\"colorControlActivated\">@color/colorPrimary</item>\n        <item name=\"android:windowBackground\">@color/bg_gray</item>\n    </style>\n\n    <style name=\"TextViewHeadline\" parent=\"TextAppearance.AppCompat.Headline\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:singleLine\">true</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewTitle\" parent=\"TextAppearance.AppCompat.Title\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:singleLine\">true</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewSubhead\" parent=\"TextAppearance.AppCompat.Subhead\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewBody\" parent=\"TextAppearance.AppCompat.Body1\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n    </style>\n\n    <style name=\"TextViewCaption\" parent=\"TextAppearance.AppCompat.Caption\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">@color/txt_light_gray</item>\n    </style>\n\n    <style name=\"EditTextSingleLine\" parent=\"@style/Widget.AppCompat.EditText\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">48dp</item>\n        <item name=\"android:textColorHint\">@color/txt_light_gray</item>\n        <item name=\"android:textColor\">@color/txt_black</item>\n        <item name=\"android:textSize\">@dimen/txtsize_subhead</item>\n        <item name=\"android:singleLine\">true</item>\n    </style>\n\n    <style name=\"ButtonPrimary\" parent=\"TextViewSubhead\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:textSize\">20sp</item>\n        <item name=\"android:textColor\">@color/txt_white2gray_sel</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:background\">@drawable/correct_primary2dark_sel</item>\n    </style>\n\n    <style name=\"RadioButtonBottomTab\">\n        <item name=\"android:layout_weight\">1</item>\n        <item name=\"android:layout_width\">0dp</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:button\">@null</item>\n        <item name=\"android:background\">@drawable/bg_white2gray_sel</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:paddingBottom\">@dimen/margin_small</item>\n        <item name=\"android:paddingTop\">@dimen/margin_small</item>\n    </style>\n\n    <style name=\"AbsListViewCommon\" parent=\"Widget.AppCompat.ListView\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:cacheColorHint\">@android:color/transparent</item>\n        <item name=\"android:listSelector\">@android:color/transparent</item>\n        <item name=\"android:divider\">@null</item>\n        <item name=\"android:dividerHeight\">0dp</item>\n        <item name=\"android:scrollbars\">none</item>\n    </style>\n\n    <style name=\"ListViewLineDivider\" parent=\"AbsListViewCommon\">\n        <item name=\"android:divider\">@color/divider_gray</item>\n        <item name=\"android:dividerHeight\">1px</item>\n    </style>\n\n    <style name=\"GridViewImages\" parent=\"AbsListViewCommon\">\n        <item name=\"android:horizontalSpacing\">4dp</item>\n        <item name=\"android:verticalSpacing\">4dp</item>\n    </style>\n\n    <!-- 自定义对话框 -->\n    <style name=\"custom_dialog\" parent=\"Theme.AppCompat.Dialog\">\n        <item name=\"android:windowFrame\">@null</item>\n        <item name=\"android:windowIsFloating\">true</item>\n        <item name=\"android:windowIsTranslucent\">false</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:background\">@android:color/transparent</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n\n    </style>\n</resources>"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.1.2'\n        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n\n// Define versions in a single place\next {\n    // Sdk and tools\n    minSdkVersion = 15\n    targetSdkVersion = 23\n    compileSdkVersion = 23\n    buildToolsVersion = '23.0.3'\n\n    // App dependencies\n    supportLibraryVersion = '23.4.0'\n    guavaVersion = '18.0'\n    junitVersion = '4.12'\n    mockitoVersion = '1.10.19'\n    powerMockito = '1.6.2'\n    hamcrestVersion = '1.3'\n    runnerVersion = '0.5'\n    rulesVersion = '0.5'\n    espressoVersion = '2.2.2'\n    retrofitVersion = '2.0.0-beta2'\n    okhttploggingVersion = '2.6.0'\n    rxjavaVersion = '1.1.0'\n    rxbindingVersion = '0.2.0'\n    glideVersion = '3.6.1'\n    glideokhttpVersion = '1.3.1'\n    photoviewVersion = '1.2.4'\n    daggerVersion = '2.5'\n}"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Dec 28 10:00:20 PST 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "DesignResCollection_MVP-Dagger2/settings.gradle",
    "content": "include ':app', ':bdcodehelper'\n"
  },
  {
    "path": "README.md",
    "content": "# DesignResCollection\n  提供同一个App的不同架构实现，对其进行对比分析，方便大家选取使用  \n  项目启发来自谷歌的同类框架项目 https://github.com/googlesamples/android-architecture  \n  \n  \n## 代码示例 [持续开发中...]\n\n  显示设计网站中收集来的资源的一个应用DesignResCollection，不同结构对应不同的[_结构后缀]。  \n比如基本的MVP结构就是 DesignResCollection_MVP。不同结构的具体介绍请查看对应文件夹中的README.md  \n  \n  \n### 已开发完成的示例\n\n  * [DesignResCollection_MVC/](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVC) - Model-View-Controller 结构。\n  * [DesignResCollection_MVP/](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP) - Model-View-Presenter 结构。其中包含了针对P层的junit逻辑测试代码以及针对V层的Espresso页面测试代码。\n  \n### 待开发的示例\n\n  * [DesignResCollection_LeanCloud/](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP-Dagger2) - 基于 LeanCloud 服务，不用自己写后台服务端代码，非全栈开发也可以完成完整网络应用。\n  * [DesignResCollection_IM/](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP-Dagger2) - 基于 LeanCloud 服务，实现IM及时聊天业务，提供最基本的IM相关功能。\n  * [DesignResCollection_Espresso/](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP-Dagger2) - 单独抽取出来一个项目，详细介绍Espresso针对各种常用场景的测试写法。\n  \n  \n### 其他相关示例\n  * [DesignResCollection（ing...）](https://github.com/boredream/DesignResCollectionApp) - 完整App代码，不断丰富完善中，实现一个最终完整版。本项目中的示例是基于此项目做了功能和页面上的精简，便于演示不同代码结构。\n  * [DesignCollectionCloudEngine](https://github.com/boredream/DesignCollectionCloudEngine) - 部署在LeanCloud上的云代码项目，用于定时爬取数据保存到LeanCloud中为应用提供数据来源的。\n  \n\n## 开发计划\n\n* 2016.8.15 ~ 8.17（已完成）\n[DesignResCollection_MVC/](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVC)\n\n* 2016.8.17 ~ 9.20（已完成）\n[DesignResCollection_MVP/](https://github.com/boredream/DesignResCollection/tree/master/DesignResCollection_MVP)\n\n\n## 通用依赖框架\n\n  * 使用LeanCloud作为后端服务，比较简单，无需自行开发。  \n  * 使用LeanCloud的Restful-API接口。（不用LeanCloud的Android SDK，更贴近于实际开发中用开发接口文档的情景）  \n  * 网络框架部分使用Retrofit2.0 + RxJava。  \n  * 图片使用Glide。  \n  * [代码助手Model ](https://github.com/boredream/bdcodehelper)常见工具类、功能等都封装到了这个依赖Model中，一来为了方便，二来让注意力更集中在项目框架结构上。\n  * 使用Espresso进行UI页面交互测试\n  * 使用mockito对Presenter分别进行真实接口数据测试以及mock模拟数据测试\n  \n\n## 到底使用哪种框架使用在我自己的app中？\n\n  每个框架示例中都有一个README，你可以先查看下每种的特点。  \n最终项目里还会对比下所有框架的优缺点列出来，方便你根据自己具体情况进行全面的比较选取。  \n  \n  \n## 应用截图\n<img src=\"https://github.com/boredream/DesignResCollection/blob/master/screenshoot/device-2016-08-17-142555.png\" width=\"300\" height=\"530\">\n<img src=\"https://github.com/boredream/DesignResCollection/blob/master/screenshoot/device-2016-08-17-142654.png\" width=\"300\" height=\"530\">\n<img src=\"https://github.com/boredream/DesignResCollection/blob/master/screenshoot/device-2016-08-17-142712.png\" width=\"300\" height=\"530\">\n<img src=\"https://github.com/boredream/DesignResCollection/blob/master/screenshoot/device-2016-08-17-142739.png\" width=\"300\" height=\"530\">\n  \n  \n## 使用\n\n下载~ 解压~ Open对应框架项目的文件夹\n\n\n## 为什么要做这样一个项目 \n\n  Android 的框架多用MVC模型进行开发，而其中的Activity经常承担了大量的V和C的工作，既处理逻辑又处理UI。  \n因此Activity中很容易聚集大量代码，造成结构复杂混乱、测试维护困难等诸多不便。  \n  \n  这个项目就是为了帮助解决这个问题的。其中将提供一个相同的应用程序，然后使用不同的框架实现之。  \n\n  您可以使用本项目中的示例代码作为参考，或者直接作为项目的架子在此之上继续开发自己的项目。  \n本项目中，主要关注的重点在于代码的结构框架、测试以及可维护性。  \n但是要注意，这里提供了不同的架构，各自有自己的优缺点。因此在选取时要根据自己的需要选择对应的框架结构。  \n比如你只是一个简单的App，不需要单元测试，功能UI都比较少，那直接MVC结构即可。  \n"
  }
]