[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n.idea\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\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"
  },
  {
    "path": "README.md",
    "content": "# LoadingStateView\n\nEnglish | [中文](README_ZH.md)\n\n[![](https://www.jitpack.io/v/DylanCaiCoding/LoadingStateView.svg)](https://www.jitpack.io/#DylanCaiCoding/LoadingLoadingStateView) [![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/LICENSE)\n\n`LoadingStateView` is a highly expandable Android library for showing loading status view on the low-coupling way, the core function is implemented with a [Kotlin file](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt) of over 200 lines. it not only shows different view like loading, content, error, empty and customized view when loading network data, but also manages title bar.\n\n**Major update: With the Kotlin feature, you can quickly add all functionality to the base class without affecting existing code. The overall usage is further simplified with removing the `ViewHolder`. It is recommended to upgrade!**\n\n## Feature\n\n- No need to add view code to the layout.\n- Quickly add all functionality to the base class without affecting existing code. (Kotlin)\n- Support for use for Activity, Fragment, RecyclerView, View.\n- Support for show custom views.\n- Support for managing the title bar and add multiple headers.\n- Support for set reload event.\n- Support for update views anytime.\n- Support for use with most third-party libraries.\n\n## Demo\n\nClick or scan QR code to download\n\n[![QR code](docs/img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper)\n\n| [Activity(error)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ActErrorActivity.java) | [View(placeholder)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPlaceholderActivity.java) | [ViewPager(timeout)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPagerActivity.java) | [RecyclerView(cool loading)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/RecyclerViewActivity.java) |\n| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |\n|                 ![](docs/gif/activity_error.gif)                  |                ![](docs/gif/view_placeholder.gif)                 |                ![](docs/gif/viewpager_timeout.gif)                |              ![](docs/gif/recyclerview_loading.gif)               |\n\n| [SpecialHeader(custom)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/CustomHeaderActivity.java) | [MultipleHeader(search)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MultipleHeaderActivity.java) | [SpecialDecorView(scrolling)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ScrollingToolbarActivity.java) | [BottomDecorView(editor)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/BottomEditorActivity.java) |\n| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |\n|              ![](docs/gif/special_header_custom.gif)              |             ![](docs/gif/multiple_header_search.gif)              |             ![](docs/gif/special_decor_scrolling.gif)             |               ![](docs/gif/bottom_decor_editor.gif)               |\n\n## Usage\n\n:pencil: **[>> Usage documentation <<](https://dylancaicoding.github.io/LoadingStateView)**\n\n## Gradle\n\nAdd it in your root `build.gradle` at the end of repositories:\n\n```groovy\nallprojects {\n    repositories {\n        // ...\n        maven { url 'https://www.jitpack.io' }\n    }\n}\n```\n\nAdd dependencies in your module `build.gradle` :\n\n```groovy\ndependencies {\n    // java\n    implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview:5.0.0'\n\n    // kotlin\n    implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0'\n}\n```\n\n\n## Change log\n\n[Releases](https://github.com/DylanCaiCoding/LoadingStateView/releases)\n\n## Author's other libraries\n\n| Library                                                      | Description                                                  |\n| ------------------------------------------------------------ | ------------------------------------------------------------ |\n| [Longan](https://github.com/DylanCaiCoding/Longan)           | Probably the best Kotlin utils library for Android.  |\n| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | The most comprehensive utils of ViewBinding.                 |\n| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX)       | Use MMKV with property delegates.                                      |\n| [MultiBaseUrls](https://github.com/DylanCaiCoding/MultiBaseUrls) | Use annotation to allow Retrofit to support multiple baseUrl and dynamically change baseUrl |\n| [Tracker](https://github.com/DylanCaiCoding/Tracker)       | A lightweight tracking framework based on the tracking idea of Buzzvideo.|\n\n## Thanks\n\n- [luckbilly/Gloading](https://github.com/luckybilly/Gloading) Optimize my library standing on the shoulders of giants.\n- [drakeet/MultiType](https://github.com/drakeet/MultiType)  Referenced the usage of multiple adapters.\n- [dinuscxj/LoadingDrawable](https://github.com/dinuscxj/LoadingDrawable) The cool loading effect in the demo.\n\n## License\n\n```\n\nCopyright (C) 2019. Dylan Cai\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n"
  },
  {
    "path": "README_ZH.md",
    "content": "# LoadingStateView\n\n[English](README.md) | 中文\n\n[![](https://www.jitpack.io/v/DylanCaiCoding/LoadingStateView.svg)](https://www.jitpack.io/#DylanCaiCoding/LoadingLoadingStateView) [![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/LICENSE)\n\n`LoadingStateView` 是一个深度解耦缺省页和标题栏的工具，核心功能的实现代码只有一个 200 多行的 [Kotlin 文件](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt)。不仅能在请求网络数据时显示加载中、加载成功、加载失败、无数据的视图或自定义视图，还可以对标题栏进行解耦。 \n\n**重大更新：结合 Kotlin 语法特性能快速将所有功能集成到基类，不会影响已有代码。移除了 `ViewHolder`，整体用法得到进一步简化，建议升级！**\n\n- 无需在布局添加视图代码\n- 支持快速集成到基类，并且不影响有代码（仅 Kotlin）\n- 支持 Activity、Fragment、列表或指定的 View\n- 支持显示自定义视图\n- 支持添加多个头部控件\n- 支持设置重新请求数据的事件\n- 支持动态更新视图样式\n- 可结合绝大部分第三方控件使用\n\n## 示例\n\n点击或者扫描二维码下载\n\n[![QR code](docs/img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper)\n\n动态添加加载状态的布局：\n\n| [Activity(error)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ActErrorActivity.java) | [View(placeholder)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPlaceholderActivity.java) | [ViewPager(timeout)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPagerActivity.java) | [RecyclerView(cool loading)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/RecyclerViewActivity.java) |\n| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |\n|                 ![](docs/gif/activity_error.gif)                  |                ![](docs/gif/view_placeholder.gif)                 |                ![](docs/gif/viewpager_timeout.gif)                |              ![](docs/gif/recyclerview_loading.gif)               |\n\n动态添加标题栏或装饰容器：\n\n| [SpecialHeader(custom)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/CustomHeaderActivity.java) | [MultipleHeader(search)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MultipleHeaderActivity.java) | [SpecialDecorView(scrolling)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ScrollingToolbarActivity.java) | [BottomDecorView(editor)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/BottomEditorActivity.java) |\n| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |\n|              ![](docs/gif/special_header_custom.gif)              |             ![](docs/gif/multiple_header_search.gif)              |             ![](docs/gif/special_decor_scrolling.gif)             |               ![](docs/gif/bottom_decor_editor.gif)               |\n\n## 用法\n\n:pencil: **[>> 使用文档 <<](https://dylancaicoding.github.io/LoadingStateView)**\n\n## Gradle\n\n在根目录的 `build.gradle` 添加:\n\n```groovy\nallprojects {\n    repositories {\n        // ...\n        maven { url 'https://www.jitpack.io' }\n    }\n}\n```\n\n在模块的 `build.gradle` 添加依赖：\n\n```groovy\ndependencies {\n    // java\n    implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview:5.0.0'\n\n    // kotlin\n    implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0'\n}\n```\n\n## 更新日志\n\n[Releases](https://github.com/DylanCaiCoding/LoadingStateView/releases)\n\n## 作者其它的库\n\n| 库                                                           | 简介                                           |\n| ------------------------------------------------------------ | ---------------------------------------------- |\n| [Longan](https://github.com/DylanCaiCoding/Longan)           | 可能是最好用的 Kotlin 工具库                  |\n| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | 最全面的 ViewBinding 工具                      |\n| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX)       | 最灵活易用的 MMKV 工具                              |\n| [MultiBaseUrls](https://github.com/DylanCaiCoding/MultiBaseUrls) | 用注解让 Retrofit 同时支持多个 baseUrl 以及动态改变 baseUrl |\n| [Tracker](https://github.com/DylanCaiCoding/Tracker)         | 基于西瓜视频的责任链埋点思路实现的轻量级埋点框架          |\n\n## 感谢\n\n- [luckbilly/Gloading](https://github.com/luckybilly/Gloading) 站在了巨人肩膀上优化了本库，非常感谢！\n- [drakeet/MultiType](https://github.com/drakeet/MultiType) 参考了注册配置多适配器的思想和用法\n- [dinuscxj/LoadingDrawable](https://github.com/dinuscxj/LoadingDrawable) 示例中的自定义加载动画\n\n## License\n\n```\nCopyright (C) 2019. Dylan Cai\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    ext.buildConfig = [\n            'versionCode'      : 1,\n            'versionName'      : \"1.0.0\",\n            'compileSdkVersion': 30,\n            'minSdkVersion'    : 14,\n            'targetSdkVersion' : 30\n    ]\n    ext {\n        appCompatVersion = '1.3.1'\n        constraintLayoutVersion = '2.1.1'\n        coreVersion = '1.7.0-alpha01'\n        espressoVersion = '3.4.0'\n        glideVersion = '4.12.0'\n        kotlinVersion = \"1.5.31\"\n        lifecycleVersion = '2.4.0-alpha03'\n        junitExtVersion = '1.1.3'\n        junitVersion = '4.13.2'\n        materialVersion = '1.4.0'\n        viewBindingKTXVersion = '2.1.0'\n    }\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.2.1'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion\"\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n        maven { url 'https://www.jitpack.io' }\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "docs/.nojekyll",
    "content": ""
  },
  {
    "path": "docs/README.md",
    "content": "# LoadingStateView\n\n[![](https://www.jitpack.io/v/DylanCaiCoding/LoadingStateView.svg)](https://www.jitpack.io/#DylanCaiCoding/LoadingLoadingStateView) \n[![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/LICENSE)\n[![GitHub Repo stars](https://img.shields.io/github/stars/DylanCaiCoding/LoadingStateView?style=social)](https://github.com/DylanCaiCoding/LoadingStateView)\n\n`LoadingStateView` 是一个深度解耦缺省页和标题栏的工具，核心功能的实现代码只有一个 200 行左右（不算注释）的 [Kotlin 文件](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt)。不仅能在请求网络数据时显示加载中、加载成功、加载失败、无数据的视图或自定义视图，还可以对标题栏进行解耦。\n\n**重大更新：结合 Kotlin 语法特性能快速将所有功能集成到基类，不会影响已有代码。移除了 `ViewHolder`，整体用法得到进一步简化，建议升级！**\n\n- 无需在布局添加视图代码\n- 支持快速集成到基类，并且不影响有代码（仅 Kotlin）\n- 支持 Activity、Fragment、列表或指定的 View\n- 支持显示自定义视图\n- 支持添加多个头部控件\n- 支持设置重新请求数据的事件\n- 支持动态更新视图样式\n- 可结合绝大部分第三方控件使用\n\n## 示例\n\n点击或者扫描二维码下载\n\n[![QR code](img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper)\n\n动态添加加载状态的布局：\n\n| [Activity(error)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ActErrorActivity.java) | [View(placeholder)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPlaceholderActivity.java) | [ViewPager(timeout)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPagerActivity.java) | [RecyclerView(cool loading)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/RecyclerViewActivity.java) |\n| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |\n|                 ![](gif/activity_error.gif)                  |                ![](gif/view_placeholder.gif)                 |                ![](gif/viewpager_timeout.gif)                |              ![](gif/recyclerview_loading.gif)               |\n\n动态添加标题栏或装饰容器：\n\n| [SpecialHeader(custom)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/CustomHeaderActivity.java) | [MultipleHeader(search)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MultipleHeaderActivity.java) | [SpecialDecorView(scrolling)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ScrollingToolbarActivity.java) | [BottomDecorView(editor)](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/BottomEditorActivity.java) |\n| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |\n|              ![](gif/special_header_custom.gif)              |             ![](gif/multiple_header_search.gif)              |             ![](gif/special_decor_scrolling.gif)             |               ![](gif/bottom_decor_editor.gif)               |\n\n## Gradle\n\n在根目录的 `build.gradle` 添加:\n\n```groovy\nallprojects {\n    repositories {\n        // ...\n        maven { url 'https://www.jitpack.io' }\n    }\n}\n```\n\n在模块的 `build.gradle` 添加依赖：\n\n```groovy\ndependencies {\n    // java\n    implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview:5.0.0'\n    \n    // kotlin\n    implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0'\n}\n```\n\n## 更新日志\n\n[Releases](https://github.com/DylanCaiCoding/LoadingStateView/releases)\n\n## 作者其它的库\n\n| 库                                                           | 简介                                           |\n| ------------------------------------------------------------ | ---------------------------------------------- |\n| [Longan](https://github.com/DylanCaiCoding/Longan)           | 可能是最好用的 Kotlin 工具库                  |\n| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | 最全面的 ViewBinding 工具                      |\n| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX)       | 用属性委托的方式使用 MMKV                              |\n| [Tracker](https://github.com/DylanCaiCoding/Tracker)         | 基于西瓜视频的责任链埋点思路实现的轻量级埋点框架          |\n\n## 感谢\n\n- [luckbilly/Gloading](https://github.com/luckybilly/Gloading) 站在了巨人肩膀上优化了本库，非常感谢！\n- [drakeet/MultiType](https://github.com/drakeet/MultiType) 参考了注册配置多适配器的思想和用法\n- [dinuscxj/LoadingDrawable](https://github.com/dinuscxj/LoadingDrawable) 示例中的自定义加载动画\n\n## License\n\n```\nCopyright (C) 2019. Dylan Cai\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n"
  },
  {
    "path": "docs/_sidebar.md",
    "content": "* [介绍](/)\n* [基础用法](/zh/basic-usage)\n* [Kotlin 委托用法](/zh/delegate)\n* [结合 ViewBinding 使用](/zh/viewbinding)\n* [老版本迁移指南](/zh/migration-guide)\n* [Q&A](/zh/q&a)"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Document</title>\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n  <meta name=\"description\" content=\"Description\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0\">\n  <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css\">\n</head>\n<body>\n  <div id=\"app\"></div>\n  <script>\n    window.$docsify = {\n      name: 'LoadingStateView',\n      repo: 'https://github.com/DylanCaiCoding/LoadingStateView',\n      themeColor: '#1E88E5',\n      loadSidebar: true,\n      subMaxLevel: 3,\n      auto2top: true,\n      tabs: {\n        persist    : true,\n        sync       : true,\n        theme      : 'classic',\n        tabComments: true,\n        tabHeadings: true\n      }\n    }\n  </script>\n  <script src=\"//cdn.jsdelivr.net/npm/docsify@4\"></script>\n  <script src=\"//cdn.jsdelivr.net/npm/prismjs@1/components/prism-kotlin.min.js\"></script>\n  <script src=\"//cdn.jsdelivr.net/npm/prismjs@1/components/prism-java.min.js\"></script>\n  <script src=\"//cdn.jsdelivr.net/npm/prismjs@1/components/prism-groovy.min.js\"></script>\n  <script src=\"//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js\"></script>\n  <script src=\"https://cdn.jsdelivr.net/npm/docsify-tabs@1\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zh/basic-usage.md",
    "content": "# 基础用法\n\n使用 Kotlin 开发推荐用[委托用法](/zh/delegate)。\n\n## 显示加载中、加载失败等缺省页\n\n第一步，使用 Activity 或 View 创建 `LoadingStateView`，不需要重新加载的话 `OnReloadListener` 可不传。\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nval loadingStateView = LoadingStateView(this, onReloadListener)\n// val loadingStateView = LoadingStateView(view, onReloadListener)\n```\n\n#### **Java**\n\n```java\nLoadingStateView loadingStateView = new LoadingStateView(this, onReloadListener); \n// LoadingStateView loadingStateView = new LoadingStateView(view, onReloadListener); \n```\n\n<!-- tabs:end -->\n\n第二步，创建一个类继承  `LoadingStateView.ViewDelegate`。\n\n构造函数需要传个参数，决定视图类型，之后显示和更新会用到。默认提供了 `ViewType.LOADING`、`ViewType.ERROR`、`ViewType.EMPTY`、`ViewType.TITLE`，其它的可以用一个 String 作为类型。\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nclass LoadingViewDelegate : LoadingStateView.ViewDelegate(ViewType.LOADING) {\n  \n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View =\n    inflater.inflate(R.layout.layout_loading, parent, false)\n}\n```\n\n#### **Java**\n\n```java\npublic class LoadingViewDelegate extends LoadingStateView.ViewDelegate {\n\n  public LoadingViewDelegate() {\n    super(ViewType.LOADING);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    return inflater.inflate(R.layout.layout_loading, parent, false);\n  }\n}\n```\n\n<!-- tabs:end -->\n\n如果需要实现点击重新请求数据，可以在点击事件调用 `onReloadListener?.onReload()` 方法。\n\n第三步，注册 `ViewDelegate`。首先在 Application 注册全局的 `ViewDelegate`：\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nLoadingStateView.setViewDelegatePool {\n  register(LoadingViewDelegate(), ErrorViewDelegate(), EmptyViewDelegate())\n}\n```\n\n#### **Java**\n\n```java\nLoadingStateView.setViewDelegatePool(pool ->\n    pool.register(new LoadingViewDelegate(), new ErrorViewDelegate(), new EmptyViewDelegate()));\n```\n\n<!-- tabs:end -->\n\n如果某个页面需要不同样式，就用该页面的 `LoadingStateView` 注册对应类型的 `ViewDelegate`，就可以把全局的替换了。\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nloadingStateView.register(CoolLoadingViewDelegate())\n```\n\n#### **Java**\n\n```java\nloadingStateView.register(new CoolLoadingViewDelegate());\n```\n\n<!-- tabs:end -->\n\n第四步，显示对应类型的视图。\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nloadingStateView.showView(viewType)\nloadingStateView.showLoadingView() // 显示 ViewType.LOADING 类型的视图\nloadingStateView.showContentView() // 显示 ViewType.CONTENT 类型的视图\nloadingStateView.showErrorView() // 显示 ViewType.ERROR 类型的视图\nloadingStateView.showEmptyView() // 显示 ViewType.EMPTY 类型的视图\n```\n\n#### **Java**\n\n```java\nloadingStateView.showView(viewType);\nloadingStateView.showLoadingView(); // 对应视图类型 ViewType.LOADING\nloadingStateView.showContentView(); // 对应视图类型 ViewType.CONTENT\nloadingStateView.showErrorView(); // 对应视图类型 ViewType.ERROR\nloadingStateView.showEmptyView(); // 对应视图类型 ViewType.EMPTY\n```\n\n<!-- tabs:end -->\n\n## 更新视图样式\n\n需要在 `ViewDelegate` 自行增加更新的方法，然后更新对应的 `ViewDelegate`。比如在 `ErrorViewDelegate` 增加了 `updateMsg(msg)` 方法修改请求失败的文字：\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nloadingStateView.updateViewDelegate<ErrorViewDelegate>(ViewType.ERROR) {\n  updateMsg(\"服务器繁忙，请稍后重试\")\n}\n```\n\n#### **Java**\n\n```java\nloadingStateView.updateViewDelegate(ViewType.ERROR, (ErrorViewDelegate delegate) ->\n    delegate.updateMsg(\"服务器繁忙，请稍后重试\"));\n```\n\n<!-- tabs:end -->\n\n## 在内容上方添加视图\n\n实现标题栏或搜索栏等 `ViewDelegate`，之后就可以用 `LoadingStateView` 在内容布局的上方添加视图。\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nloadingStateView.setHeaders(ToolbarViewDelegate(\"消息\"), SearchViewDelegate())\n```\n\n#### **Java**\n\n```java\nloadingStateView.setHeaders(new ToolbarViewDelegate(\"消息\"), new SearchViewDelegate());\n```\n\n<!-- tabs:end -->\n\n## 给内容增加装饰\n\n可以给内容布局外层添加一层装饰，实现更复杂的样式，非简单地在内容上方增加控件，比如带联动效果的标题栏、DrawerLayout、底部输入框等布局。\n\n接下来以滑动隐藏标题栏的效果为例，先写一个带联动效果的标题栏布局，其中有个 FragmentLayout 是用于填充内容和显示缺省页。\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <com.google.android.material.appbar.AppBarLayout\n    android:id=\"@+id/app_bar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:elevation=\"2dp\">\n\n    <androidx.appcompat.widget.Toolbar\n      android:id=\"@+id/toolbar\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"?attr/actionBarSize\"\n      app:layout_collapseMode=\"pin\"\n      app:layout_scrollFlags=\"scroll|enterAlways\"\n      app:navigationIcon=\"@drawable/ic_arrow_back_ios\"\n      android:background=\"@color/white\"\n      app:titleTextAppearance=\"@style/ToolbarTextAppearance\" />\n\n  </com.google.android.material.appbar.AppBarLayout>\n\n  <FrameLayout\n    android:id=\"@+id/content_parent\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n```\n\n然后写一个类继承 `LoadingStateView.DecorViewDelegate`。\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nclass ScrollingDecorViewDelegate(\n  private val activity: Activity,\n  private val title: String\n) : LoadingStateView.DecorViewDelegate() {\n\n  override fun onCreateDecorView(context: Context, inflater: LayoutInflater): View {\n    val view = inflater.inflate(R.layout.layout_scrolling_toolbar, null)\n    val toolbar: Toolbar = view.findViewById(R.id.toolbar)\n    toolbar.title = title\n    toolbar.setNavigationOnClickListener { activity.finish() }\n    return view\n  }\n\n  override fun getContentParent(decorView: View): ViewGroup {\n    return decorView.findViewById(R.id.content_parent)\n  }\n}\n```\n\n#### **Java**\n\n```java\npublic class ScrollingDecorViewDelegate extends LoadingStateView.DecorViewDelegate {\n  private final Activity activity;\n  private final String title;\n\n  public ScrollingDecorViewDelegate(Activity activity, String title) {\n    this.activity = activity;\n    this.title = title;\n  }\n\n  @NotNull\n  @Override\n  public View onCreateDecorView(@NonNull Context context, @NotNull LayoutInflater inflater) {\n    View view = inflater.inflate(R.layout.layout_scrolling_toolbar, null);\n    Toolbar toolbar = view.findViewById(R.id.toolbar);\n    toolbar.setTitle(title);\n    toolbar.setNavigationOnClickListener(v -> activity.finish());\n    return view;\n  }\n\n  @NotNull\n  @Override\n  public ViewGroup getContentParent(@NotNull View decorView) {\n    return decorView.findViewById(R.id.content_parent);\n  }\n}\n```\n\n<!-- tabs:end -->\n\n与 `ViewDelegate` 不同的是，需要多实现一个 `getContentParent(decorView)` 方法来指定添加内容的容器，这里我们返回前面的 FrameLayout。\n\n之后就可以给内容进行装饰了。\n\n<!-- tabs:start -->\n\n\n#### **Kotlin**\n\n```kotlin\nloadingStateView.setDecorView(ScrollingDecorViewDelegate(this, \"title\"))\n```\n\n#### **Java**\n\n```java\nloadingStateView.setDecorView(new ScrollingDecorViewDelegate(this, \"title\"));\n```\n\n<!-- tabs:end -->\n"
  },
  {
    "path": "docs/zh/delegate.md",
    "content": "# Kotlin 委托用法\n\n## 准备工作\n\n需要修改基类，只需简单的两步就可以把本库的功能集成到基类，并且不会影响到已有的代码，只是给基类扩展了新的方法。\n\n注意添加的依赖需要是 `loadingstateview-ktx`：\n\n```groovy\ndependencies {\n  implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0'\n}\n```\n\n修改步骤如下：\n\n1. 实现 `LoadingState by LoadingStateDelegate()` 。\n2. 在 Activity 的 `setContentView()` 方法后执行 `decorateContentView(this)`。在 Fragment 的 `onCreateView()` 返回 `view.decorate(this)`。\n\n<!-- tabs:start -->\n\n#### **Activity**\n\n![img.png](../img/base_activity_code.png)\n\n<details>\n  <summary>查看代码</summary>\n\n```kotlin\nabstract class BaseActivity(private val layoutRes: Int) : AppCompatActivity(),\n  LoadingState by LoadingStateDelegate() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(layoutRes)\n    decorateContentView(this)\n  }\n}\n```\n\n</details>\n\n#### **Fragment**\n\n![img.png](../img/base_fragment_code.png)\n\n<details>\n  <summary>查看代码</summary>\n\n```kotlin\nabstract class BaseFragment(private val layoutRes: Int) : Fragment(),\n  LoadingState by LoadingStateDelegate() {\n\n  override fun onCreateView(\n    inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?\n  ): View? {\n    val root = inflater.inflate(layoutRes, container, false)\n    return root.decorate(this)\n  }\n}\n```\n\n</details>\n\n<!-- tabs:end -->\n\n这样改造基类后会得到以下的增强：\n\n- 在不影响已有代码的情况下，增加了 [LoadingState](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingState.kt) 接口提供的常用方法，该接口包含了 `LoadingStateView` 所有功能。\n- 如果担心对基类有什么影响，在页面重写 `override val isDecorated = false` 会把一切还原，即使调用了新增的接口方法也不会生效，请放心使用。\n\n## 显示缺省页\n\n先注册各类型缺省页的样式，之后才能调用对应的 `showView()` 方法。\n\n创建类继承 `LoadingStateView.ViewDelegate`，构造函数传个视图类型参数，默认提供了 `ViewType.LOADING`、`ViewType.ERROR`、`ViewType.EMPTY`。\n\n<!-- tabs:start -->\n\n#### **ViewType.LOADING**\n\n```kotlin\nclass LoadingViewDelegate : LoadingStateView.ViewDelegate(ViewType.LOADING) {\n\n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View =\n    inflater.inflate(R.layout.layout_loading, parent, false)\n}\n```\n\n#### **ViewType.ERROR**\n\n```kotlin\nclass ErrorViewDelegate : LoadingStateView.ViewDelegate(ViewType.ERROR) {\n\n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View =\n    inflater.inflate(R.layout.layout_error, parent, false).apply {\n      findViewById<View>(R.id.btn_reload).setOnClickListener {\n        onReloadListener?.onReload()\n      }\n    }\n}\n```\n\n#### **ViewType.EMPTY**\n\n```kotlin\nclass EmptyViewDelegate : LoadingStateView.ViewDelegate(ViewType.EMPTY) {\n\n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View =\n    inflater.inflate(R.layout.layout_empty, parent, false)\n}\n```\n\n<!-- tabs:end -->\n\n在 Application 注册全局的 `ViewDelegate`。\n\n```kotlin\nLoadingStateView.setViewDelegatePool {\n  register(LoadingViewDelegate(), ErrorViewDelegate(), EmptyViewDelegate())\n}\n```\n\n在实现了基类的 `Activity` 或 `Fragment` 可以调用对应的 `showView()` 方法。\n\n```kotlin\nshowLoadingView()  // 显示 ViewType.LOADING 类型的视图\nshowErrorView()    // 显示 ViewType.ERROR 类型的视图\nshowEmptyView()    // 显示 ViewType.EMPTY 类型的视图\nshowContentView()  // 显示原来的内容视图\nshowView(viewType) // 显示自定义类型的视图\n```\n\n如果需要实现点击重新加载，就在基类重写 `onReload()` 方法。\n\n如果某个页面需要显示不同的缺省页，可以在显示前调用一下 `registerView(viewDelegate)` 方法覆盖默认的样式。比如：\n\n```kotlin\nregisterView(CoolLoadingViewDelegate())\nshowLoadingView()\n```\n\n如果需要动态更新某个样式，在 `ViewDelegate` 自行增加更新的方法，比如在 `ErrorViewDelegate` 增加了 `updateMsg(msg)` 方法修改请求失败的文字，然后就能更新了。\n\n```kotlin\nupdateView<ErrorViewDelegate>(ViewType.ERROR) {\n  updateMsg(\"服务器繁忙，请稍后重试\")\n}\n```\n\n## 设置标题栏\n\n先注册标题栏样式，之后才能调用 `setToolbar()` 方法。\n\n创建一个类继承 `BaseToolbarViewDelegate`，通常项目都有各自的标题栏封装，我们能基于已有的标题栏布局或者自定义的标题栏控件实现 `ToolbarViewDelegate`。比如：\n\n```kotlin\nclass ToolbarViewDelegate : BaseToolbarViewDelegate() {\n  private lateinit var tvTitle: TextView\n  private lateinit var ivLeft: ImageView\n  private lateinit var ivRight: ImageView\n\n  override fun onCreateToolbar(inflater: LayoutInflater, parent: ViewGroup): View {\n    val view = inflater.inflate(R.layout.layout_toolbar, parent, false)\n    tvTitle = view.findViewById(R.id.tv_title)\n    ivLeft = view.findViewById(R.id.iv_left)\n    ivRight = view.findViewById(R.id.iv_right)\n    return view\n  }\n\n  override fun onBindToolbar(config: ToolbarConfig) {\n    tvTitle.text = config.title\n\n    if (config.navBtnType == NavBtnType.NONE) {\n      ivLeft.visibility = View.GONE\n    } else {\n      ivLeft.setOnClickListener(config.onNavClickListener)\n      ivLeft.visibility = View.VISIBLE\n    }\n\n    if (config.rightIcon != null) {\n      ivRight.setImageResource(config.rightIcon!!)\n      ivRight.setOnClickListener(config.onRightClickListener)\n      ivRight.visibility = View.VISIBLE\n    }\n  }\n}\n```\n\n`ToolbarConfig` 提供了几个常用的属性。可以根据需要选择处理，比如上述例子只实现了有无返回键和右侧按钮的逻辑，项目中有功能相对完整的[示例代码](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ToolbarViewDelegate.kt)。\n\n| 属性                 | 含义                  |\n| -------------------- | -------------------- |\n| title                | 标题                  |\n| navBtnType           | 导航 (左侧) 按钮类型    |\n| navIcon              | 导航 (左侧) 图标       |\n| navText              | 导航 (左侧) 文字       |\n| onNavClickListener   | 导航 (左侧) 按钮点击事件 |\n| rightIcon            | 右侧图标               |\n| rightText            | 右侧文字               |\n| onRightClickListener | 右侧按钮点击事件        |\n\n`onNavClickListener` 默认执行 `finish()` 操作。`navBtnType` 默认类型是 `NavBtnType.ICON`，还有 `NavBtnType.NONE`、`NavBtnType.TEXT`、`NavBtnType.ICON_TEXT`类型。其它的属性默认为空，为空的时候不用处理使用默认样式即可。\n\n当然这点属性肯定不能满足所有的需求，所以本库支持给 `ToolbarConfig` 增加扩展属性。比如需要动态修改右侧文字颜色：\n\n```kotlin\nvar ToolbarConfig.rightTextColor: Int? by toolbarExtras() // 增加 rightTextColor 扩展属性\n\nclass ToolbarViewDelegate : BaseToolbarViewDelegate() {\n\n  // ...\n\n  override fun onBindToolbar(config: ToolbarConfig) {\n    // ... \n    config.rightTextColor?.let { tvRight.setTextColor(it) } // 处理扩展属性\n  }\n}\n```\n\n在 Application 注册全局的标题栏 `ViewDelegate`。\n\n```kotlin\nLoadingStateView.setViewDelegatePool {\n  register(ToolbarViewDelegate(), // ... )\n}\n```\n\n之后就能在实现了基类的 `Activity` 或 `Fragment` 设置标题栏了。\n\n```kotlin\nsetToolbar() // 默认有返回键\n\nsetToolbar(\"title\") // 有标题和返回键\n\nsetToolbar(\"title\", NavBtnType.NONE) // 只有标题，无返回键\n\nsetToolbar(\"title\") {                 // 以下可选\n  navIcon = R.drawable.account        // 只修改返回键图标\n  navIcon { ... }                     // 只修改返回键的点击事件\n  navIcon(R.drawable.message) { ... } // 修改返回键的图标和点击事件\n  rightIcon(R.drawable.add) { ... }   // 添加右侧图标\n  rightText(\"Delete\") { ... }         // 添加右侧文字\n  rightTextColor = Color.RED          // 新增的扩展属性，修改右侧文字颜色\n}\n```\n\n这样就多了一种添加标题栏的方式，新写的代码可以用上述的方式添加标题栏，老的代码保留已有的 `<include/>` 布局或者自定义标题栏控件的用法。样式都是一样的，因为是基于已有标题栏实现的。\n\n如果某个页面的标题栏样式变动很大，不建议写太多扩展属性来配置，这样代码阅读性也差。推荐用新布局再写一个 `BaseToolbarViewDelegate` 的实现类，在设置标题栏之前注册，这会覆盖掉默认的样式。\n\n```kotlin\nregisterView(SpecialToolbarViewDelegate())\nsetToolbar(\"title\")\n```\n\n如果需要动态更新标题栏样式：\n\n```kotlin\nupdateToolbar { title = \"Loading...\" }\n```\n\n如果有扩展属性不好配置的需求，比如开启或关闭动画，可以在 `ToolbarViewDelegate` 自行增加对应功能的函数，然后在更新的时候调用。\n\n```kotlin\nupdateView<ToolbarViewDelegate>(ViewType.TITLE) {\n  startAnimation()\n}\n```\n\n## 在顶部添加控件\n\n可添加多个控件，比如添加标题栏和搜索栏，搜索栏需要另写一个类继承 `LoadingStateView.ViewDelegate`。\n\n```kotlin\nsetHeaders(\n  ToolbarViewDelegate(\"Search\") {\n    rightIcon(R.drawable.more) { ... }\n  },\n  SearchViewDelegate(onSearchListener)\n)\n```\n\n## 给内容增加装饰\n\n可以给内容布局再套上一层装饰，实现更复杂的样式，非简单地在顶部增加控件，比如带联动效果的标题栏、DrawerLayout、底部输入框等布局。\n\n接下来以滑动隐藏标题栏的效果为例，先写一个带联动效果的标题栏布局，其中有个 FragmentLayout 是用于填充内容和显示缺省页。\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <com.google.android.material.appbar.AppBarLayout\n    android:id=\"@+id/app_bar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:elevation=\"2dp\">\n\n    <androidx.appcompat.widget.Toolbar\n      android:id=\"@+id/toolbar\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"?attr/actionBarSize\"\n      app:layout_collapseMode=\"pin\"\n      app:layout_scrollFlags=\"scroll|enterAlways\"\n      app:navigationIcon=\"@drawable/ic_arrow_back_ios\"\n      android:background=\"@color/white\"\n      app:titleTextAppearance=\"@style/ToolbarTextAppearance\" />\n\n  </com.google.android.material.appbar.AppBarLayout>\n\n  <FrameLayout\n    android:id=\"@+id/content_parent\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n```\n\n然后写一个类继承 `LoadingStateView.DecorViewDelegate`。\n\n```kotlin\nclass ScrollingDecorViewDelegate(\n  private val activity: Activity,\n  private val title: String\n) : LoadingStateView.DecorViewDelegate() {\n\n  override fun onCreateDecorView(context: Context, inflater: LayoutInflater): View {\n    val view = inflater.inflate(R.layout.layout_scrolling_toolbar, null)\n    val toolbar: Toolbar = view.findViewById(R.id.toolbar)\n    toolbar.title = title\n    toolbar.setNavigationOnClickListener { activity.finish() }\n    return view\n  }\n\n  override fun getContentParent(decorView: View): ViewGroup {\n    return decorView.findViewById(R.id.content_parent)\n  }\n}\n```\n\n与 `LoadingStateView.ViewDelegate` 不同的是，需要多实现一个 `getContentParent(decorView)` 方法来指定添加内容的容器，这里我们返回前面的 FrameLayout。\n\n之后就可以给内容进行装饰了。\n\n```kotlin\nsetDecorView(ScrollingDecorViewDelegate(this, \"title\"))\n```"
  },
  {
    "path": "docs/zh/migration-guide.md",
    "content": "# 老版本升级指南\n\n`4.0.1` 版本对用法进行了优化，移除了 `ViewHolder`，使用起来更加简单，不过就意味着不能兼容之前的代码。建议根据[文档](/zh/basic-usage)改成新的用法，通常是封装在基类，要改的不多，`ViewHolder` 的代码需要移到 `onCreateView()` 中。\n\n但是如果报红的地方特别多，个人有一个折中的方案。由于之前版本只有一个两三百行的 kt 文件，那么可以把源码拷贝出来并删除依赖，也就是说改成源码的方式集成，全局改一下相关包名。然后就可以添加新版本依赖进行使用，再慢慢将老用法改成新用法。"
  },
  {
    "path": "docs/zh/q&a.md",
    "content": "# Q&A\n\n## 为什么不分成标题栏库和缺省页库？\n\n个人深思熟虑了非常久才决定写成一个库，有以下考虑：\n\n- 支持给内容和缺省页添加头部，所以具有管理标题栏的应用场景，感觉没什么不妥。\n- 大多数情况下标题栏和缺省页关联性很强，因为缺省页往往是要在标题栏下方显示，如果分成两个库就经常需要调用两个工具类，使用起来更加麻烦。\n- 分成两个库可能会多一层无意义的布局嵌套。\n- 即使写在一起，核心功能的实现类才 200 多行代码，还要啥自行车。由于适配器和 View 的缓存代码能复用，在解耦缺省页后，仅加多几十行代码就能把标题栏给一起解耦了，何乐而不为。\n\n## 可以在布局上预览标题栏吗？\n\n不能，这可能是本库唯一的缺点，但是本库解耦标题栏的收益远大于在布局上预览标题栏的收益。\n"
  },
  {
    "path": "docs/zh/viewbinding.md",
    "content": "# 结合 ViewBinding 使用\n\n## 基础用法\n\n如果要同时使用 `LoadingStateView` 和 `ViewBinding`，需要先得到对应的 `ViewBinding` 实例，再用其根视图去创建 `LoadingStateView`。\n\n<!-- tabs:start -->\n\n#### **Kotlin**\n\n```kotlin\nval loadingStateView = LoadingStateView(binding.root, onReloadListener)\n```\n\n#### **Java**\n\n```java\nLoadingStateView loadingStateView = new LoadingStateView(binding.getRoot(), onReloadListener); \n```\n\n<!-- tabs:end -->\n\n## Kotlin 委托用法\n\n委托用法再结合上 ViewBinding 才是个人理想中的用法。会使用到个人的另一个库 [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX)，可以快速集成 ViewBinding 到基类中。\n\n添加依赖：\n\n```groovy\nimplementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-base:2.1.0'\n```\n\n根据[文档](https://dylancaicoding.github.io/ViewBindingKTX/#/zh/baseclass)集成 ViewBinding，再对 ViewBinding 的根视图进行装饰。以下是在委托用法基础上修改的代码：\n\n<!-- tabs:start -->\n\n#### **Activity**\n\n![img.png](../img/base_binding_activity_code.png)\n\n<details>\n  <summary>查看代码</summary>\n\n```kotlin\nabstract class BaseBindingActivity<VB : ViewBinding> : AppCompatActivity(),\n  LoadingState by LoadingStateDelegate(), ActivityBinding<VB> by ActivityBindingDelegate() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentViewWithBinding()\n    binding.root.decorate(this)\n  }\n}\n```\n\n</details>\n\n#### **Fragment**\n\n![img.png](../img/base_binding_fragment_code.png)\n\n<details>\n  <summary>查看代码</summary>\n\n```kotlin\nabstract class BaseBindingFragment<VB : ViewBinding> : Fragment(),\n  LoadingState by LoadingStateDelegate(), FragmentBinding<VB> by FragmentBindingDelegate() {\n\n  override fun onCreateView(\n    inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?\n  ): View? {\n    return createViewWithBinding(inflater, container).decorate(this)\n  }\n}\n```\n\n</details>\n\n<!-- tabs:end -->\n\n这样封装后不仅能在 Activity 或 Fragment 获取 `binding` 属性，还能很方便地指定显示缺省页的区域。\n\n比如我们在已有的项目迭代开发，一些页面的布局已经写了标题栏。如果直接调用 `showLoadingView()` 函数，缺省页会把标题栏给覆盖了，通常要在标题栏下方显示缺省页，此时就可以重写 `contentView` 属性，声明在哪个控件显示缺省页，比如：\n\n```kotlin\nclass MainActivity : BaseBindingActivity<ActivityMainBinding>() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    showLoadingView()\n    // ...\n  }\n  \n  override val contentView get() = binding.container\n}\n```\n\n### 已有的基类如何修改\n\n由于要给基类增加 ViewBinding 泛型，肯定不可能直接修改基类，这会影响到已有的代码，建议继承原基类再扩展出一个支持 ViewBinding 的基类。\n\n假设已有的基类是这种常见的封装，通过 `getLayoutId()` 函数去设置布局。\n\n```java\npublic abstract class BaseActivity extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(getLayoutId());\n    initData();\n    initViews();\n  }\n\n  public abstract int getLayoutId();\n  public abstract void initData();\n  public abstract void initViews();\n}\n```\n\n目前直接继承是实现不了的，因为需要重写 `setContentView()` 的代码，所以要先将 `setContentView()` 抽到一个函数中。\n\n```java\n@Override\nprotected void onCreate(@Nullable Bundle savedInstanceState) {\n  super.onCreate(savedInstanceState);\n  initContentView();\n  initData();\n  initViews();\n}\n\nprotected void initContentView() {\n  setContentView(getLayoutId());\n}\n```\n\n之后就可以继承基类重写该函数替换掉原来的 `setContentView()` 工作。\n\n```kotlin\nabstract class BaseBindingActivity<VB : ViewBinding> : BaseActivity(),\n  LoadingState by LoadingStateDelegate(), OnReloadListener, Decorative,\n  ActivityBinding<VB> by ActivityBindingDelegate() {\n\n  override fun initContentView() {\n    setContentViewWithBinding()\n    binding.root.decorate(this, this)\n  }\n\n  override fun getLayoutId() = -1 // 使用 ViewBinding 后，就不需要布局 id 了\n}\n```\n\nFragment 的修改也同理。"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Nov 18 20:32:14 CST 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\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\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\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\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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\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\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\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\" -a \"$nonstop\" = \"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# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=$(save \"$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"$(uname)\" = \"Darwin\" ] && [ \"$HOME\" = \"$PWD\" ]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "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\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\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\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 Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_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=%*\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": "loadingstateview/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "loadingstateview/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion buildConfig.compileSdkVersion\n\n    defaultConfig {\n        minSdkVersion buildConfig.minSdkVersion\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    subprojects {\n        tasks.withType(Javadoc).all { enabled = false }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n        freeCompilerArgs += ['-module-name', \"loading_state_view\"]\n    }\n}\n\ndependencies {\n    implementation \"androidx.constraintlayout:constraintlayout:$constraintLayoutVersion\"\n}"
  },
  {
    "path": "loadingstateview/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "loadingstateview/src/main/AndroidManifest.xml",
    "content": "<manifest package=\"com.dylanc.loadingstateview\" />\n"
  },
  {
    "path": "loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview\n\nimport android.app.Activity\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.ViewGroup.LayoutParams.MATCH_PARENT\nimport android.widget.FrameLayout\nimport android.widget.LinearLayout\nimport androidx.constraintlayout.widget.ConstraintLayout\n\n/**\n * @author Dylan Cai\n */\nclass LoadingStateView @JvmOverloads constructor(\n  private val contentView: View,\n  var onReloadListener: OnReloadListener? = null\n) {\n  lateinit var decorView: View private set\n  lateinit var currentViewType: Any private set\n  private lateinit var contentParent: ViewGroup\n  private val parent: ViewGroup?\n  private var currentView: View? = null\n  private var viewDelegates: HashMap<Any, ViewDelegate> = HashMap()\n  private val viewCaches: HashMap<Any, View> = HashMap()\n\n  /**\n   * Constructs a LoadingStateView with an activity and listener.\n   */\n  @JvmOverloads\n  constructor(activity: Activity, listener: OnReloadListener? = null) :\n      this(activity.findViewById<ViewGroup>(android.R.id.content).getChildAt(0), listener)\n\n  init {\n    poolInitializer?.apply { PoolInitializer(this@LoadingStateView).invoke() }\n    parent = contentView.parent as ViewGroup?\n    register(ContentViewDelegate())\n    setDecorView(LinearDecorViewDelegate(emptyList()))\n  }\n\n  /**\n   * Adds one or more views to decorate content in the header.\n   *\n   * @param delegates the view delegates of creating view\n   */\n  fun setHeaders(vararg delegates: ViewDelegate) = setDecorView(LinearDecorViewDelegate(delegates))\n\n  /**\n   * Sets an view delegate for decorating content view.\n   *\n   * @param decorViewDelegate the view delegate for decorating content view.\n   */\n  fun setDecorView(decorViewDelegate: DecorViewDelegate) {\n    currentView = null\n    if (parent != null) {\n      val index = parent.indexOfChild(contentView)\n      if (index >= 0) {\n        parent.removeView(contentView)\n      } else {\n        parent.removeView(decorView)\n        (contentView.parent as ViewGroup).removeView(contentView)\n      }\n      decorView = decorViewDelegate.createDecorView()\n      parent.addView(decorView, index)\n    } else {\n      decorView = decorViewDelegate.createDecorView()\n    }\n    contentParent = decorViewDelegate.getContentParent(decorView)\n    showView(ViewType.CONTENT)\n  }\n\n  /**\n   * Adds child decorative header between the content and the decorative view.\n   *\n   * @param delegates the view delegates of creating view\n   */\n  fun addChildHeaders(vararg delegates: ViewDelegate) = addChildDecorView(LinearDecorViewDelegate(delegates))\n\n  /**\n   * Adds child decorative view between the content and the decorative view.\n   *\n   * @param decorViewDelegate the view delegate for decorating content view.\n   */\n  fun addChildDecorView(decorViewDelegate: DecorViewDelegate) {\n    contentParent.removeView(currentView)\n    currentView = null\n    val childDecorView = decorViewDelegate.createDecorView()\n    contentParent.addView(childDecorView)\n    contentParent = decorViewDelegate.getContentParent(childDecorView)\n    showView(ViewType.CONTENT)\n  }\n\n  private fun DecorViewDelegate.createDecorView() =\n    onCreateDecorView(contentView.context, LayoutInflater.from(contentView.context)).also { decorView ->\n      contentView.layoutParams?.let {\n        decorView.layoutParams = if (it is ConstraintLayout.LayoutParams) ConstraintLayout.LayoutParams(it) else it\n        (it as? ViewGroup.MarginLayoutParams)?.setMargins(0, 0, 0, 0)\n      }\n    }\n\n  /**\n   * Registers the view delegate of creating view before showing view.\n   *\n   * @param delegates the view delegate of creating view\n   */\n  fun register(vararg delegates: ViewDelegate) = delegates.forEach { viewDelegates[it.viewType] = it }\n\n  @JvmOverloads\n  fun showLoadingView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.LOADING, animatable)\n\n  @JvmOverloads\n  fun showContentView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.CONTENT, animatable)\n\n  @JvmOverloads\n  fun showErrorView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.ERROR, animatable)\n\n  @JvmOverloads\n  fun showEmptyView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.EMPTY, animatable)\n\n  /**\n   * Shows the view by view type\n   *\n   * @param viewType the view type of view delegate\n   */\n  @JvmOverloads\n  fun showView(viewType: Any, animatable: Animatable? = defaultAnimatable) {\n    val currentView = currentView\n    if (currentView == null) {\n      addView(viewType)\n    } else {\n      if (viewCaches[viewType] == null) addView(viewType)\n      if (viewType != currentViewType) {\n        val nextView = getOrCreateView(viewType)\n        nextView.visibility = View.VISIBLE\n        val nextViewDelegate = getViewDelegate<ViewDelegate>(viewType)\n        nextViewDelegate?.onViewAttached(nextView)\n        getViewDelegate<ViewDelegate>(currentViewType)?.onViewDetached(nextView)\n        if (animatable != null && nextViewDelegate != null) {\n          animatable.toggleViewsAnimation(nextView, currentView, viewType, currentViewType)\n        } else {\n          currentView.visibility = View.GONE\n        }\n        this.currentView = nextView\n      }\n    }\n    currentViewType = viewType\n  }\n\n  fun <T : ViewDelegate> updateViewDelegate(viewType: Any, callback: Callback<T>) =\n    callback.apply { getViewDelegate<T>(viewType)?.invoke() }\n\n  @Suppress(\"UNCHECKED_CAST\")\n  fun <T : ViewDelegate> getViewDelegate(viewType: Any) = viewDelegates[viewType] as? T\n\n  private fun addView(viewType: Any) {\n    val view = getOrCreateView(viewType)\n    (view.parent as? ViewGroup)?.removeView(view)\n    if (parent is ConstraintLayout && viewType == ViewType.CONTENT) {\n      val params = view.layoutParams\n      if (view.measuredWidth == 0) params.width = MATCH_PARENT\n      if (view.measuredHeight == 0) params.height = MATCH_PARENT\n      view.layoutParams = params\n    }\n    contentParent.addView(view)\n    currentView = view\n  }\n\n  private fun getOrCreateView(viewType: Any): View {\n    if (viewCaches[viewType] == null) {\n      val viewDelegate = requireNotNull(getViewDelegate(viewType)) { \"Please register view delegate for $viewType type.\" }\n      val view = viewDelegate.onCreateView(LayoutInflater.from(contentParent.context), contentParent)\n      viewDelegate.onReloadListener = onReloadListener\n      viewCaches[viewType] = view\n    }\n    return viewCaches[viewType]!!\n  }\n\n  abstract class ViewDelegate(val viewType: Any) {\n    abstract fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View\n    open fun onViewAttached(view: View) = Unit\n    open fun onViewDetached(view: View) = Unit\n    var onReloadListener: OnReloadListener? = null\n      internal set\n  }\n\n  private inner class ContentViewDelegate : ViewDelegate(ViewType.CONTENT) {\n    override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup) = contentView\n  }\n\n  abstract class DecorViewDelegate {\n    abstract fun onCreateDecorView(context: Context, inflater: LayoutInflater): View\n    abstract fun getContentParent(decorView: View): ViewGroup\n  }\n\n  private inner class LinearDecorViewDelegate(private val views: List<View>) : DecorViewDelegate() {\n    private lateinit var contentParent: FrameLayout\n\n    constructor(delegates: Array<out ViewDelegate>) : this(delegates.map {\n      register(it)\n      getOrCreateView(it.viewType)\n    })\n\n    override fun onCreateDecorView(context: Context, inflater: LayoutInflater) =\n      LinearLayout(inflater.context).apply {\n        orientation = LinearLayout.VERTICAL\n        contentParent = FrameLayout(context)\n        contentParent.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)\n        views.forEach { addView(it) }\n        addView(contentParent)\n      }\n\n    override fun getContentParent(decorView: View) = contentParent\n  }\n\n  class PoolInitializer internal constructor(private val stateView: LoadingStateView) {\n    fun register(vararg delegates: ViewDelegate) = stateView.register(*delegates)\n  }\n\n  fun interface Callback<in T> {\n    fun T.invoke()\n  }\n\n  interface Animatable {\n    fun toggleViewsAnimation(showView: View, hideView: View, showViewType: Any, hideViewType: Any)\n  }\n\n  companion object {\n    private var poolInitializer: Callback<PoolInitializer>? = null\n\n    @JvmStatic\n    var defaultAnimatable: Animatable? = null\n\n    @JvmStatic\n    fun setViewDelegatePool(poolInitializer: Callback<PoolInitializer>) {\n      this.poolInitializer = poolInitializer\n    }\n  }\n}\n\ninterface OnReloadListener {\n  fun onReload() = Unit\n}\n\nenum class ViewType {\n  TITLE, LOADING, CONTENT, ERROR, EMPTY\n}"
  },
  {
    "path": "loadingstateview/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\">Library</string>\n</resources>\n"
  },
  {
    "path": "loadingstateview-ktx/.gitignore",
    "content": "/build"
  },
  {
    "path": "loadingstateview-ktx/build.gradle",
    "content": "plugins {\n    id 'com.android.library'\n    id 'org.jetbrains.kotlin.android'\n}\n\nandroid {\n    compileSdkVersion buildConfig.compileSdkVersion\n\n    defaultConfig {\n        minSdkVersion buildConfig.minSdkVersion\n        consumerProguardFiles \"consumer-rules.pro\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n        freeCompilerArgs += ['-module-name', \"loading_state_view_ktx\"]\n    }\n}\n\ndependencies {\n    api project(':loadingstateview')\n    implementation \"androidx.appcompat:appcompat:$appCompatVersion\"\n}"
  },
  {
    "path": "loadingstateview-ktx/consumer-rules.pro",
    "content": ""
  },
  {
    "path": "loadingstateview-ktx/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "loadingstateview-ktx/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.dylanc.loadingstateview.ext\">\n\n</manifest>"
  },
  {
    "path": "loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/BaseToolbarViewDelegate.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\n\nabstract class BaseToolbarViewDelegate : LoadingStateView.ViewDelegate(ViewType.TITLE) {\n  internal lateinit var config: ToolbarConfig\n\n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup) =\n    onCreateToolbar(inflater, parent).apply { onBindToolbar(config) }\n\n  abstract fun onCreateToolbar(inflater: LayoutInflater, parent: ViewGroup): View\n\n  abstract fun onBindToolbar(config: ToolbarConfig)\n}"
  },
  {
    "path": "loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/Decorative.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview\n\nimport android.view.View\n\ninterface Decorative : OnReloadListener {\n  val isDecorated: Boolean get() = true\n  val contentView: View? get() = null\n}"
  },
  {
    "path": "loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingState.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview\n\nimport android.app.Activity\nimport android.view.View\nimport androidx.annotation.StringRes\nimport androidx.fragment.app.Fragment\n\ninterface LoadingState : Decorative, OnReloadListener {\n  val loadingStateViewType: Any?\n\n  @Deprecated(\"Use Activity.decorateContentView(this) instead\", ReplaceWith(\"decorateContentView(decorative)\"))\n  fun Activity.decorateContentView(listener: OnReloadListener, decorative: Decorative) = decorateContentView(decorative)\n\n  fun Activity.decorateContentView(decorative: Decorative)\n\n  @Deprecated(\"Use View.decorate(this) instead\", ReplaceWith(\"decorate(decorative)\"))\n  fun View.decorate(listener: OnReloadListener, decorative: Decorative): View = decorate(decorative)\n\n  fun View.decorate(decorative: Decorative): View\n\n  fun registerView(vararg viewDelegates: LoadingStateView.ViewDelegate)\n\n  fun Activity.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null)\n\n  fun Activity.setToolbar(title: String? = null, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null)\n\n  fun Fragment.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null)\n\n  fun Fragment.setToolbar(title: String? = null, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null)\n\n  fun Activity.setHeaders(vararg delegates: LoadingStateView.ViewDelegate)\n\n  fun Fragment.setHeaders(vararg delegates: LoadingStateView.ViewDelegate)\n\n  fun Activity.setDecorView(delegate: LoadingStateView.DecorViewDelegate)\n\n  fun Fragment.setDecorView(delegate: LoadingStateView.DecorViewDelegate)\n\n  fun showLoadingView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable)\n\n  fun showContentView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable)\n\n  fun showErrorView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable)\n\n  fun showEmptyView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable)\n\n  fun showCustomView(viewType: Any, animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable)\n\n  fun updateToolbar(block: ToolbarConfig.() -> Unit)\n\n  fun <T : LoadingStateView.ViewDelegate> updateView(viewType: Any, block: T.() -> Unit)\n\n  @Suppress(\"FunctionName\")\n  fun ToolbarViewDelegate(\n    title: String? = null, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null\n  ): BaseToolbarViewDelegate\n}"
  },
  {
    "path": "loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingStateDelegate.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview\n\nimport android.app.Activity\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.annotation.StringRes\nimport androidx.fragment.app.Fragment\n\nclass LoadingStateDelegate : LoadingState {\n  private var loadingStateView: LoadingStateView? = null\n\n  override val loadingStateViewType: Any?\n    get() = loadingStateView?.currentViewType\n\n  override fun Activity.decorateContentView(decorative: Decorative) {\n    findViewById<ViewGroup>(android.R.id.content).getChildAt(0).decorate(decorative)\n  }\n\n  override fun View.decorate(decorative: Decorative): View =\n    when {\n      !decorative.isDecorated -> this\n      decorative.contentView == null ->\n        LoadingStateView(this, decorative).also { loadingStateView = it }.decorView\n\n      else -> {\n        loadingStateView = LoadingStateView(decorative.contentView!!, decorative)\n        this\n      }\n    }\n\n  override fun registerView(vararg viewDelegates: LoadingStateView.ViewDelegate) {\n    loadingStateView?.register(*viewDelegates)\n  }\n\n  override fun Activity.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) {\n    setToolbar(getString(titleId), navBtnType, block)\n  }\n\n  override fun Activity.setToolbar(title: String?, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) {\n    loadingStateView?.setHeaders(ToolbarViewDelegate(title, navBtnType, block))\n  }\n\n  override fun Fragment.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) {\n    setToolbar(getString(titleId), navBtnType, block)\n  }\n\n  override fun Fragment.setToolbar(title: String?, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) {\n    loadingStateView?.addChildHeaders(ToolbarViewDelegate(title, navBtnType, block))\n  }\n\n  override fun Activity.setHeaders(vararg delegates: LoadingStateView.ViewDelegate) {\n    loadingStateView?.setHeaders(*delegates)\n  }\n\n  override fun Fragment.setHeaders(vararg delegates: LoadingStateView.ViewDelegate) {\n    loadingStateView?.addChildHeaders(*delegates)\n  }\n\n  override fun Activity.setDecorView(delegate: LoadingStateView.DecorViewDelegate) {\n    loadingStateView?.setDecorView(delegate)\n  }\n\n  override fun Fragment.setDecorView(delegate: LoadingStateView.DecorViewDelegate) {\n    loadingStateView?.addChildDecorView(delegate)\n  }\n\n  override fun showLoadingView(animatable: LoadingStateView.Animatable?) {\n    loadingStateView?.showLoadingView(animatable)\n  }\n\n  override fun showContentView(animatable: LoadingStateView.Animatable?) {\n    loadingStateView?.showContentView(animatable)\n  }\n\n  override fun showErrorView(animatable: LoadingStateView.Animatable?) {\n    loadingStateView?.showErrorView(animatable)\n  }\n\n  override fun showEmptyView(animatable: LoadingStateView.Animatable?) {\n    loadingStateView?.showEmptyView(animatable)\n  }\n\n  override fun showCustomView(viewType: Any, animatable: LoadingStateView.Animatable?) {\n    loadingStateView?.showView(viewType, animatable)\n  }\n\n  override fun updateToolbar(block: ToolbarConfig.() -> Unit) {\n    updateView<BaseToolbarViewDelegate>(ViewType.TITLE) { onBindToolbar(config.apply(block)) }\n  }\n\n  override fun <T : LoadingStateView.ViewDelegate> updateView(viewType: Any, block: T.() -> Unit) {\n    loadingStateView?.updateViewDelegate(viewType, block)\n  }\n\n  override fun ToolbarViewDelegate(title: String?, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) =\n    requireNotNull(loadingStateView?.getViewDelegate<BaseToolbarViewDelegate>(ViewType.TITLE)) {\n      \"ToolbarViewDelegate must be registered before.\"\n    }.apply {\n      config = ToolbarConfig(title, navBtnType).apply { block?.invoke(this) }\n    }\n}"
  },
  {
    "path": "loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/ToolbarConfig.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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\n@file:Suppress(\"unused\")\n\npackage com.dylanc.loadingstateview\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.ContextWrapper\nimport android.view.View\nimport androidx.annotation.DrawableRes\nimport kotlin.properties.ReadWriteProperty\nimport kotlin.reflect.KProperty\n\nenum class NavBtnType {\n  ICON, TEXT, ICON_TEXT, NONE\n}\n\nclass ToolbarConfig(\n  var title: String? = null,\n  var navBtnType: NavBtnType = NavBtnType.ICON,\n  val extras: HashMap<String, Any?> = HashMap(),\n) {\n  @DrawableRes\n  var navIcon: Int? = null\n  var navText: String? = null\n    private set\n  var onNavClickListener = View.OnClickListener {\n    var context: Context? = it.context\n    while (context is ContextWrapper) {\n      if (context is Activity) {\n        context.finish()\n        return@OnClickListener\n      }\n      context = context.baseContext\n    }\n  }\n    private set\n\n  @DrawableRes\n  var rightIcon: Int? = null\n    private set\n  var rightText: String? = null\n    private set\n  var onRightClickListener: View.OnClickListener? = null\n    private set\n\n  fun navIcon(@DrawableRes icon: Int? = navIcon, listener: View.OnClickListener) {\n    navIcon = icon\n    onNavClickListener = listener\n  }\n\n  fun navText(text: String, listener: View.OnClickListener) {\n    navText = text\n    onNavClickListener = listener\n  }\n\n  fun rightIcon(@DrawableRes icon: Int, listener: View.OnClickListener) {\n    rightIcon = icon\n    onRightClickListener = listener\n  }\n\n  fun rightText(text: String, listener: View.OnClickListener) {\n    rightText = text\n    onRightClickListener = listener\n  }\n}\n\nfun <T> toolbarExtras() = object : ReadWriteProperty<ToolbarConfig, T?> {\n  @Suppress(\"UNCHECKED_CAST\")\n  override fun getValue(thisRef: ToolbarConfig, property: KProperty<*>): T? =\n    thisRef.extras[property.name] as? T\n\n  override fun setValue(thisRef: ToolbarConfig, property: KProperty<*>, value: T?) {\n    thisRef.extras[property.name] = value\n  }\n}"
  },
  {
    "path": "sample-java/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "sample-java/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion buildConfig.compileSdkVersion\n\n    defaultConfig {\n        applicationId \"com.dylanc.loadingstateview.sample.java\"\n        minSdkVersion buildConfig.minSdkVersion\n        targetSdkVersion buildConfig.targetSdkVersion\n        versionCode buildConfig.versionCode\n        versionName buildConfig.versionName\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    viewBinding {\n        enabled = true\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation project(':loadingstateview')\n    implementation \"androidx.appcompat:appcompat:$appCompatVersion\"\n    implementation \"androidx.constraintlayout:constraintlayout:$constraintLayoutVersion\"\n    implementation \"com.google.android.material:material:$materialVersion\"\n    implementation \"com.github.bumptech.glide:glide:$glideVersion\"\n    testImplementation \"junit:junit:$junitVersion\"\n    androidTestImplementation \"androidx.test.ext:junit:$junitExtVersion\"\n    androidTestImplementation \"androidx.test.espresso:espresso-core:$espressoVersion\"\n}\n"
  },
  {
    "path": "sample-java/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n\n-keep public class com.dylanc.loadingstateview.sample.java.widget.**{*;}\n"
  },
  {
    "path": "sample-java/release/output.json",
    "content": "[{\"outputType\":{\"type\":\"APK\"},\"apkData\":{\"type\":\"MAIN\",\"splits\":[],\"versionCode\":2,\"versionName\":\"1.0.1\",\"enabled\":true,\"outputFile\":\"app-release.apk\",\"fullName\":\"release\",\"baseName\":\"release\",\"dirName\":\"\"},\"path\":\"app-release.apk\",\"properties\":{}}]"
  },
  {
    "path": "sample-java/src/androidTest/java/com/dylanc/loadingstateview/sample/java/ExampleInstrumentedTest.kt",
    "content": "package com.dylanc.loadingstateview.sample.java\n\nimport androidx.test.platform.app.InstrumentationRegistry\nimport androidx.test.ext.junit.runners.AndroidJUnit4\n\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\nimport org.junit.Assert.*\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\n@RunWith(AndroidJUnit4::class)\nclass ExampleInstrumentedTest {\n    @Test\n    fun useAppContext() {\n        // Context of the app under test.\n        val appContext = InstrumentationRegistry.getInstrumentation().targetContext\n        assertEquals(\"com.dylanc.loadinghelper.sample\", appContext.packageName)\n    }\n}\n"
  },
  {
    "path": "sample-java/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:tools=\"http://schemas.android.com/tools\"\n  package=\"com.dylanc.loadingstateview.sample.java\">\n\n  <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n  <uses-permission android:name=\"android.permission.INTERNET\" />\n\n  <application\n    android:name=\".App\"\n    android:allowBackup=\"true\"\n    android:icon=\"@drawable/ic_logo\"\n    android:label=\"@string/app_name\"\n    android:screenOrientation=\"portrait\"\n    android:supportsRtl=\"true\"\n    android:theme=\"@style/AppTheme\"\n    tools:ignore=\"GoogleAppIndexingWarning\">\n    <activity android:name=\".ui.MainActivity\">\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.ActErrorActivity\" />\n    <activity android:name=\".ui.FragmentEmptyActivity\" />\n    <activity android:name=\".ui.ViewPlaceholderActivity\" />\n    <activity android:name=\".ui.ViewPagerActivity\" />\n    <activity android:name=\".ui.RecyclerViewActivity\" />\n    <activity android:name=\".ui.CustomHeaderActivity\" />\n    <activity android:name=\".ui.MultipleHeaderActivity\" />\n    <activity android:name=\".ui.ScrollingToolbarActivity\" />\n    <activity android:name=\".ui.BottomEditorActivity\"/>\n  </application>\n\n</manifest>"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/App.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java;\n\nimport android.app.Application;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.sample.java.animation.FadeAnimatable;\nimport com.dylanc.loadingstateview.sample.java.delegate.EmptyViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.ErrorViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.LoadingViewDelegate;\n\n/**\n * @author Dylan Cai\n */\npublic class App extends Application {\n  @Override\n  public void onCreate() {\n    super.onCreate();\n    LoadingStateView.setViewDelegatePool(pool ->\n        pool.register(new LoadingViewDelegate(), new ErrorViewDelegate(), new EmptyViewDelegate()));\n    LoadingStateView.setDefaultAnimatable(new FadeAnimatable());\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/animation/FadeAnimatable.java",
    "content": "package com.dylanc.loadingstateview.sample.java.animation;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author Dylan Cai\n */\npublic class FadeAnimatable implements LoadingStateView.Animatable {\n\n  private static final long DEFAULT_DURATION = 500;\n  private final long duration;\n\n  public FadeAnimatable() {\n    this(DEFAULT_DURATION);\n  }\n\n  public FadeAnimatable(long duration) {\n    this.duration = duration;\n  }\n\n  @Override\n  public void toggleViewsAnimation(@NonNull View showView, @NonNull View hideView, @NonNull Object showViewType, @NonNull Object hideViewType) {\n    showView.setAlpha(0);\n    showView.setVisibility(View.VISIBLE);\n    showView.animate().alpha(1).setDuration(duration);\n\n    if (showViewType == ViewType.LOADING && hideViewType == ViewType.CONTENT) {\n      hideView.setVisibility(View.GONE);\n    } else {\n      hideView.animate().alpha(0).setDuration(duration).withEndAction(() -> {\n        hideView.setAlpha(1);\n        hideView.setVisibility(View.GONE);\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/base/BaseActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.base;\n\nimport androidx.annotation.IdRes;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.OnReloadListener;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.delegate.ToolbarViewDelegate;\n\n/**\n * 这是耦合度较低的封装方式，没有任何抽象方法，可以很方便地将基类里的代码拷贝到其它项目的基类里使用。\n * <p>\n * 使用该基类时注意以下事项：\n * 1. 显示对应视图之前需要注册适配器，可以设置全局适配器，某个页面想修改样式时再注册个新的适配器。\n * 2. 设置标题栏的方法应该根据项目需要进行编写，下面提供了参考示例。\n *\n * @author Dylan Cai\n */\n@SuppressWarnings(\"unused\")\npublic class BaseActivity extends AppCompatActivity implements OnReloadListener {\n\n  private LoadingStateView loadingStateView;\n\n  @Override\n  public void setContentView(int layoutResID) {\n    this.setContentView(layoutResID, 0);\n  }\n\n  public void setContentView(int layoutResID, @IdRes int contentViewId) {\n    super.setContentView(layoutResID);\n    if (contentViewId == 0) {\n      loadingStateView = new LoadingStateView(this, this);\n    } else {\n      loadingStateView = new LoadingStateView(findViewById(contentViewId));\n    }\n  }\n\n  /**\n   * 添加标题栏的示例方法，请根据自己的需求进行修改\n   */\n  public void setToolbar(String title) {\n    setToolbar(title, NavIconType.BACK, 0);\n  }\n\n  public void setToolbar(String title, NavIconType type) {\n    setToolbar(title, type, 0);\n  }\n\n  public void setToolbar(String title, NavIconType type, int menuId) {\n    loadingStateView.setHeaders(new ToolbarViewDelegate(title, type, menuId, this::onOptionsItemSelected));\n  }\n\n  public void showLoadingView() {\n    loadingStateView.showLoadingView();\n  }\n\n  public void showContentView() {\n    loadingStateView.showContentView();\n  }\n\n  public void showErrorView() {\n    loadingStateView.showErrorView();\n  }\n\n  public void showEmptyView() {\n    loadingStateView.showEmptyView();\n  }\n\n  public void showCustomView(Object viewType) {\n    loadingStateView.showView(viewType);\n  }\n\n  @Override\n  public void onReload() {\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/BottomEditorDecorViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.EditText;\n\nimport androidx.annotation.NonNull;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.utils.KeyboardUtils;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author Dylan Cai\n */\npublic class BottomEditorDecorViewDelegate extends LoadingStateView.DecorViewDelegate {\n  private final OnSendListener onSendListener;\n\n  public BottomEditorDecorViewDelegate(OnSendListener onSendListener) {\n    this.onSendListener = onSendListener;\n  }\n\n  @NotNull\n  @Override\n  @SuppressLint(\"InflateParams\")\n  public View onCreateDecorView(@NonNull Context context, @NotNull LayoutInflater inflater) {\n    View view = inflater.inflate(R.layout.layout_bottom_editor, null);\n    EditText edtContent = view.findViewById(R.id.edt_content);\n    view.findViewById(R.id.btn_send).setOnClickListener(v -> {\n      if (onSendListener != null) {\n        onSendListener.onSend(edtContent.getText().toString());\n        edtContent.setText(\"\");\n        KeyboardUtils.hideKeyboard(edtContent);\n      }\n    });\n    return view;\n  }\n\n  @NotNull\n  @Override\n  public ViewGroup getContentParent(@NotNull View decorView) {\n    return decorView.findViewById(R.id.content_parent);\n  }\n\n  public interface OnSendListener {\n    void onSend(String content);\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CoolLoadingViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport androidx.annotation.NonNull;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class CoolLoadingViewDelegate extends LoadingStateView.ViewDelegate {\n\n  public CoolLoadingViewDelegate() {\n    super(ViewType.LOADING);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    return inflater.inflate(R.layout.layout_cool_loading, parent, false);\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CustomHeaderViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport android.app.Activity;\nimport android.os.Build;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.content.ContextCompat;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class CustomHeaderViewDelegate extends LoadingStateView.ViewDelegate {\n\n  private final View.OnClickListener onMessageClickListener;\n  private final int firstDrawableId;\n  private final View.OnClickListener onFirstBtnClickListener;\n  private final int secondDrawableId;\n  private final View.OnClickListener onSecondBtnClickListener;\n\n  public CustomHeaderViewDelegate(View.OnClickListener onMessageClickListener, int firstDrawableId,\n                                  View.OnClickListener onFirstBtnClickListener, int secondDrawableId,\n                                  View.OnClickListener onSecondBtnClickListener) {\n    super(ViewType.TITLE);\n    this.onMessageClickListener = onMessageClickListener;\n    this.firstDrawableId = firstDrawableId;\n    this.onFirstBtnClickListener = onFirstBtnClickListener;\n    this.secondDrawableId = secondDrawableId;\n    this.onSecondBtnClickListener = onSecondBtnClickListener;\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    View view = inflater.inflate(R.layout.layout_custom_header, parent, false);\n    ImageView btnFirst = view.findViewById(R.id.btn_first);\n    ImageView btnSecond = view.findViewById(R.id.btn_second);\n    View btnMessage = view.findViewById(R.id.btn_message);\n    Activity activity = (Activity) view.getContext();\n    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n      activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);\n    }\n\n    btnMessage.setOnClickListener(onMessageClickListener);\n\n    btnFirst.setImageDrawable(ContextCompat.getDrawable(activity, firstDrawableId));\n    btnFirst.setOnClickListener(onFirstBtnClickListener);\n\n    btnSecond.setImageDrawable(ContextCompat.getDrawable(activity, secondDrawableId));\n    btnSecond.setOnClickListener(onSecondBtnClickListener);\n    return view;\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/EmptyViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport androidx.annotation.NonNull;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class EmptyViewDelegate extends LoadingStateView.ViewDelegate {\n\n  public EmptyViewDelegate() {\n    super(ViewType.EMPTY);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    return inflater.inflate(R.layout.layout_empty, parent, false);\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ErrorViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport androidx.annotation.NonNull;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class ErrorViewDelegate extends LoadingStateView.ViewDelegate {\n\n  public ErrorViewDelegate() {\n    super(ViewType.ERROR);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    View view = inflater.inflate(R.layout.layout_error, parent, false);\n    view.findViewById(R.id.btn_reload).setOnClickListener(v -> {\n      if (getOnReloadListener() != null) {\n        getOnReloadListener().onReload();\n      }\n    });\n    return view;\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/LoadingViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport androidx.annotation.NonNull;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class LoadingViewDelegate extends LoadingStateView.ViewDelegate {\n\n  public int height = ViewGroup.LayoutParams.MATCH_PARENT;\n\n  public LoadingViewDelegate() {\n    super(ViewType.LOADING);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    View view = inflater.inflate(R.layout.layout_loading, parent, false);\n    ViewGroup.LayoutParams layoutParams = view.getLayoutParams();\n    layoutParams.height = height;\n    view.setLayoutParams(layoutParams);\n    return view;\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NavIconType.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\n/**\n * @author Dylan Cai\n */\npublic enum NavIconType {\n  BACK, NONE\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NothingViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport androidx.annotation.NonNull;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\n\n/**\n * @author Dylan Cai\n */\npublic class NothingViewDelegate extends LoadingStateView.ViewDelegate {\n\n  public NothingViewDelegate() {\n    super(ViewType.EMPTY);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    return new View(parent.getContext());\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/PlaceholderViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport androidx.annotation.NonNull;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class PlaceholderViewDelegate extends LoadingStateView.ViewDelegate {\n\n  public PlaceholderViewDelegate() {\n    super(ViewType.LOADING);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    return inflater.inflate(R.layout.layout_placeholder, parent, false);\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ScrollingDecorViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.Build;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.Toolbar;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.sample.java.R;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * @author Dylan Cai\n */\npublic class ScrollingDecorViewDelegate extends LoadingStateView.DecorViewDelegate {\n  private final String title;\n\n  public ScrollingDecorViewDelegate(String title) {\n    this.title = title;\n  }\n\n  @NotNull\n  @Override\n  @SuppressLint(\"InflateParams\")\n  public View onCreateDecorView(@NonNull Context context, @NotNull LayoutInflater inflater) {\n    View view = inflater.inflate(R.layout.layout_scrolling_toolbar, null);\n    Activity activity = (Activity) inflater.getContext();\n    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n      activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);\n    }\n    Toolbar toolbar = view.findViewById(R.id.toolbar);\n    toolbar.setTitle(title);\n    toolbar.setNavigationOnClickListener(v -> activity.finish());\n    return view;\n  }\n\n  @NotNull\n  @Override\n  public ViewGroup getContentParent(@NotNull View decorView) {\n    return decorView.findViewById(R.id.content_parent);\n  }\n\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/SearchHeaderViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.inputmethod.EditorInfo;\nimport android.widget.EditText;\n\nimport androidx.annotation.NonNull;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.utils.KeyboardUtils;\n\n/**\n * @author Dylan Cai\n */\npublic class SearchHeaderViewDelegate extends LoadingStateView.ViewDelegate{\n\n  public static final String VIEW_TYPE_SEARCH = \"search\";\n  private final OnSearchListener onSearchListener;\n\n  public SearchHeaderViewDelegate(OnSearchListener onSearchListener) {\n    super(VIEW_TYPE_SEARCH);\n    this.onSearchListener = onSearchListener;\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    View view = inflater.inflate(R.layout.layout_search_header, parent, false);\n    EditText edtSearch = view.findViewById(R.id.edt_search);\n    edtSearch.setOnEditorActionListener((v, actionId, event) -> {\n      if (actionId == EditorInfo.IME_ACTION_SEARCH) {\n        KeyboardUtils.hideKeyboard(edtSearch);\n        if (onSearchListener != null) {\n          onSearchListener.onSearch(edtSearch.getText().toString());\n        }\n        return true;\n      }\n      return false;\n    });\n    return view;\n  }\n\n  public interface OnSearchListener {\n    void onSearch(String keyword);\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/TimeoutViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport androidx.annotation.NonNull;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class TimeoutViewDelegate extends LoadingStateView.ViewDelegate {\n  public static final String VIEW_TYPE_TIMEOUT = \"timeout\";\n\n  public TimeoutViewDelegate() {\n    super(VIEW_TYPE_TIMEOUT);\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    View view = inflater.inflate(R.layout.layout_timeout, parent, false);\n    view.setOnClickListener(v -> {\n      if (getOnReloadListener() != null) {\n        getOnReloadListener().onReload();\n      }\n    });\n    return view;\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ToolbarViewDelegate.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.delegate;\n\nimport android.app.Activity;\nimport android.os.Build;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.Toolbar;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport kotlin.jvm.functions.Function1;\n\n/**\n * @author Dylan Cai\n */\npublic class ToolbarViewDelegate extends LoadingStateView.ViewDelegate {\n\n  private final String title;\n  private final NavIconType type;\n  private final int menuId;\n  private final Function1<? super MenuItem, Boolean> onMenuItemClick;\n\n  public ToolbarViewDelegate(String title, NavIconType type) {\n    this(title, type, 0, null);\n  }\n\n  public ToolbarViewDelegate(String title, NavIconType type, int menuId, Function1<? super MenuItem, Boolean> onMenuItemClick) {\n    super(ViewType.TITLE);\n    this.title = title;\n    this.type = type;\n    this.menuId = menuId;\n    this.onMenuItemClick = onMenuItemClick;\n  }\n\n  @NonNull\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {\n    View view = inflater.inflate(R.layout.layout_toolbar, parent, false);\n    Activity activity = (Activity) view.getContext();\n    Toolbar toolbar = view.findViewById(R.id.toolbar);\n    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n      activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);\n    }\n\n    if (!TextUtils.isEmpty(title)) {\n      toolbar.setTitle(title);\n    }\n\n    if (type == NavIconType.BACK) {\n      toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black);\n      toolbar.setNavigationOnClickListener(v -> activity.finish());\n    } else {\n      toolbar.setNavigationIcon(null);\n    }\n\n    if (menuId > 0 && onMenuItemClick != null) {\n      toolbar.inflateMenu(menuId);\n      toolbar.setOnMenuItemClickListener(onMenuItemClick::invoke);\n    }\n    return view;\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ActErrorActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.OnReloadListener;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\n\n/**\n * @author Dylan Cai\n */\npublic class ActErrorActivity extends AppCompatActivity implements OnReloadListener {\n\n  private LoadingStateView loadingStateView;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.layout_content);\n    loadingStateView = ToolbarUtils.setToolbar(this, \"Activity(error)\", NavIconType.BACK);\n    loadingStateView.setOnReloadListener(this);\n    loadData();\n  }\n\n  private void loadData() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestFailure(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showErrorView();\n      }\n    });\n  }\n\n  @Override\n  public void onReload() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showErrorView();\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/BottomEditorActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.BottomEditorDecorViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.NothingViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\n\n/**\n * @author Dylan Cai\n */\npublic class BottomEditorActivity extends AppCompatActivity implements BottomEditorDecorViewDelegate.OnSendListener {\n\n  private LoadingStateView loadingStateView;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.layout_content);\n    loadingStateView = ToolbarUtils.setToolbar(this, \"BottomDecorView(editor)\", NavIconType.BACK);\n    loadingStateView.addChildDecorView(new BottomEditorDecorViewDelegate(this));\n    loadingStateView.register(new NothingViewDelegate());\n    loadingStateView.showEmptyView();\n  }\n\n  @Override\n  public void onSend(String content) {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showErrorView();\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/CustomHeaderActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\nimport androidx.fragment.app.FragmentPagerAdapter;\nimport androidx.viewpager.widget.ViewPager;\n\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.ui.fragment.SimpleFragment;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\nimport com.google.android.material.tabs.TabLayout;\n\n/**\n * @author Dylan Cai\n */\npublic class CustomHeaderActivity extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_view_pager);\n    ToolbarUtils.setCustomToolbar(this, this::onMessageClick,\n        R.drawable.ic_baseline_photo_camera_24, this::onFirstBtnClick,\n        R.drawable.ic_baseline_favorite_24, this::onSecondBtnClick);\n\n    // This TabLayout is in the custom toolbar.\n    TabLayout tabLayout = findViewById(R.id.tab_layout);\n    ViewPager viewPager = findViewById(R.id.view_pager);\n    viewPager.setAdapter(new TabPagerAdapter(getSupportFragmentManager()));\n    tabLayout.setupWithViewPager(viewPager);\n  }\n\n  private void onMessageClick(View view) {\n    Toast.makeText(this, \"message\", Toast.LENGTH_SHORT).show();\n  }\n\n  private void onFirstBtnClick(View view) {\n    Toast.makeText(this, \"camera\", Toast.LENGTH_SHORT).show();\n  }\n\n  private void onSecondBtnClick(View view) {\n    Toast.makeText(this, \"favorite\", Toast.LENGTH_SHORT).show();\n  }\n\n  public static class TabPagerAdapter extends FragmentPagerAdapter {\n\n    public TabPagerAdapter(FragmentManager fm) {\n      super(fm, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);\n    }\n\n    @NonNull\n    @Override\n    public Fragment getItem(int i) {\n      return new SimpleFragment();\n    }\n\n    @Override\n    public int getCount() {\n      return 2;\n    }\n\n    @Nullable\n    @Override\n    public CharSequence getPageTitle(int position) {\n      return \"tab \" + position;\n    }\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/FragmentEmptyActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.fragment.app.FragmentTransaction;\n\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.ui.fragment.EmptyFragment;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\n\n/**\n * @author Dylan Cai\n */\npublic class FragmentEmptyActivity extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_fragment);\n    ToolbarUtils.setToolbar(this,\"Fragment(empty)\", NavIconType.BACK);\n    final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n    transaction.add(R.id.content_view, new EmptyFragment());\n    transaction.commit();\n  }\n\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MainActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.base.BaseActivity;\n\n/**\n * @author Dylan Cai\n */\npublic class MainActivity extends BaseActivity {\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_main);\n    setToolbar(getString(R.string.app_name), NavIconType.NONE, R.menu.menu_about);\n  }\n\n  @Override\n  public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n    if (item.getItemId() == R.id.about) {\n      Uri uri = Uri.parse(\"https://github.com/DylanCaiCoding/LoadingHelper\");\n      Intent intent = new Intent(\"android.intent.action.VIEW\", uri);\n      startActivity(intent);\n    }\n    return true;\n  }\n\n  public void onViewClicked(View view) {\n    switch (view.getId()) {\n      case R.id.btn_activity_error:\n        startActivity(new Intent(this, ActErrorActivity.class));\n        break;\n      case R.id.btn_fragment_empty:\n        startActivity(new Intent(this, FragmentEmptyActivity.class));\n        break;\n      case R.id.btn_view_placeholder:\n        startActivity(new Intent(this, ViewPlaceholderActivity.class));\n        break;\n      case R.id.btn_viewpager_timeout:\n        startActivity(new Intent(this, ViewPagerActivity.class));\n        break;\n      case R.id.btn_recyclerview_loading:\n        startActivity(new Intent(this, RecyclerViewActivity.class));\n        break;\n      case R.id.btn_custom_header:\n        startActivity(new Intent(this, CustomHeaderActivity.class));\n        break;\n      case R.id.btn_search_header:\n        startActivity(new Intent(this, MultipleHeaderActivity.class));\n        break;\n      case R.id.btn_scrolling:\n        startActivity(new Intent(this, ScrollingToolbarActivity.class));\n        break;\n      case R.id.btn_bottom_editor:\n        startActivity(new Intent(this, BottomEditorActivity.class));\n        break;\n    }\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MultipleHeaderActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\nimport android.widget.Toast;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.NothingViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.SearchHeaderViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.ToolbarViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\n\n/**\n * @author Dylan Cai\n */\npublic class MultipleHeaderActivity extends AppCompatActivity implements SearchHeaderViewDelegate.OnSearchListener {\n\n  private LoadingStateView loadingStateView;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.layout_content);\n    loadingStateView = new LoadingStateView(this);\n    loadingStateView.register(new NothingViewDelegate());\n    loadingStateView.setHeaders(\n        new ToolbarViewDelegate(\"MultipleHeader(search)\", NavIconType.BACK),\n        new SearchHeaderViewDelegate(this)\n    );\n    loadingStateView.showEmptyView();\n  }\n\n  @Override\n  public void onSearch(String keyword) {\n    Toast.makeText(this, \"search: \" + keyword, Toast.LENGTH_SHORT).show();\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showErrorView();\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/RecyclerViewActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.recyclerview.widget.GridLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.bumptech.glide.Glide;\nimport com.bumptech.glide.load.DataSource;\nimport com.bumptech.glide.load.engine.GlideException;\nimport com.bumptech.glide.request.RequestListener;\nimport com.bumptech.glide.request.target.Target;\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.CoolLoadingViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\n\n\n/**\n * @author Dylan Cai\n */\npublic class RecyclerViewActivity extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_recycler_view);\n    ToolbarUtils.setToolbar(this,\"RecyclerView(cool loading)\", NavIconType.BACK);\n\n    RecyclerView recyclerView = findViewById(R.id.recycler_view);\n    recyclerView.setNestedScrollingEnabled(false);\n    recyclerView.setAdapter(new ImageAdapter());\n    recyclerView.setLayoutManager(new GridLayoutManager(this, 2));\n  }\n\n  public static class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder> {\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {\n      final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_image, parent, false);\n      return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {\n      holder.showImage(HttpUtils.getRandomImageUrl());\n    }\n\n    @Override\n    public int getItemCount() {\n      return 10;\n    }\n\n    static class ViewHolder extends RecyclerView.ViewHolder{\n\n      private final LoadingStateView loadingStateView;\n      ImageView imageView;\n      private String url;\n\n      ViewHolder(@NonNull View itemView) {\n        super(itemView);\n        loadingStateView = new LoadingStateView(itemView.findViewById(R.id.loading_view));\n        loadingStateView.register(new CoolLoadingViewDelegate());\n        loadingStateView.setOnReloadListener(() -> showImage(url));\n        imageView = itemView.findViewById(R.id.image_view);\n      }\n\n      void showImage(String url) {\n        this.url = url;\n        loadingStateView.showLoadingView();\n        Glide.with(imageView.getContext())\n            .load(url)\n            .listener(new RequestListener<Drawable>() {\n              @Override\n              public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target,\n                                          boolean isFirstResource) {\n                loadingStateView.showErrorView();\n                return false;\n              }\n\n              @Override\n              public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target,\n                                             DataSource dataSource, boolean isFirstResource) {\n                loadingStateView.showContentView();\n                return false;\n              }\n            })\n            .into(imageView);\n      }\n\n    }\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ScrollingToolbarActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.LoadingViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\n\n/**\n * @author Dylan Cai\n */\npublic class ScrollingToolbarActivity extends AppCompatActivity {\n\n  private LoadingStateView loadingStateView;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_scrolling);\n    loadingStateView = ToolbarUtils.setScrollingToolbar(this, \"SpecialDecorView(scrolling)\");\n    loadingStateView.updateViewDelegate(ViewType.LOADING, (LoadingViewDelegate delegate) ->\n        delegate.height = ViewGroup.LayoutParams.WRAP_CONTENT);\n    loadData();\n  }\n\n  private void loadData() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showErrorView();\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPagerActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\nimport androidx.fragment.app.FragmentPagerAdapter;\nimport androidx.viewpager.widget.ViewPager;\n\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.ui.fragment.TimeoutFragment;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\nimport com.google.android.material.tabs.TabLayout;\n\n/**\n * @author Dylan Cai\n */\npublic class ViewPagerActivity extends AppCompatActivity {\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_tab_layout);\n    ToolbarUtils.setToolbar(this, \"ViewPager(timeout)\", NavIconType.BACK);\n\n    TabLayout tabLayout = findViewById(R.id.tab_layout);\n    ViewPager viewPager = findViewById(R.id.view_pager);\n    viewPager.setAdapter(new TabPagerAdapter(getSupportFragmentManager()));\n    tabLayout.setupWithViewPager(viewPager);\n  }\n\n  public static class TabPagerAdapter extends FragmentPagerAdapter {\n\n    public TabPagerAdapter(FragmentManager fm) {\n      super(fm, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);\n    }\n\n    @NonNull\n    @Override\n    public Fragment getItem(int i) {\n      return new TimeoutFragment();\n    }\n\n    @Override\n    public int getCount() {\n      return 2;\n    }\n\n    @Nullable\n    @Override\n    public CharSequence getPageTitle(int position) {\n      return \"tab \" + position;\n    }\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPlaceholderActivity.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.ViewType;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.delegate.PlaceholderViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\nimport com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils;\n\n/**\n * @author Dylan Cai\n */\npublic class ViewPlaceholderActivity extends AppCompatActivity {\n\n  private LoadingStateView loadingStateView;\n\n  @Override\n  protected void onCreate(@Nullable Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity_view);\n    ToolbarUtils.setToolbar(this,\"View(placeholder)\", NavIconType.BACK);\n\n    View view = findViewById(R.id.content);\n    loadingStateView = new LoadingStateView(view);\n    loadingStateView.register(new PlaceholderViewDelegate());\n\n    loadData();\n  }\n\n  private void loadData() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showLoadingView();\n      }\n    });\n  }\n\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/EmptyFragment.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.OnReloadListener;\nimport com.dylanc.loadingstateview.sample.java.databinding.LayoutContentBinding;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\n\n/**\n * @author Dylan Cai\n */\n@SuppressWarnings(\"FieldCanBeLocal\")\npublic class EmptyFragment extends Fragment implements OnReloadListener {\n\n  private LayoutContentBinding binding;\n  private LoadingStateView loadingStateView;\n\n  @Nullable\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n    binding = LayoutContentBinding.inflate(inflater, container, false);\n    loadingStateView = new LoadingStateView(binding.getRoot());\n    loadingStateView.setOnReloadListener(this);\n    return loadingStateView.getDecorView();\n  }\n\n  @Override\n  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n    super.onViewCreated(view, savedInstanceState);\n    loadData();\n  }\n\n  private void loadData() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showEmptyView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showErrorView();\n      }\n    });\n  }\n\n  @Override\n  public void onReload() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showEmptyView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showErrorView();\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/SimpleFragment.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport com.dylanc.loadingstateview.sample.java.R;\n\n/**\n * @author Dylan Cai\n */\npublic class SimpleFragment extends Fragment {\n\n  @Nullable\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n    return inflater.inflate(R.layout.layout_content, container, false);\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/TimeoutFragment.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.ui.fragment;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.OnReloadListener;\nimport com.dylanc.loadingstateview.sample.java.delegate.TimeoutViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.databinding.LayoutContentBinding;\nimport com.dylanc.loadingstateview.sample.java.utils.HttpUtils;\n\n/**\n * @author Dylan Cai\n */\n@SuppressWarnings(\"FieldCanBeLocal\")\npublic class TimeoutFragment extends Fragment implements OnReloadListener {\n\n  public static final String VIEW_TYPE_TIMEOUT = \"timeout\";\n  private LayoutContentBinding binding;\n  private LoadingStateView loadingStateView;\n\n  @Nullable\n  @Override\n  public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n    binding = LayoutContentBinding.inflate(inflater, container, false);\n    loadingStateView = new LoadingStateView(binding.getRoot());\n    loadingStateView.register(new TimeoutViewDelegate());\n    loadingStateView.setOnReloadListener(this);\n    return loadingStateView.getDecorView();\n  }\n\n  @Override\n  public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n    super.onViewCreated(view, savedInstanceState);\n    loadData();\n  }\n\n  private void loadData() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestFailure(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showView(VIEW_TYPE_TIMEOUT);\n      }\n    });\n  }\n\n  @Override\n  public void onReload() {\n    loadingStateView.showLoadingView();\n    HttpUtils.requestSuccess(new HttpUtils.Callback() {\n      @Override\n      public void onSuccess() {\n        loadingStateView.showContentView();\n      }\n\n      @Override\n      public void onFailure() {\n        loadingStateView.showView(VIEW_TYPE_TIMEOUT);\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/DensityUtils.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.utils;\n\nimport android.content.Context;\n\n/**\n * @author Dylan Cai\n */\npublic class DensityUtils {\n\n  public static float dip2px(Context context, float dpValue) {\n    float scale = context.getResources().getDisplayMetrics().density;\n    return dpValue * scale;\n  }\n}"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/HttpUtils.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.utils;\n\nimport android.os.Handler;\n\nimport java.util.Random;\n\n/**\n * @author Dylan Cai\n */\npublic class HttpUtils {\n\n  /**\n   * 模拟请求，两秒后回调请求成功方法\n   */\n  public static void requestSuccess(final Callback callback){\n    new Handler().postDelayed(() -> {\n      if (callback!=null){\n        callback.onSuccess();\n      }\n    },2000);\n  }\n\n  /**\n   * 模拟请求，两秒后回调请求失败方法\n   */\n  public static void requestFailure(final Callback callback){\n    new Handler().postDelayed(() -> {\n      if (callback!=null){\n        callback.onFailure();\n      }\n    },2000);\n  }\n\n  public static String getRandomImageUrl(){\n    int position = new Random().nextInt(100);\n    return \"https://source.unsplash.com/collection/\"+position+\"/1600x900\";\n  }\n\n  public interface Callback{\n    void onSuccess();\n\n    void onFailure();\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/KeyboardUtils.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.utils;\n\nimport android.content.Context;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\n\n/**\n * @author Dylan Cai\n */\npublic class KeyboardUtils {\n\n  public static void showKeyboard( EditText editText) {\n    InputMethodManager imm = (InputMethodManager) editText.getContext()\n        .getSystemService(Context.INPUT_METHOD_SERVICE);\n    if (imm != null) {\n      imm.showSoftInput(editText, InputMethodManager.RESULT_SHOWN);\n      imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,\n          InputMethodManager.HIDE_IMPLICIT_ONLY);\n    }\n  }\n\n  public static void hideKeyboard(EditText editText) {\n    InputMethodManager imm = (InputMethodManager) editText.getContext()\n        .getSystemService(Context.INPUT_METHOD_SERVICE);\n    if (imm != null) {\n      imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);\n    }\n  }\n\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/ToolbarUtils.java",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.java.utils;\n\nimport android.app.Activity;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport com.dylanc.loadingstateview.LoadingStateView;\nimport com.dylanc.loadingstateview.sample.java.delegate.CustomHeaderViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.ScrollingDecorViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.ToolbarViewDelegate;\nimport com.dylanc.loadingstateview.sample.java.delegate.NavIconType;\n\nimport kotlin.jvm.functions.Function1;\n\n/**\n * @author Dylan Cai\n */\n@SuppressWarnings(\"UnusedReturnValue\")\npublic class ToolbarUtils {\n  public static LoadingStateView setToolbar(Activity activity, String title, NavIconType type) {\n    return setToolbar(activity, title, type, 0, null);\n  }\n\n  public static LoadingStateView setToolbar(Activity activity, String title, NavIconType type, int menuId,\n                                            Function1<? super MenuItem, Boolean> onMenuItemClick) {\n    LoadingStateView loadingStateView = new LoadingStateView(activity);\n    loadingStateView.setHeaders(new ToolbarViewDelegate(title, type, menuId, onMenuItemClick));\n    return loadingStateView;\n  }\n\n  public static LoadingStateView setCustomToolbar(Activity activity, View.OnClickListener onMessageClick,\n                                                  int firstDrawableId, View.OnClickListener onFirstBtnClick,\n                                                  int secondDrawableId, View.OnClickListener onSecondBtnClick) {\n    LoadingStateView loadingStateView = new LoadingStateView(activity);\n    loadingStateView.setHeaders(new CustomHeaderViewDelegate(onMessageClick,\n        firstDrawableId, onFirstBtnClick, secondDrawableId, onSecondBtnClick));\n    return loadingStateView;\n  }\n\n  public static LoadingStateView setScrollingToolbar(Activity activity, String title) {\n    LoadingStateView loadingStateView = new LoadingStateView(activity);\n    loadingStateView.setDecorView(new ScrollingDecorViewDelegate(title));\n    return loadingStateView;\n  }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingDrawable.java",
    "content": "package com.dylanc.loadingstateview.sample.java.widget;\n\nimport android.graphics.Canvas;\nimport android.graphics.ColorFilter;\nimport android.graphics.PixelFormat;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Animatable;\nimport android.graphics.drawable.Drawable;\n\nimport androidx.annotation.NonNull;\n\npublic class LoadingDrawable extends Drawable implements Animatable {\n    private final LoadingRenderer mLoadingRender;\n\n    LoadingDrawable(LoadingRenderer loadingRender) {\n        this.mLoadingRender = loadingRender;\n        Callback mCallback = new Callback() {\n            @Override\n            public void invalidateDrawable(@NonNull Drawable d) {\n                invalidateSelf();\n            }\n\n            @Override\n            public void scheduleDrawable(@NonNull Drawable d, @NonNull Runnable what, long when) {\n                scheduleSelf(what, when);\n            }\n\n            @Override\n            public void unscheduleDrawable(@NonNull Drawable d, @NonNull Runnable what) {\n                unscheduleSelf(what);\n            }\n        };\n        this.mLoadingRender.setCallback(mCallback);\n    }\n\n    @Override\n    protected void onBoundsChange(Rect bounds) {\n        super.onBoundsChange(bounds);\n        this.mLoadingRender.setBounds(bounds);\n    }\n\n    @Override\n    public void draw(@NonNull Canvas canvas) {\n        if (!getBounds().isEmpty()) {\n            this.mLoadingRender.draw(canvas);\n        }\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n        this.mLoadingRender.setAlpha(alpha);\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter cf) {\n        this.mLoadingRender.setColorFilter(cf);\n    }\n\n    @Override\n    public int getOpacity() {\n        return PixelFormat.TRANSLUCENT;\n    }\n\n    @Override\n    public void start() {\n        this.mLoadingRender.start();\n    }\n\n    @Override\n    public void stop() {\n        this.mLoadingRender.stop();\n    }\n\n    @Override\n    public boolean isRunning() {\n        return this.mLoadingRender.isRunning();\n    }\n\n    @Override\n    public int getIntrinsicHeight() {\n        return (int) this.mLoadingRender.mHeight;\n    }\n\n    @Override\n    public int getIntrinsicWidth() {\n        return (int) this.mLoadingRender.mWidth;\n    }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRenderer.java",
    "content": "package com.dylanc.loadingstateview.sample.java.widget;\n\nimport android.animation.Animator;\nimport android.animation.ValueAnimator;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.ColorFilter;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.view.animation.Animation;\nimport android.view.animation.LinearInterpolator;\nimport com.dylanc.loadingstateview.sample.java.utils.DensityUtils;\n\npublic abstract class LoadingRenderer {\n    private static final long ANIMATION_DURATION = 1333;\n    private static final float DEFAULT_SIZE = 56.0f;\n\n    private final ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener\n            = animation -> {\n                computeRender((float) animation.getAnimatedValue());\n                invalidateSelf();\n            };\n\n    /**\n     * Whenever {@link LoadingDrawable} boundary changes mBounds will be updated.\n     * More details you can see {@link LoadingDrawable#onBoundsChange(Rect)}\n     */\n    @SuppressWarnings(\"WeakerAccess\")\n    protected final Rect mBounds = new Rect();\n\n    private Drawable.Callback mCallback;\n    private ValueAnimator mRenderAnimator;\n\n    protected long mDuration;\n\n    protected float mWidth;\n    protected float mHeight;\n\n    public LoadingRenderer(Context context) {\n        initParams(context);\n        setupAnimators();\n    }\n\n    @SuppressWarnings(\"DeprecatedIsStillUsed\")\n    @Deprecated\n    protected void draw(Canvas canvas, Rect bounds) {\n    }\n\n    @SuppressWarnings({\"WeakerAccess\", \"deprecation\"})\n    protected void draw(Canvas canvas) {\n        draw(canvas, mBounds);\n    }\n\n    protected abstract void computeRender(float renderProgress);\n\n    protected abstract void setAlpha(int alpha);\n\n    protected abstract void setColorFilter(ColorFilter cf);\n\n    protected abstract void reset();\n\n    protected void addRenderListener(Animator.AnimatorListener animatorListener) {\n        mRenderAnimator.addListener(animatorListener);\n    }\n\n    void start() {\n        reset();\n        mRenderAnimator.addUpdateListener(mAnimatorUpdateListener);\n\n        mRenderAnimator.setRepeatCount(ValueAnimator.INFINITE);\n        mRenderAnimator.setDuration(mDuration);\n        mRenderAnimator.start();\n    }\n\n    void stop() {\n        // if I just call mRenderAnimator.end(),\n        // it will always call the method onAnimationUpdate(ValueAnimator animation)\n        // why ? if you know why please send email to me (dinus_developer@163.com)\n        mRenderAnimator.removeUpdateListener(mAnimatorUpdateListener);\n\n        mRenderAnimator.setRepeatCount(0);\n        mRenderAnimator.setDuration(0);\n        mRenderAnimator.end();\n    }\n\n    boolean isRunning() {\n        return mRenderAnimator.isRunning();\n    }\n\n    void setCallback(Drawable.Callback callback) {\n        this.mCallback = callback;\n    }\n\n    void setBounds(Rect bounds) {\n        mBounds.set(bounds);\n    }\n\n    private void initParams(Context context) {\n        mWidth = DensityUtils.dip2px(context, DEFAULT_SIZE);\n        mHeight = DensityUtils.dip2px(context, DEFAULT_SIZE);\n\n        mDuration = ANIMATION_DURATION;\n    }\n\n    @SuppressLint(\"WrongConstant\")\n    private void setupAnimators() {\n        mRenderAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);\n        mRenderAnimator.setRepeatCount(Animation.INFINITE);\n        mRenderAnimator.setRepeatMode(Animation.RESTART);\n        mRenderAnimator.setDuration(mDuration);\n        //fuck you! the default interpolator is AccelerateDecelerateInterpolator\n        mRenderAnimator.setInterpolator(new LinearInterpolator());\n        mRenderAnimator.addUpdateListener(mAnimatorUpdateListener);\n    }\n\n    private void invalidateSelf() {\n        mCallback.invalidateDrawable(null);\n    }\n\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRendererFactory.java",
    "content": "package com.dylanc.loadingstateview.sample.java.widget;\n\nimport android.content.Context;\nimport android.util.SparseArray;\nimport com.dylanc.loadingstateview.sample.java.widget.renderer.ElectricFanLoadingRenderer;\n\nimport java.lang.reflect.Constructor;\n\nfinal class LoadingRendererFactory {\n    private static final SparseArray<Class<? extends LoadingRenderer>> LOADING_RENDERERS = new SparseArray<>();\n\n    static {\n        LOADING_RENDERERS.put(9, ElectricFanLoadingRenderer.class);\n    }\n\n    private LoadingRendererFactory() {\n    }\n\n    static LoadingRenderer createLoadingRenderer(Context context, int loadingRendererId) throws Exception {\n        Class<?> loadingRendererClazz = LOADING_RENDERERS.get(loadingRendererId);\n        Constructor<?>[] constructors = loadingRendererClazz.getDeclaredConstructors();\n        for (Constructor<?> constructor : constructors) {\n            Class<?>[] parameterTypes = constructor.getParameterTypes();\n            if (parameterTypes.length == 1 && parameterTypes[0].equals(Context.class)) {\n                constructor.setAccessible(true);\n                return (LoadingRenderer) constructor.newInstance(context);\n            }\n        }\n\n        throw new InstantiationException();\n    }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingView.java",
    "content": "package com.dylanc.loadingstateview.sample.java.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.AppCompatImageView;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport com.dylanc.loadingstateview.sample.java.R;\n\npublic class LoadingView extends AppCompatImageView {\n    private LoadingDrawable mLoadingDrawable;\n\n    public LoadingView(Context context) {\n        super(context);\n    }\n\n    public LoadingView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initAttrs(context, attrs);\n    }\n\n    private void initAttrs(Context context, AttributeSet attrs) {\n        try {\n            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);\n            int loadingRendererId = ta.getInt(R.styleable.LoadingView_loading_renderer, 0);\n            LoadingRenderer loadingRenderer = LoadingRendererFactory.createLoadingRenderer(context, loadingRendererId);\n            setLoadingRenderer(loadingRenderer);\n            ta.recycle();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void setLoadingRenderer(LoadingRenderer loadingRenderer) {\n        mLoadingDrawable = new LoadingDrawable(loadingRenderer);\n        setImageDrawable(mLoadingDrawable);\n    }\n\n    @Override\n    protected void onAttachedToWindow() {\n        super.onAttachedToWindow();\n        startAnimation();\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        super.onDetachedFromWindow();\n        stopAnimation();\n    }\n\n    @Override\n    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {\n        super.onVisibilityChanged(changedView, visibility);\n\n        final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;\n        if (visible) {\n            startAnimation();\n        } else {\n            stopAnimation();\n        }\n    }\n\n    private void startAnimation() {\n        if (mLoadingDrawable != null) {\n            mLoadingDrawable.start();\n        }\n    }\n\n    private void stopAnimation() {\n        if (mLoadingDrawable != null) {\n            mLoadingDrawable.stop();\n        }\n    }\n}\n"
  },
  {
    "path": "sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/renderer/ElectricFanLoadingRenderer.java",
    "content": "package com.dylanc.loadingstateview.sample.java.widget.renderer;\n\nimport android.animation.*;\nimport android.content.Context;\nimport android.graphics.*;\nimport android.graphics.drawable.Drawable;\nimport androidx.annotation.IntDef;\nimport androidx.interpolator.view.animation.FastOutLinearInInterpolator;\nimport androidx.interpolator.view.animation.FastOutSlowInInterpolator;\nimport android.view.animation.AccelerateInterpolator;\nimport android.view.animation.DecelerateInterpolator;\nimport android.view.animation.Interpolator;\nimport android.view.animation.LinearInterpolator;\nimport com.dylanc.loadingstateview.sample.java.R;\nimport com.dylanc.loadingstateview.sample.java.utils.DensityUtils;\nimport com.dylanc.loadingstateview.sample.java.widget.LoadingRenderer;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\npublic class ElectricFanLoadingRenderer extends LoadingRenderer {\n    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();\n    private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();\n    private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();\n    private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator();\n    private static final Interpolator FASTOUTLINEARIN_INTERPOLATOR = new FastOutLinearInInterpolator();\n\n    private static final Interpolator[] INTERPOLATORS = new Interpolator[]{LINEAR_INTERPOLATOR,\n            DECELERATE_INTERPOLATOR, ACCELERATE_INTERPOLATOR, FASTOUTLINEARIN_INTERPOLATOR, MATERIAL_INTERPOLATOR};\n    private static final List<LeafHolder> mLeafHolders = new ArrayList<>();\n    private static final Random mRandom = new Random();\n\n    static final int MODE_NORMAL = 0;\n    static final int MODE_LEAF_COUNT = 1;\n\n    @SuppressWarnings(\"WeakerAccess\")\n    @IntDef({MODE_NORMAL, MODE_LEAF_COUNT})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface MODE {\n    }\n\n    private static final String PERCENTAGE_100 = \"100%\";\n\n    private static final long ANIMATION_DURATION = 7333;\n\n    private static final int LEAF_COUNT = 28;\n    private static final int DEGREE_180 = 180;\n    private static final int DEGREE_360 = 360;\n    private static final int FULL_GROUP_ROTATION = (int) (5.25f * DEGREE_360);\n\n    private static final int DEFAULT_PROGRESS_COLOR = 0xfffca72e;\n    private static final int DEFAULT_PROGRESS_BGCOLOR = 0xfffcd49f;\n    private static final int DEFAULT_ELECTRIC_FAN_BGCOLOR = 0xfffccc59;\n    private static final int DEFAULT_ELECTRIC_FAN_OUTLINE_COLOR = Color.WHITE;\n\n    private static final float DEFAULT_WIDTH = 182.0f;\n    private static final float DEFAULT_HEIGHT = 65.0f;\n    private static final float DEFAULT_TEXT_SIZE = 11.0f;\n    private static final float DEFAULT_STROKE_WIDTH = 2.0f;\n    private static final float DEFAULT_STROKE_INTERVAL = .2f;\n    private static final float DEFAULT_CENTER_RADIUS = 16.0f;\n    private static final float DEFAULT_PROGRESS_CENTER_RADIUS = 11.0f;\n\n    private static final float DEFAULT_LEAF_FLY_DURATION_FACTOR = 0.1f;\n\n    private static final float LEAF_CREATE_DURATION_INTERVAL = 1.0f / LEAF_COUNT;\n    private static final float DECELERATE_DURATION_PERCENTAGE = 0.4f;\n    private static final float ACCELERATE_DURATION_PERCENTAGE = 0.6f;\n\n    private final Paint mPaint = new Paint();\n    private final RectF mTempBounds = new RectF();\n    private final RectF mCurrentProgressBounds = new RectF();\n\n    private float mTextSize;\n    private float mStrokeXInset;\n    private float mStrokeYInset;\n    private float mProgressCenterRadius;\n\n    private float mScale;\n    private float mRotation;\n    private float mProgress;\n\n    private float mNextLeafCreateThreshold;\n\n    private int mProgressColor;\n    private int mProgressBgColor;\n    private int mElectricFanBgColor;\n    private int mElectricFanOutlineColor;\n\n    private float mStrokeWidth;\n    private float mCenterRadius;\n\n    @MODE\n    private int mMode;\n    private int mCurrentLeafCount;\n\n    private Drawable mLeafDrawable;\n    private Drawable mLoadingDrawable;\n    private Drawable mElectricFanDrawable;\n\n    private ElectricFanLoadingRenderer(Context context) {\n        super(context);\n        init(context);\n        setupPaint();\n        Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {\n            @Override\n            public void onAnimationRepeat(Animator animator) {\n                super.onAnimationRepeat(animator);\n                reset();\n            }\n        };\n        addRenderListener(mAnimatorListener);\n    }\n\n    private void init(Context context) {\n        mMode = MODE_NORMAL;\n\n        mWidth = DensityUtils.dip2px(context, DEFAULT_WIDTH);\n        mHeight = DensityUtils.dip2px(context, DEFAULT_HEIGHT);\n        mTextSize = DensityUtils.dip2px(context, DEFAULT_TEXT_SIZE);\n        mStrokeWidth = DensityUtils.dip2px(context, DEFAULT_STROKE_WIDTH);\n        mCenterRadius = DensityUtils.dip2px(context, DEFAULT_CENTER_RADIUS);\n        mProgressCenterRadius = DensityUtils.dip2px(context, DEFAULT_PROGRESS_CENTER_RADIUS);\n\n        mProgressColor = DEFAULT_PROGRESS_COLOR;\n        mProgressBgColor = DEFAULT_PROGRESS_BGCOLOR;\n        mElectricFanBgColor = DEFAULT_ELECTRIC_FAN_BGCOLOR;\n        mElectricFanOutlineColor = DEFAULT_ELECTRIC_FAN_OUTLINE_COLOR;\n\n        mLeafDrawable = context.getResources().getDrawable(R.drawable.ic_leaf);\n        mLoadingDrawable = context.getResources().getDrawable(R.drawable.ic_loading);\n        mElectricFanDrawable = context.getResources().getDrawable(R.drawable.ic_eletric_fan);\n\n        mDuration = ANIMATION_DURATION;\n        setInsets((int) mWidth, (int) mHeight);\n    }\n\n    private void setupPaint() {\n        mPaint.setAntiAlias(true);\n        mPaint.setStrokeWidth(mStrokeWidth);\n        mPaint.setStyle(Paint.Style.STROKE);\n        mPaint.setStrokeCap(Paint.Cap.ROUND);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    protected void draw(Canvas canvas, Rect bounds) {\n        int saveCount = canvas.save();\n\n        RectF arcBounds = mTempBounds;\n        arcBounds.set(bounds);\n        arcBounds.inset(mStrokeXInset, mStrokeYInset);\n\n        mCurrentProgressBounds.set(arcBounds.left, arcBounds.bottom - 2 * mCenterRadius,\n                arcBounds.right, arcBounds.bottom);\n\n        //draw loading drawable\n        mLoadingDrawable.setBounds((int) arcBounds.centerX() - mLoadingDrawable.getIntrinsicWidth() / 2,\n                0,\n                (int) arcBounds.centerX() + mLoadingDrawable.getIntrinsicWidth() / 2,\n                mLoadingDrawable.getIntrinsicHeight());\n        mLoadingDrawable.draw(canvas);\n\n        //draw progress background\n        float progressInset = mCenterRadius - mProgressCenterRadius;\n        RectF progressRect = new RectF(mCurrentProgressBounds);\n        //sub DEFAULT_STROKE_INTERVAL, otherwise will have a interval between progress background and progress outline\n        progressRect.inset(progressInset - DEFAULT_STROKE_INTERVAL, progressInset - DEFAULT_STROKE_INTERVAL);\n        mPaint.setColor(mProgressBgColor);\n        mPaint.setStyle(Paint.Style.FILL);\n        canvas.drawRoundRect(progressRect, mProgressCenterRadius, mProgressCenterRadius, mPaint);\n\n        //draw progress\n        mPaint.setColor(mProgressColor);\n        mPaint.setStyle(Paint.Style.FILL);\n        canvas.drawPath(createProgressPath(mProgress, mProgressCenterRadius, progressRect), mPaint);\n\n        //draw leaves\n        for (int i = 0; i < mLeafHolders.size(); i++) {\n            int leafSaveCount = canvas.save();\n            LeafHolder leafHolder = mLeafHolders.get(i);\n            Rect leafBounds = leafHolder.mLeafRect;\n\n            canvas.rotate(leafHolder.mLeafRotation, leafBounds.centerX(), leafBounds.centerY());\n            mLeafDrawable.setBounds(leafBounds);\n            mLeafDrawable.draw(canvas);\n\n            canvas.restoreToCount(leafSaveCount);\n        }\n\n        //draw progress background outline,\n        //after drawing the leaves and then draw the outline of the progress background can\n        //prevent the leaves from flying to the outside\n        RectF progressOutlineRect = new RectF(mCurrentProgressBounds);\n        float progressOutlineStrokeInset = (mCenterRadius - mProgressCenterRadius) / 2.0f;\n        progressOutlineRect.inset(progressOutlineStrokeInset, progressOutlineStrokeInset);\n        mPaint.setStyle(Paint.Style.STROKE);\n        mPaint.setColor(mProgressBgColor);\n        mPaint.setStrokeWidth(mCenterRadius - mProgressCenterRadius);\n        canvas.drawRoundRect(progressOutlineRect, mCenterRadius, mCenterRadius, mPaint);\n\n        //draw electric fan outline\n        float electricFanCenterX = arcBounds.right - mCenterRadius;\n        float electricFanCenterY = arcBounds.bottom - mCenterRadius;\n\n        mPaint.setColor(mElectricFanOutlineColor);\n        mPaint.setStyle(Paint.Style.STROKE);\n        mPaint.setStrokeWidth(mStrokeWidth);\n        canvas.drawCircle(arcBounds.right - mCenterRadius, arcBounds.bottom - mCenterRadius,\n                mCenterRadius - mStrokeWidth / 2.0f, mPaint);\n\n        //draw electric background\n        mPaint.setColor(mElectricFanBgColor);\n        mPaint.setStyle(Paint.Style.FILL);\n        canvas.drawCircle(arcBounds.right - mCenterRadius, arcBounds.bottom - mCenterRadius,\n                mCenterRadius - mStrokeWidth + DEFAULT_STROKE_INTERVAL, mPaint);\n\n        //draw electric fan\n        int rotateSaveCount = canvas.save();\n        canvas.rotate(mRotation, electricFanCenterX, electricFanCenterY);\n        mElectricFanDrawable.setBounds((int) (electricFanCenterX - mElectricFanDrawable.getIntrinsicWidth() / 2 * mScale),\n                (int) (electricFanCenterY - mElectricFanDrawable.getIntrinsicHeight() / 2 * mScale),\n                (int) (electricFanCenterX + mElectricFanDrawable.getIntrinsicWidth() / 2 * mScale),\n                (int) (electricFanCenterY + mElectricFanDrawable.getIntrinsicHeight() / 2 * mScale));\n        mElectricFanDrawable.draw(canvas);\n        canvas.restoreToCount(rotateSaveCount);\n\n        //draw 100% text\n        if (mScale < 1.0f) {\n            mPaint.setTextSize(mTextSize * (1 - mScale));\n            mPaint.setColor(mElectricFanOutlineColor);\n            Rect textRect = new Rect();\n            mPaint.getTextBounds(PERCENTAGE_100, 0, PERCENTAGE_100.length(), textRect);\n            canvas.drawText(PERCENTAGE_100, electricFanCenterX - textRect.width() / 2.0f,\n                    electricFanCenterY + textRect.height() / 2.0f, mPaint);\n        }\n\n        canvas.restoreToCount(saveCount);\n    }\n\n    private Path createProgressPath(float progress, float circleRadius, RectF progressRect) {\n        RectF arcProgressRect = new RectF(progressRect.left, progressRect.top, progressRect.left + circleRadius * 2, progressRect.bottom);\n        RectF rectProgressRect = null;\n\n        float progressWidth = progress * progressRect.width();\n        float progressModeWidth = mMode == MODE_LEAF_COUNT ?\n                (float) mCurrentLeafCount / (float) LEAF_COUNT * progressRect.width() : progress * progressRect.width();\n\n        float swipeAngle = DEGREE_180;\n        //the left half circle of the progressbar\n        if (progressModeWidth < circleRadius) {\n            swipeAngle = progressModeWidth / circleRadius * DEGREE_180;\n        }\n\n        //the center rect of the progressbar\n        if (progressModeWidth < progressRect.width() - circleRadius && progressModeWidth >= circleRadius) {\n            rectProgressRect = new RectF(progressRect.left + circleRadius, progressRect.top, progressRect.left + progressModeWidth, progressRect.bottom);\n        }\n\n        //the right half circle of the progressbar\n        if (progressWidth >= progressRect.width() - circleRadius) {\n            rectProgressRect = new RectF(progressRect.left + circleRadius, progressRect.top, progressRect.right - circleRadius, progressRect.bottom);\n            mScale = (progressRect.width() - progressWidth) / circleRadius;\n        }\n\n        //the left of the right half circle\n        if (progressWidth < progressRect.width() - circleRadius) {\n            mRotation = (progressWidth / (progressRect.width() - circleRadius)) * FULL_GROUP_ROTATION % DEGREE_360;\n\n            RectF leafRect = new RectF(progressRect.left + progressWidth, progressRect.top, progressRect.right - circleRadius, progressRect.bottom);\n            addLeaf(progress, leafRect);\n        }\n\n        Path path = new Path();\n        path.addArc(arcProgressRect, DEGREE_180 - swipeAngle / 2, swipeAngle);\n\n        if (rectProgressRect != null) {\n            path.addRect(rectProgressRect, Path.Direction.CW);\n        }\n\n        return path;\n    }\n\n    @Override\n    protected void computeRender(float renderProgress) {\n        if (renderProgress < DECELERATE_DURATION_PERCENTAGE) {\n            mProgress = DECELERATE_INTERPOLATOR.getInterpolation(renderProgress / DECELERATE_DURATION_PERCENTAGE) * DECELERATE_DURATION_PERCENTAGE;\n        } else {\n            mProgress = ACCELERATE_INTERPOLATOR.getInterpolation((renderProgress - DECELERATE_DURATION_PERCENTAGE) / ACCELERATE_DURATION_PERCENTAGE) * ACCELERATE_DURATION_PERCENTAGE + DECELERATE_DURATION_PERCENTAGE;\n        }\n    }\n\n    @Override\n    protected void setAlpha(int alpha) {\n        mPaint.setAlpha(alpha);\n\n    }\n\n    @Override\n    protected void setColorFilter(ColorFilter cf) {\n        mPaint.setColorFilter(cf);\n\n    }\n\n    @Override\n    protected void reset() {\n        mScale = 1.0f;\n        mCurrentLeafCount = 0;\n        mNextLeafCreateThreshold = 0.0f;\n        mLeafHolders.clear();\n    }\n\n    private void setInsets(int width, int height) {\n        final float minEdge = (float) Math.min(width, height);\n        float insetXs;\n        if (mCenterRadius <= 0 || minEdge < 0) {\n            insetXs = (float) Math.ceil(mCenterRadius / 2.0f);\n        } else {\n            insetXs = mCenterRadius;\n        }\n        mStrokeYInset = (float) Math.ceil(mCenterRadius / 2.0f);\n        mStrokeXInset = insetXs;\n    }\n\n    private void addLeaf(float progress, RectF leafFlyRect) {\n        if (progress < mNextLeafCreateThreshold) {\n            return;\n        }\n        mNextLeafCreateThreshold += LEAF_CREATE_DURATION_INTERVAL;\n\n        LeafHolder leafHolder = new LeafHolder();\n        mLeafHolders.add(leafHolder);\n        Animator leafAnimator = getAnimator(leafHolder, leafFlyRect, progress);\n        leafAnimator.addListener(new AnimEndListener(leafHolder));\n        leafAnimator.start();\n    }\n\n    private Animator getAnimator(LeafHolder target, RectF leafFlyRect, float progress) {\n        ValueAnimator bezierValueAnimator = getBezierValueAnimator(target, leafFlyRect, progress);\n\n        AnimatorSet finalSet = new AnimatorSet();\n        finalSet.playSequentially(bezierValueAnimator);\n        finalSet.setInterpolator(INTERPOLATORS[mRandom.nextInt(INTERPOLATORS.length)]);\n        finalSet.setTarget(target);\n        return finalSet;\n    }\n\n    private ValueAnimator getBezierValueAnimator(LeafHolder target, RectF leafFlyRect, float progress) {\n        BezierEvaluator evaluator = new BezierEvaluator(getPoint1(leafFlyRect), getPoint2(leafFlyRect));\n\n        int leafFlyStartY = (int) (mCurrentProgressBounds.bottom - mLeafDrawable.getIntrinsicHeight());\n        int leafFlyRange = (int) (mCurrentProgressBounds.height() - mLeafDrawable.getIntrinsicHeight());\n\n        int startPointY = leafFlyStartY - mRandom.nextInt(leafFlyRange);\n        int endPointY = leafFlyStartY - mRandom.nextInt(leafFlyRange);\n\n        ValueAnimator animator = ValueAnimator.ofObject(evaluator,\n                new PointF((int) (leafFlyRect.right - mLeafDrawable.getIntrinsicWidth()), startPointY),\n                new PointF(leafFlyRect.left, endPointY));\n        animator.addUpdateListener(new BezierListener(target));\n        animator.setTarget(target);\n\n        animator.setDuration((long) ((mRandom.nextInt(300) + mDuration * DEFAULT_LEAF_FLY_DURATION_FACTOR) * (1.0f - progress)));\n\n        return animator;\n    }\n\n    //get the pointF which belong to the right half side\n    private PointF getPoint1(RectF leafFlyRect) {\n        PointF point = new PointF();\n        point.x = leafFlyRect.right - mRandom.nextInt((int) (leafFlyRect.width() / 2));\n        point.y = (int) (leafFlyRect.bottom - mRandom.nextInt((int) leafFlyRect.height()));\n        return point;\n    }\n\n    //get the pointF which belong to the left half side\n    private PointF getPoint2(RectF leafFlyRect) {\n        PointF point = new PointF();\n        point.x = leafFlyRect.left + mRandom.nextInt((int) (leafFlyRect.width() / 2));\n        point.y = (int) (leafFlyRect.bottom - mRandom.nextInt((int) leafFlyRect.height()));\n        return point;\n    }\n\n    private static class BezierEvaluator implements TypeEvaluator<PointF> {\n\n        private PointF point1;\n        private PointF point2;\n\n        BezierEvaluator(PointF point1, PointF point2) {\n            this.point1 = point1;\n            this.point2 = point2;\n        }\n\n        //Third-order Bezier curve formula: B(t) = point0 * (1-t)^3 + 3 * point1 * t * (1-t)^2 + 3 * point2 * t^2 * (1-t) + point3 * t^3\n        @Override\n        public PointF evaluate(float fraction, PointF point0, PointF point3) {\n\n            float tLeft = 1.0f - fraction;\n\n            float x = (float) (point0.x * Math.pow(tLeft, 3) + 3 * point1.x * fraction * Math.pow(tLeft, 2) + 3 * point2.x * Math.pow(fraction, 2) * tLeft + point3.x * Math.pow(fraction, 3));\n            float y = (float) (point0.y * Math.pow(tLeft, 3) + 3 * point1.y * fraction * Math.pow(tLeft, 2) + 3 * point2.y * Math.pow(fraction, 2) * tLeft + point3.y * Math.pow(fraction, 3));\n\n            return new PointF(x, y);\n        }\n    }\n\n    private class BezierListener implements ValueAnimator.AnimatorUpdateListener {\n\n        private LeafHolder target;\n\n        BezierListener(LeafHolder target) {\n            this.target = target;\n        }\n\n        @Override\n        public void onAnimationUpdate(ValueAnimator animation) {\n            PointF point = (PointF) animation.getAnimatedValue();\n            target.mLeafRect.set((int) point.x, (int) point.y,\n                    (int) (point.x + mLeafDrawable.getIntrinsicWidth()), (int) (point.y + mLeafDrawable.getIntrinsicHeight()));\n            target.mLeafRotation = target.mMaxRotation * animation.getAnimatedFraction();\n        }\n    }\n\n    private class AnimEndListener extends AnimatorListenerAdapter {\n        private LeafHolder target;\n\n        AnimEndListener(LeafHolder target) {\n            this.target = target;\n        }\n\n        @Override\n        public void onAnimationEnd(Animator animation) {\n            super.onAnimationEnd(animation);\n            mLeafHolders.remove(target);\n            mCurrentLeafCount++;\n        }\n    }\n\n    private static class LeafHolder {\n        Rect mLeafRect = new Rect();\n        float mLeafRotation = 0.0f;\n\n        float mMaxRotation = mRandom.nextInt(120);\n    }\n\n}\n"
  },
  {
    "path": "sample-java/src/main/res/drawable/bg_reload_btn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <corners android:radius=\"4dp\"/>\n  <stroke android:width=\"1dp\"\n          android:color=\"#bbb\"/>\n</shape>"
  },
  {
    "path": "sample-java/src/main/res/drawable/bg_search.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <corners android:radius=\"18dp\"/>\n  <solid android:color=\"#eee\"/>\n</shape>"
  },
  {
    "path": "sample-java/src/main/res/drawable/ic_baseline_favorite_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#666666\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z\"/>\n</vector>\n"
  },
  {
    "path": "sample-java/src/main/res/drawable/ic_baseline_message_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#666666\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z\"/>\n</vector>\n"
  },
  {
    "path": "sample-java/src/main/res/drawable/ic_baseline_photo_camera_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#666666\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z\"/>\n</vector>\n"
  },
  {
    "path": "sample-java/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:height=\"108dp\"\n        android:width=\"108dp\"\n        android:viewportHeight=\"108\"\n        android:viewportWidth=\"108\">\n    <path android:fillColor=\"#008577\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "sample-java/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"108dp\"\n        android:height=\"108dp\"\n        android:viewportHeight=\"108\"\n        android:viewportWidth=\"108\">\n    <path\n            android:fillType=\"evenOdd\"\n            android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n            android:strokeColor=\"#00000000\"\n            android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:endX=\"78.5885\"\n                    android:endY=\"90.9159\"\n                    android:startX=\"48.7653\"\n                    android:startY=\"61.0927\"\n                    android:type=\"linear\">\n                <item\n                        android:color=\"#44000000\"\n                        android:offset=\"0.0\"/>\n                <item\n                        android:color=\"#00000000\"\n                        android:offset=\"1.0\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n            android:fillColor=\"#FFFFFF\"\n            android:fillType=\"nonZero\"\n            android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n            android:strokeColor=\"#00000000\"\n            android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "sample-java/src/main/res/layout/activity_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:id=\"@+id/content_view\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:id=\"@+id/content\"\n  xmlns:tools=\"http://schemas.android.com/tools\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <Button\n    android:id=\"@+id/btn_activity_error\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"Activity(error)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\" />\n\n  <Button\n    android:id=\"@+id/btn_fragment_empty\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"Fragment(empty)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_activity_error\" />\n\n  <Button\n    android:id=\"@+id/btn_view_placeholder\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"View(placeholder)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_fragment_empty\" />\n\n  <Button\n    android:id=\"@+id/btn_viewpager_timeout\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"ViewPager(timeout)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_view_placeholder\" />\n\n  <Button\n    android:id=\"@+id/btn_recyclerview_loading\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"RecyclerView(cool loading)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_viewpager_timeout\" />\n\n  <Button\n    android:id=\"@+id/btn_custom_header\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"SpecialHeader(custom)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_recyclerview_loading\" />\n\n\n  <Button\n    android:id=\"@+id/btn_search_header\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"MultipleHeader(search)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_custom_header\" />\n\n  <Button\n    android:id=\"@+id/btn_scrolling\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"SpecialDecorView(scrolling)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_search_header\" />\n\n  <Button\n    android:id=\"@+id/btn_bottom_editor\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginTop=\"8dp\"\n    android:onClick=\"onViewClicked\"\n    android:text=\"BottomDecorView(editor)\"\n    android:textAllCaps=\"false\"\n    app:layout_constraintEnd_toEndOf=\"@+id/btn_activity_error\"\n    app:layout_constraintStart_toStartOf=\"@+id/btn_activity_error\"\n    app:layout_constraintTop_toBottomOf=\"@+id/btn_scrolling\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/activity_recycler_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <androidx.recyclerview.widget.RecyclerView\n    android:id=\"@+id/recycler_view\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"/>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/activity_scrolling.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.core.widget.NestedScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:tools=\"http://schemas.android.com/tools\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\"\n  tools:showIn=\"@layout/layout_scrolling_toolbar\">\n\n  <TextView\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"16dp\"\n    android:text=\"@string/large_text\" />\n\n</androidx.core.widget.NestedScrollView>"
  },
  {
    "path": "sample-java/src/main/res/layout/activity_tab_layout.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  <com.google.android.material.tabs.TabLayout\n    android:id=\"@+id/tab_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@android:color/white\"\n    android:elevation=\"2dp\" />\n\n  <androidx.viewpager.widget.ViewPager\n    android:id=\"@+id/view_pager\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" />\n\n</LinearLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/activity_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  xmlns:tools=\"http://schemas.android.com/tools\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <androidx.cardview.widget.CardView\n    android:layout_width=\"0dp\"\n    android:layout_height=\"wrap_content\"\n    android:layout_centerHorizontal=\"true\"\n    app:cardCornerRadius=\"6dp\"\n    android:background=\"@android:color/white\"\n    android:layout_marginStart=\"16dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginTop=\"16dp\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    android:layout_marginEnd=\"16dp\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:cardElevation=\"1dp\">\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n      android:id=\"@+id/content\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\">\n\n      <ImageView\n        android:layout_width=\"36dp\"\n        android:layout_height=\"36dp\"\n        app:srcCompat=\"@drawable/ic_logo_core\"\n        android:id=\"@+id/imageView4\"\n        android:layout_marginTop=\"16dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        android:layout_marginStart=\"16dp\"/>\n\n      <TextView\n        android:text=\"@string/app_name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/textView4\"\n        app:layout_constraintStart_toEndOf=\"@+id/imageView4\"\n        android:layout_marginStart=\"16dp\"\n        android:textSize=\"18sp\"\n        android:textColor=\"#666\"\n        android:layout_marginTop=\"12dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"/>\n\n      <TextView\n        android:text=\"@string/app_introduce\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/textView5\"\n        android:layout_marginTop=\"4dp\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView4\"\n        app:layout_constraintStart_toStartOf=\"@+id/textView4\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        android:layout_marginEnd=\"8dp\"\n        android:layout_marginBottom=\"16dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"/>\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n  </androidx.cardview.widget.CardView>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/activity_view_pager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.viewpager.widget.ViewPager xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:id=\"@+id/view_pager\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\"/>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_bottom_editor.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  <ScrollView\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"0dp\"\n    android:layout_weight=\"1\">\n\n    <LinearLayout\n      android:id=\"@+id/content_parent\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:orientation=\"vertical\" />\n  </ScrollView>\n\n  <LinearLayout\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48dp\"\n    android:background=\"@android:color/white\"\n    android:elevation=\"4dp\"\n    android:orientation=\"horizontal\">\n\n    <EditText\n      android:id=\"@+id/edt_content\"\n      android:layout_width=\"0dp\"\n      android:layout_height=\"wrap_content\"\n      android:layout_gravity=\"center_vertical\"\n      android:layout_marginStart=\"12dp\"\n      android:layout_weight=\"1\" />\n\n    <Button\n      android:id=\"@+id/btn_send\"\n      android:layout_width=\"64dp\"\n      android:layout_height=\"42dp\"\n      android:layout_gravity=\"center\"\n      android:layout_marginStart=\"8dp\"\n      android:layout_marginEnd=\"12dp\"\n      android:text=\"send\" />\n\n  </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_content.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:id=\"@+id/container\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <TextView\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"16dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:layout_marginBottom=\"16dp\"\n    android:text=\"This is content view\"\n    android:textSize=\"16sp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_cool_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <com.dylanc.loadingstateview.sample.java.widget.LoadingView\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:loading_renderer=\"ElectricFanLoadingRenderer\"/>\n\n</FrameLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_custom_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"?attr/actionBarSize\"\n  android:background=\"@color/colorPrimary\"\n  android:elevation=\"2dp\">\n\n  <androidx.constraintlayout.widget.ConstraintLayout\n    android:id=\"@+id/btn_message\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"0dp\"\n    android:layout_marginStart=\"8dp\"\n    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\">\n\n    <ImageView\n      android:id=\"@+id/iv_message\"\n      android:layout_width=\"20dp\"\n      android:layout_height=\"20dp\"\n      app:layout_constraintBottom_toTopOf=\"@+id/tv_message\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toTopOf=\"parent\"\n      app:layout_constraintVertical_bias=\"0.66\"\n      app:layout_constraintVertical_chainStyle=\"packed\"\n      app:srcCompat=\"@drawable/ic_baseline_message_24\" />\n\n    <TextView\n      android:id=\"@+id/tv_message\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:layout_marginStart=\"8dp\"\n      android:layout_marginEnd=\"8dp\"\n      android:text=\"message\"\n      android:textSize=\"10sp\"\n      app:layout_constraintBottom_toBottomOf=\"parent\"\n      app:layout_constraintEnd_toEndOf=\"parent\"\n      app:layout_constraintStart_toStartOf=\"parent\"\n      app:layout_constraintTop_toBottomOf=\"@+id/iv_message\" />\n  </androidx.constraintlayout.widget.ConstraintLayout>\n\n  <com.google.android.material.tabs.TabLayout\n    android:id=\"@+id/tab_layout\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"0dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\" />\n\n  <ImageView\n    android:id=\"@+id/btn_first\"\n    android:layout_width=\"30dp\"\n    android:layout_height=\"30dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n    android:padding=\"4dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toStartOf=\"@+id/btn_second\"\n    app:layout_constraintTop_toTopOf=\"parent\" />\n\n  <ImageView\n    android:id=\"@+id/btn_second\"\n    android:layout_width=\"30dp\"\n    android:layout_height=\"30dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n    android:padding=\"4dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_empty.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <TextView\n    android:id=\"@+id/tv_empty_text\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginBottom=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:layout_marginStart=\"8dp\"\n    android:text=\"There's nothing here.\"\n    android:textColor=\"@color/loading_empty_text\"\n    android:textSize=\"16sp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginTop=\"16dp\"\n    app:layout_constraintTop_toBottomOf=\"@+id/imageView\"/>\n\n  <ImageView\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    app:srcCompat=\"@drawable/ic_empty\"\n    android:id=\"@+id/imageView\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_constraintVertical_chainStyle=\"packed\"\n    app:layout_constraintBottom_toTopOf=\"@+id/tv_empty_text\"/>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_error.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  xmlns:tools=\"http://schemas.android.com/tools\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <TextView\n    android:id=\"@+id/tv_error_text\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:text=\" Failured to load\"\n    android:textColor=\"@color/loading_error_text\"\n    android:textSize=\"16sp\"\n    app:layout_constraintHorizontal_chainStyle=\"packed\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toBottomOf=\"@+id/imageView3\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintBottom_toTopOf=\"@+id/btn_reload\"/>\n\n  <TextView\n    android:id=\"@+id/btn_reload\"\n    android:layout_width=\"72dp\"\n    android:layout_height=\"24dp\"\n    android:gravity=\"center\"\n    android:text=\"Retry\"\n    android:textColor=\"#999\"\n    android:textSize=\"14sp\"\n    android:background=\"@drawable/bg_reload_btn\"\n    android:layout_marginBottom=\"8dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/tv_error_text\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginTop=\"8dp\"/>\n\n  <ImageView\n    android:layout_width=\"48dp\"\n    android:layout_height=\"48dp\"\n    app:srcCompat=\"@drawable/ic_error\"\n    android:id=\"@+id/imageView3\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_constraintVertical_chainStyle=\"packed\"\n    app:layout_constraintBottom_toTopOf=\"@+id/tv_error_text\"/>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <ProgressBar\n    android:id=\"@+id/progress_bar\"\n    style=\"?android:attr/progressBarStyle\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"24dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:layout_marginBottom=\"24dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_constraintVertical_chainStyle=\"packed\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_placeholder.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"wrap_content\">\n\n  <View\n    android:layout_width=\"36dp\"\n    android:layout_height=\"36dp\"\n    android:id=\"@+id/textView6\"\n    android:layout_marginTop=\"16dp\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginStart=\"16dp\"\n    android:background=\"@color/loading_placeholder_view_color\"/>\n\n  <View\n    android:layout_width=\"48dp\"\n    android:layout_height=\"16dp\"\n    android:id=\"@+id/textView7\"\n    app:layout_constraintTop_toTopOf=\"@+id/textView6\"\n    app:layout_constraintStart_toEndOf=\"@+id/textView6\"\n    android:layout_marginStart=\"16dp\"\n    android:background=\"@color/loading_placeholder_view_color\"/>\n\n  <View\n    android:layout_width=\"0dp\"\n    android:layout_height=\"16dp\"\n    android:id=\"@+id/textView8\"\n    android:layout_marginTop=\"12dp\"\n    app:layout_constraintTop_toBottomOf=\"@+id/textView7\"\n    app:layout_constraintStart_toStartOf=\"@+id/textView7\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginEnd=\"16dp\"\n    android:background=\"@color/loading_placeholder_view_color\"/>\n\n  <View\n    android:layout_width=\"0dp\"\n    android:layout_height=\"16dp\"\n    android:id=\"@+id/textView9\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toBottomOf=\"@+id/textView8\"\n    app:layout_constraintStart_toStartOf=\"@+id/textView8\"\n    app:layout_constraintEnd_toEndOf=\"@+id/textView8\"\n    android:background=\"@color/loading_placeholder_view_color\"\n    android:layout_marginBottom=\"16dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"/>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_scrolling_toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <com.google.android.material.appbar.AppBarLayout\n    android:id=\"@+id/app_bar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:elevation=\"2dp\">\n\n    <androidx.appcompat.widget.Toolbar\n      android:id=\"@+id/toolbar\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"?attr/actionBarSize\"\n      app:layout_collapseMode=\"pin\"\n      app:layout_scrollFlags=\"scroll|enterAlways\"\n      app:navigationIcon=\"@drawable/ic_arrow_back_black\"\n      app:titleTextAppearance=\"@style/ToolbarTextAppearance\" />\n\n  </com.google.android.material.appbar.AppBarLayout>\n\n  <FrameLayout\n    android:id=\"@+id/content_parent\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_search_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"wrap_content\"\n  android:background=\"@android:color/white\"\n  android:elevation=\"2dp\"\n  android:focusable=\"true\"\n  android:focusableInTouchMode=\"true\">\n\n  <EditText\n    android:id=\"@+id/edt_search\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"30dp\"\n    android:layout_marginStart=\"16dp\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginEnd=\"16dp\"\n    android:layout_marginBottom=\"16dp\"\n    android:background=\"@drawable/bg_search\"\n    android:gravity=\"center_vertical\"\n    android:hint=\"Search\"\n    android:imeOptions=\"actionSearch\"\n    android:paddingStart=\"16dp\"\n    android:paddingEnd=\"16dp\"\n    android:singleLine=\"true\"\n    android:textSize=\"14sp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_timeout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <ImageView\n    android:layout_width=\"48dp\"\n    android:layout_height=\"48dp\"\n    app:srcCompat=\"@drawable/ic_timeout\"\n    android:id=\"@+id/imageView2\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_constraintVertical_chainStyle=\"packed\"\n    app:layout_constraintBottom_toTopOf=\"@+id/tv_empty_text\"/>\n\n  <TextView\n    android:id=\"@+id/tv_empty_text\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginEnd=\"8dp\"\n    android:layout_marginStart=\"8dp\"\n    android:text=\"Connect timeout\"\n    android:textColor=\"#333\"\n    android:textSize=\"16sp\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/imageView2\"\n    android:layout_marginTop=\"8dp\"\n    android:layout_marginBottom=\"8dp\"\n    app:layout_constraintBottom_toTopOf=\"@+id/textView3\"/>\n\n  <TextView\n    android:text=\"please click retry\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:id=\"@+id/textView3\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginEnd=\"8dp\"\n    android:textSize=\"12sp\"\n    android:layout_marginBottom=\"8dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/tv_empty_text\"/>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-java/src/main/res/layout/layout_toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.appcompat.widget.Toolbar xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:id=\"@+id/toolbar\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"?attr/actionBarSize\"\n  android:background=\"?attr/colorPrimary\"\n  app:navigationIcon=\"@drawable/ic_arrow_back_black\"\n  app:titleTextAppearance=\"@style/ToolbarTextAppearance\"\n  android:elevation=\"2dp\"/>"
  },
  {
    "path": "sample-java/src/main/res/layout/recycler_item_image.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=\"250dp\">\n\n  <ImageView\n    android:id=\"@+id/image_view\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:scaleType=\"centerCrop\"/>\n\n  <View\n    android:id=\"@+id/loading_view\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"/>\n\n</FrameLayout>"
  },
  {
    "path": "sample-java/src/main/res/menu/menu_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n  <item\n    android:id=\"@+id/about\"\n    app:showAsAction=\"ifRoom\"\n    android:title=\"about\">\n  </item>\n</menu>"
  },
  {
    "path": "sample-java/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "sample-java/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "sample-java/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"LoadingView\">\n        <attr name=\"loading_renderer\">\n            <!--circle rotate-->\n            <enum name=\"MaterialLoadingRenderer\" value=\"0\"/>\n            <enum name=\"LevelLoadingRenderer\" value=\"1\"/>\n            <enum name=\"WhorlLoadingRenderer\" value=\"2\"/>\n            <enum name=\"GearLoadingRenderer\" value=\"3\"/>\n            <!--circle jump-->\n            <enum name=\"SwapLoadingRenderer\" value=\"4\"/>\n            <enum name=\"GuardLoadingRenderer\" value=\"5\"/>\n            <enum name=\"DanceLoadingRenderer\" value=\"6\"/>\n            <enum name=\"CollisionLoadingRenderer\" value=\"7\"/>\n            <!--Scenery-->\n            <enum name=\"DayNightLoadingRenderer\" value=\"8\"/>\n            <enum name=\"ElectricFanLoadingRenderer\" value=\"9\"/>\n            <!--Animal-->\n            <enum name=\"FishLoadingRenderer\" value=\"10\"/>\n            <enum name=\"GhostsEyeLoadingRenderer\" value=\"11\"/>\n            <!--Goods-->\n            <enum name=\"BalloonLoadingRenderer\" value=\"12\"/>\n            <enum name=\"WaterBottleLoadingRenderer\" value=\"13\"/>\n            <!--ShapeChange-->\n            <enum name=\"CircleBroodLoadingRenderer\" value=\"14\"/>\n            <enum name=\"CoolWaitLoadingRenderer\" value=\"15\"/>\n        </attr>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "sample-java/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#fff</color>\n    <color name=\"colorPrimaryDark\">#fff</color>\n    <color name=\"colorAccent\">#1E88E5</color>\n\n    <color name=\"loading_placeholder_view_color\">#ddd</color>\n    <color name=\"loading_title_text\">#666</color>\n    <color name=\"loading_loading_text\">#666</color>\n    <color name=\"loading_error_text\">#666</color>\n    <color name=\"loading_empty_text\">#666</color>\n    <color name=\"loading_reload_btn_text\">#2196F3</color>\n</resources>\n"
  },
  {
    "path": "sample-java/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\">LoadingStateView</string>\n  <string name=\"app_introduce\">A highly expandable Android library for showing loading status view with the low-coupling way.</string>\n  <string name=\"large_text\">\n    \"Material is the metaphor.\\n\\n\"\n\n    \"A material metaphor is the unifying theory of a rationalized space and a system of motion.\"\n    \"The material is grounded in tactile reality, inspired by the study of paper and ink, yet \"\n    \"technologically advanced and open to imagination and magic.\\n\"\n    \"Surfaces and edges of the material provide visual cues that are grounded in reality. The \"\n    \"use of familiar tactile attributes helps users quickly understand affordances. Yet the \"\n    \"flexibility of the material creates new affordances that supercede those in the physical \"\n    \"world, without breaking the rules of physics.\\n\"\n    \"The fundamentals of light, surface, and movement are key to conveying how objects move, \"\n    \"interact, and exist in space and in relation to each other. Realistic lighting shows \"\n    \"seams, divides space, and indicates moving parts.\\n\\n\"\n\n    \"Bold, graphic, intentional.\\n\\n\"\n\n    \"The foundational elements of print based design typography, grids, space, scale, color, \"\n    \"and use of imagery guide visual treatments. These elements do far more than please the \"\n    \"eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge \"\n    \"imagery, large scale typography, and intentional white space create a bold and graphic \"\n    \"interface that immerse the user in the experience.\\n\"\n    \"An emphasis on user actions makes core functionality immediately apparent and provides \"\n    \"waypoints for the user.\\n\\n\"\n\n    \"Motion provides meaning.\\n\\n\"\n\n    \"Motion respects and reinforces the user as the prime mover. Primary user actions are \"\n    \"inflection points that initiate motion, transforming the whole design.\\n\"\n    \"All action takes place in a single environment. Objects are presented to the user without \"\n    \"breaking the continuity of experience even as they transform and reorganize.\\n\"\n    \"Motion is meaningful and appropriate, serving to focus attention and maintain continuity. \"\n    \"Feedback is subtle yet clear. Transitions are efﬁcient yet coherent.\\n\\n\"\n\n    \"3D world.\\n\\n\"\n\n    \"The material environment is a 3D space, which means all objects have x, y, and z \"\n    \"dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the \"\n    \"positive z-axis extending towards the viewer. Every sheet of material occupies a single \"\n    \"position along the z-axis and has a standard 1dp thickness.\\n\"\n    \"On the web, the z-axis is used for layering and not for perspective. The 3D world is \"\n    \"emulated by manipulating the y-axis.\\n\\n\"\n\n    \"Light and shadow.\\n\\n\"\n\n    \"Within the material environment, virtual lights illuminate the scene. Key lights create \"\n    \"directional shadows, while ambient light creates soft shadows from all angles.\\n\"\n    \"Shadows in the material environment are cast by these two light sources. In Android \"\n    \"development, shadows occur when light sources are blocked by sheets of material at \"\n    \"various positions along the z-axis. On the web, shadows are depicted by manipulating the \"\n    \"y-axis only. The following example shows the card with a height of 6dp.\\n\\n\"\n\n    \"Resting elevation.\\n\\n\"\n\n    \"All material objects, regardless of size, have a resting elevation, or default elevation \"\n    \"that does not change. If an object changes elevation, it should return to its resting \"\n    \"elevation as soon as possible.\\n\\n\"\n\n    \"Component elevations.\\n\\n\"\n\n    \"The resting elevation for a component type is consistent across apps (e.g., FAB elevation \"\n    \"does not vary from 6dp in one app to 16dp in another app).\\n\"\n    \"Components may have different resting elevations across platforms, depending on the depth \"\n    \"of the environment (e.g., TV has a greater depth than mobile or desktop).\\n\\n\"\n\n    \"Responsive elevation and dynamic elevation offsets.\\n\\n\"\n\n    \"Some component types have responsive elevation, meaning they change elevation in response \"\n    \"to user input (e.g., normal, focused, and pressed) or system events. These elevation \"\n    \"changes are consistently implemented using dynamic elevation offsets.\\n\"\n    \"Dynamic elevation offsets are the goal elevation that a component moves towards, relative \"\n    \"to the component’s resting state. They ensure that elevation changes are consistent \"\n    \"across actions and component types. For example, all components that lift on press have \"\n    \"the same elevation change relative to their resting elevation.\\n\"\n    \"Once the input event is completed or cancelled, the component will return to its resting \"\n    \"elevation.\\n\\n\"\n\n    \"Avoiding elevation interference.\\n\\n\"\n\n    \"Components with responsive elevations may encounter other components as they move between \"\n    \"their resting elevations and dynamic elevation offsets. Because material cannot pass \"\n    \"through other material, components avoid interfering with one another any number of ways, \"\n    \"whether on a per component basis or using the entire app layout.\\n\"\n    \"On a component level, components can move or be removed before they cause interference. \"\n    \"For example, a floating action button (FAB) can disappear or move off screen before a \"\n    \"user picks up a card, or it can move if a snackbar appears.\\n\"\n    \"On the layout level, design your app layout to minimize opportunities for interference. \"\n    \"For example, position the FAB to one side of stream of a cards so the FAB won’t interfere \"\n    \"when a user tries to pick up one of cards.\\n\\n\"\n  </string>\n</resources>\n"
  },
  {
    "path": "sample-java/src/main/res/values/styles.xml",
    "content": "<resources>\n\n  <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n    <item name=\"colorPrimary\">@color/colorPrimary</item>\n    <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n    <item name=\"colorAccent\">@color/colorAccent</item>\n  </style>\n\n  <style name=\"AppTheme.NoActionBar\">\n    <item name=\"windowActionBar\">false</item>\n    <item name=\"windowNoTitle\">true</item>\n  </style>\n\n  <style name=\"ToolbarTextAppearance\">\n    <item name=\"android:textSize\">18sp</item>\n    <item name=\"android:textColor\">#000</item>\n  </style>\n</resources>\n"
  },
  {
    "path": "sample-java/src/test/java/com/dylanc/loadingstateview/sample/java/ExampleUnitTest.kt",
    "content": "package com.dylanc.loadingstateview.sample.java\n\nimport org.junit.Test\n\nimport org.junit.Assert.*\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\nclass ExampleUnitTest {\n    @Test\n    fun addition_isCorrect() {\n        assertEquals(4, 2 + 2)\n    }\n}\n"
  },
  {
    "path": "sample-kotlin/.gitignore",
    "content": "/build"
  },
  {
    "path": "sample-kotlin/build.gradle",
    "content": "plugins {\n    id 'com.android.application'\n    id 'org.jetbrains.kotlin.android'\n}\n\nandroid {\n    compileSdkVersion buildConfig.compileSdkVersion\n\n    defaultConfig {\n        applicationId \"com.dylanc.loadingstateview.sample.kotlin\"\n        minSdkVersion buildConfig.minSdkVersion\n        targetSdkVersion buildConfig.targetSdkVersion\n        versionCode buildConfig.versionCode\n        versionName buildConfig.versionName\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n\n    viewBinding {\n        enabled true\n    }\n}\n\ndependencies {\n    implementation project(':loadingstateview-ktx')\n    implementation \"androidx.appcompat:appcompat:$appCompatVersion\"\n    implementation \"androidx.constraintlayout:constraintlayout:$constraintLayoutVersion\"\n    implementation \"com.google.android.material:material:$materialVersion\"\n    implementation \"com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-base:$viewBindingKTXVersion\"\n    testImplementation \"junit:junit:$junitVersion\"\n    androidTestImplementation \"androidx.test.ext:junit:$junitExtVersion\"\n    androidTestImplementation \"androidx.test.espresso:espresso-core:$espressoVersion\"\n}"
  },
  {
    "path": "sample-kotlin/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "sample-kotlin/src/androidTest/java/com/dylanc/loadingstateview/sample/kotlin/ExampleInstrumentedTest.kt",
    "content": "package com.dylanc.loadingstateview.sample.kotlin\n\nimport androidx.test.platform.app.InstrumentationRegistry\nimport androidx.test.ext.junit.runners.AndroidJUnit4\n\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\nimport org.junit.Assert.*\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\n@RunWith(AndroidJUnit4::class)\nclass ExampleInstrumentedTest {\n  @Test\n  fun useAppContext() {\n    // Context of the app under test.\n    val appContext = InstrumentationRegistry.getInstrumentation().targetContext\n    assertEquals(\"com.dylanc.loadingstateview.sample.kotlin\", appContext.packageName)\n  }\n}"
  },
  {
    "path": "sample-kotlin/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.dylanc.loadingstateview.sample.kotlin\">\n\n  <application\n    android:name=\".App\"\n    android:allowBackup=\"true\"\n    android:icon=\"@mipmap/ic_launcher\"\n    android:label=\"@string/app_name\"\n    android:roundIcon=\"@mipmap/ic_launcher_round\"\n    android:supportsRtl=\"true\"\n    android:theme=\"@style/Theme.LoadingStateView\">\n    <activity\n      android:name=\".ui.MainActivity\"\n      android:exported=\"true\">\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  </application>\n\n</manifest>"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/App.kt",
    "content": "package com.dylanc.loadingstateview.sample.kotlin\n\nimport android.app.Application\nimport com.dylanc.loadingstateview.LoadingStateView\nimport com.dylanc.loadingstateview.sample.kotlin.delegate.ErrorViewDelegate\nimport com.dylanc.loadingstateview.sample.kotlin.delegate.LoadingViewDelegate\nimport com.dylanc.loadingstateview.sample.kotlin.delegate.ToolbarViewDelegate\nimport com.dylanc.loadingstateview.sample.kotlin.delegate.EmptyViewDelegate\nimport com.dylanc.loadingstateview.sample.kotlin.delegate.FadeAnimatable\n\nclass App : Application() {\n\n  override fun onCreate() {\n    super.onCreate()\n    LoadingStateView.setViewDelegatePool {\n      register(ToolbarViewDelegate(), LoadingViewDelegate(), ErrorViewDelegate(), EmptyViewDelegate())\n    }\n    LoadingStateView.defaultAnimatable = FadeAnimatable()\n  }\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseActivity.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.base\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport com.dylanc.loadingstateview.LoadingState\nimport com.dylanc.loadingstateview.LoadingStateDelegate\n\nabstract class BaseActivity(private val layoutRes: Int) : AppCompatActivity(), LoadingState by LoadingStateDelegate() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(layoutRes)\n    decorateContentView(this)\n  }\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingActivity.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.base\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.viewbinding.ViewBinding\nimport com.dylanc.loadingstateview.LoadingState\nimport com.dylanc.loadingstateview.LoadingStateDelegate\nimport com.dylanc.viewbinding.base.ActivityBinding\nimport com.dylanc.viewbinding.base.ActivityBindingDelegate\n\nabstract class BaseBindingActivity<VB : ViewBinding> : AppCompatActivity(),\n  LoadingState by LoadingStateDelegate(), ActivityBinding<VB> by ActivityBindingDelegate() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentViewWithBinding()\n    binding.root.decorate(this)\n  }\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingFragment.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.base\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.fragment.app.Fragment\nimport androidx.viewbinding.ViewBinding\nimport com.dylanc.loadingstateview.LoadingState\nimport com.dylanc.loadingstateview.LoadingStateDelegate\nimport com.dylanc.viewbinding.base.FragmentBinding\nimport com.dylanc.viewbinding.base.FragmentBindingDelegate\n\nabstract class BaseBindingFragment<VB : ViewBinding> : Fragment(), LoadingState by LoadingStateDelegate(),\n  FragmentBinding<VB> by FragmentBindingDelegate() {\n\n  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =\n    createViewWithBinding(inflater, container).decorate(this)\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseFragment.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.base\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.fragment.app.Fragment\nimport com.dylanc.loadingstateview.LoadingState\nimport com.dylanc.loadingstateview.LoadingStateDelegate\n\nabstract class BaseFragment(private val layoutRes: Int) : Fragment(), LoadingState by LoadingStateDelegate() {\n\n  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =\n    inflater.inflate(layoutRes, container, false).decorate(this)\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/EmptyViewDelegate.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.delegate\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport com.dylanc.loadingstateview.LoadingStateView.ViewDelegate\nimport com.dylanc.loadingstateview.ViewType\nimport com.dylanc.loadingstateview.sample.kotlin.R\n\n/**\n * @author Dylan Cai\n */\nclass EmptyViewDelegate : ViewDelegate(ViewType.EMPTY) {\n\n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View =\n    inflater.inflate(R.layout.layout_empty, parent, false)\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ErrorViewDelegate.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.delegate\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport com.dylanc.loadingstateview.LoadingStateView.ViewDelegate\nimport com.dylanc.loadingstateview.ViewType\nimport com.dylanc.loadingstateview.sample.kotlin.R\n\n/**\n * @author Dylan Cai\n */\nclass ErrorViewDelegate : ViewDelegate(ViewType.ERROR) {\n\n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View =\n    inflater.inflate(R.layout.layout_error, parent, false).apply {\n      findViewById<View>(R.id.btn_reload).setOnClickListener {\n        onReloadListener?.onReload()\n      }\n    }\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/FadeAnimatable.kt",
    "content": "package com.dylanc.loadingstateview.sample.kotlin.delegate\n\nimport android.view.View\nimport com.dylanc.loadingstateview.LoadingStateView\nimport com.dylanc.loadingstateview.ViewType\n\n/**\n * @author Dylan Cai\n */\nclass FadeAnimatable(private val duration: Long = 600) : LoadingStateView.Animatable {\n  override fun toggleViewsAnimation(showView: View, hideView: View, showViewType: Any, hideViewType: Any) {\n    if (showViewType === ViewType.LOADING && hideViewType === ViewType.CONTENT) {\n      showView.visibility = View.VISIBLE\n      hideView.visibility = View.GONE\n    } else {\n      showView.alpha = 0f\n      showView.visibility = View.VISIBLE\n      showView.animate().alpha(1f).setDuration(duration)\n      hideView.animate().alpha(0f).setDuration(duration).withEndAction {\n        hideView.alpha = 1f\n        hideView.visibility = View.GONE\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/LoadingViewDelegate.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.delegate\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport com.dylanc.loadingstateview.LoadingStateView\nimport com.dylanc.loadingstateview.ViewType\nimport com.dylanc.loadingstateview.sample.kotlin.R\n\n/**\n * @author Dylan Cai\n */\nclass LoadingViewDelegate : LoadingStateView.ViewDelegate(ViewType.LOADING) {\n\n  override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View =\n    inflater.inflate(R.layout.layout_loading, parent, false)\n\n  override fun onViewAttached(view: View) {\n    view.animate().rotationBy(360f)\n      .setDuration(800)\n      .withEndAction { onViewAttached(view) }\n      .start()\n  }\n\n  override fun onViewDetached(view: View) {\n    view.animate().cancel()\n  }\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ScrollingDecorViewDelegate.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.delegate\n\nimport android.app.Activity\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.appcompat.widget.Toolbar\nimport com.dylanc.loadingstateview.LoadingStateView\nimport com.dylanc.loadingstateview.sample.kotlin.R\n\n/**\n * @author Dylan Cai\n */\nclass ScrollingDecorViewDelegate(private val title: String) : LoadingStateView.DecorViewDelegate() {\n\n  override fun onCreateDecorView(context: Context, inflater: LayoutInflater): View {\n    val view = inflater.inflate(R.layout.layout_scrolling_toolbar, null)\n    val toolbar: Toolbar = view.findViewById(R.id.toolbar)\n    toolbar.title = title\n    toolbar.setNavigationOnClickListener {\n      if (context is Activity) context.finish()\n    }\n    return view\n  }\n\n  override fun getContentParent(decorView: View): ViewGroup {\n    return decorView.findViewById(R.id.content_parent)\n  }\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ToolbarViewDelegate.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.delegate\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.Toolbar\nimport com.dylanc.loadingstateview.NavBtnType\nimport com.dylanc.loadingstateview.ToolbarConfig\nimport com.dylanc.loadingstateview.BaseToolbarViewDelegate\nimport com.dylanc.loadingstateview.sample.kotlin.databinding.LayoutToolbarBinding\nimport com.dylanc.loadingstateview.toolbarExtras\n\nvar ToolbarConfig.rightTextColor: Int? by toolbarExtras()\n\nclass ToolbarViewDelegate : BaseToolbarViewDelegate() {\n  private lateinit var binding: LayoutToolbarBinding\n\n  override fun onCreateToolbar(inflater: LayoutInflater, parent: ViewGroup): View {\n    binding = LayoutToolbarBinding.inflate(inflater, parent, false)\n    return binding.root\n  }\n\n  override fun onBindToolbar(config: ToolbarConfig) {\n    binding.apply {\n      tvTitle.text = config.title\n\n      when (config.navBtnType) {\n        NavBtnType.ICON -> {\n          config.navIcon?.let { ivLeft.setImageResource(it) }\n          ivLeft.setOnClickListener(config.onNavClickListener)\n          tvLeft.visibility = View.GONE\n          ivLeft.visibility = View.VISIBLE\n        }\n        NavBtnType.TEXT -> {\n          tvLeft.text = config.navText\n          tvLeft.setOnClickListener(config.onNavClickListener)\n          tvLeft.visibility = View.VISIBLE\n          ivLeft.visibility = View.GONE\n        }\n        NavBtnType.ICON_TEXT -> {\n          config.navIcon?.let { ivLeft.setImageResource(it) }\n          tvLeft.text = config.navText\n          ivLeft.setOnClickListener(config.onNavClickListener)\n          tvLeft.setOnClickListener(config.onNavClickListener)\n          tvLeft.visibility = View.VISIBLE\n          ivLeft.visibility = View.VISIBLE\n        }\n        NavBtnType.NONE -> {\n          ivLeft.visibility = View.GONE\n          tvLeft.visibility = View.GONE\n        }\n      }\n\n      if (config.rightText != null) {\n        tvRight.text = config.rightText\n        tvRight.setOnClickListener(config.onRightClickListener)\n        tvRight.visibility = View.VISIBLE\n        config.rightTextColor?.let { tvRight.setTextColor(it) }\n      } else {\n        tvRight.visibility = View.GONE\n      }\n\n      if (config.rightIcon != null) {\n        ivRight.setImageResource(config.rightIcon!!)\n        ivRight.setOnClickListener(config.onRightClickListener)\n        ivRight.visibility = View.VISIBLE\n      } else {\n        ivRight.visibility = View.GONE\n      }\n    }\n  }\n}"
  },
  {
    "path": "sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/ui/MainActivity.kt",
    "content": "/*\n * Copyright (c) 2019. Dylan Cai\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.dylanc.loadingstateview.sample.kotlin.ui\n\nimport android.graphics.Color\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport com.dylanc.loadingstateview.NavBtnType\nimport com.dylanc.loadingstateview.sample.kotlin.base.BaseBindingActivity\nimport com.dylanc.loadingstateview.sample.kotlin.databinding.ActivityMainBinding\nimport com.dylanc.loadingstateview.sample.kotlin.delegate.rightTextColor\n\nclass MainActivity : BaseBindingActivity<ActivityMainBinding>() {\n\n  override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setToolbar(\"Home\", NavBtnType.NONE) {\n      rightTextColor = Color.BLUE\n      rightText(\"Edit\") { onEdit() }\n    }\n    showLoadingView()\n    Handler(Looper.getMainLooper()).postDelayed({\n      showErrorView()\n    }, 2000)\n  }\n\n  private fun onEdit() {\n    updateToolbar {\n      title = \"Selected 0\"\n      rightText(\"Complete\") { onComplete() }\n    }\n  }\n\n  private fun onComplete() {\n    updateToolbar {\n      title = \"Home\"\n      rightText(\"Edit\") { onEdit() }\n    }\n  }\n\n  override fun onReload() {\n    showLoadingView()\n    Handler(Looper.getMainLooper()).postDelayed({\n      showContentView()\n    }, 2000)\n  }\n}\n"
  },
  {
    "path": "sample-kotlin/src/main/res/drawable/bg_reload_btn.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <corners android:radius=\"4dp\"/>\n  <stroke android:width=\"1dp\"\n          android:color=\"#bbb\"/>\n</shape>"
  },
  {
    "path": "sample-kotlin/src/main/res/drawable/ic_add.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#333333\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"/>\n</vector>\n"
  },
  {
    "path": "sample-kotlin/src/main/res/drawable/ic_arrow_back_ios.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:width=\"24dp\"\n  android:height=\"24dp\"\n  android:tint=\"#333\"\n  android:viewportWidth=\"24\"\n  android:viewportHeight=\"24\">\n  <path\n    android:fillColor=\"@android:color/white\"\n    android:pathData=\"M17.77,3.77l-1.77,-1.77l-10,10l10,10l1.77,-1.77l-8.23,-8.23z\" />\n</vector>\n"
  },
  {
    "path": "sample-kotlin/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:width=\"108dp\"\n  android:height=\"108dp\"\n  android:viewportWidth=\"108\"\n  android:viewportHeight=\"108\">\n  <path\n    android:fillColor=\"#3DDC84\"\n    android:pathData=\"M0,0h108v108h-108z\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M9,0L9,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M19,0L19,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M29,0L29,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M39,0L39,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M49,0L49,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M59,0L59,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M69,0L69,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M79,0L79,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M89,0L89,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M99,0L99,108\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,9L108,9\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,19L108,19\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,29L108,29\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,39L108,39\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,49L108,49\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,59L108,59\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,69L108,69\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,79L108,79\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,89L108,89\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M0,99L108,99\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M19,29L89,29\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M19,39L89,39\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M19,49L89,49\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M19,59L89,59\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M19,69L89,69\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M19,79L89,79\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M29,19L29,89\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M39,19L39,89\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M49,19L49,89\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M59,19L59,89\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M69,19L69,89\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n  <path\n    android:fillColor=\"#00000000\"\n    android:pathData=\"M79,19L79,89\"\n    android:strokeWidth=\"0.8\"\n    android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "sample-kotlin/src/main/res/drawable/ic_refresh.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:width=\"48dp\"\n  android:height=\"48dp\"\n  android:tint=\"#bbbbbb\"\n  android:viewportWidth=\"24\"\n  android:viewportHeight=\"24\">\n\n  <path\n    android:fillColor=\"@android:color/white\"\n    android:pathData=\"M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z\" />\n\n</vector>\n"
  },
  {
    "path": "sample-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:aapt=\"http://schemas.android.com/aapt\"\n  android:width=\"108dp\"\n  android:height=\"108dp\"\n  android:viewportWidth=\"108\"\n  android:viewportHeight=\"108\">\n  <path android:pathData=\"M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z\">\n    <aapt:attr name=\"android:fillColor\">\n      <gradient\n        android:endX=\"85.84757\"\n        android:endY=\"92.4963\"\n        android:startX=\"42.9492\"\n        android:startY=\"49.59793\"\n        android:type=\"linear\">\n        <item\n          android:color=\"#44000000\"\n          android:offset=\"0.0\" />\n        <item\n          android:color=\"#00000000\"\n          android:offset=\"1.0\" />\n      </gradient>\n    </aapt:attr>\n  </path>\n  <path\n    android:fillColor=\"#FFFFFF\"\n    android:fillType=\"nonZero\"\n    android:pathData=\"M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z\"\n    android:strokeWidth=\"1\"\n    android:strokeColor=\"#00000000\" />\n</vector>"
  },
  {
    "path": "sample-kotlin/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  xmlns:tools=\"http://schemas.android.com/tools\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\"\n  tools:context=\".ui.MainActivity\">\n\n  <TextView\n    android:id=\"@+id/button\"\n    android:layout_width=\"0dp\"\n    android:layout_height=\"0dp\"\n    android:gravity=\"center\"\n    android:text=\"This is content view\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintLeft_toLeftOf=\"parent\"\n    app:layout_constraintRight_toRightOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-kotlin/src/main/res/layout/layout_empty.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <TextView\n    android:id=\"@+id/tv_empty_text\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginBottom=\"8dp\"\n    android:layout_marginEnd=\"8dp\"\n    android:layout_marginStart=\"8dp\"\n    android:text=\"There's nothing here.\"\n    android:textColor=\"@color/loading_empty_text\"\n    android:textSize=\"16sp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginTop=\"16dp\"\n    app:layout_constraintTop_toBottomOf=\"@+id/imageView\"/>\n\n  <ImageView\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    app:srcCompat=\"@drawable/ic_empty\"\n    android:id=\"@+id/imageView\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_constraintVertical_chainStyle=\"packed\"\n    app:layout_constraintBottom_toTopOf=\"@+id/tv_empty_text\"/>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-kotlin/src/main/res/layout/layout_error.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <TextView\n    android:id=\"@+id/tv_error_text\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"8dp\"\n    android:text=\" Failured to load\"\n    android:textColor=\"@color/loading_error_text\"\n    android:textSize=\"16sp\"\n    app:layout_constraintHorizontal_chainStyle=\"packed\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toBottomOf=\"@+id/imageView3\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintBottom_toTopOf=\"@+id/btn_reload\"/>\n\n  <TextView\n    android:id=\"@+id/btn_reload\"\n    android:layout_width=\"72dp\"\n    android:layout_height=\"24dp\"\n    android:gravity=\"center\"\n    android:text=\"Retry\"\n    android:textColor=\"#999\"\n    android:textSize=\"14sp\"\n    android:background=\"@drawable/bg_reload_btn\"\n    android:layout_marginBottom=\"8dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toBottomOf=\"@+id/tv_error_text\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginTop=\"8dp\"/>\n\n  <ImageView\n    android:layout_width=\"48dp\"\n    android:layout_height=\"48dp\"\n    app:srcCompat=\"@drawable/ic_error\"\n    android:id=\"@+id/imageView3\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    android:layout_marginEnd=\"8dp\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    android:layout_marginStart=\"8dp\"\n    android:layout_marginTop=\"8dp\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_constraintVertical_chainStyle=\"packed\"\n    app:layout_constraintBottom_toTopOf=\"@+id/tv_error_text\"/>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-kotlin/src/main/res/layout/layout_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <ImageView\n    android:id=\"@+id/iv_loading\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:importantForAccessibility=\"no\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:srcCompat=\"@drawable/ic_refresh\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-kotlin/src/main/res/layout/layout_scrolling_toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\">\n\n  <com.google.android.material.appbar.AppBarLayout\n    android:id=\"@+id/app_bar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:elevation=\"2dp\">\n\n    <androidx.appcompat.widget.Toolbar\n      android:id=\"@+id/toolbar\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"?attr/actionBarSize\"\n      app:layout_collapseMode=\"pin\"\n      app:layout_scrollFlags=\"scroll|enterAlways\"\n      app:navigationIcon=\"@drawable/ic_arrow_back_ios\"\n      android:background=\"@color/white\"\n      app:titleTextAppearance=\"@style/ToolbarTextAppearance\" />\n\n  </com.google.android.material.appbar.AppBarLayout>\n\n  <FrameLayout\n    android:id=\"@+id/content_parent\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"/>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "sample-kotlin/src/main/res/layout/layout_toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n  xmlns:tools=\"http://schemas.android.com/tools\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"54dp\">\n\n  <TextView\n    android:id=\"@+id/tv_title\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:textColor=\"#333\"\n    android:textSize=\"18sp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    tools:text=\"Title\" />\n\n  <ImageView\n    android:id=\"@+id/iv_left\"\n    android:layout_width=\"24dp\"\n    android:layout_height=\"24dp\"\n    android:layout_marginStart=\"16dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:srcCompat=\"@drawable/ic_arrow_back_ios\"\n    tools:visibility=\"visible\" />\n\n  <TextView\n    android:id=\"@+id/tv_left\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:textColor=\"#333\"\n    android:textSize=\"16sp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintStart_toEndOf=\"@+id/iv_left\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_goneMarginStart=\"16dp\"\n    tools:text=\"TextView\" />\n\n  <TextView\n    android:id=\"@+id/tv_right\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginEnd=\"16dp\"\n    android:textColor=\"#333\"\n    android:textSize=\"16sp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toStartOf=\"@+id/iv_right\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_goneMarginEnd=\"16dp\"\n    tools:text=\"Next\" />\n\n  <ImageView\n    android:id=\"@+id/iv_right\"\n    android:layout_width=\"24dp\"\n    android:layout_height=\"24dp\"\n    android:layout_marginEnd=\"16dp\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\"\n    app:layout_goneMarginEnd=\"16dp\"\n    app:srcCompat=\"@android:drawable/ic_media_pause\"\n    tools:visibility=\"gone\" />\n\n  <View\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"1px\"\n    android:background=\"#999\"\n    app:layout_constraintBottom_toBottomOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <background android:drawable=\"@drawable/ic_launcher_background\" />\n  <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <background android:drawable=\"@drawable/ic_launcher_background\" />\n  <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "sample-kotlin/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <color name=\"purple_200\">#FFBB86FC</color>\n  <color name=\"purple_500\">#FF6200EE</color>\n  <color name=\"purple_700\">#FF3700B3</color>\n  <color name=\"teal_200\">#FF03DAC5</color>\n  <color name=\"teal_700\">#FF018786</color>\n  <color name=\"black\">#FF000000</color>\n  <color name=\"white\">#FFFFFFFF</color>\n\n  <color name=\"loading_placeholder_view_color\">#ddd</color>\n  <color name=\"loading_title_text\">#666</color>\n  <color name=\"loading_loading_text\">#666</color>\n  <color name=\"loading_error_text\">#666</color>\n  <color name=\"loading_empty_text\">#666</color>\n  <color name=\"loading_reload_btn_text\">#2196F3</color>\n</resources>"
  },
  {
    "path": "sample-kotlin/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\">LoadingStateView</string>\n</resources>"
  },
  {
    "path": "sample-kotlin/src/main/res/values/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n  <!-- Base application theme. -->\n  <style name=\"Theme.LoadingStateView\" parent=\"Theme.MaterialComponents.DayNight.NoActionBar\">\n    <!-- Primary brand color. -->\n    <item name=\"colorPrimary\">@color/purple_500</item>\n    <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n    <item name=\"colorOnPrimary\">@color/white</item>\n    <!-- Secondary brand color. -->\n    <item name=\"colorSecondary\">@color/teal_200</item>\n    <item name=\"colorSecondaryVariant\">@color/teal_700</item>\n    <item name=\"colorOnSecondary\">@color/black</item>\n    <!-- Status bar color. -->\n    <item name=\"android:statusBarColor\" tools:targetApi=\"l\">@color/white</item>\n    <item name=\"android:windowLightStatusBar\" tools:targetApi=\"m\">true</item>\n    <!-- Customize your theme here. -->\n  </style>\n\n  <style name=\"ToolbarTextAppearance\">\n    <item name=\"android:textSize\">18sp</item>\n    <item name=\"android:textColor\">#000</item>\n  </style>\n</resources>"
  },
  {
    "path": "sample-kotlin/src/main/res/values-night/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n  <!-- Base application theme. -->\n  <style name=\"Theme.LoadingStateView\" parent=\"Theme.MaterialComponents.DayNight.DarkActionBar\">\n    <!-- Primary brand color. -->\n    <item name=\"colorPrimary\">@color/purple_200</item>\n    <item name=\"colorPrimaryVariant\">@color/purple_700</item>\n    <item name=\"colorOnPrimary\">@color/black</item>\n    <!-- Secondary brand color. -->\n    <item name=\"colorSecondary\">@color/teal_200</item>\n    <item name=\"colorSecondaryVariant\">@color/teal_200</item>\n    <item name=\"colorOnSecondary\">@color/black</item>\n    <!-- Status bar color. -->\n    <item name=\"android:statusBarColor\" tools:targetApi=\"l\">?attr/colorPrimaryVariant</item>\n    <!-- Customize your theme here. -->\n  </style>\n</resources>"
  },
  {
    "path": "sample-kotlin/src/test/java/com/dylanc/loadingstateview/sample/kotlin/ExampleUnitTest.kt",
    "content": "package com.dylanc.loadingstateview.sample.kotlin\n\nimport org.junit.Test\n\nimport org.junit.Assert.*\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\nclass ExampleUnitTest {\n  @Test\n  fun addition_isCorrect() {\n    assertEquals(4, 2 + 2)\n  }\n}"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = \"LoadingStateView\"\ninclude ':loadingstateview'\ninclude ':loadingstateview-ktx'\ninclude ':sample-java'\ninclude ':sample-kotlin'\n"
  }
]