diff --git a/README.md b/README.md index d6f128f..4b7790f 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ -# LoadingHelper +# LoadingStateView -English | [中文](README_ZH_CN.md) +English | [中文](README_ZH.md) -[![](https://www.jitpack.io/v/DylanCaiCoding/LoadingHelper.svg)](https://www.jitpack.io/#DylanCaiCoding/LoadingHelper) [![](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/LoadingHelper/blob/master/LICENSE) +[![](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) -`LoadingHelper` is a highly expandable Android library for showing loading status view on the low-coupling way, it is implemented with a Kotlin code of less than 300 lines without comment statement . it not only **shows different view like loading, content, error, empty or customized view** when loading network data, but also **manages title bar.** +`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. + +**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!** ## Feature - No need to add view code to the layout. -- Support for show custom views. +- Quickly add all functionality to the base class without affecting existing code. (Kotlin) - Support for use for Activity, Fragment, RecyclerView, View. +- Support for show custom views. - Support for managing the title bar and add multiple headers. - Support for set reload event. - Support for update views anytime. @@ -20,24 +23,28 @@ English | [中文](README_ZH_CN.md) Click or scan QR code to download -[![QR code](img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper) +[![QR code](docs/img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper) -| [Activity(error)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ActErrorActivity.java) | [View(placeholder)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPlaceholderActivity.java) | [ViewPager(timeout)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPagerActivity.java) | [RecyclerView(cool loading)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/RecyclerViewActivity.java) | -| :---: | :----: | :---: | :---: | -| ![](gif/activity_error.gif) | ![](gif/view_placeholder.gif) | ![](gif/viewpager_timeout.gif) | ![](gif/recyclerview_loading.gif) | +| [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) | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| ![](docs/gif/activity_error.gif) | ![](docs/gif/view_placeholder.gif) | ![](docs/gif/viewpager_timeout.gif) | ![](docs/gif/recyclerview_loading.gif) | -| [SpecialHeader(custom)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/CustomHeaderActivity.java) | [MultipleHeader(search)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/MultipleHeaderActivity.java) | [SpecialDecorView(scrolling)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ScrollingToolbarActivity.java) | [BottomDecorView(editor)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/BottomEditorActivity.java) | -| :---: | :---: | :---: | :---: | -| ![](gif/special_header_custom.gif) | ![](gif/multiple_header_search.gif) | ![](gif/special_decor_scrolling.gif) | ![](gif/bottom_decor_editor.gif) | +| [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) | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| ![](docs/gif/special_header_custom.gif) | ![](docs/gif/multiple_header_search.gif) | ![](docs/gif/special_decor_scrolling.gif) | ![](docs/gif/bottom_decor_editor.gif) | +## Usage -## Getting started +:pencil: **[>> Usage documentation <<](https://dylancaicoding.github.io/LoadingStateView)** + +## Gradle Add it in your root `build.gradle` at the end of repositories: + ```groovy allprojects { repositories { - ... + // ... maven { url 'https://www.jitpack.io' } } } @@ -45,132 +52,41 @@ allprojects { Add dependencies in your module `build.gradle` : -``` +```groovy dependencies { - implementation 'com.github.DylanCaiCoding:LoadingHelper:2.3.0' -} -``` - -### Usage - -#### Step 1. Create a class extends `LoadingHelper.Adapter`, for example: + // java + implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview:5.0.0' -```java -public class LoadingAdapter extends LoadingHelper.Adapter { - - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(inflater.inflate(R.layout.layout_loading_view, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - - } + // kotlin + implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0' } ``` -#### Step 2. Register your adapter with a view type, for example: - -```java -LoadingHelper loadingHelper = new LoadingHelper(this); -loadingHelper.register(ViewType.LOADING, new LoadingAdapter()); -``` - -##### Or if you want to register a global adapter. - -```java -LoadingHelper.setDefaultAdapterPool(adapterPool -> { - adapterPool.register(ViewType.LOADING, new LoadingAdapter()); - return Unit.INSTANCE; -}); -``` - -#### Step 3. Show view by view type, for example: - -```java -loadingHelper.showView(viewType); -loadingHelper.showLoadingView(); // view type is ViewType.LOADING -loadingHelper.showContentView(); // view type is ViewType.CONTENT -loadingHelper.showErrorView(); // view type is ViewType.ERROR -loadingHelper.showEmptyView(); // view type is ViewType.EMPTY -``` -#### When you need to reload data. +## Change log -```java -loadingHelper.setOnReloadListener(new LoadingHelper.OnReloadListener() { - @Override - public void onReload() { - // request data again - } -}); - -//In the adapter -holder.getOnReloadListener.onReload(); -``` - -#### When you need to change view after view showed. - -```java -ErrorAdapter adapter = loadingHelper.getAdapter(ViewType.Error); -adapter.errorText = "Fail to load, please wait"; -adapter.notifyDataSetChanged(); -``` - -### Advanced usage - -#### Add title view - -If you want to add an ordinary title bar above the content. - -Similar to the previous usage, create a class extends `LoadingHelper.Adapter` and set header. - -```java -loadingHelper.setDecorHeader(new TitleAdapter("title"), new SearchHeaderAdapter(onSearchListener)); -``` - -If you want to add an special title bar with linkage effect. - -Create a class extends `LoadingHelper.DecorAdapter` to create a decorated view and specify a loading container. - -```java -public class ScrollDecorAdapter extends LoadingHelper.DecorAdapter { - @NotNull - @Override - public View onCreateDecorView(@NotNull LayoutInflater inflater) { - return inflater.inflate(R.layout.layout_scrolling, null); - } - - @NotNull - @Override - public ViewGroup getContentParent(@NotNull View decorView) { - return decorView.findViewById(R.id.content_parent); - } -} -``` - -Then set it up. - -```java -loadingHelper.setDecorAdapter(new ScrollDecorAdapter()); -``` +[Releases](https://github.com/DylanCaiCoding/LoadingStateView/releases) ## Author's other libraries -- [LoadingHelper](https://github.com/DylanCaiCoding/LoadingHelper), a highly expandable Android library for decoupling the code of toolbar or loading status view. -- [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX), the most comprehensive utils of ViewBinding. +| Library | Description | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| [Longan](https://github.com/DylanCaiCoding/Longan) | Probably the best Kotlin utils library for Android. | +| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | The most comprehensive utils of ViewBinding. | +| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX) | Use MMKV with property delegates. | +| [MultiBaseUrls](https://github.com/DylanCaiCoding/MultiBaseUrls) | Use annotation to allow Retrofit to support multiple baseUrl and dynamically change baseUrl | +| [Tracker](https://github.com/DylanCaiCoding/Tracker) | A lightweight tracking framework based on the tracking idea of Buzzvideo.| ## Thanks - [luckbilly/Gloading](https://github.com/luckybilly/Gloading) Optimize my library standing on the shoulders of giants. -- [drakeet/MultiType](https://github.com/drakeet/MultiType) Referenced the usage of ​​multiple adapters. +- [drakeet/MultiType](https://github.com/drakeet/MultiType) Referenced the usage of multiple adapters. - [dinuscxj/LoadingDrawable](https://github.com/dinuscxj/LoadingDrawable) The cool loading effect in the demo. ## License ``` + Copyright (C) 2019. Dylan Cai Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/README_ZH.md b/README_ZH.md new file mode 100644 index 0000000..94bc0b6 --- /dev/null +++ b/README_ZH.md @@ -0,0 +1,103 @@ +# LoadingStateView + +[English](README.md) | 中文 + +[![](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) + +`LoadingStateView` 是一个深度解耦缺省页和标题栏的工具,核心功能的实现代码只有一个 200 多行的 [Kotlin 文件](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt)。不仅能在请求网络数据时显示加载中、加载成功、加载失败、无数据的视图或自定义视图,还可以对标题栏进行解耦。 + +**重大更新:结合 Kotlin 语法特性能快速将所有功能集成到基类,不会影响已有代码。移除了 `ViewHolder`,整体用法得到进一步简化,建议升级!** + +- 无需在布局添加视图代码 +- 支持快速集成到基类,并且不影响有代码(仅 Kotlin) +- 支持 Activity、Fragment、列表或指定的 View +- 支持显示自定义视图 +- 支持添加多个头部控件 +- 支持设置重新请求数据的事件 +- 支持动态更新视图样式 +- 可结合绝大部分第三方控件使用 + +## 示例 + +点击或者扫描二维码下载 + +[![QR code](docs/img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper) + +动态添加加载状态的布局: + +| [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) | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| ![](docs/gif/activity_error.gif) | ![](docs/gif/view_placeholder.gif) | ![](docs/gif/viewpager_timeout.gif) | ![](docs/gif/recyclerview_loading.gif) | + +动态添加标题栏或装饰容器: + +| [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) | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| ![](docs/gif/special_header_custom.gif) | ![](docs/gif/multiple_header_search.gif) | ![](docs/gif/special_decor_scrolling.gif) | ![](docs/gif/bottom_decor_editor.gif) | + +## 用法 + +:pencil: **[>> 使用文档 <<](https://dylancaicoding.github.io/LoadingStateView)** + +## Gradle + +在根目录的 `build.gradle` 添加: + +```groovy +allprojects { + repositories { + // ... + maven { url 'https://www.jitpack.io' } + } +} +``` + +在模块的 `build.gradle` 添加依赖: + +```groovy +dependencies { + // java + implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview:5.0.0' + + // kotlin + implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0' +} +``` + +## 更新日志 + +[Releases](https://github.com/DylanCaiCoding/LoadingStateView/releases) + +## 作者其它的库 + +| 库 | 简介 | +| ------------------------------------------------------------ | ---------------------------------------------- | +| [Longan](https://github.com/DylanCaiCoding/Longan) | 可能是最好用的 Kotlin 工具库 | +| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | 最全面的 ViewBinding 工具 | +| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX) | 最灵活易用的 MMKV 工具 | +| [MultiBaseUrls](https://github.com/DylanCaiCoding/MultiBaseUrls) | 用注解让 Retrofit 同时支持多个 baseUrl 以及动态改变 baseUrl | +| [Tracker](https://github.com/DylanCaiCoding/Tracker) | 基于西瓜视频的责任链埋点思路实现的轻量级埋点框架 | + +## 感谢 + +- [luckbilly/Gloading](https://github.com/luckybilly/Gloading) 站在了巨人肩膀上优化了本库,非常感谢! +- [drakeet/MultiType](https://github.com/drakeet/MultiType) 参考了注册配置多适配器的思想和用法 +- [dinuscxj/LoadingDrawable](https://github.com/dinuscxj/LoadingDrawable) 示例中的自定义加载动画 + +## License + +``` +Copyright (C) 2019. Dylan Cai + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/README_ZH_CN.md b/README_ZH_CN.md deleted file mode 100644 index ea218d5..0000000 --- a/README_ZH_CN.md +++ /dev/null @@ -1,229 +0,0 @@ -# LoadingHelper - -[English](README.md) | 中文 - -[![](https://www.jitpack.io/v/DylanCaiCoding/LoadingHelper.svg)](https://www.jitpack.io/#DylanCaiCoding/LoadingHelper) [![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://github.com/DylanCaiCoding/LoadingHelper/blob/master/LICENSE) - -`LoadingHelper` 是一个深度解耦加载界面和标题栏的工具,只用了一个 Kotlin 文件实现,不算上注释少于 300 行代码。不仅能在请求网络数据时**显示加载中、加载成功、加载失败、无数据的视图或自定义视图**,还可以**对标题栏进行管理**。 - -详细的标题栏用法可以查看这篇文章[《史上耦合度最低的添加标题栏方式》](https://juejin.im/post/5ef01e22e51d4573eb40dab1)。 - -- 无需在布局添加视图代码 -- 可显示自定义视图 -- 可用于 Activity、Fragment、列表或指定的 View -- 可管理标题栏和添加多个头部控件 -- 可设置重新请求数据的事件 -- 可动态更新视图样式 -- 可结合绝大部分第三方控件使用 - -## 示例 - -点击或者扫描二维码下载 - -[![QR code](img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper) - -动态添加加载状态的布局: - -| [Activity(error)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ActErrorActivity.java) | [View(placeholder)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPlaceholderActivity.java) | [ViewPager(timeout)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPagerActivity.java) | [RecyclerView(cool loading)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/RecyclerViewActivity.java) | -| :---: | :----: | :---: | :---: | -| ![](gif/activity_error.gif) | ![](gif/view_placeholder.gif) | ![](gif/viewpager_timeout.gif) | ![](gif/recyclerview_loading.gif) | - -动态添加标题栏或装饰容器: - -| [SpecialHeader(custom)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/CustomHeaderActivity.java) | [MultipleHeader(search)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/MultipleHeaderActivity.java) | [SpecialDecorView(scrolling)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/ScrollingToolbarActivity.java) | [BottomDecorView(editor)](app/src/main/java/com/dylanc/loadinghelper/sample/ui/BottomEditorActivity.java) | -| :---: | :---: | :---: | :---: | -| ![](gif/special_header_custom.gif) | ![](gif/multiple_header_search.gif) | ![](gif/special_decor_scrolling.gif) | ![](gif/bottom_decor_editor.gif) | - - -## 开始使用 - -在根目录的 `build.gradle` 添加: - -```groovy -allprojects { - repositories { - ... - maven { url 'https://www.jitpack.io' } - } -} -``` - -在模块的 `build.gradle` 添加依赖: - -``` -dependencies { - implementation 'com.github.DylanCaiCoding:LoadingHelper:2.3.0' -} -``` - -### 基础用法 - -第一步,创建一个适配器继承 `LoadingHelper.Adapter`,写法与 `RecyclerView.Adapter` 类似。如果需要实现点击重新请求数据,可以在点击事件调用 holder.getOnReloadListener.onReload() 方法。 - -```java -public class LoadingAdapter extends LoadingHelper.Adapter { - - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(inflater.inflate(R.layout.layout_loading_view, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - - } -} -``` - -第二步,注册适配器,关联一个视图类型。有五个默认类型,也可以传任意类型数据进行注册。 - -```java -LoadingHelper loadingHelper = new LoadingHelper(this); // 可传 Activity 或 View -loadingHelper.register(ViewType.LOADING, new LoadingAdapter()); -// 当需要支持点击重新请求数据时 -loadingHelper.setOnReloadListener(() -> {}) -``` - -如果想注册成全局的适配器,需要配置默认的适配器池。 - -```java -LoadingHelper.setDefaultAdapterPool(adapterPool -> { - adapterPool.register(ViewType.LOADING, new LoadingAdapter()); - return Unit.INSTANCE; -}); -``` - -第三步,显示对应类型的视图。 - -```java -loadingHelper.showView(viewType); -loadingHelper.showLoadingView(); // 对应视图类型 ViewType.LOADING -loadingHelper.showContentView(); // 对应视图类型 ViewType.CONTENT -loadingHelper.showErrorView(); // 对应视图类型 ViewType.ERROR -loadingHelper.showEmptyView(); // 对应视图类型 ViewType.EMPTY -``` - -**动态更新已显示视图** - -在显示了视图之后,可以对视图进行更改刷新。用法和 `RecyclerView.Adapter` 一样,调用 `notifyDataSetChanged()` 后,会执行适配器的 `onBindViewHolder()` 方法。 - -```java -ErrorAdapter errorAdapter = loadingHelper.getAdapter(ViewType.ERROR); -errorAdapter.errorText = "服务器繁忙,请稍后重试"; -errorAdapter.notifyDataSetChanged(); -``` - -### 高级用法 - -#### 添加标题栏 - -如果是**普通的标题栏**,就是简单地在内容的上方添加标题栏: - -和前面的用法类似,先创建一个继承 `LoadingHelper.Adapter` 的标题栏适配器,然后就能在内容的上方添加标题栏了,可以添加多个头部。 - -```java -loadingHelper.setDecorHeader(new TitleAdapter("标题名"), new SearchHeaderAdapter(onSearchListener)); -``` - -如果是**特殊的标题栏**,比如有联动效果,就不能直接使用上面的方式了。这时我们要给内容增加个装饰的容器。 - -先实现一个不含内容的布局。 - -```xml - - - - - - - - - - - - - - - -``` - -创建一个类继承另一个适配器 `LoadingHelper.DecorAdapter` ,加载实现的布局,并指定一个添加内容的容器。 - -```java -public class ScrollDecorAdapter extends LoadingHelper.DecorAdapter { - @NotNull - @Override - public View onCreateDecorView(@NotNull LayoutInflater inflater) { - return inflater.inflate(R.layout.layout_scrolling, null); - } - - @NotNull - @Override - public ViewGroup getContentParent(@NotNull View decorView) { - return decorView.findViewById(R.id.content_parent); - } -} -``` - -最后设置一下就可以了。 - -```java -loadingHelper.setDecorAdapter(new ScrollDecorAdapter()); -``` - -上述的两种使用方式都是可以进行多次设置,不过每次设置会把上一次设置的样式给替换掉。 - -## 作者其它的库 - -- [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) —— 最全面的 ViewBinding 工具 -- [ActivityResultLauncher](https://github.com/DylanCaiCoding/ActivityResultLauncher) —— 完美替代 `startActivityForResult()` - -## 感谢 - -- [luckbilly/Gloading](https://github.com/luckybilly/Gloading) 站在了巨人肩膀上优化了本库,非常感谢! -- [drakeet/MultiType](https://github.com/drakeet/MultiType) 参考了注册配置多适配器的思想和用法 -- [dinuscxj/LoadingDrawable](https://github.com/dinuscxj/LoadingDrawable) 示例中的自定义加载动画 - -## License - -``` -Copyright (C) 2019. Dylan Cai - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -``` diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 0228753..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,46 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' - -android { - compileSdkVersion 30 - - defaultConfig { - applicationId "com.dylanc.loadinghelper.sample" - minSdkVersion 21 - targetSdkVersion 30 - versionCode 2 - versionName "1.0.1" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - viewBinding { - enabled = true - } -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation project(':library') - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'androidx.recyclerview:recyclerview:1.2.0' - implementation 'androidx.cardview:cardview:1.0.0' - implementation 'com.google.android.material:material:1.3.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'com.github.bumptech.glide:glide:4.12.0' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' -} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/CustomHeaderAdapter.java b/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/CustomHeaderAdapter.java deleted file mode 100644 index 6574f47..0000000 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/CustomHeaderAdapter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019. Dylan Cai - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.dylanc.loadinghelper.sample.adapter; - -import android.app.Activity; -import android.os.Build; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -import androidx.annotation.NonNull; -import androidx.core.content.ContextCompat; - -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; - -import org.jetbrains.annotations.NotNull; - -/** - * @author Dylan Cai - */ -public class CustomHeaderAdapter extends LoadingHelper.Adapter { - - private View.OnClickListener onMessageClickListener; - private int firstDrawableId; - private View.OnClickListener onFirstBtnClickListener; - private int secondDrawableId; - private View.OnClickListener onSecondBtnClickListener; - - public CustomHeaderAdapter(View.OnClickListener onMessageClickListener, int firstDrawableId, - View.OnClickListener onFirstBtnClickListener, int secondDrawableId, - View.OnClickListener onSecondBtnClickListener) { - this.onMessageClickListener = onMessageClickListener; - this.firstDrawableId = firstDrawableId; - this.onFirstBtnClickListener = onFirstBtnClickListener; - this.secondDrawableId = secondDrawableId; - this.onSecondBtnClickListener = onSecondBtnClickListener; - } - - @NotNull - @Override - public ViewHolder onCreateViewHolder(@NotNull LayoutInflater inflater, @NotNull ViewGroup parent) { - return new ViewHolder(inflater.inflate(R.layout.layout_custom_header, parent, false)); - } - - @Override - public void onBindViewHolder(@NotNull ViewHolder holder) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - holder.getActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - } - - holder.btnMessage.setOnClickListener(onMessageClickListener); - - holder.btnFirst.setImageDrawable(ContextCompat.getDrawable(holder.getActivity(), firstDrawableId)); - holder.btnFirst.setOnClickListener(onFirstBtnClickListener); - - holder.btnSecond.setImageDrawable(ContextCompat.getDrawable(holder.getActivity(), secondDrawableId)); - holder.btnSecond.setOnClickListener(onSecondBtnClickListener); - } - - static class ViewHolder extends LoadingHelper.ViewHolder { - private final ImageView btnFirst; - private final ImageView btnSecond; - private final View btnMessage; - - ViewHolder(@NonNull View rootView) { - super(rootView); - btnFirst = rootView.findViewById(R.id.btn_first); - btnSecond = rootView.findViewById(R.id.btn_second); - btnMessage = rootView.findViewById(R.id.btn_message); - } - - private Activity getActivity() { - return (Activity) getRootView().getContext(); - } - } -} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ErrorAdapter.java b/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ErrorAdapter.java deleted file mode 100644 index e11c002..0000000 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ErrorAdapter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019. Dylan Cai - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.dylanc.loadinghelper.sample.adapter; - -import androidx.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; - -/** - * @author Dylan Cai - */ -public class ErrorAdapter extends LoadingHelper.Adapter { - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new ViewHolder(inflater.inflate(R.layout.layout_error, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull final ViewHolder holder) { - holder.btnReload.setOnClickListener(v -> { - if (holder.getOnReloadListener() != null) { - holder.getOnReloadListener().onReload(); - } - }); - } - - public static class ViewHolder extends LoadingHelper.ViewHolder { - - private final View btnReload; - - ViewHolder(@NonNull View rootView) { - super(rootView); - btnReload = rootView.findViewById(R.id.btn_reload); - } - } -} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/LoadingAdapter.java b/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/LoadingAdapter.java deleted file mode 100644 index 583913e..0000000 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/LoadingAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2019. Dylan Cai - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.dylanc.loadinghelper.sample.adapter; - -import androidx.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.ViewGroup; - -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; - -/** - * @author Dylan Cai - */ -public class LoadingAdapter extends LoadingHelper.Adapter { - - private int height = ViewGroup.LayoutParams.MATCH_PARENT; - - public LoadingAdapter() { - } - - public LoadingAdapter(int height) { - this.height = height; - } - - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(inflater.inflate(R.layout.layout_loading, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - ViewGroup.LayoutParams layoutParams = holder.getRootView().getLayoutParams(); - layoutParams.height = height; - holder.getRootView().setLayoutParams(layoutParams); - } -} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ToolbarAdapter.java b/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ToolbarAdapter.java deleted file mode 100644 index 05310cc..0000000 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ToolbarAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2019. Dylan Cai - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.dylanc.loadinghelper.sample.adapter; - -import android.app.Activity; -import android.os.Build; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.appcompat.widget.Toolbar; - -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; - -import org.jetbrains.annotations.NotNull; - -import kotlin.jvm.functions.Function1; - -/** - * @author Dylan Cai - */ -public class ToolbarAdapter extends LoadingHelper.Adapter { - - private final String title; - private final NavIconType type; - private int menuId; - private Function1 onMenuItemClick; - - public ToolbarAdapter(String title, NavIconType type) { - this.title = title; - this.type = type; - } - - public ToolbarAdapter(String title, NavIconType type, int menuId, Function1 onMenuItemClick) { - this.title = title; - this.type = type; - this.menuId = menuId; - this.onMenuItemClick = onMenuItemClick; - } - - @NotNull - @Override - public ViewHolder onCreateViewHolder(@NotNull LayoutInflater inflater, @NotNull ViewGroup parent) { - return new ToolbarAdapter.ViewHolder(inflater.inflate(R.layout.layout_toolbar, parent, false)); - } - - @Override - public void onBindViewHolder(@NotNull ViewHolder holder) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - holder.getActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); - } - - if (!TextUtils.isEmpty(title)) { - holder.toolbar.setTitle(title); - } - - if (type == NavIconType.BACK) { - holder.toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black); - holder.toolbar.setNavigationOnClickListener(v -> holder.getActivity().finish()); - } else { - holder.toolbar.setNavigationIcon(null); - } - - if (menuId > 0 && onMenuItemClick != null) { - holder.toolbar.inflateMenu(menuId); - holder.toolbar.setOnMenuItemClickListener(item -> onMenuItemClick.invoke(item)); - } - } - - static class ViewHolder extends LoadingHelper.ViewHolder { - - private final Toolbar toolbar; - - ViewHolder(@NonNull View rootView) { - super(rootView); - toolbar = (Toolbar) rootView; - } - - private Activity getActivity() { - return (Activity) getRootView().getContext(); - } - } -} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/animation/FadeAnimation.java b/app/src/main/java/com/dylanc/loadinghelper/sample/animation/FadeAnimation.java deleted file mode 100644 index 0be2cde..0000000 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/animation/FadeAnimation.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.dylanc.loadinghelper.sample.animation; - -import android.view.View; - -import com.dylanc.loadinghelper.LoadingHelper; - -import org.jetbrains.annotations.NotNull; - -/** - * @author Dylan Cai - */ -public class FadeAnimation implements LoadingHelper.Animation { - - private static final long DEFAULT_DURATION = 500; - private final long duration; - - public FadeAnimation() { - this(DEFAULT_DURATION); - } - - public FadeAnimation(long duration) { - this.duration = duration; - } - - @Override - public void onStartShowAnimation(@NotNull View view, @NotNull Object viewType) { - view.setAlpha(0); - view.animate().alpha(1).setDuration(duration); - } - - @Override - public void onStartHideAnimation(@NotNull View view, @NotNull Object viewType) { - view.setAlpha(1); - view.animate().alpha(0).setDuration(duration).withEndAction(() -> { - view.setAlpha(1); - view.setVisibility(View.GONE); - }); - } -} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/ToolbarUtils.java b/app/src/main/java/com/dylanc/loadinghelper/sample/utils/ToolbarUtils.java deleted file mode 100644 index 7ef9f7c..0000000 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/ToolbarUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2019. Dylan Cai - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.dylanc.loadinghelper.sample.utils; - -import android.app.Activity; -import android.view.MenuItem; -import android.view.View; - -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.ViewType; -import com.dylanc.loadinghelper.sample.adapter.CustomHeaderAdapter; -import com.dylanc.loadinghelper.sample.adapter.ScrollingDecorAdapter; -import com.dylanc.loadinghelper.sample.adapter.ToolbarAdapter; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; - -import kotlin.jvm.functions.Function1; - -/** - * @author Dylan Cai - */ -@SuppressWarnings("UnusedReturnValue") -public class ToolbarUtils { - public static LoadingHelper setToolbar(Activity activity, String title, NavIconType type) { - return setToolbar(activity, title, type, 0, null); - } - - public static LoadingHelper setToolbar(Activity activity, String title, NavIconType type, int menuId, - Function1 onMenuItemClick) { - LoadingHelper loadingHelper = new LoadingHelper(activity); - loadingHelper.register(ViewType.TITLE, new ToolbarAdapter(title, type, menuId, onMenuItemClick)); - loadingHelper.setDecorHeader(ViewType.TITLE); - return loadingHelper; - } - - public static LoadingHelper setCustomToolbar(Activity activity, View.OnClickListener onMessageClick, - int firstDrawableId, View.OnClickListener onFirstBtnClick, - int secondDrawableId, View.OnClickListener onSecondBtnClick) { - LoadingHelper loadingHelper = new LoadingHelper(activity); - loadingHelper.register(ViewType.TITLE, new CustomHeaderAdapter(onMessageClick, - firstDrawableId, onFirstBtnClick, secondDrawableId, onSecondBtnClick)); - loadingHelper.setDecorHeader(ViewType.TITLE); - return loadingHelper; - } - - public static LoadingHelper setScrollingToolbar(Activity activity, String title) { - LoadingHelper loadingHelper = new LoadingHelper(activity); - loadingHelper.setDecorAdapter(new ScrollingDecorAdapter(title)); - return loadingHelper; - } -} diff --git a/build.gradle b/build.gradle index b7ec2a1..8c18614 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,31 @@ - buildscript { - ext.kotlin_version = '1.5.30' + ext.buildConfig = [ + 'versionCode' : 1, + 'versionName' : "1.0.0", + 'compileSdkVersion': 30, + 'minSdkVersion' : 14, + 'targetSdkVersion' : 30 + ] + ext { + appCompatVersion = '1.3.1' + constraintLayoutVersion = '2.1.1' + coreVersion = '1.7.0-alpha01' + espressoVersion = '3.4.0' + glideVersion = '4.12.0' + kotlinVersion = "1.5.31" + lifecycleVersion = '2.4.0-alpha03' + junitExtVersion = '1.1.3' + junitVersion = '4.13.2' + materialVersion = '1.4.0' + viewBindingKTXVersion = '2.1.0' + } repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:4.2.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } } diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..079400f --- /dev/null +++ b/docs/README.md @@ -0,0 +1,98 @@ +# LoadingStateView + +[![](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) +[![GitHub Repo stars](https://img.shields.io/github/stars/DylanCaiCoding/LoadingStateView?style=social)](https://github.com/DylanCaiCoding/LoadingStateView) + +`LoadingStateView` 是一个深度解耦缺省页和标题栏的工具,核心功能的实现代码只有一个 200 行左右(不算注释)的 [Kotlin 文件](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt)。不仅能在请求网络数据时显示加载中、加载成功、加载失败、无数据的视图或自定义视图,还可以对标题栏进行解耦。 + +**重大更新:结合 Kotlin 语法特性能快速将所有功能集成到基类,不会影响已有代码。移除了 `ViewHolder`,整体用法得到进一步简化,建议升级!** + +- 无需在布局添加视图代码 +- 支持快速集成到基类,并且不影响有代码(仅 Kotlin) +- 支持 Activity、Fragment、列表或指定的 View +- 支持显示自定义视图 +- 支持添加多个头部控件 +- 支持设置重新请求数据的事件 +- 支持动态更新视图样式 +- 可结合绝大部分第三方控件使用 + +## 示例 + +点击或者扫描二维码下载 + +[![QR code](img/app_download_qr_code.png)](https://www.pgyer.com/loadinghelper) + +动态添加加载状态的布局: + +| [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) | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| ![](gif/activity_error.gif) | ![](gif/view_placeholder.gif) | ![](gif/viewpager_timeout.gif) | ![](gif/recyclerview_loading.gif) | + +动态添加标题栏或装饰容器: + +| [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) | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | +| ![](gif/special_header_custom.gif) | ![](gif/multiple_header_search.gif) | ![](gif/special_decor_scrolling.gif) | ![](gif/bottom_decor_editor.gif) | + +## Gradle + +在根目录的 `build.gradle` 添加: + +```groovy +allprojects { + repositories { + // ... + maven { url 'https://www.jitpack.io' } + } +} +``` + +在模块的 `build.gradle` 添加依赖: + +```groovy +dependencies { + // java + implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview:5.0.0' + + // kotlin + implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0' +} +``` + +## 更新日志 + +[Releases](https://github.com/DylanCaiCoding/LoadingStateView/releases) + +## 作者其它的库 + +| 库 | 简介 | +| ------------------------------------------------------------ | ---------------------------------------------- | +| [Longan](https://github.com/DylanCaiCoding/Longan) | 可能是最好用的 Kotlin 工具库 | +| [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX) | 最全面的 ViewBinding 工具 | +| [MMKV-KTX](https://github.com/DylanCaiCoding/MMKV-KTX) | 用属性委托的方式使用 MMKV | +| [Tracker](https://github.com/DylanCaiCoding/Tracker) | 基于西瓜视频的责任链埋点思路实现的轻量级埋点框架 | + +## 感谢 + +- [luckbilly/Gloading](https://github.com/luckybilly/Gloading) 站在了巨人肩膀上优化了本库,非常感谢! +- [drakeet/MultiType](https://github.com/drakeet/MultiType) 参考了注册配置多适配器的思想和用法 +- [dinuscxj/LoadingDrawable](https://github.com/dinuscxj/LoadingDrawable) 示例中的自定义加载动画 + +## License + +``` +Copyright (C) 2019. Dylan Cai + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 0000000..5cee9a8 --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,6 @@ +* [介绍](/) +* [基础用法](/zh/basic-usage) +* [Kotlin 委托用法](/zh/delegate) +* [结合 ViewBinding 使用](/zh/viewbinding) +* [老版本迁移指南](/zh/migration-guide) +* [Q&A](/zh/q&a) \ No newline at end of file diff --git a/gif/activity_error.gif b/docs/gif/activity_error.gif similarity index 100% rename from gif/activity_error.gif rename to docs/gif/activity_error.gif diff --git a/gif/bottom_decor_editor.gif b/docs/gif/bottom_decor_editor.gif similarity index 100% rename from gif/bottom_decor_editor.gif rename to docs/gif/bottom_decor_editor.gif diff --git a/gif/fragment_empty.gif b/docs/gif/fragment_empty.gif similarity index 100% rename from gif/fragment_empty.gif rename to docs/gif/fragment_empty.gif diff --git a/gif/multiple_header_search.gif b/docs/gif/multiple_header_search.gif similarity index 100% rename from gif/multiple_header_search.gif rename to docs/gif/multiple_header_search.gif diff --git a/gif/recyclerview_loading.gif b/docs/gif/recyclerview_loading.gif similarity index 100% rename from gif/recyclerview_loading.gif rename to docs/gif/recyclerview_loading.gif diff --git a/gif/special_decor_scrolling.gif b/docs/gif/special_decor_scrolling.gif similarity index 100% rename from gif/special_decor_scrolling.gif rename to docs/gif/special_decor_scrolling.gif diff --git a/gif/special_header_custom.gif b/docs/gif/special_header_custom.gif similarity index 100% rename from gif/special_header_custom.gif rename to docs/gif/special_header_custom.gif diff --git a/gif/view_placeholder.gif b/docs/gif/view_placeholder.gif similarity index 100% rename from gif/view_placeholder.gif rename to docs/gif/view_placeholder.gif diff --git a/gif/viewpager_timeout.gif b/docs/gif/viewpager_timeout.gif similarity index 100% rename from gif/viewpager_timeout.gif rename to docs/gif/viewpager_timeout.gif diff --git a/img/app_download_qr_code.png b/docs/img/app_download_qr_code.png similarity index 100% rename from img/app_download_qr_code.png rename to docs/img/app_download_qr_code.png diff --git a/docs/img/base_activity_code.png b/docs/img/base_activity_code.png new file mode 100644 index 0000000..9549651 Binary files /dev/null and b/docs/img/base_activity_code.png differ diff --git a/docs/img/base_binding_activity_code.png b/docs/img/base_binding_activity_code.png new file mode 100644 index 0000000..cc4c2c3 Binary files /dev/null and b/docs/img/base_binding_activity_code.png differ diff --git a/docs/img/base_binding_fragment_code.png b/docs/img/base_binding_fragment_code.png new file mode 100644 index 0000000..260539f Binary files /dev/null and b/docs/img/base_binding_fragment_code.png differ diff --git a/docs/img/base_fragment_code.png b/docs/img/base_fragment_code.png new file mode 100644 index 0000000..3d1566e Binary files /dev/null and b/docs/img/base_fragment_code.png differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..11eb427 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,37 @@ + + + + + Document + + + + + + +
+ + + + + + + + + diff --git a/docs/zh/basic-usage.md b/docs/zh/basic-usage.md new file mode 100644 index 0000000..c76453b --- /dev/null +++ b/docs/zh/basic-usage.md @@ -0,0 +1,289 @@ +# 基础用法 + +使用 Kotlin 开发推荐用[委托用法](/zh/delegate)。 + +## 显示加载中、加载失败等缺省页 + +第一步,使用 Activity 或 View 创建 `LoadingStateView`,不需要重新加载的话 `OnReloadListener` 可不传。 + + + +#### **Kotlin** + +```kotlin +val loadingStateView = LoadingStateView(this, onReloadListener) +// val loadingStateView = LoadingStateView(view, onReloadListener) +``` + +#### **Java** + +```java +LoadingStateView loadingStateView = new LoadingStateView(this, onReloadListener); +// LoadingStateView loadingStateView = new LoadingStateView(view, onReloadListener); +``` + + + +第二步,创建一个类继承 `LoadingStateView.ViewDelegate`。 + +构造函数需要传个参数,决定视图类型,之后显示和更新会用到。默认提供了 `ViewType.LOADING`、`ViewType.ERROR`、`ViewType.EMPTY`、`ViewType.TITLE`,其它的可以用一个 String 作为类型。 + + + +#### **Kotlin** + +```kotlin +class LoadingViewDelegate : LoadingStateView.ViewDelegate(ViewType.LOADING) { + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View = + inflater.inflate(R.layout.layout_loading, parent, false) +} +``` + +#### **Java** + +```java +public class LoadingViewDelegate extends LoadingStateView.ViewDelegate { + + public LoadingViewDelegate() { + super(ViewType.LOADING); + } + + @NonNull + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + return inflater.inflate(R.layout.layout_loading, parent, false); + } +} +``` + + + +如果需要实现点击重新请求数据,可以在点击事件调用 `onReloadListener?.onReload()` 方法。 + +第三步,注册 `ViewDelegate`。首先在 Application 注册全局的 `ViewDelegate`: + + + +#### **Kotlin** + +```kotlin +LoadingStateView.setViewDelegatePool { + register(LoadingViewDelegate(), ErrorViewDelegate(), EmptyViewDelegate()) +} +``` + +#### **Java** + +```java +LoadingStateView.setViewDelegatePool(pool -> + pool.register(new LoadingViewDelegate(), new ErrorViewDelegate(), new EmptyViewDelegate())); +``` + + + +如果某个页面需要不同样式,就用该页面的 `LoadingStateView` 注册对应类型的 `ViewDelegate`,就可以把全局的替换了。 + + + +#### **Kotlin** + +```kotlin +loadingStateView.register(CoolLoadingViewDelegate()) +``` + +#### **Java** + +```java +loadingStateView.register(new CoolLoadingViewDelegate()); +``` + + + +第四步,显示对应类型的视图。 + + + +#### **Kotlin** + +```kotlin +loadingStateView.showView(viewType) +loadingStateView.showLoadingView() // 显示 ViewType.LOADING 类型的视图 +loadingStateView.showContentView() // 显示 ViewType.CONTENT 类型的视图 +loadingStateView.showErrorView() // 显示 ViewType.ERROR 类型的视图 +loadingStateView.showEmptyView() // 显示 ViewType.EMPTY 类型的视图 +``` + +#### **Java** + +```java +loadingStateView.showView(viewType); +loadingStateView.showLoadingView(); // 对应视图类型 ViewType.LOADING +loadingStateView.showContentView(); // 对应视图类型 ViewType.CONTENT +loadingStateView.showErrorView(); // 对应视图类型 ViewType.ERROR +loadingStateView.showEmptyView(); // 对应视图类型 ViewType.EMPTY +``` + + + +## 更新视图样式 + +需要在 `ViewDelegate` 自行增加更新的方法,然后更新对应的 `ViewDelegate`。比如在 `ErrorViewDelegate` 增加了 `updateMsg(msg)` 方法修改请求失败的文字: + + + +#### **Kotlin** + +```kotlin +loadingStateView.updateViewDelegate(ViewType.ERROR) { + updateMsg("服务器繁忙,请稍后重试") +} +``` + +#### **Java** + +```java +loadingStateView.updateViewDelegate(ViewType.ERROR, (ErrorViewDelegate delegate) -> + delegate.updateMsg("服务器繁忙,请稍后重试")); +``` + + + +## 在内容上方添加视图 + +实现标题栏或搜索栏等 `ViewDelegate`,之后就可以用 `LoadingStateView` 在内容布局的上方添加视图。 + + + +#### **Kotlin** + +```kotlin +loadingStateView.setHeaders(ToolbarViewDelegate("消息"), SearchViewDelegate()) +``` + +#### **Java** + +```java +loadingStateView.setHeaders(new ToolbarViewDelegate("消息"), new SearchViewDelegate()); +``` + + + +## 给内容增加装饰 + +可以给内容布局外层添加一层装饰,实现更复杂的样式,非简单地在内容上方增加控件,比如带联动效果的标题栏、DrawerLayout、底部输入框等布局。 + +接下来以滑动隐藏标题栏的效果为例,先写一个带联动效果的标题栏布局,其中有个 FragmentLayout 是用于填充内容和显示缺省页。 + +```xml + + + + + + + + + + + + +``` + +然后写一个类继承 `LoadingStateView.DecorViewDelegate`。 + + + +#### **Kotlin** + +```kotlin +class ScrollingDecorViewDelegate( + private val activity: Activity, + private val title: String +) : LoadingStateView.DecorViewDelegate() { + + override fun onCreateDecorView(context: Context, inflater: LayoutInflater): View { + val view = inflater.inflate(R.layout.layout_scrolling_toolbar, null) + val toolbar: Toolbar = view.findViewById(R.id.toolbar) + toolbar.title = title + toolbar.setNavigationOnClickListener { activity.finish() } + return view + } + + override fun getContentParent(decorView: View): ViewGroup { + return decorView.findViewById(R.id.content_parent) + } +} +``` + +#### **Java** + +```java +public class ScrollingDecorViewDelegate extends LoadingStateView.DecorViewDelegate { + private final Activity activity; + private final String title; + + public ScrollingDecorViewDelegate(Activity activity, String title) { + this.activity = activity; + this.title = title; + } + + @NotNull + @Override + public View onCreateDecorView(@NonNull Context context, @NotNull LayoutInflater inflater) { + View view = inflater.inflate(R.layout.layout_scrolling_toolbar, null); + Toolbar toolbar = view.findViewById(R.id.toolbar); + toolbar.setTitle(title); + toolbar.setNavigationOnClickListener(v -> activity.finish()); + return view; + } + + @NotNull + @Override + public ViewGroup getContentParent(@NotNull View decorView) { + return decorView.findViewById(R.id.content_parent); + } +} +``` + + + +与 `ViewDelegate` 不同的是,需要多实现一个 `getContentParent(decorView)` 方法来指定添加内容的容器,这里我们返回前面的 FrameLayout。 + +之后就可以给内容进行装饰了。 + + + + +#### **Kotlin** + +```kotlin +loadingStateView.setDecorView(ScrollingDecorViewDelegate(this, "title")) +``` + +#### **Java** + +```java +loadingStateView.setDecorView(new ScrollingDecorViewDelegate(this, "title")); +``` + + diff --git a/docs/zh/delegate.md b/docs/zh/delegate.md new file mode 100644 index 0000000..395c959 --- /dev/null +++ b/docs/zh/delegate.md @@ -0,0 +1,352 @@ +# Kotlin 委托用法 + +## 准备工作 + +需要修改基类,只需简单的两步就可以把本库的功能集成到基类,并且不会影响到已有的代码,只是给基类扩展了新的方法。 + +注意添加的依赖需要是 `loadingstateview-ktx`: + +```groovy +dependencies { + implementation 'com.github.DylanCaiCoding.LoadingStateView:loadingstateview-ktx:5.0.0' +} +``` + +修改步骤如下: + +1. 实现 `LoadingState by LoadingStateDelegate()` 。 +2. 在 Activity 的 `setContentView()` 方法后执行 `decorateContentView(this)`。在 Fragment 的 `onCreateView()` 返回 `view.decorate(this)`。 + + + +#### **Activity** + +![img.png](../img/base_activity_code.png) + +
+ 查看代码 + +```kotlin +abstract class BaseActivity(private val layoutRes: Int) : AppCompatActivity(), + LoadingState by LoadingStateDelegate() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(layoutRes) + decorateContentView(this) + } +} +``` + +
+ +#### **Fragment** + +![img.png](../img/base_fragment_code.png) + +
+ 查看代码 + +```kotlin +abstract class BaseFragment(private val layoutRes: Int) : Fragment(), + LoadingState by LoadingStateDelegate() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View? { + val root = inflater.inflate(layoutRes, container, false) + return root.decorate(this) + } +} +``` + +
+ + + +这样改造基类后会得到以下的增强: + +- 在不影响已有代码的情况下,增加了 [LoadingState](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingState.kt) 接口提供的常用方法,该接口包含了 `LoadingStateView` 所有功能。 +- 如果担心对基类有什么影响,在页面重写 `override val isDecorated = false` 会把一切还原,即使调用了新增的接口方法也不会生效,请放心使用。 + +## 显示缺省页 + +先注册各类型缺省页的样式,之后才能调用对应的 `showView()` 方法。 + +创建类继承 `LoadingStateView.ViewDelegate`,构造函数传个视图类型参数,默认提供了 `ViewType.LOADING`、`ViewType.ERROR`、`ViewType.EMPTY`。 + + + +#### **ViewType.LOADING** + +```kotlin +class LoadingViewDelegate : LoadingStateView.ViewDelegate(ViewType.LOADING) { + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View = + inflater.inflate(R.layout.layout_loading, parent, false) +} +``` + +#### **ViewType.ERROR** + +```kotlin +class ErrorViewDelegate : LoadingStateView.ViewDelegate(ViewType.ERROR) { + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View = + inflater.inflate(R.layout.layout_error, parent, false).apply { + findViewById(R.id.btn_reload).setOnClickListener { + onReloadListener?.onReload() + } + } +} +``` + +#### **ViewType.EMPTY** + +```kotlin +class EmptyViewDelegate : LoadingStateView.ViewDelegate(ViewType.EMPTY) { + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View = + inflater.inflate(R.layout.layout_empty, parent, false) +} +``` + + + +在 Application 注册全局的 `ViewDelegate`。 + +```kotlin +LoadingStateView.setViewDelegatePool { + register(LoadingViewDelegate(), ErrorViewDelegate(), EmptyViewDelegate()) +} +``` + +在实现了基类的 `Activity` 或 `Fragment` 可以调用对应的 `showView()` 方法。 + +```kotlin +showLoadingView() // 显示 ViewType.LOADING 类型的视图 +showErrorView() // 显示 ViewType.ERROR 类型的视图 +showEmptyView() // 显示 ViewType.EMPTY 类型的视图 +showContentView() // 显示原来的内容视图 +showView(viewType) // 显示自定义类型的视图 +``` + +如果需要实现点击重新加载,就在基类重写 `onReload()` 方法。 + +如果某个页面需要显示不同的缺省页,可以在显示前调用一下 `registerView(viewDelegate)` 方法覆盖默认的样式。比如: + +```kotlin +registerView(CoolLoadingViewDelegate()) +showLoadingView() +``` + +如果需要动态更新某个样式,在 `ViewDelegate` 自行增加更新的方法,比如在 `ErrorViewDelegate` 增加了 `updateMsg(msg)` 方法修改请求失败的文字,然后就能更新了。 + +```kotlin +updateView(ViewType.ERROR) { + updateMsg("服务器繁忙,请稍后重试") +} +``` + +## 设置标题栏 + +先注册标题栏样式,之后才能调用 `setToolbar()` 方法。 + +创建一个类继承 `BaseToolbarViewDelegate`,通常项目都有各自的标题栏封装,我们能基于已有的标题栏布局或者自定义的标题栏控件实现 `ToolbarViewDelegate`。比如: + +```kotlin +class ToolbarViewDelegate : BaseToolbarViewDelegate() { + private lateinit var tvTitle: TextView + private lateinit var ivLeft: ImageView + private lateinit var ivRight: ImageView + + override fun onCreateToolbar(inflater: LayoutInflater, parent: ViewGroup): View { + val view = inflater.inflate(R.layout.layout_toolbar, parent, false) + tvTitle = view.findViewById(R.id.tv_title) + ivLeft = view.findViewById(R.id.iv_left) + ivRight = view.findViewById(R.id.iv_right) + return view + } + + override fun onBindToolbar(config: ToolbarConfig) { + tvTitle.text = config.title + + if (config.navBtnType == NavBtnType.NONE) { + ivLeft.visibility = View.GONE + } else { + ivLeft.setOnClickListener(config.onNavClickListener) + ivLeft.visibility = View.VISIBLE + } + + if (config.rightIcon != null) { + ivRight.setImageResource(config.rightIcon!!) + ivRight.setOnClickListener(config.onRightClickListener) + ivRight.visibility = View.VISIBLE + } + } +} +``` + +`ToolbarConfig` 提供了几个常用的属性。可以根据需要选择处理,比如上述例子只实现了有无返回键和右侧按钮的逻辑,项目中有功能相对完整的[示例代码](https://github.com/DylanCaiCoding/LoadingStateView/blob/master/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ToolbarViewDelegate.kt)。 + +| 属性 | 含义 | +| -------------------- | -------------------- | +| title | 标题 | +| navBtnType | 导航 (左侧) 按钮类型 | +| navIcon | 导航 (左侧) 图标 | +| navText | 导航 (左侧) 文字 | +| onNavClickListener | 导航 (左侧) 按钮点击事件 | +| rightIcon | 右侧图标 | +| rightText | 右侧文字 | +| onRightClickListener | 右侧按钮点击事件 | + +`onNavClickListener` 默认执行 `finish()` 操作。`navBtnType` 默认类型是 `NavBtnType.ICON`,还有 `NavBtnType.NONE`、`NavBtnType.TEXT`、`NavBtnType.ICON_TEXT`类型。其它的属性默认为空,为空的时候不用处理使用默认样式即可。 + +当然这点属性肯定不能满足所有的需求,所以本库支持给 `ToolbarConfig` 增加扩展属性。比如需要动态修改右侧文字颜色: + +```kotlin +var ToolbarConfig.rightTextColor: Int? by toolbarExtras() // 增加 rightTextColor 扩展属性 + +class ToolbarViewDelegate : BaseToolbarViewDelegate() { + + // ... + + override fun onBindToolbar(config: ToolbarConfig) { + // ... + config.rightTextColor?.let { tvRight.setTextColor(it) } // 处理扩展属性 + } +} +``` + +在 Application 注册全局的标题栏 `ViewDelegate`。 + +```kotlin +LoadingStateView.setViewDelegatePool { + register(ToolbarViewDelegate(), // ... ) +} +``` + +之后就能在实现了基类的 `Activity` 或 `Fragment` 设置标题栏了。 + +```kotlin +setToolbar() // 默认有返回键 + +setToolbar("title") // 有标题和返回键 + +setToolbar("title", NavBtnType.NONE) // 只有标题,无返回键 + +setToolbar("title") { // 以下可选 + navIcon = R.drawable.account // 只修改返回键图标 + navIcon { ... } // 只修改返回键的点击事件 + navIcon(R.drawable.message) { ... } // 修改返回键的图标和点击事件 + rightIcon(R.drawable.add) { ... } // 添加右侧图标 + rightText("Delete") { ... } // 添加右侧文字 + rightTextColor = Color.RED // 新增的扩展属性,修改右侧文字颜色 +} +``` + +这样就多了一种添加标题栏的方式,新写的代码可以用上述的方式添加标题栏,老的代码保留已有的 `` 布局或者自定义标题栏控件的用法。样式都是一样的,因为是基于已有标题栏实现的。 + +如果某个页面的标题栏样式变动很大,不建议写太多扩展属性来配置,这样代码阅读性也差。推荐用新布局再写一个 `BaseToolbarViewDelegate` 的实现类,在设置标题栏之前注册,这会覆盖掉默认的样式。 + +```kotlin +registerView(SpecialToolbarViewDelegate()) +setToolbar("title") +``` + +如果需要动态更新标题栏样式: + +```kotlin +updateToolbar { title = "Loading..." } +``` + +如果有扩展属性不好配置的需求,比如开启或关闭动画,可以在 `ToolbarViewDelegate` 自行增加对应功能的函数,然后在更新的时候调用。 + +```kotlin +updateView(ViewType.TITLE) { + startAnimation() +} +``` + +## 在顶部添加控件 + +可添加多个控件,比如添加标题栏和搜索栏,搜索栏需要另写一个类继承 `LoadingStateView.ViewDelegate`。 + +```kotlin +setHeaders( + ToolbarViewDelegate("Search") { + rightIcon(R.drawable.more) { ... } + }, + SearchViewDelegate(onSearchListener) +) +``` + +## 给内容增加装饰 + +可以给内容布局再套上一层装饰,实现更复杂的样式,非简单地在顶部增加控件,比如带联动效果的标题栏、DrawerLayout、底部输入框等布局。 + +接下来以滑动隐藏标题栏的效果为例,先写一个带联动效果的标题栏布局,其中有个 FragmentLayout 是用于填充内容和显示缺省页。 + +```xml + + + + + + + + + + + + +``` + +然后写一个类继承 `LoadingStateView.DecorViewDelegate`。 + +```kotlin +class ScrollingDecorViewDelegate( + private val activity: Activity, + private val title: String +) : LoadingStateView.DecorViewDelegate() { + + override fun onCreateDecorView(context: Context, inflater: LayoutInflater): View { + val view = inflater.inflate(R.layout.layout_scrolling_toolbar, null) + val toolbar: Toolbar = view.findViewById(R.id.toolbar) + toolbar.title = title + toolbar.setNavigationOnClickListener { activity.finish() } + return view + } + + override fun getContentParent(decorView: View): ViewGroup { + return decorView.findViewById(R.id.content_parent) + } +} +``` + +与 `LoadingStateView.ViewDelegate` 不同的是,需要多实现一个 `getContentParent(decorView)` 方法来指定添加内容的容器,这里我们返回前面的 FrameLayout。 + +之后就可以给内容进行装饰了。 + +```kotlin +setDecorView(ScrollingDecorViewDelegate(this, "title")) +``` \ No newline at end of file diff --git a/docs/zh/migration-guide.md b/docs/zh/migration-guide.md new file mode 100644 index 0000000..b4fdae7 --- /dev/null +++ b/docs/zh/migration-guide.md @@ -0,0 +1,5 @@ +# 老版本升级指南 + +`4.0.1` 版本对用法进行了优化,移除了 `ViewHolder`,使用起来更加简单,不过就意味着不能兼容之前的代码。建议根据[文档](/zh/basic-usage)改成新的用法,通常是封装在基类,要改的不多,`ViewHolder` 的代码需要移到 `onCreateView()` 中。 + +但是如果报红的地方特别多,个人有一个折中的方案。由于之前版本只有一个两三百行的 kt 文件,那么可以把源码拷贝出来并删除依赖,也就是说改成源码的方式集成,全局改一下相关包名。然后就可以添加新版本依赖进行使用,再慢慢将老用法改成新用法。 \ No newline at end of file diff --git a/docs/zh/q&a.md b/docs/zh/q&a.md new file mode 100644 index 0000000..d9f293f --- /dev/null +++ b/docs/zh/q&a.md @@ -0,0 +1,14 @@ +# Q&A + +## 为什么不分成标题栏库和缺省页库? + +个人深思熟虑了非常久才决定写成一个库,有以下考虑: + +- 支持给内容和缺省页添加头部,所以具有管理标题栏的应用场景,感觉没什么不妥。 +- 大多数情况下标题栏和缺省页关联性很强,因为缺省页往往是要在标题栏下方显示,如果分成两个库就经常需要调用两个工具类,使用起来更加麻烦。 +- 分成两个库可能会多一层无意义的布局嵌套。 +- 即使写在一起,核心功能的实现类才 200 多行代码,还要啥自行车。由于适配器和 View 的缓存代码能复用,在解耦缺省页后,仅加多几十行代码就能把标题栏给一起解耦了,何乐而不为。 + +## 可以在布局上预览标题栏吗? + +不能,这可能是本库唯一的缺点,但是本库解耦标题栏的收益远大于在布局上预览标题栏的收益。 diff --git a/docs/zh/viewbinding.md b/docs/zh/viewbinding.md new file mode 100644 index 0000000..76bad08 --- /dev/null +++ b/docs/zh/viewbinding.md @@ -0,0 +1,153 @@ +# 结合 ViewBinding 使用 + +## 基础用法 + +如果要同时使用 `LoadingStateView` 和 `ViewBinding`,需要先得到对应的 `ViewBinding` 实例,再用其根视图去创建 `LoadingStateView`。 + + + +#### **Kotlin** + +```kotlin +val loadingStateView = LoadingStateView(binding.root, onReloadListener) +``` + +#### **Java** + +```java +LoadingStateView loadingStateView = new LoadingStateView(binding.getRoot(), onReloadListener); +``` + + + +## Kotlin 委托用法 + +委托用法再结合上 ViewBinding 才是个人理想中的用法。会使用到个人的另一个库 [ViewBindingKTX](https://github.com/DylanCaiCoding/ViewBindingKTX),可以快速集成 ViewBinding 到基类中。 + +添加依赖: + +```groovy +implementation 'com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-base:2.1.0' +``` + +根据[文档](https://dylancaicoding.github.io/ViewBindingKTX/#/zh/baseclass)集成 ViewBinding,再对 ViewBinding 的根视图进行装饰。以下是在委托用法基础上修改的代码: + + + +#### **Activity** + +![img.png](../img/base_binding_activity_code.png) + +
+ 查看代码 + +```kotlin +abstract class BaseBindingActivity : AppCompatActivity(), + LoadingState by LoadingStateDelegate(), ActivityBinding by ActivityBindingDelegate() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentViewWithBinding() + binding.root.decorate(this) + } +} +``` + +
+ +#### **Fragment** + +![img.png](../img/base_binding_fragment_code.png) + +
+ 查看代码 + +```kotlin +abstract class BaseBindingFragment : Fragment(), + LoadingState by LoadingStateDelegate(), FragmentBinding by FragmentBindingDelegate() { + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View? { + return createViewWithBinding(inflater, container).decorate(this) + } +} +``` + +
+ + + +这样封装后不仅能在 Activity 或 Fragment 获取 `binding` 属性,还能很方便地指定显示缺省页的区域。 + +比如我们在已有的项目迭代开发,一些页面的布局已经写了标题栏。如果直接调用 `showLoadingView()` 函数,缺省页会把标题栏给覆盖了,通常要在标题栏下方显示缺省页,此时就可以重写 `contentView` 属性,声明在哪个控件显示缺省页,比如: + +```kotlin +class MainActivity : BaseBindingActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + showLoadingView() + // ... + } + + override val contentView get() = binding.container +} +``` + +### 已有的基类如何修改 + +由于要给基类增加 ViewBinding 泛型,肯定不可能直接修改基类,这会影响到已有的代码,建议继承原基类再扩展出一个支持 ViewBinding 的基类。 + +假设已有的基类是这种常见的封装,通过 `getLayoutId()` 函数去设置布局。 + +```java +public abstract class BaseActivity extends AppCompatActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutId()); + initData(); + initViews(); + } + + public abstract int getLayoutId(); + public abstract void initData(); + public abstract void initViews(); +} +``` + +目前直接继承是实现不了的,因为需要重写 `setContentView()` 的代码,所以要先将 `setContentView()` 抽到一个函数中。 + +```java +@Override +protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initContentView(); + initData(); + initViews(); +} + +protected void initContentView() { + setContentView(getLayoutId()); +} +``` + +之后就可以继承基类重写该函数替换掉原来的 `setContentView()` 工作。 + +```kotlin +abstract class BaseBindingActivity : BaseActivity(), + LoadingState by LoadingStateDelegate(), OnReloadListener, Decorative, + ActivityBinding by ActivityBindingDelegate() { + + override fun initContentView() { + setContentViewWithBinding() + binding.root.decorate(this, this) + } + + override fun getLayoutId() = -1 // 使用 ViewBinding 后,就不需要布局 id 了 +} +``` + +Fragment 的修改也同理。 \ No newline at end of file diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml deleted file mode 100644 index 1eb665f..0000000 --- a/library/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/library/src/main/java/com/dylanc/loadinghelper/LoadingHelper.kt b/library/src/main/java/com/dylanc/loadinghelper/LoadingHelper.kt deleted file mode 100644 index 9ce1cb6..0000000 --- a/library/src/main/java/com/dylanc/loadinghelper/LoadingHelper.kt +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2019. Dylan Cai - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:Suppress("unused") - -package com.dylanc.loadinghelper - -import android.app.Activity -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.* -import android.widget.FrameLayout -import android.widget.LinearLayout -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.view.updateLayoutParams -import java.util.* - -/** - * @author Dylan Cai - */ -class LoadingHelper(private val contentView: View) { - lateinit var decorView: View private set - private lateinit var contentParent: ViewGroup - private val parent: ViewGroup? - private var currentViewHolder: ViewHolder? = null - private var onReloadListener: OnReloadListener? = null - private var adapters: HashMap> = HashMap() - private val viewHolders: HashMap = HashMap() - - companion object { - private var adapterPool: (AdapterPool.() -> Unit)? = null - - @JvmStatic - fun setDefaultAdapterPool(adapterPool: AdapterPool.() -> Unit) { - this.adapterPool = adapterPool - } - } - - /** - * Constructs a LoadingHelper with a activity and a content adapter - * - * @param activity the activity - */ - constructor(activity: Activity) : this((activity.findViewById(android.R.id.content) as ViewGroup).getChildAt(0)) - - init { - adapterPool?.let { AdapterPool(this).apply(it) } - parent = contentView.parent as ViewGroup? - register(ViewType.CONTENT, ContentAdapter()) - setDecorAdapter(LinearDecorAdapter(listOf())) - } - - /** - * Sets an adapter for decorating content view. - * - * @param decorAdapter the adapter for decorating content view. - * @since v2.0.0 - */ - fun setDecorAdapter(decorAdapter: DecorAdapter) { - currentViewHolder = null - if (parent != null) { - val index = parent.indexOfChild(contentView) - if (index >= 0) { - parent.removeView(contentView) - } else { - parent.removeView(decorView) - (contentView.parent as ViewGroup).removeView(contentView) - } - decorView = decorAdapter.createDecorView() - parent.addView(decorView, index) - } else { - decorView = decorAdapter.createDecorView() - } - contentParent = decorAdapter.getContentParent(decorView) - showView(ViewType.CONTENT) - } - - /** - * Adds one or more views to decorate content in the header. - * - * @param adapters the adapters of creating view - * @since v2.3.0 - */ - fun setDecorHeader(vararg adapters: Adapter<*>) { - val viewType = Array(adapters.size) { adapters[it].javaClass.name } - for (i in adapters.indices) { - register(viewType[i], adapters[i]) - } - setDecorHeader(*viewType) - } - - /** - * Adds one or more views to decorate content in the header. - * - * @param viewType the view type of adapter - * @since v2.0.0 - */ - fun setDecorHeader(vararg viewType: Any) { - val views = mutableListOf() - for (t in viewType) { - views.add(getViewHolder(t).rootView) - } - setDecorAdapter(LinearDecorAdapter(views)) - } - - /** - * Adds child decorative view between the content and the decorative view. - * - * @param decorAdapter the adapter for decorating content view. - * @since v2.1.0 - */ - fun addChildDecorAdapter(decorAdapter: DecorAdapter) { - contentParent.removeView(currentViewHolder?.rootView) - currentViewHolder = null - val childDecorView = decorAdapter.createDecorView() - contentParent.addView(childDecorView) - contentParent = decorAdapter.getContentParent(childDecorView) - showView(ViewType.CONTENT) - } - - /** - * Adds child decorative header between the content and the decorative view. - * - * @param adapters the adapters of creating view - * @since v2.3.0 - */ - fun addChildDecorHeader(vararg adapters: Adapter<*>) { - val viewType = Array(adapters.size) { adapters[it].javaClass.name } - for (i in adapters.indices) { - register(viewType[i], adapters[i]) - } - addChildDecorHeader(*viewType) - } - - /** - * Adds child decorative header between the content and the decorative view. - * - * @param viewTypes the view type of adapter - * @since v2.1.0 - */ - @Suppress("MemberVisibilityCanBePrivate") - fun addChildDecorHeader(vararg viewTypes: Any) { - val views = mutableListOf() - for (viewType in viewTypes) { - views.add(getViewHolder(viewType).rootView) - } - addChildDecorAdapter(LinearDecorAdapter(views)) - } - - private fun DecorAdapter.createDecorView() = - onCreateDecorView(LayoutInflater.from(contentView.context)).also { decorView -> - if (contentView.layoutParams != null) { - decorView.layoutParams = contentView.layoutParams - } - } - - /** - * Registers the adapter of creating view before showing view. - * - * @param viewType the view type of adapter - * @param adapter the adapter of creating view - */ - fun register(viewType: Any, adapter: Adapter<*>) { - adapters[viewType] = adapter - } - - /** - * Called if you need to handle reload event, you can get the listener of reloading data from view holder. - * - * @param onReloadListener the listener of reloading data - */ - fun setOnReloadListener(onReloadListener: OnReloadListener) { - this.onReloadListener = onReloadListener - } - - @JvmOverloads - fun showLoadingView(animation: Animation? = null) = showView(ViewType.LOADING, animation) - - @JvmOverloads - fun showContentView(animation: Animation? = null) = showView(ViewType.CONTENT, animation) - - @JvmOverloads - fun showErrorView(animation: Animation? = null) = showView(ViewType.ERROR, animation) - - @JvmOverloads - fun showEmptyView(animation: Animation? = null) = showView(ViewType.EMPTY, animation) - - /** - * Shows the view by view type - * - * @param viewType the view type of adapter - */ - @JvmOverloads - fun showView(viewType: Any, animation: Animation? = null) { - val currentViewHolder = currentViewHolder - if (currentViewHolder == null) { - addView(viewType) - } else { - if (viewHolders[viewType] == null) { - addView(viewType) - } - if (viewType != currentViewHolder.viewType) { - getViewHolder(viewType).rootView.visibility = View.VISIBLE - if (animation != null) { - animation.onStartHideAnimation(currentViewHolder.rootView, currentViewHolder.viewType!!) - animation.onStartShowAnimation(getViewHolder(viewType).rootView, getViewHolder(viewType).viewType!!) - } else { - currentViewHolder.rootView.visibility = View.GONE - } - this.currentViewHolder = getViewHolder(viewType) - } - } - } - - private fun addView(viewType: Any) { - val viewHolder = getViewHolder(viewType) - val rootView = viewHolder.rootView - if (rootView.parent != null) { - (rootView.parent as ViewGroup).removeView(rootView) - } - if (parent is ConstraintLayout && viewType == ViewType.CONTENT) { - rootView.updateLayoutParams { - if (rootView.measuredWidth == 0) width = MATCH_PARENT - if (rootView.measuredHeight == 0) height = MATCH_PARENT - } - } - contentParent.addView(rootView) - currentViewHolder = viewHolder - } - - private fun notifyDataSetChanged(adapter: Adapter) { - for (entry in adapters.entries) { - if (entry.value == adapter) { - adapter.onBindViewHolder(getViewHolder(entry.key)) - } - } - } - - private fun getViewHolder(viewType: Any): ViewHolder { - if (viewHolders[viewType] == null) { - addViewHolder(viewType) - } - return viewHolders[viewType] as ViewHolder - } - - @Suppress("UNCHECKED_CAST") - fun > getAdapter(viewType: Any) = adapters[viewType] as T - - private fun addViewHolder(viewType: Any) { - val adapter: Adapter = getAdapter(viewType) - val viewHolder = adapter.onCreateViewHolder(LayoutInflater.from(contentParent.context), contentParent) - viewHolder.viewType = viewType - viewHolder.onReloadListener = onReloadListener - viewHolders[viewType] = viewHolder - adapter.onBindViewHolder(viewHolder) - adapter.listener = this::notifyDataSetChanged - } - - abstract class Adapter { - internal lateinit var listener: (adapter: Adapter) -> Unit - - abstract fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): VH - - abstract fun onBindViewHolder(holder: VH) - - @Suppress("UNCHECKED_CAST") - fun notifyDataSetChanged() = listener.invoke(this as Adapter) - } - - private inner class ContentAdapter : LoadingHelper.Adapter() { - override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup) = ViewHolder(contentView) - - override fun onBindViewHolder(holder: ViewHolder) = Unit - } - - open class ViewHolder(val rootView: View) { - internal var viewType: Any? = null - var onReloadListener: OnReloadListener? = null - internal set - } - - abstract class DecorAdapter { - abstract fun onCreateDecorView(inflater: LayoutInflater): View - - abstract fun getContentParent(decorView: View): ViewGroup - } - - private class LinearDecorAdapter(private val views: List) : DecorAdapter() { - private lateinit var contentParent: FrameLayout - - override fun onCreateDecorView(inflater: LayoutInflater) = - LinearLayout(inflater.context).apply { - orientation = LinearLayout.VERTICAL - contentParent = FrameLayout(inflater.context) - contentParent.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - views.forEach { addView(it) } - addView(contentParent) - } - - override fun getContentParent(decorView: View) = contentParent - } - - class AdapterPool internal constructor(private val helper: LoadingHelper) { - fun register(viewType: Any, adapter: Adapter<*>) { - helper.register(viewType, adapter) - } - } - - fun interface OnReloadListener { - fun onReload() - } - - interface Animation { - fun onStartShowAnimation(view: View, viewType: Any) - - fun onStartHideAnimation(view: View, viewType: Any) - } -} - -enum class ViewType { - TITLE, LOADING, CONTENT, ERROR, EMPTY -} \ No newline at end of file diff --git a/loadingstateview-ktx/.gitignore b/loadingstateview-ktx/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/loadingstateview-ktx/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/loadingstateview-ktx/build.gradle b/loadingstateview-ktx/build.gradle new file mode 100644 index 0000000..878e7b8 --- /dev/null +++ b/loadingstateview-ktx/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdkVersion buildConfig.compileSdkVersion + + defaultConfig { + minSdkVersion buildConfig.minSdkVersion + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + freeCompilerArgs += ['-module-name', "loading_state_view_ktx"] + } +} + +dependencies { + api project(':loadingstateview') + implementation "androidx.appcompat:appcompat:$appCompatVersion" +} \ No newline at end of file diff --git a/loadingstateview-ktx/consumer-rules.pro b/loadingstateview-ktx/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/loadingstateview-ktx/proguard-rules.pro b/loadingstateview-ktx/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/loadingstateview-ktx/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/loadingstateview-ktx/src/main/AndroidManifest.xml b/loadingstateview-ktx/src/main/AndroidManifest.xml new file mode 100644 index 0000000..24187dc --- /dev/null +++ b/loadingstateview-ktx/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/BaseToolbarViewDelegate.kt b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/BaseToolbarViewDelegate.kt new file mode 100644 index 0000000..05dc578 --- /dev/null +++ b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/BaseToolbarViewDelegate.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup + +abstract class BaseToolbarViewDelegate : LoadingStateView.ViewDelegate(ViewType.TITLE) { + internal lateinit var config: ToolbarConfig + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup) = + onCreateToolbar(inflater, parent).apply { onBindToolbar(config) } + + abstract fun onCreateToolbar(inflater: LayoutInflater, parent: ViewGroup): View + + abstract fun onBindToolbar(config: ToolbarConfig) +} \ No newline at end of file diff --git a/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/Decorative.kt b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/Decorative.kt new file mode 100644 index 0000000..bbe9d5f --- /dev/null +++ b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/Decorative.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview + +import android.view.View + +interface Decorative : OnReloadListener { + val isDecorated: Boolean get() = true + val contentView: View? get() = null +} \ No newline at end of file diff --git a/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingState.kt b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingState.kt new file mode 100644 index 0000000..ffdc0f2 --- /dev/null +++ b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingState.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview + +import android.app.Activity +import android.view.View +import androidx.annotation.StringRes +import androidx.fragment.app.Fragment + +interface LoadingState : Decorative, OnReloadListener { + val loadingStateViewType: Any? + + @Deprecated("Use Activity.decorateContentView(this) instead", ReplaceWith("decorateContentView(decorative)")) + fun Activity.decorateContentView(listener: OnReloadListener, decorative: Decorative) = decorateContentView(decorative) + + fun Activity.decorateContentView(decorative: Decorative) + + @Deprecated("Use View.decorate(this) instead", ReplaceWith("decorate(decorative)")) + fun View.decorate(listener: OnReloadListener, decorative: Decorative): View = decorate(decorative) + + fun View.decorate(decorative: Decorative): View + + fun registerView(vararg viewDelegates: LoadingStateView.ViewDelegate) + + fun Activity.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null) + + fun Activity.setToolbar(title: String? = null, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null) + + fun Fragment.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null) + + fun Fragment.setToolbar(title: String? = null, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null) + + fun Activity.setHeaders(vararg delegates: LoadingStateView.ViewDelegate) + + fun Fragment.setHeaders(vararg delegates: LoadingStateView.ViewDelegate) + + fun Activity.setDecorView(delegate: LoadingStateView.DecorViewDelegate) + + fun Fragment.setDecorView(delegate: LoadingStateView.DecorViewDelegate) + + fun showLoadingView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable) + + fun showContentView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable) + + fun showErrorView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable) + + fun showEmptyView(animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable) + + fun showCustomView(viewType: Any, animatable: LoadingStateView.Animatable? = LoadingStateView.defaultAnimatable) + + fun updateToolbar(block: ToolbarConfig.() -> Unit) + + fun updateView(viewType: Any, block: T.() -> Unit) + + @Suppress("FunctionName") + fun ToolbarViewDelegate( + title: String? = null, navBtnType: NavBtnType = NavBtnType.ICON, block: (ToolbarConfig.() -> Unit)? = null + ): BaseToolbarViewDelegate +} \ No newline at end of file diff --git a/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingStateDelegate.kt b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingStateDelegate.kt new file mode 100644 index 0000000..4637c05 --- /dev/null +++ b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/LoadingStateDelegate.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview + +import android.app.Activity +import android.view.View +import android.view.ViewGroup +import androidx.annotation.StringRes +import androidx.fragment.app.Fragment + +class LoadingStateDelegate : LoadingState { + private var loadingStateView: LoadingStateView? = null + + override val loadingStateViewType: Any? + get() = loadingStateView?.currentViewType + + override fun Activity.decorateContentView(decorative: Decorative) { + findViewById(android.R.id.content).getChildAt(0).decorate(decorative) + } + + override fun View.decorate(decorative: Decorative): View = + when { + !decorative.isDecorated -> this + decorative.contentView == null -> + LoadingStateView(this, decorative).also { loadingStateView = it }.decorView + + else -> { + loadingStateView = LoadingStateView(decorative.contentView!!, decorative) + this + } + } + + override fun registerView(vararg viewDelegates: LoadingStateView.ViewDelegate) { + loadingStateView?.register(*viewDelegates) + } + + override fun Activity.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) { + setToolbar(getString(titleId), navBtnType, block) + } + + override fun Activity.setToolbar(title: String?, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) { + loadingStateView?.setHeaders(ToolbarViewDelegate(title, navBtnType, block)) + } + + override fun Fragment.setToolbar(@StringRes titleId: Int, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) { + setToolbar(getString(titleId), navBtnType, block) + } + + override fun Fragment.setToolbar(title: String?, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) { + loadingStateView?.addChildHeaders(ToolbarViewDelegate(title, navBtnType, block)) + } + + override fun Activity.setHeaders(vararg delegates: LoadingStateView.ViewDelegate) { + loadingStateView?.setHeaders(*delegates) + } + + override fun Fragment.setHeaders(vararg delegates: LoadingStateView.ViewDelegate) { + loadingStateView?.addChildHeaders(*delegates) + } + + override fun Activity.setDecorView(delegate: LoadingStateView.DecorViewDelegate) { + loadingStateView?.setDecorView(delegate) + } + + override fun Fragment.setDecorView(delegate: LoadingStateView.DecorViewDelegate) { + loadingStateView?.addChildDecorView(delegate) + } + + override fun showLoadingView(animatable: LoadingStateView.Animatable?) { + loadingStateView?.showLoadingView(animatable) + } + + override fun showContentView(animatable: LoadingStateView.Animatable?) { + loadingStateView?.showContentView(animatable) + } + + override fun showErrorView(animatable: LoadingStateView.Animatable?) { + loadingStateView?.showErrorView(animatable) + } + + override fun showEmptyView(animatable: LoadingStateView.Animatable?) { + loadingStateView?.showEmptyView(animatable) + } + + override fun showCustomView(viewType: Any, animatable: LoadingStateView.Animatable?) { + loadingStateView?.showView(viewType, animatable) + } + + override fun updateToolbar(block: ToolbarConfig.() -> Unit) { + updateView(ViewType.TITLE) { onBindToolbar(config.apply(block)) } + } + + override fun updateView(viewType: Any, block: T.() -> Unit) { + loadingStateView?.updateViewDelegate(viewType, block) + } + + override fun ToolbarViewDelegate(title: String?, navBtnType: NavBtnType, block: (ToolbarConfig.() -> Unit)?) = + requireNotNull(loadingStateView?.getViewDelegate(ViewType.TITLE)) { + "ToolbarViewDelegate must be registered before." + }.apply { + config = ToolbarConfig(title, navBtnType).apply { block?.invoke(this) } + } +} \ No newline at end of file diff --git a/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/ToolbarConfig.kt b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/ToolbarConfig.kt new file mode 100644 index 0000000..800c9ed --- /dev/null +++ b/loadingstateview-ktx/src/main/java/com/dylanc/loadingstateview/ToolbarConfig.kt @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("unused") + +package com.dylanc.loadingstateview + +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper +import android.view.View +import androidx.annotation.DrawableRes +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +enum class NavBtnType { + ICON, TEXT, ICON_TEXT, NONE +} + +class ToolbarConfig( + var title: String? = null, + var navBtnType: NavBtnType = NavBtnType.ICON, + val extras: HashMap = HashMap(), +) { + @DrawableRes + var navIcon: Int? = null + var navText: String? = null + private set + var onNavClickListener = View.OnClickListener { + var context: Context? = it.context + while (context is ContextWrapper) { + if (context is Activity) { + context.finish() + return@OnClickListener + } + context = context.baseContext + } + } + private set + + @DrawableRes + var rightIcon: Int? = null + private set + var rightText: String? = null + private set + var onRightClickListener: View.OnClickListener? = null + private set + + fun navIcon(@DrawableRes icon: Int? = navIcon, listener: View.OnClickListener) { + navIcon = icon + onNavClickListener = listener + } + + fun navText(text: String, listener: View.OnClickListener) { + navText = text + onNavClickListener = listener + } + + fun rightIcon(@DrawableRes icon: Int, listener: View.OnClickListener) { + rightIcon = icon + onRightClickListener = listener + } + + fun rightText(text: String, listener: View.OnClickListener) { + rightText = text + onRightClickListener = listener + } +} + +fun toolbarExtras() = object : ReadWriteProperty { + @Suppress("UNCHECKED_CAST") + override fun getValue(thisRef: ToolbarConfig, property: KProperty<*>): T? = + thisRef.extras[property.name] as? T + + override fun setValue(thisRef: ToolbarConfig, property: KProperty<*>, value: T?) { + thisRef.extras[property.name] = value + } +} \ No newline at end of file diff --git a/app/.gitignore b/loadingstateview/.gitignore similarity index 100% rename from app/.gitignore rename to loadingstateview/.gitignore diff --git a/library/build.gradle b/loadingstateview/build.gradle similarity index 58% rename from library/build.gradle rename to loadingstateview/build.gradle index 8fa1817..c55f661 100644 --- a/library/build.gradle +++ b/loadingstateview/build.gradle @@ -2,13 +2,10 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 30 + compileSdkVersion buildConfig.compileSdkVersion defaultConfig { - minSdkVersion 14 - targetSdkVersion 30 - versionCode 1 - versionName "1.0" + minSdkVersion buildConfig.minSdkVersion } buildTypes { @@ -22,10 +19,6 @@ android { tasks.withType(Javadoc).all { enabled = false } } - compileOptions { - kotlinOptions.freeCompilerArgs += ['-module-name', "loading_helper"] - } - compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -33,11 +26,10 @@ android { kotlinOptions { jvmTarget = '1.8' + freeCompilerArgs += ['-module-name', "loading_state_view"] } } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.core:core-ktx:1.5.0' + implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion" } \ No newline at end of file diff --git a/library/proguard-rules.pro b/loadingstateview/proguard-rules.pro similarity index 100% rename from library/proguard-rules.pro rename to loadingstateview/proguard-rules.pro diff --git a/loadingstateview/src/main/AndroidManifest.xml b/loadingstateview/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8818fc9 --- /dev/null +++ b/loadingstateview/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt b/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt new file mode 100644 index 0000000..92d9f48 --- /dev/null +++ b/loadingstateview/src/main/java/com/dylanc/loadingstateview/LoadingStateView.kt @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview + +import android.app.Activity +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.widget.FrameLayout +import android.widget.LinearLayout +import androidx.constraintlayout.widget.ConstraintLayout + +/** + * @author Dylan Cai + */ +class LoadingStateView @JvmOverloads constructor( + private val contentView: View, + var onReloadListener: OnReloadListener? = null +) { + lateinit var decorView: View private set + lateinit var currentViewType: Any private set + private lateinit var contentParent: ViewGroup + private val parent: ViewGroup? + private var currentView: View? = null + private var viewDelegates: HashMap = HashMap() + private val viewCaches: HashMap = HashMap() + + /** + * Constructs a LoadingStateView with an activity and listener. + */ + @JvmOverloads + constructor(activity: Activity, listener: OnReloadListener? = null) : + this(activity.findViewById(android.R.id.content).getChildAt(0), listener) + + init { + poolInitializer?.apply { PoolInitializer(this@LoadingStateView).invoke() } + parent = contentView.parent as ViewGroup? + register(ContentViewDelegate()) + setDecorView(LinearDecorViewDelegate(emptyList())) + } + + /** + * Adds one or more views to decorate content in the header. + * + * @param delegates the view delegates of creating view + */ + fun setHeaders(vararg delegates: ViewDelegate) = setDecorView(LinearDecorViewDelegate(delegates)) + + /** + * Sets an view delegate for decorating content view. + * + * @param decorViewDelegate the view delegate for decorating content view. + */ + fun setDecorView(decorViewDelegate: DecorViewDelegate) { + currentView = null + if (parent != null) { + val index = parent.indexOfChild(contentView) + if (index >= 0) { + parent.removeView(contentView) + } else { + parent.removeView(decorView) + (contentView.parent as ViewGroup).removeView(contentView) + } + decorView = decorViewDelegate.createDecorView() + parent.addView(decorView, index) + } else { + decorView = decorViewDelegate.createDecorView() + } + contentParent = decorViewDelegate.getContentParent(decorView) + showView(ViewType.CONTENT) + } + + /** + * Adds child decorative header between the content and the decorative view. + * + * @param delegates the view delegates of creating view + */ + fun addChildHeaders(vararg delegates: ViewDelegate) = addChildDecorView(LinearDecorViewDelegate(delegates)) + + /** + * Adds child decorative view between the content and the decorative view. + * + * @param decorViewDelegate the view delegate for decorating content view. + */ + fun addChildDecorView(decorViewDelegate: DecorViewDelegate) { + contentParent.removeView(currentView) + currentView = null + val childDecorView = decorViewDelegate.createDecorView() + contentParent.addView(childDecorView) + contentParent = decorViewDelegate.getContentParent(childDecorView) + showView(ViewType.CONTENT) + } + + private fun DecorViewDelegate.createDecorView() = + onCreateDecorView(contentView.context, LayoutInflater.from(contentView.context)).also { decorView -> + contentView.layoutParams?.let { + decorView.layoutParams = if (it is ConstraintLayout.LayoutParams) ConstraintLayout.LayoutParams(it) else it + (it as? ViewGroup.MarginLayoutParams)?.setMargins(0, 0, 0, 0) + } + } + + /** + * Registers the view delegate of creating view before showing view. + * + * @param delegates the view delegate of creating view + */ + fun register(vararg delegates: ViewDelegate) = delegates.forEach { viewDelegates[it.viewType] = it } + + @JvmOverloads + fun showLoadingView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.LOADING, animatable) + + @JvmOverloads + fun showContentView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.CONTENT, animatable) + + @JvmOverloads + fun showErrorView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.ERROR, animatable) + + @JvmOverloads + fun showEmptyView(animatable: Animatable? = defaultAnimatable) = showView(ViewType.EMPTY, animatable) + + /** + * Shows the view by view type + * + * @param viewType the view type of view delegate + */ + @JvmOverloads + fun showView(viewType: Any, animatable: Animatable? = defaultAnimatable) { + val currentView = currentView + if (currentView == null) { + addView(viewType) + } else { + if (viewCaches[viewType] == null) addView(viewType) + if (viewType != currentViewType) { + val nextView = getOrCreateView(viewType) + nextView.visibility = View.VISIBLE + val nextViewDelegate = getViewDelegate(viewType) + nextViewDelegate?.onViewAttached(nextView) + getViewDelegate(currentViewType)?.onViewDetached(nextView) + if (animatable != null && nextViewDelegate != null) { + animatable.toggleViewsAnimation(nextView, currentView, viewType, currentViewType) + } else { + currentView.visibility = View.GONE + } + this.currentView = nextView + } + } + currentViewType = viewType + } + + fun updateViewDelegate(viewType: Any, callback: Callback) = + callback.apply { getViewDelegate(viewType)?.invoke() } + + @Suppress("UNCHECKED_CAST") + fun getViewDelegate(viewType: Any) = viewDelegates[viewType] as? T + + private fun addView(viewType: Any) { + val view = getOrCreateView(viewType) + (view.parent as? ViewGroup)?.removeView(view) + if (parent is ConstraintLayout && viewType == ViewType.CONTENT) { + val params = view.layoutParams + if (view.measuredWidth == 0) params.width = MATCH_PARENT + if (view.measuredHeight == 0) params.height = MATCH_PARENT + view.layoutParams = params + } + contentParent.addView(view) + currentView = view + } + + private fun getOrCreateView(viewType: Any): View { + if (viewCaches[viewType] == null) { + val viewDelegate = requireNotNull(getViewDelegate(viewType)) { "Please register view delegate for $viewType type." } + val view = viewDelegate.onCreateView(LayoutInflater.from(contentParent.context), contentParent) + viewDelegate.onReloadListener = onReloadListener + viewCaches[viewType] = view + } + return viewCaches[viewType]!! + } + + abstract class ViewDelegate(val viewType: Any) { + abstract fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View + open fun onViewAttached(view: View) = Unit + open fun onViewDetached(view: View) = Unit + var onReloadListener: OnReloadListener? = null + internal set + } + + private inner class ContentViewDelegate : ViewDelegate(ViewType.CONTENT) { + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup) = contentView + } + + abstract class DecorViewDelegate { + abstract fun onCreateDecorView(context: Context, inflater: LayoutInflater): View + abstract fun getContentParent(decorView: View): ViewGroup + } + + private inner class LinearDecorViewDelegate(private val views: List) : DecorViewDelegate() { + private lateinit var contentParent: FrameLayout + + constructor(delegates: Array) : this(delegates.map { + register(it) + getOrCreateView(it.viewType) + }) + + override fun onCreateDecorView(context: Context, inflater: LayoutInflater) = + LinearLayout(inflater.context).apply { + orientation = LinearLayout.VERTICAL + contentParent = FrameLayout(context) + contentParent.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + views.forEach { addView(it) } + addView(contentParent) + } + + override fun getContentParent(decorView: View) = contentParent + } + + class PoolInitializer internal constructor(private val stateView: LoadingStateView) { + fun register(vararg delegates: ViewDelegate) = stateView.register(*delegates) + } + + fun interface Callback { + fun T.invoke() + } + + interface Animatable { + fun toggleViewsAnimation(showView: View, hideView: View, showViewType: Any, hideViewType: Any) + } + + companion object { + private var poolInitializer: Callback? = null + + @JvmStatic + var defaultAnimatable: Animatable? = null + + @JvmStatic + fun setViewDelegatePool(poolInitializer: Callback) { + this.poolInitializer = poolInitializer + } + } +} + +interface OnReloadListener { + fun onReload() = Unit +} + +enum class ViewType { + TITLE, LOADING, CONTENT, ERROR, EMPTY +} \ No newline at end of file diff --git a/library/src/main/res/values/strings.xml b/loadingstateview/src/main/res/values/strings.xml similarity index 100% rename from library/src/main/res/values/strings.xml rename to loadingstateview/src/main/res/values/strings.xml diff --git a/library/.gitignore b/sample-java/.gitignore similarity index 100% rename from library/.gitignore rename to sample-java/.gitignore diff --git a/sample-java/build.gradle b/sample-java/build.gradle new file mode 100644 index 0000000..1a1cc8f --- /dev/null +++ b/sample-java/build.gradle @@ -0,0 +1,43 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion buildConfig.compileSdkVersion + + defaultConfig { + applicationId "com.dylanc.loadingstateview.sample.java" + minSdkVersion buildConfig.minSdkVersion + targetSdkVersion buildConfig.targetSdkVersion + versionCode buildConfig.versionCode + versionName buildConfig.versionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + viewBinding { + enabled = true + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':loadingstateview') + implementation "androidx.appcompat:appcompat:$appCompatVersion" + implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion" + implementation "com.google.android.material:material:$materialVersion" + implementation "com.github.bumptech.glide:glide:$glideVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$junitExtVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" +} diff --git a/app/proguard-rules.pro b/sample-java/proguard-rules.pro similarity index 91% rename from app/proguard-rules.pro rename to sample-java/proguard-rules.pro index 7942562..fb266e5 100644 --- a/app/proguard-rules.pro +++ b/sample-java/proguard-rules.pro @@ -20,4 +20,4 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --keep public class com.dylanc.loadinghelper.sample.widget.**{*;} +-keep public class com.dylanc.loadingstateview.sample.java.widget.**{*;} diff --git a/app/release/app-release.apk b/sample-java/release/app-release.apk similarity index 100% rename from app/release/app-release.apk rename to sample-java/release/app-release.apk diff --git a/app/release/output.json b/sample-java/release/output.json similarity index 100% rename from app/release/output.json rename to sample-java/release/output.json diff --git a/app/src/androidTest/java/com/dylanc/loadinghelper/sample/ExampleInstrumentedTest.kt b/sample-java/src/androidTest/java/com/dylanc/loadingstateview/sample/java/ExampleInstrumentedTest.kt similarity index 93% rename from app/src/androidTest/java/com/dylanc/loadinghelper/sample/ExampleInstrumentedTest.kt rename to sample-java/src/androidTest/java/com/dylanc/loadingstateview/sample/java/ExampleInstrumentedTest.kt index 45c913f..ca199c3 100644 --- a/app/src/androidTest/java/com/dylanc/loadinghelper/sample/ExampleInstrumentedTest.kt +++ b/sample-java/src/androidTest/java/com/dylanc/loadingstateview/sample/java/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.dylanc.loadinghelper.sample +package com.dylanc.loadingstateview.sample.java import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 diff --git a/app/src/main/AndroidManifest.xml b/sample-java/src/main/AndroidManifest.xml similarity index 96% rename from app/src/main/AndroidManifest.xml rename to sample-java/src/main/AndroidManifest.xml index d711ebf..79bcbd4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/sample-java/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="com.dylanc.loadingstateview.sample.java"> diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/App.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/App.java similarity index 52% rename from app/src/main/java/com/dylanc/loadinghelper/sample/App.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/App.java index 92f11ab..8a1c0de 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/App.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/App.java @@ -14,18 +14,15 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample; +package com.dylanc.loadingstateview.sample.java; import android.app.Application; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.ViewType; -import com.dylanc.loadinghelper.sample.adapter.EmptyAdapter; -import com.dylanc.loadinghelper.sample.adapter.ErrorAdapter; -import com.dylanc.loadinghelper.sample.adapter.LoadingAdapter; -import com.dylanc.loadinghelper.sample.adapter.ToolbarAdapter; - -import kotlin.Unit; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.sample.java.animation.FadeAnimatable; +import com.dylanc.loadingstateview.sample.java.delegate.EmptyViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.ErrorViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.LoadingViewDelegate; /** * @author Dylan Cai @@ -34,11 +31,8 @@ public class App extends Application { @Override public void onCreate() { super.onCreate(); - LoadingHelper.setDefaultAdapterPool(adapterPool -> { - adapterPool.register(ViewType.LOADING, new LoadingAdapter()); - adapterPool.register(ViewType.ERROR, new ErrorAdapter()); - adapterPool.register(ViewType.EMPTY, new EmptyAdapter()); - return Unit.INSTANCE; - }); + LoadingStateView.setViewDelegatePool(pool -> + pool.register(new LoadingViewDelegate(), new ErrorViewDelegate(), new EmptyViewDelegate())); + LoadingStateView.setDefaultAnimatable(new FadeAnimatable()); } } diff --git a/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/animation/FadeAnimatable.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/animation/FadeAnimatable.java new file mode 100644 index 0000000..86b18d2 --- /dev/null +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/animation/FadeAnimatable.java @@ -0,0 +1,43 @@ +package com.dylanc.loadingstateview.sample.java.animation; + +import android.view.View; + +import androidx.annotation.NonNull; + +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Dylan Cai + */ +public class FadeAnimatable implements LoadingStateView.Animatable { + + private static final long DEFAULT_DURATION = 500; + private final long duration; + + public FadeAnimatable() { + this(DEFAULT_DURATION); + } + + public FadeAnimatable(long duration) { + this.duration = duration; + } + + @Override + public void toggleViewsAnimation(@NonNull View showView, @NonNull View hideView, @NonNull Object showViewType, @NonNull Object hideViewType) { + showView.setAlpha(0); + showView.setVisibility(View.VISIBLE); + showView.animate().alpha(1).setDuration(duration); + + if (showViewType == ViewType.LOADING && hideViewType == ViewType.CONTENT) { + hideView.setVisibility(View.GONE); + } else { + hideView.animate().alpha(0).setDuration(duration).withEndAction(() -> { + hideView.setAlpha(1); + hideView.setVisibility(View.GONE); + }); + } + } +} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/base/BaseActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/base/BaseActivity.java similarity index 68% rename from app/src/main/java/com/dylanc/loadinghelper/sample/base/BaseActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/base/BaseActivity.java index f426089..e08dd40 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/base/BaseActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/base/BaseActivity.java @@ -14,18 +14,19 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.base; +package com.dylanc.loadingstateview.sample.java.base; import androidx.annotation.IdRes; import androidx.appcompat.app.AppCompatActivity; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.adapter.ToolbarAdapter; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.OnReloadListener; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.delegate.ToolbarViewDelegate; /** * 这是耦合度较低的封装方式,没有任何抽象方法,可以很方便地将基类里的代码拷贝到其它项目的基类里使用。 - * + *

* 使用该基类时注意以下事项: * 1. 显示对应视图之前需要注册适配器,可以设置全局适配器,某个页面想修改样式时再注册个新的适配器。 * 2. 设置标题栏的方法应该根据项目需要进行编写,下面提供了参考示例。 @@ -33,9 +34,9 @@ * @author Dylan Cai */ @SuppressWarnings("unused") -public class BaseActivity extends AppCompatActivity { +public class BaseActivity extends AppCompatActivity implements OnReloadListener { - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Override public void setContentView(int layoutResID) { @@ -45,11 +46,10 @@ public void setContentView(int layoutResID) { public void setContentView(int layoutResID, @IdRes int contentViewId) { super.setContentView(layoutResID); if (contentViewId == 0) { - loadingHelper = new LoadingHelper(this); + loadingStateView = new LoadingStateView(this, this); } else { - loadingHelper = new LoadingHelper(findViewById(contentViewId)); + loadingStateView = new LoadingStateView(findViewById(contentViewId)); } - loadingHelper.setOnReloadListener(this::onReload); } /** @@ -64,29 +64,30 @@ public void setToolbar(String title, NavIconType type) { } public void setToolbar(String title, NavIconType type, int menuId) { - loadingHelper.setDecorHeader(new ToolbarAdapter(title, type, menuId, this::onOptionsItemSelected)); + loadingStateView.setHeaders(new ToolbarViewDelegate(title, type, menuId, this::onOptionsItemSelected)); } public void showLoadingView() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); } public void showContentView() { - loadingHelper.showContentView(); + loadingStateView.showContentView(); } public void showErrorView() { - loadingHelper.showErrorView(); + loadingStateView.showErrorView(); } public void showEmptyView() { - loadingHelper.showEmptyView(); + loadingStateView.showEmptyView(); } public void showCustomView(Object viewType) { - loadingHelper.showView(viewType); + loadingStateView.showView(viewType); } - protected void onReload() { + @Override + public void onReload() { } } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/BottomEditorDecorAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/BottomEditorDecorViewDelegate.java similarity index 72% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/BottomEditorDecorAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/BottomEditorDecorViewDelegate.java index eac3000..f6a395f 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/BottomEditorDecorAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/BottomEditorDecorViewDelegate.java @@ -14,34 +14,37 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import android.annotation.SuppressLint; +import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.utils.KeyboardUtils; +import androidx.annotation.NonNull; + +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.utils.KeyboardUtils; import org.jetbrains.annotations.NotNull; /** * @author Dylan Cai */ -public class BottomEditorDecorAdapter extends LoadingHelper.DecorAdapter { - private OnSendListener onSendListener; +public class BottomEditorDecorViewDelegate extends LoadingStateView.DecorViewDelegate { + private final OnSendListener onSendListener; - public BottomEditorDecorAdapter(OnSendListener onSendListener) { + public BottomEditorDecorViewDelegate(OnSendListener onSendListener) { this.onSendListener = onSendListener; } @NotNull @Override @SuppressLint("InflateParams") - public View onCreateDecorView(@NotNull LayoutInflater inflater) { + public View onCreateDecorView(@NonNull Context context, @NotNull LayoutInflater inflater) { View view = inflater.inflate(R.layout.layout_bottom_editor, null); EditText edtContent = view.findViewById(R.id.edt_content); view.findViewById(R.id.btn_send).setOnClickListener(v -> { diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/PlaceholderAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CoolLoadingViewDelegate.java similarity index 58% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/PlaceholderAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CoolLoadingViewDelegate.java index 6fe95dd..c60c799 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/PlaceholderAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CoolLoadingViewDelegate.java @@ -14,28 +14,29 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import androidx.annotation.NonNull; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; /** * @author Dylan Cai */ -public class PlaceholderAdapter extends LoadingHelper.Adapter { +public class CoolLoadingViewDelegate extends LoadingStateView.ViewDelegate { - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(inflater.inflate(R.layout.layout_placeholder, parent, false)); + public CoolLoadingViewDelegate() { + super(ViewType.LOADING); } + @NonNull @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + return inflater.inflate(R.layout.layout_cool_loading, parent, false); } } diff --git a/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CustomHeaderViewDelegate.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CustomHeaderViewDelegate.java new file mode 100644 index 0000000..8dc1001 --- /dev/null +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/CustomHeaderViewDelegate.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.java.delegate; + +import android.app.Activity; +import android.os.Build; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; + +/** + * @author Dylan Cai + */ +public class CustomHeaderViewDelegate extends LoadingStateView.ViewDelegate { + + private final View.OnClickListener onMessageClickListener; + private final int firstDrawableId; + private final View.OnClickListener onFirstBtnClickListener; + private final int secondDrawableId; + private final View.OnClickListener onSecondBtnClickListener; + + public CustomHeaderViewDelegate(View.OnClickListener onMessageClickListener, int firstDrawableId, + View.OnClickListener onFirstBtnClickListener, int secondDrawableId, + View.OnClickListener onSecondBtnClickListener) { + super(ViewType.TITLE); + this.onMessageClickListener = onMessageClickListener; + this.firstDrawableId = firstDrawableId; + this.onFirstBtnClickListener = onFirstBtnClickListener; + this.secondDrawableId = secondDrawableId; + this.onSecondBtnClickListener = onSecondBtnClickListener; + } + + @NonNull + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + View view = inflater.inflate(R.layout.layout_custom_header, parent, false); + ImageView btnFirst = view.findViewById(R.id.btn_first); + ImageView btnSecond = view.findViewById(R.id.btn_second); + View btnMessage = view.findViewById(R.id.btn_message); + Activity activity = (Activity) view.getContext(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + + btnMessage.setOnClickListener(onMessageClickListener); + + btnFirst.setImageDrawable(ContextCompat.getDrawable(activity, firstDrawableId)); + btnFirst.setOnClickListener(onFirstBtnClickListener); + + btnSecond.setImageDrawable(ContextCompat.getDrawable(activity, secondDrawableId)); + btnSecond.setOnClickListener(onSecondBtnClickListener); + return view; + } +} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/EmptyAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/EmptyViewDelegate.java similarity index 59% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/EmptyAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/EmptyViewDelegate.java index 2df7eee..cbacffc 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/EmptyAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/EmptyViewDelegate.java @@ -14,28 +14,29 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import androidx.annotation.NonNull; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; /** * @author Dylan Cai */ -public class EmptyAdapter extends LoadingHelper.Adapter { +public class EmptyViewDelegate extends LoadingStateView.ViewDelegate { - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(inflater.inflate(R.layout.layout_empty, parent, false)); + public EmptyViewDelegate() { + super(ViewType.EMPTY); } + @NonNull @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + return inflater.inflate(R.layout.layout_empty, parent, false); } } diff --git a/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ErrorViewDelegate.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ErrorViewDelegate.java new file mode 100644 index 0000000..7d5373f --- /dev/null +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ErrorViewDelegate.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.java.delegate; + +import androidx.annotation.NonNull; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; + +/** + * @author Dylan Cai + */ +public class ErrorViewDelegate extends LoadingStateView.ViewDelegate { + + public ErrorViewDelegate() { + super(ViewType.ERROR); + } + + @NonNull + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + View view = inflater.inflate(R.layout.layout_error, parent, false); + view.findViewById(R.id.btn_reload).setOnClickListener(v -> { + if (getOnReloadListener() != null) { + getOnReloadListener().onReload(); + } + }); + return view; + } +} diff --git a/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/LoadingViewDelegate.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/LoadingViewDelegate.java new file mode 100644 index 0000000..c5afcf0 --- /dev/null +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/LoadingViewDelegate.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.java.delegate; + +import androidx.annotation.NonNull; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; + +/** + * @author Dylan Cai + */ +public class LoadingViewDelegate extends LoadingStateView.ViewDelegate { + + public int height = ViewGroup.LayoutParams.MATCH_PARENT; + + public LoadingViewDelegate() { + super(ViewType.LOADING); + } + + @NonNull + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + View view = inflater.inflate(R.layout.layout_loading, parent, false); + ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); + layoutParams.height = height; + view.setLayoutParams(layoutParams); + return view; + } +} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/NavIconType.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NavIconType.java similarity index 92% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/NavIconType.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NavIconType.java index 9ab41f8..77751d2 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/NavIconType.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NavIconType.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; /** * @author Dylan Cai diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/NothingAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NothingViewDelegate.java similarity index 63% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/NothingAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NothingViewDelegate.java index 27c952e..7e39e62 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/NothingAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/NothingViewDelegate.java @@ -14,28 +14,28 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import androidx.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import com.dylanc.loadinghelper.LoadingHelper; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; /** * @author Dylan Cai */ -public class NothingAdapter extends LoadingHelper.Adapter { +public class NothingViewDelegate extends LoadingStateView.ViewDelegate { - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(new View(parent.getContext())); + public NothingViewDelegate() { + super(ViewType.EMPTY); } + @NonNull @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + return new View(parent.getContext()); } } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/CoolLoadingAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/PlaceholderViewDelegate.java similarity index 58% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/CoolLoadingAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/PlaceholderViewDelegate.java index 996eb8a..3596244 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/CoolLoadingAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/PlaceholderViewDelegate.java @@ -14,28 +14,29 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import androidx.annotation.NonNull; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; /** * @author Dylan Cai */ -public class CoolLoadingAdapter extends LoadingHelper.Adapter { +public class PlaceholderViewDelegate extends LoadingStateView.ViewDelegate { - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(inflater.inflate(R.layout.layout_cool_loading, parent, false)); + public PlaceholderViewDelegate() { + super(ViewType.LOADING); } + @NonNull @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + return inflater.inflate(R.layout.layout_placeholder, parent, false); } } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ScrollingDecorAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ScrollingDecorViewDelegate.java similarity index 76% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ScrollingDecorAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ScrollingDecorViewDelegate.java index ac3cee3..4a70102 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/ScrollingDecorAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ScrollingDecorViewDelegate.java @@ -14,36 +14,38 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import android.annotation.SuppressLint; import android.app.Activity; +import android.content.Context; import android.os.Build; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.appcompat.widget.Toolbar; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.sample.java.R; import org.jetbrains.annotations.NotNull; /** * @author Dylan Cai */ -public class ScrollingDecorAdapter extends LoadingHelper.DecorAdapter { - private String title; +public class ScrollingDecorViewDelegate extends LoadingStateView.DecorViewDelegate { + private final String title; - public ScrollingDecorAdapter(String title) { + public ScrollingDecorViewDelegate(String title) { this.title = title; } @NotNull @Override @SuppressLint("InflateParams") - public View onCreateDecorView(@NotNull LayoutInflater inflater) { + public View onCreateDecorView(@NonNull Context context, @NotNull LayoutInflater inflater) { View view = inflater.inflate(R.layout.layout_scrolling_toolbar, null); Activity activity = (Activity) inflater.getContext(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/SearchHeaderAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/SearchHeaderViewDelegate.java similarity index 54% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/SearchHeaderAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/SearchHeaderViewDelegate.java index d714984..81130f4 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/SearchHeaderAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/SearchHeaderViewDelegate.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import android.view.LayoutInflater; import android.view.View; @@ -24,50 +24,40 @@ import androidx.annotation.NonNull; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.utils.KeyboardUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.utils.KeyboardUtils; /** * @author Dylan Cai */ -public class SearchHeaderAdapter extends LoadingHelper.Adapter { +public class SearchHeaderViewDelegate extends LoadingStateView.ViewDelegate{ - private OnSearchListener onSearchListener; + public static final String VIEW_TYPE_SEARCH = "search"; + private final OnSearchListener onSearchListener; - public SearchHeaderAdapter(OnSearchListener onSearchListener) { + public SearchHeaderViewDelegate(OnSearchListener onSearchListener) { + super(VIEW_TYPE_SEARCH); this.onSearchListener = onSearchListener; } @NonNull @Override - public ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { View view = inflater.inflate(R.layout.layout_search_header, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder) { - holder.edtSearch.setOnEditorActionListener((v, actionId, event) -> { + EditText edtSearch = view.findViewById(R.id.edt_search); + edtSearch.setOnEditorActionListener((v, actionId, event) -> { if (actionId == EditorInfo.IME_ACTION_SEARCH) { - KeyboardUtils.hideKeyboard(holder.edtSearch); + KeyboardUtils.hideKeyboard(edtSearch); if (onSearchListener != null) { - onSearchListener.onSearch(holder.edtSearch.getText().toString()); + onSearchListener.onSearch(edtSearch.getText().toString()); } return true; } return false; }); - } - - static class ViewHolder extends LoadingHelper.ViewHolder { - - final EditText edtSearch; - - ViewHolder(@NonNull final View rootView) { - super(rootView); - edtSearch = rootView.findViewById(R.id.edt_search); - } + return view; } public interface OnSearchListener { diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/TimeoutAdapter.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/TimeoutViewDelegate.java similarity index 53% rename from app/src/main/java/com/dylanc/loadinghelper/sample/adapter/TimeoutAdapter.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/TimeoutViewDelegate.java index f5091bb..79dc5c0 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/adapter/TimeoutAdapter.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/TimeoutViewDelegate.java @@ -14,32 +14,36 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.adapter; +package com.dylanc.loadingstateview.sample.java.delegate; import androidx.annotation.NonNull; + import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.sample.java.R; /** * @author Dylan Cai */ -public class TimeoutAdapter extends LoadingHelper.Adapter { +public class TimeoutViewDelegate extends LoadingStateView.ViewDelegate { + public static final String VIEW_TYPE_TIMEOUT = "timeout"; - @NonNull - @Override - public LoadingHelper.ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new LoadingHelper.ViewHolder(inflater.inflate(R.layout.layout_timeout, parent, false)); + public TimeoutViewDelegate() { + super(VIEW_TYPE_TIMEOUT); } + @NonNull @Override - public void onBindViewHolder(@NonNull LoadingHelper.ViewHolder holder) { - holder.getRootView().setOnClickListener(v -> { - if (holder.getOnReloadListener() != null) { - holder.getOnReloadListener().onReload(); + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + View view = inflater.inflate(R.layout.layout_timeout, parent, false); + view.setOnClickListener(v -> { + if (getOnReloadListener() != null) { + getOnReloadListener().onReload(); } }); + return view; } } diff --git a/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ToolbarViewDelegate.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ToolbarViewDelegate.java new file mode 100644 index 0000000..d7663ee --- /dev/null +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/delegate/ToolbarViewDelegate.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.java.delegate; + +import android.app.Activity; +import android.os.Build; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.Toolbar; + +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; + +import org.jetbrains.annotations.NotNull; + +import kotlin.jvm.functions.Function1; + +/** + * @author Dylan Cai + */ +public class ToolbarViewDelegate extends LoadingStateView.ViewDelegate { + + private final String title; + private final NavIconType type; + private final int menuId; + private final Function1 onMenuItemClick; + + public ToolbarViewDelegate(String title, NavIconType type) { + this(title, type, 0, null); + } + + public ToolbarViewDelegate(String title, NavIconType type, int menuId, Function1 onMenuItemClick) { + super(ViewType.TITLE); + this.title = title; + this.type = type; + this.menuId = menuId; + this.onMenuItemClick = onMenuItemClick; + } + + @NonNull + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + View view = inflater.inflate(R.layout.layout_toolbar, parent, false); + Activity activity = (Activity) view.getContext(); + Toolbar toolbar = view.findViewById(R.id.toolbar); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + + if (!TextUtils.isEmpty(title)) { + toolbar.setTitle(title); + } + + if (type == NavIconType.BACK) { + toolbar.setNavigationIcon(R.drawable.ic_arrow_back_black); + toolbar.setNavigationOnClickListener(v -> activity.finish()); + } else { + toolbar.setNavigationIcon(null); + } + + if (menuId > 0 && onMenuItemClick != null) { + toolbar.inflateMenu(menuId); + toolbar.setOnMenuItemClickListener(onMenuItemClick::invoke); + } + return view; + } +} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ActErrorActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ActErrorActivity.java similarity index 58% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/ActErrorActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ActErrorActivity.java index 6ee9726..e2a91bd 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ActErrorActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ActErrorActivity.java @@ -14,62 +14,63 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.animation.FadeAnimation; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.OnReloadListener; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; /** * @author Dylan Cai */ -public class ActErrorActivity extends AppCompatActivity { +public class ActErrorActivity extends AppCompatActivity implements OnReloadListener { - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_content); - loadingHelper = ToolbarUtils.setToolbar(this, "Activity(error)", NavIconType.BACK); - loadingHelper.setOnReloadListener(this::onReload); + loadingStateView = ToolbarUtils.setToolbar(this, "Activity(error)", NavIconType.BACK); + loadingStateView.setOnReloadListener(this); loadData(); } private void loadData() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestFailure(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(new FadeAnimation()); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showErrorView(new FadeAnimation()); + loadingStateView.showErrorView(); } }); } + @Override public void onReload() { - loadingHelper.showLoadingView(new FadeAnimation()); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(new FadeAnimation()); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showErrorView(new FadeAnimation()); + loadingStateView.showErrorView(); } }); } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/BottomEditorActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/BottomEditorActivity.java similarity index 53% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/BottomEditorActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/BottomEditorActivity.java index 0a2cf0c..d1a3bcb 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/BottomEditorActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/BottomEditorActivity.java @@ -14,51 +14,51 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.ViewType; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.BottomEditorDecorAdapter; -import com.dylanc.loadinghelper.sample.adapter.NothingAdapter; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.BottomEditorDecorViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.NothingViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; /** * @author Dylan Cai */ -public class BottomEditorActivity extends AppCompatActivity implements BottomEditorDecorAdapter.OnSendListener { +public class BottomEditorActivity extends AppCompatActivity implements BottomEditorDecorViewDelegate.OnSendListener { - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_content); - loadingHelper = ToolbarUtils.setToolbar(this, "BottomDecorView(editor)", NavIconType.BACK); - loadingHelper.addChildDecorAdapter(new BottomEditorDecorAdapter(this)); - loadingHelper.register(ViewType.EMPTY, new NothingAdapter()); - loadingHelper.showEmptyView(); + loadingStateView = ToolbarUtils.setToolbar(this, "BottomDecorView(editor)", NavIconType.BACK); + loadingStateView.addChildDecorView(new BottomEditorDecorViewDelegate(this)); + loadingStateView.register(new NothingViewDelegate()); + loadingStateView.showEmptyView(); } @Override public void onSend(String content) { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showErrorView(); + loadingStateView.showErrorView(); } }); } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/CustomHeaderActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/CustomHeaderActivity.java similarity index 91% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/CustomHeaderActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/CustomHeaderActivity.java index 58d1b25..c3800b3 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/CustomHeaderActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/CustomHeaderActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; import android.view.View; @@ -28,9 +28,9 @@ import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.ui.fragment.SimpleFragment; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.ui.fragment.SimpleFragment; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; import com.google.android.material.tabs.TabLayout; /** diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/FragmentEmptyActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/FragmentEmptyActivity.java similarity index 80% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/FragmentEmptyActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/FragmentEmptyActivity.java index 405ea17..2f1944d 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/FragmentEmptyActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/FragmentEmptyActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; @@ -22,10 +22,10 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.FragmentTransaction; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.ui.fragment.EmptyFragment; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.ui.fragment.EmptyFragment; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; /** * @author Dylan Cai diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/MainActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MainActivity.java similarity index 88% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/MainActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MainActivity.java index 61ad43a..4ec3a7f 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/MainActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MainActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.content.Intent; import android.net.Uri; @@ -25,9 +25,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.base.BaseActivity; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.base.BaseActivity; /** * @author Dylan Cai @@ -38,7 +38,7 @@ public class MainActivity extends BaseActivity { protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - setToolbar("LoadingHelper", NavIconType.NONE, R.menu.menu_about); + setToolbar(getString(R.string.app_name), NavIconType.NONE, R.menu.menu_about); } @Override diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/MultipleHeaderActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MultipleHeaderActivity.java similarity index 53% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/MultipleHeaderActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MultipleHeaderActivity.java index c793704..196ee9d 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/MultipleHeaderActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/MultipleHeaderActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; import android.widget.Toast; @@ -22,48 +22,47 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.ViewType; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.NothingAdapter; -import com.dylanc.loadinghelper.sample.adapter.SearchHeaderAdapter; -import com.dylanc.loadinghelper.sample.adapter.ToolbarAdapter; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.NothingViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.SearchHeaderViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.ToolbarViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; /** * @author Dylan Cai */ -public class MultipleHeaderActivity extends AppCompatActivity implements SearchHeaderAdapter.OnSearchListener { +public class MultipleHeaderActivity extends AppCompatActivity implements SearchHeaderViewDelegate.OnSearchListener { - private static final String VIEW_TYPE_SEARCH = "search_header"; - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_content); - loadingHelper = new LoadingHelper(this); - loadingHelper.register(ViewType.TITLE, new ToolbarAdapter("MultipleHeader(search)", NavIconType.BACK)); - loadingHelper.register(VIEW_TYPE_SEARCH, new SearchHeaderAdapter(this)); - loadingHelper.register(ViewType.EMPTY, new NothingAdapter()); - loadingHelper.setDecorHeader(ViewType.TITLE, VIEW_TYPE_SEARCH); - loadingHelper.showEmptyView(); + loadingStateView = new LoadingStateView(this); + loadingStateView.register(new NothingViewDelegate()); + loadingStateView.setHeaders( + new ToolbarViewDelegate("MultipleHeader(search)", NavIconType.BACK), + new SearchHeaderViewDelegate(this) + ); + loadingStateView.showEmptyView(); } @Override public void onSearch(String keyword) { Toast.makeText(this, "search: " + keyword, Toast.LENGTH_SHORT).show(); - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showErrorView(); + loadingStateView.showErrorView(); } }); } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/RecyclerViewActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/RecyclerViewActivity.java similarity index 79% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/RecyclerViewActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/RecyclerViewActivity.java index 8be4b70..a593bd8 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/RecyclerViewActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/RecyclerViewActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -34,13 +34,13 @@ import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.ViewType; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.CoolLoadingAdapter; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.CoolLoadingViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; /** @@ -81,35 +81,35 @@ public int getItemCount() { static class ViewHolder extends RecyclerView.ViewHolder{ - private final LoadingHelper loadingHelper; + private final LoadingStateView loadingStateView; ImageView imageView; private String url; ViewHolder(@NonNull View itemView) { super(itemView); - loadingHelper = new LoadingHelper(itemView.findViewById(R.id.loading_view)); - loadingHelper.register(ViewType.LOADING, new CoolLoadingAdapter()); - loadingHelper.setOnReloadListener(() -> showImage(url)); + loadingStateView = new LoadingStateView(itemView.findViewById(R.id.loading_view)); + loadingStateView.register(new CoolLoadingViewDelegate()); + loadingStateView.setOnReloadListener(() -> showImage(url)); imageView = itemView.findViewById(R.id.image_view); } void showImage(String url) { this.url = url; - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); Glide.with(imageView.getContext()) .load(url) .listener(new RequestListener() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { - loadingHelper.showErrorView(); + loadingStateView.showErrorView(); return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { - loadingHelper.showContentView(); + loadingStateView.showContentView(); return false; } }) diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ScrollingToolbarActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ScrollingToolbarActivity.java similarity index 59% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/ScrollingToolbarActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ScrollingToolbarActivity.java index a43bc6d..08dd6a8 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ScrollingToolbarActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ScrollingToolbarActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; import android.view.ViewGroup; @@ -22,40 +22,41 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.ViewType; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.LoadingAdapter; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.LoadingViewDelegate; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; /** * @author Dylan Cai */ public class ScrollingToolbarActivity extends AppCompatActivity { - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_scrolling); - loadingHelper = ToolbarUtils.setScrollingToolbar(this, "SpecialDecorView(scrolling)"); - loadingHelper.register(ViewType.LOADING, new LoadingAdapter(ViewGroup.LayoutParams.WRAP_CONTENT)); + loadingStateView = ToolbarUtils.setScrollingToolbar(this, "SpecialDecorView(scrolling)"); + loadingStateView.updateViewDelegate(ViewType.LOADING, (LoadingViewDelegate delegate) -> + delegate.height = ViewGroup.LayoutParams.WRAP_CONTENT); loadData(); } private void loadData() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showErrorView(); + loadingStateView.showErrorView(); } }); } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPagerActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPagerActivity.java similarity index 86% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPagerActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPagerActivity.java index ebbaac6..27b6ce1 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPagerActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPagerActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; @@ -26,10 +26,10 @@ import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.ui.fragment.TimeoutFragment; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.ui.fragment.TimeoutFragment; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; import com.google.android.material.tabs.TabLayout; /** diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPlaceholderActivity.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPlaceholderActivity.java similarity index 63% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPlaceholderActivity.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPlaceholderActivity.java index 711bc4a..ba80ebe 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/ViewPlaceholderActivity.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/ViewPlaceholderActivity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui; +package com.dylanc.loadingstateview.sample.java.ui; import android.os.Bundle; import android.view.View; @@ -22,20 +22,20 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.ViewType; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.adapter.PlaceholderAdapter; -import com.dylanc.loadinghelper.sample.adapter.NavIconType; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; -import com.dylanc.loadinghelper.sample.utils.ToolbarUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.ViewType; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.delegate.PlaceholderViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; +import com.dylanc.loadingstateview.sample.java.utils.ToolbarUtils; /** * @author Dylan Cai */ public class ViewPlaceholderActivity extends AppCompatActivity { - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -44,23 +44,23 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ToolbarUtils.setToolbar(this,"View(placeholder)", NavIconType.BACK); View view = findViewById(R.id.content); - loadingHelper = new LoadingHelper(view); - loadingHelper.register(ViewType.LOADING, new PlaceholderAdapter()); + loadingStateView = new LoadingStateView(view); + loadingStateView.register(new PlaceholderViewDelegate()); loadData(); } private void loadData() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); } }); } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/EmptyFragment.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/EmptyFragment.java similarity index 68% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/EmptyFragment.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/EmptyFragment.java index 5822228..5cb2556 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/EmptyFragment.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/EmptyFragment.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui.fragment; +package com.dylanc.loadingstateview.sample.java.ui.fragment; import android.os.Bundle; import android.view.LayoutInflater; @@ -25,26 +25,27 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.databinding.LayoutContentBinding; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.OnReloadListener; +import com.dylanc.loadingstateview.sample.java.databinding.LayoutContentBinding; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; /** * @author Dylan Cai */ @SuppressWarnings("FieldCanBeLocal") -public class EmptyFragment extends Fragment implements LoadingHelper.OnReloadListener { +public class EmptyFragment extends Fragment implements OnReloadListener { private LayoutContentBinding binding; - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = LayoutContentBinding.inflate(inflater, container, false); - loadingHelper = new LoadingHelper(binding.getRoot()); - loadingHelper.setOnReloadListener(this); - return loadingHelper.getDecorView(); + loadingStateView = new LoadingStateView(binding.getRoot()); + loadingStateView.setOnReloadListener(this); + return loadingStateView.getDecorView(); } @Override @@ -54,32 +55,32 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat } private void loadData() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showEmptyView(); + loadingStateView.showEmptyView(); } @Override public void onFailure() { - loadingHelper.showErrorView(); + loadingStateView.showErrorView(); } }); } @Override public void onReload() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showEmptyView(); + loadingStateView.showEmptyView(); } @Override public void onFailure() { - loadingHelper.showErrorView(); + loadingStateView.showErrorView(); } }); } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/SimpleFragment.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/SimpleFragment.java similarity index 91% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/SimpleFragment.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/SimpleFragment.java index 4d391f4..8ed6584 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/SimpleFragment.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/SimpleFragment.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui.fragment; +package com.dylanc.loadingstateview.sample.java.ui.fragment; import android.os.Bundle; import android.view.LayoutInflater; @@ -25,7 +25,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import com.dylanc.loadinghelper.sample.R; +import com.dylanc.loadingstateview.sample.java.R; /** * @author Dylan Cai diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/TimeoutFragment.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/TimeoutFragment.java similarity index 64% rename from app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/TimeoutFragment.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/TimeoutFragment.java index 8556875..b9f7acb 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/ui/fragment/TimeoutFragment.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/ui/fragment/TimeoutFragment.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.ui.fragment; +package com.dylanc.loadingstateview.sample.java.ui.fragment; import android.os.Bundle; import android.view.LayoutInflater; @@ -25,29 +25,30 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import com.dylanc.loadinghelper.LoadingHelper; -import com.dylanc.loadinghelper.sample.adapter.TimeoutAdapter; -import com.dylanc.loadinghelper.sample.databinding.LayoutContentBinding; -import com.dylanc.loadinghelper.sample.utils.HttpUtils; +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.OnReloadListener; +import com.dylanc.loadingstateview.sample.java.delegate.TimeoutViewDelegate; +import com.dylanc.loadingstateview.sample.java.databinding.LayoutContentBinding; +import com.dylanc.loadingstateview.sample.java.utils.HttpUtils; /** * @author Dylan Cai */ @SuppressWarnings("FieldCanBeLocal") -public class TimeoutFragment extends Fragment implements LoadingHelper.OnReloadListener { +public class TimeoutFragment extends Fragment implements OnReloadListener { public static final String VIEW_TYPE_TIMEOUT = "timeout"; private LayoutContentBinding binding; - private LoadingHelper loadingHelper; + private LoadingStateView loadingStateView; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = LayoutContentBinding.inflate(inflater, container, false); - loadingHelper = new LoadingHelper(binding.getRoot()); - loadingHelper.register(VIEW_TYPE_TIMEOUT, new TimeoutAdapter()); - loadingHelper.setOnReloadListener(this); - return loadingHelper.getDecorView(); + loadingStateView = new LoadingStateView(binding.getRoot()); + loadingStateView.register(new TimeoutViewDelegate()); + loadingStateView.setOnReloadListener(this); + return loadingStateView.getDecorView(); } @Override @@ -57,32 +58,32 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat } private void loadData() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestFailure(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showView(VIEW_TYPE_TIMEOUT); + loadingStateView.showView(VIEW_TYPE_TIMEOUT); } }); } @Override public void onReload() { - loadingHelper.showLoadingView(); + loadingStateView.showLoadingView(); HttpUtils.requestSuccess(new HttpUtils.Callback() { @Override public void onSuccess() { - loadingHelper.showContentView(); + loadingStateView.showContentView(); } @Override public void onFailure() { - loadingHelper.showView(VIEW_TYPE_TIMEOUT); + loadingStateView.showView(VIEW_TYPE_TIMEOUT); } }); } diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/DensityUtils.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/DensityUtils.java similarity index 93% rename from app/src/main/java/com/dylanc/loadinghelper/sample/utils/DensityUtils.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/DensityUtils.java index 4c3d2e7..e48750e 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/DensityUtils.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/DensityUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.utils; +package com.dylanc.loadingstateview.sample.java.utils; import android.content.Context; diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/HttpUtils.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/HttpUtils.java similarity index 96% rename from app/src/main/java/com/dylanc/loadinghelper/sample/utils/HttpUtils.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/HttpUtils.java index f605f77..0b17cba 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/HttpUtils.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/HttpUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.utils; +package com.dylanc.loadingstateview.sample.java.utils; import android.os.Handler; diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/KeyboardUtils.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/KeyboardUtils.java similarity index 96% rename from app/src/main/java/com/dylanc/loadinghelper/sample/utils/KeyboardUtils.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/KeyboardUtils.java index 71f355a..99a84c9 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/utils/KeyboardUtils.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/KeyboardUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.dylanc.loadinghelper.sample.utils; +package com.dylanc.loadingstateview.sample.java.utils; import android.content.Context; import android.view.inputmethod.InputMethodManager; diff --git a/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/ToolbarUtils.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/ToolbarUtils.java new file mode 100644 index 0000000..85a73e7 --- /dev/null +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/utils/ToolbarUtils.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.java.utils; + +import android.app.Activity; +import android.view.MenuItem; +import android.view.View; + +import com.dylanc.loadingstateview.LoadingStateView; +import com.dylanc.loadingstateview.sample.java.delegate.CustomHeaderViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.ScrollingDecorViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.ToolbarViewDelegate; +import com.dylanc.loadingstateview.sample.java.delegate.NavIconType; + +import kotlin.jvm.functions.Function1; + +/** + * @author Dylan Cai + */ +@SuppressWarnings("UnusedReturnValue") +public class ToolbarUtils { + public static LoadingStateView setToolbar(Activity activity, String title, NavIconType type) { + return setToolbar(activity, title, type, 0, null); + } + + public static LoadingStateView setToolbar(Activity activity, String title, NavIconType type, int menuId, + Function1 onMenuItemClick) { + LoadingStateView loadingStateView = new LoadingStateView(activity); + loadingStateView.setHeaders(new ToolbarViewDelegate(title, type, menuId, onMenuItemClick)); + return loadingStateView; + } + + public static LoadingStateView setCustomToolbar(Activity activity, View.OnClickListener onMessageClick, + int firstDrawableId, View.OnClickListener onFirstBtnClick, + int secondDrawableId, View.OnClickListener onSecondBtnClick) { + LoadingStateView loadingStateView = new LoadingStateView(activity); + loadingStateView.setHeaders(new CustomHeaderViewDelegate(onMessageClick, + firstDrawableId, onFirstBtnClick, secondDrawableId, onSecondBtnClick)); + return loadingStateView; + } + + public static LoadingStateView setScrollingToolbar(Activity activity, String title) { + LoadingStateView loadingStateView = new LoadingStateView(activity); + loadingStateView.setDecorView(new ScrollingDecorViewDelegate(title)); + return loadingStateView; + } +} diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingDrawable.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingDrawable.java similarity index 97% rename from app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingDrawable.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingDrawable.java index 8189627..fa75059 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingDrawable.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingDrawable.java @@ -1,4 +1,4 @@ -package com.dylanc.loadinghelper.sample.widget; +package com.dylanc.loadingstateview.sample.java.widget; import android.graphics.Canvas; import android.graphics.ColorFilter; diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingRenderer.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRenderer.java similarity index 96% rename from app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingRenderer.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRenderer.java index f60d899..b824dff 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingRenderer.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRenderer.java @@ -1,4 +1,4 @@ -package com.dylanc.loadinghelper.sample.widget; +package com.dylanc.loadingstateview.sample.java.widget; import android.animation.Animator; import android.animation.ValueAnimator; @@ -10,7 +10,7 @@ import android.graphics.drawable.Drawable; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; -import com.dylanc.loadinghelper.sample.utils.DensityUtils; +import com.dylanc.loadingstateview.sample.java.utils.DensityUtils; public abstract class LoadingRenderer { private static final long ANIMATION_DURATION = 1333; diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingRendererFactory.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRendererFactory.java similarity index 88% rename from app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingRendererFactory.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRendererFactory.java index ea902a1..11cc02e 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingRendererFactory.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingRendererFactory.java @@ -1,8 +1,8 @@ -package com.dylanc.loadinghelper.sample.widget; +package com.dylanc.loadingstateview.sample.java.widget; import android.content.Context; import android.util.SparseArray; -import com.dylanc.loadinghelper.sample.widget.renderer.ElectricFanLoadingRenderer; +import com.dylanc.loadingstateview.sample.java.widget.renderer.ElectricFanLoadingRenderer; import java.lang.reflect.Constructor; diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingView.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingView.java similarity index 95% rename from app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingView.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingView.java index 86b0eaf..36c0ef3 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/LoadingView.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/LoadingView.java @@ -1,4 +1,4 @@ -package com.dylanc.loadinghelper.sample.widget; +package com.dylanc.loadingstateview.sample.java.widget; import android.content.Context; import android.content.res.TypedArray; @@ -7,7 +7,7 @@ import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; import android.view.View; -import com.dylanc.loadinghelper.sample.R; +import com.dylanc.loadingstateview.sample.java.R; public class LoadingView extends AppCompatImageView { private LoadingDrawable mLoadingDrawable; diff --git a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/renderer/ElectricFanLoadingRenderer.java b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/renderer/ElectricFanLoadingRenderer.java similarity index 98% rename from app/src/main/java/com/dylanc/loadinghelper/sample/widget/renderer/ElectricFanLoadingRenderer.java rename to sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/renderer/ElectricFanLoadingRenderer.java index 10716b4..2522c22 100644 --- a/app/src/main/java/com/dylanc/loadinghelper/sample/widget/renderer/ElectricFanLoadingRenderer.java +++ b/sample-java/src/main/java/com/dylanc/loadingstateview/sample/java/widget/renderer/ElectricFanLoadingRenderer.java @@ -1,4 +1,4 @@ -package com.dylanc.loadinghelper.sample.widget.renderer; +package com.dylanc.loadingstateview.sample.java.widget.renderer; import android.animation.*; import android.content.Context; @@ -11,9 +11,9 @@ import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; -import com.dylanc.loadinghelper.sample.R; -import com.dylanc.loadinghelper.sample.utils.DensityUtils; -import com.dylanc.loadinghelper.sample.widget.LoadingRenderer; +import com.dylanc.loadingstateview.sample.java.R; +import com.dylanc.loadingstateview.sample.java.utils.DensityUtils; +import com.dylanc.loadingstateview.sample.java.widget.LoadingRenderer; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/sample-java/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from app/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to sample-java/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/app/src/main/res/drawable-xhdpi/ic_eletric_fan.png b/sample-java/src/main/res/drawable-xhdpi/ic_eletric_fan.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_eletric_fan.png rename to sample-java/src/main/res/drawable-xhdpi/ic_eletric_fan.png diff --git a/app/src/main/res/drawable-xhdpi/ic_leaf.png b/sample-java/src/main/res/drawable-xhdpi/ic_leaf.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_leaf.png rename to sample-java/src/main/res/drawable-xhdpi/ic_leaf.png diff --git a/app/src/main/res/drawable-xhdpi/ic_loading.png b/sample-java/src/main/res/drawable-xhdpi/ic_loading.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_loading.png rename to sample-java/src/main/res/drawable-xhdpi/ic_loading.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_back_black.png b/sample-java/src/main/res/drawable-xxhdpi/ic_arrow_back_black.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_arrow_back_black.png rename to sample-java/src/main/res/drawable-xxhdpi/ic_arrow_back_black.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_empty.png b/sample-java/src/main/res/drawable-xxhdpi/ic_empty.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_empty.png rename to sample-java/src/main/res/drawable-xxhdpi/ic_empty.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_error.png b/sample-java/src/main/res/drawable-xxhdpi/ic_error.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_error.png rename to sample-java/src/main/res/drawable-xxhdpi/ic_error.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_logo.png b/sample-java/src/main/res/drawable-xxhdpi/ic_logo.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_logo.png rename to sample-java/src/main/res/drawable-xxhdpi/ic_logo.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_logo_core.png b/sample-java/src/main/res/drawable-xxhdpi/ic_logo_core.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_logo_core.png rename to sample-java/src/main/res/drawable-xxhdpi/ic_logo_core.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_timeout.png b/sample-java/src/main/res/drawable-xxhdpi/ic_timeout.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_timeout.png rename to sample-java/src/main/res/drawable-xxhdpi/ic_timeout.png diff --git a/app/src/main/res/drawable/bg_reload_btn.xml b/sample-java/src/main/res/drawable/bg_reload_btn.xml similarity index 100% rename from app/src/main/res/drawable/bg_reload_btn.xml rename to sample-java/src/main/res/drawable/bg_reload_btn.xml diff --git a/app/src/main/res/drawable/bg_search.xml b/sample-java/src/main/res/drawable/bg_search.xml similarity index 100% rename from app/src/main/res/drawable/bg_search.xml rename to sample-java/src/main/res/drawable/bg_search.xml diff --git a/app/src/main/res/drawable/ic_baseline_favorite_24.xml b/sample-java/src/main/res/drawable/ic_baseline_favorite_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_favorite_24.xml rename to sample-java/src/main/res/drawable/ic_baseline_favorite_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_message_24.xml b/sample-java/src/main/res/drawable/ic_baseline_message_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_message_24.xml rename to sample-java/src/main/res/drawable/ic_baseline_message_24.xml diff --git a/app/src/main/res/drawable/ic_baseline_photo_camera_24.xml b/sample-java/src/main/res/drawable/ic_baseline_photo_camera_24.xml similarity index 100% rename from app/src/main/res/drawable/ic_baseline_photo_camera_24.xml rename to sample-java/src/main/res/drawable/ic_baseline_photo_camera_24.xml diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/sample-java/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from app/src/main/res/drawable/ic_launcher_background.xml rename to sample-java/src/main/res/drawable/ic_launcher_background.xml diff --git a/app/src/main/res/layout/activity_fragment.xml b/sample-java/src/main/res/layout/activity_fragment.xml similarity index 100% rename from app/src/main/res/layout/activity_fragment.xml rename to sample-java/src/main/res/layout/activity_fragment.xml diff --git a/app/src/main/res/layout/activity_main.xml b/sample-java/src/main/res/layout/activity_main.xml similarity index 100% rename from app/src/main/res/layout/activity_main.xml rename to sample-java/src/main/res/layout/activity_main.xml diff --git a/app/src/main/res/layout/activity_recycler_view.xml b/sample-java/src/main/res/layout/activity_recycler_view.xml similarity index 100% rename from app/src/main/res/layout/activity_recycler_view.xml rename to sample-java/src/main/res/layout/activity_recycler_view.xml diff --git a/app/src/main/res/layout/activity_scrolling.xml b/sample-java/src/main/res/layout/activity_scrolling.xml similarity index 100% rename from app/src/main/res/layout/activity_scrolling.xml rename to sample-java/src/main/res/layout/activity_scrolling.xml diff --git a/app/src/main/res/layout/activity_tab_layout.xml b/sample-java/src/main/res/layout/activity_tab_layout.xml similarity index 100% rename from app/src/main/res/layout/activity_tab_layout.xml rename to sample-java/src/main/res/layout/activity_tab_layout.xml diff --git a/app/src/main/res/layout/activity_view.xml b/sample-java/src/main/res/layout/activity_view.xml similarity index 100% rename from app/src/main/res/layout/activity_view.xml rename to sample-java/src/main/res/layout/activity_view.xml diff --git a/app/src/main/res/layout/activity_view_pager.xml b/sample-java/src/main/res/layout/activity_view_pager.xml similarity index 100% rename from app/src/main/res/layout/activity_view_pager.xml rename to sample-java/src/main/res/layout/activity_view_pager.xml diff --git a/app/src/main/res/layout/layout_bottom_editor.xml b/sample-java/src/main/res/layout/layout_bottom_editor.xml similarity index 100% rename from app/src/main/res/layout/layout_bottom_editor.xml rename to sample-java/src/main/res/layout/layout_bottom_editor.xml diff --git a/app/src/main/res/layout/layout_content.xml b/sample-java/src/main/res/layout/layout_content.xml similarity index 100% rename from app/src/main/res/layout/layout_content.xml rename to sample-java/src/main/res/layout/layout_content.xml diff --git a/app/src/main/res/layout/layout_cool_loading.xml b/sample-java/src/main/res/layout/layout_cool_loading.xml similarity index 86% rename from app/src/main/res/layout/layout_cool_loading.xml rename to sample-java/src/main/res/layout/layout_cool_loading.xml index 7dd31f8..ed0b1c8 100644 --- a/app/src/main/res/layout/layout_cool_loading.xml +++ b/sample-java/src/main/res/layout/layout_cool_loading.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - diff --git a/app/src/main/res/layout/layout_custom_header.xml b/sample-java/src/main/res/layout/layout_custom_header.xml similarity index 100% rename from app/src/main/res/layout/layout_custom_header.xml rename to sample-java/src/main/res/layout/layout_custom_header.xml diff --git a/app/src/main/res/layout/layout_empty.xml b/sample-java/src/main/res/layout/layout_empty.xml similarity index 100% rename from app/src/main/res/layout/layout_empty.xml rename to sample-java/src/main/res/layout/layout_empty.xml diff --git a/app/src/main/res/layout/layout_error.xml b/sample-java/src/main/res/layout/layout_error.xml similarity index 100% rename from app/src/main/res/layout/layout_error.xml rename to sample-java/src/main/res/layout/layout_error.xml diff --git a/app/src/main/res/layout/layout_loading.xml b/sample-java/src/main/res/layout/layout_loading.xml similarity index 100% rename from app/src/main/res/layout/layout_loading.xml rename to sample-java/src/main/res/layout/layout_loading.xml diff --git a/app/src/main/res/layout/layout_placeholder.xml b/sample-java/src/main/res/layout/layout_placeholder.xml similarity index 100% rename from app/src/main/res/layout/layout_placeholder.xml rename to sample-java/src/main/res/layout/layout_placeholder.xml diff --git a/app/src/main/res/layout/layout_scrolling_toolbar.xml b/sample-java/src/main/res/layout/layout_scrolling_toolbar.xml similarity index 100% rename from app/src/main/res/layout/layout_scrolling_toolbar.xml rename to sample-java/src/main/res/layout/layout_scrolling_toolbar.xml diff --git a/app/src/main/res/layout/layout_search_header.xml b/sample-java/src/main/res/layout/layout_search_header.xml similarity index 100% rename from app/src/main/res/layout/layout_search_header.xml rename to sample-java/src/main/res/layout/layout_search_header.xml diff --git a/app/src/main/res/layout/layout_timeout.xml b/sample-java/src/main/res/layout/layout_timeout.xml similarity index 100% rename from app/src/main/res/layout/layout_timeout.xml rename to sample-java/src/main/res/layout/layout_timeout.xml diff --git a/app/src/main/res/layout/layout_toolbar.xml b/sample-java/src/main/res/layout/layout_toolbar.xml similarity index 100% rename from app/src/main/res/layout/layout_toolbar.xml rename to sample-java/src/main/res/layout/layout_toolbar.xml diff --git a/app/src/main/res/layout/recycler_item_image.xml b/sample-java/src/main/res/layout/recycler_item_image.xml similarity index 100% rename from app/src/main/res/layout/recycler_item_image.xml rename to sample-java/src/main/res/layout/recycler_item_image.xml diff --git a/app/src/main/res/menu/menu_about.xml b/sample-java/src/main/res/menu/menu_about.xml similarity index 100% rename from app/src/main/res/menu/menu_about.xml rename to sample-java/src/main/res/menu/menu_about.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/sample-java/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to sample-java/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/sample-java/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to sample-java/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/sample-java/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher.png rename to sample-java/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/sample-java/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to sample-java/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/sample-java/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher.png rename to sample-java/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/sample-java/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to sample-java/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/sample-java/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to sample-java/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/sample-java/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to sample-java/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sample-java/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to sample-java/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/sample-java/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to sample-java/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/sample-java/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to sample-java/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/sample-java/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to sample-java/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/app/src/main/res/values/attrs.xml b/sample-java/src/main/res/values/attrs.xml similarity index 100% rename from app/src/main/res/values/attrs.xml rename to sample-java/src/main/res/values/attrs.xml diff --git a/app/src/main/res/values/colors.xml b/sample-java/src/main/res/values/colors.xml similarity index 91% rename from app/src/main/res/values/colors.xml rename to sample-java/src/main/res/values/colors.xml index 32baea3..460cda8 100644 --- a/app/src/main/res/values/colors.xml +++ b/sample-java/src/main/res/values/colors.xml @@ -2,7 +2,7 @@ #fff #fff - #29b6f6 + #1E88E5 #ddd #666 diff --git a/app/src/main/res/values/strings.xml b/sample-java/src/main/res/values/strings.xml similarity index 99% rename from app/src/main/res/values/strings.xml rename to sample-java/src/main/res/values/strings.xml index 7465c44..37101ac 100644 --- a/app/src/main/res/values/strings.xml +++ b/sample-java/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - LoadingHelper + LoadingStateView A highly expandable Android library for showing loading status view with the low-coupling way. "Material is the metaphor.\n\n" diff --git a/app/src/main/res/values/styles.xml b/sample-java/src/main/res/values/styles.xml similarity index 100% rename from app/src/main/res/values/styles.xml rename to sample-java/src/main/res/values/styles.xml diff --git a/app/src/test/java/com/dylanc/loadinghelper/sample/ExampleUnitTest.kt b/sample-java/src/test/java/com/dylanc/loadingstateview/sample/java/ExampleUnitTest.kt similarity index 86% rename from app/src/test/java/com/dylanc/loadinghelper/sample/ExampleUnitTest.kt rename to sample-java/src/test/java/com/dylanc/loadingstateview/sample/java/ExampleUnitTest.kt index a1a26c8..82cbb7a 100644 --- a/app/src/test/java/com/dylanc/loadinghelper/sample/ExampleUnitTest.kt +++ b/sample-java/src/test/java/com/dylanc/loadingstateview/sample/java/ExampleUnitTest.kt @@ -1,4 +1,4 @@ -package com.dylanc.loadinghelper.sample +package com.dylanc.loadingstateview.sample.java import org.junit.Test diff --git a/sample-kotlin/.gitignore b/sample-kotlin/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/sample-kotlin/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/sample-kotlin/build.gradle b/sample-kotlin/build.gradle new file mode 100644 index 0000000..a1e83aa --- /dev/null +++ b/sample-kotlin/build.gradle @@ -0,0 +1,48 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdkVersion buildConfig.compileSdkVersion + + defaultConfig { + applicationId "com.dylanc.loadingstateview.sample.kotlin" + minSdkVersion buildConfig.minSdkVersion + targetSdkVersion buildConfig.targetSdkVersion + versionCode buildConfig.versionCode + versionName buildConfig.versionName + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + viewBinding { + enabled true + } +} + +dependencies { + implementation project(':loadingstateview-ktx') + implementation "androidx.appcompat:appcompat:$appCompatVersion" + implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion" + implementation "com.google.android.material:material:$materialVersion" + implementation "com.github.DylanCaiCoding.ViewBindingKTX:viewbinding-base:$viewBindingKTXVersion" + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$junitExtVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" +} \ No newline at end of file diff --git a/sample-kotlin/proguard-rules.pro b/sample-kotlin/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/sample-kotlin/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/sample-kotlin/src/androidTest/java/com/dylanc/loadingstateview/sample/kotlin/ExampleInstrumentedTest.kt b/sample-kotlin/src/androidTest/java/com/dylanc/loadingstateview/sample/kotlin/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..70cc8a4 --- /dev/null +++ b/sample-kotlin/src/androidTest/java/com/dylanc/loadingstateview/sample/kotlin/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.dylanc.loadingstateview.sample.kotlin + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.dylanc.loadingstateview.sample.kotlin", appContext.packageName) + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/AndroidManifest.xml b/sample-kotlin/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2d3939d --- /dev/null +++ b/sample-kotlin/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/App.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/App.kt new file mode 100644 index 0000000..b6e2f5b --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/App.kt @@ -0,0 +1,20 @@ +package com.dylanc.loadingstateview.sample.kotlin + +import android.app.Application +import com.dylanc.loadingstateview.LoadingStateView +import com.dylanc.loadingstateview.sample.kotlin.delegate.ErrorViewDelegate +import com.dylanc.loadingstateview.sample.kotlin.delegate.LoadingViewDelegate +import com.dylanc.loadingstateview.sample.kotlin.delegate.ToolbarViewDelegate +import com.dylanc.loadingstateview.sample.kotlin.delegate.EmptyViewDelegate +import com.dylanc.loadingstateview.sample.kotlin.delegate.FadeAnimatable + +class App : Application() { + + override fun onCreate() { + super.onCreate() + LoadingStateView.setViewDelegatePool { + register(ToolbarViewDelegate(), LoadingViewDelegate(), ErrorViewDelegate(), EmptyViewDelegate()) + } + LoadingStateView.defaultAnimatable = FadeAnimatable() + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseActivity.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseActivity.kt new file mode 100644 index 0000000..7b29354 --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseActivity.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.base + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.dylanc.loadingstateview.LoadingState +import com.dylanc.loadingstateview.LoadingStateDelegate + +abstract class BaseActivity(private val layoutRes: Int) : AppCompatActivity(), LoadingState by LoadingStateDelegate() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(layoutRes) + decorateContentView(this) + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingActivity.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingActivity.kt new file mode 100644 index 0000000..56915dc --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingActivity.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.base + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.viewbinding.ViewBinding +import com.dylanc.loadingstateview.LoadingState +import com.dylanc.loadingstateview.LoadingStateDelegate +import com.dylanc.viewbinding.base.ActivityBinding +import com.dylanc.viewbinding.base.ActivityBindingDelegate + +abstract class BaseBindingActivity : AppCompatActivity(), + LoadingState by LoadingStateDelegate(), ActivityBinding by ActivityBindingDelegate() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentViewWithBinding() + binding.root.decorate(this) + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingFragment.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingFragment.kt new file mode 100644 index 0000000..d16205e --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseBindingFragment.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.base + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.viewbinding.ViewBinding +import com.dylanc.loadingstateview.LoadingState +import com.dylanc.loadingstateview.LoadingStateDelegate +import com.dylanc.viewbinding.base.FragmentBinding +import com.dylanc.viewbinding.base.FragmentBindingDelegate + +abstract class BaseBindingFragment : Fragment(), LoadingState by LoadingStateDelegate(), + FragmentBinding by FragmentBindingDelegate() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = + createViewWithBinding(inflater, container).decorate(this) +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseFragment.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseFragment.kt new file mode 100644 index 0000000..ceec70b --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/base/BaseFragment.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.base + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import com.dylanc.loadingstateview.LoadingState +import com.dylanc.loadingstateview.LoadingStateDelegate + +abstract class BaseFragment(private val layoutRes: Int) : Fragment(), LoadingState by LoadingStateDelegate() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = + inflater.inflate(layoutRes, container, false).decorate(this) +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/EmptyViewDelegate.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/EmptyViewDelegate.kt new file mode 100644 index 0000000..4ace30c --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/EmptyViewDelegate.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.dylanc.loadingstateview.sample.kotlin.delegate + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.dylanc.loadingstateview.LoadingStateView.ViewDelegate +import com.dylanc.loadingstateview.ViewType +import com.dylanc.loadingstateview.sample.kotlin.R + +/** + * @author Dylan Cai + */ +class EmptyViewDelegate : ViewDelegate(ViewType.EMPTY) { + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View = + inflater.inflate(R.layout.layout_empty, parent, false) +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ErrorViewDelegate.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ErrorViewDelegate.kt new file mode 100644 index 0000000..368c1bc --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ErrorViewDelegate.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.delegate + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.dylanc.loadingstateview.LoadingStateView.ViewDelegate +import com.dylanc.loadingstateview.ViewType +import com.dylanc.loadingstateview.sample.kotlin.R + +/** + * @author Dylan Cai + */ +class ErrorViewDelegate : ViewDelegate(ViewType.ERROR) { + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View = + inflater.inflate(R.layout.layout_error, parent, false).apply { + findViewById(R.id.btn_reload).setOnClickListener { + onReloadListener?.onReload() + } + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/FadeAnimatable.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/FadeAnimatable.kt new file mode 100644 index 0000000..bb52b5f --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/FadeAnimatable.kt @@ -0,0 +1,25 @@ +package com.dylanc.loadingstateview.sample.kotlin.delegate + +import android.view.View +import com.dylanc.loadingstateview.LoadingStateView +import com.dylanc.loadingstateview.ViewType + +/** + * @author Dylan Cai + */ +class FadeAnimatable(private val duration: Long = 600) : LoadingStateView.Animatable { + override fun toggleViewsAnimation(showView: View, hideView: View, showViewType: Any, hideViewType: Any) { + if (showViewType === ViewType.LOADING && hideViewType === ViewType.CONTENT) { + showView.visibility = View.VISIBLE + hideView.visibility = View.GONE + } else { + showView.alpha = 0f + showView.visibility = View.VISIBLE + showView.animate().alpha(1f).setDuration(duration) + hideView.animate().alpha(0f).setDuration(duration).withEndAction { + hideView.alpha = 1f + hideView.visibility = View.GONE + } + } + } +} diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/LoadingViewDelegate.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/LoadingViewDelegate.kt new file mode 100644 index 0000000..7ea83f5 --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/LoadingViewDelegate.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.delegate + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.dylanc.loadingstateview.LoadingStateView +import com.dylanc.loadingstateview.ViewType +import com.dylanc.loadingstateview.sample.kotlin.R + +/** + * @author Dylan Cai + */ +class LoadingViewDelegate : LoadingStateView.ViewDelegate(ViewType.LOADING) { + + override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup): View = + inflater.inflate(R.layout.layout_loading, parent, false) + + override fun onViewAttached(view: View) { + view.animate().rotationBy(360f) + .setDuration(800) + .withEndAction { onViewAttached(view) } + .start() + } + + override fun onViewDetached(view: View) { + view.animate().cancel() + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ScrollingDecorViewDelegate.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ScrollingDecorViewDelegate.kt new file mode 100644 index 0000000..51b31b0 --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ScrollingDecorViewDelegate.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.dylanc.loadingstateview.sample.kotlin.delegate + +import android.app.Activity +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar +import com.dylanc.loadingstateview.LoadingStateView +import com.dylanc.loadingstateview.sample.kotlin.R + +/** + * @author Dylan Cai + */ +class ScrollingDecorViewDelegate(private val title: String) : LoadingStateView.DecorViewDelegate() { + + override fun onCreateDecorView(context: Context, inflater: LayoutInflater): View { + val view = inflater.inflate(R.layout.layout_scrolling_toolbar, null) + val toolbar: Toolbar = view.findViewById(R.id.toolbar) + toolbar.title = title + toolbar.setNavigationOnClickListener { + if (context is Activity) context.finish() + } + return view + } + + override fun getContentParent(decorView: View): ViewGroup { + return decorView.findViewById(R.id.content_parent) + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ToolbarViewDelegate.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ToolbarViewDelegate.kt new file mode 100644 index 0000000..43daafc --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/delegate/ToolbarViewDelegate.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.delegate + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toolbar +import com.dylanc.loadingstateview.NavBtnType +import com.dylanc.loadingstateview.ToolbarConfig +import com.dylanc.loadingstateview.BaseToolbarViewDelegate +import com.dylanc.loadingstateview.sample.kotlin.databinding.LayoutToolbarBinding +import com.dylanc.loadingstateview.toolbarExtras + +var ToolbarConfig.rightTextColor: Int? by toolbarExtras() + +class ToolbarViewDelegate : BaseToolbarViewDelegate() { + private lateinit var binding: LayoutToolbarBinding + + override fun onCreateToolbar(inflater: LayoutInflater, parent: ViewGroup): View { + binding = LayoutToolbarBinding.inflate(inflater, parent, false) + return binding.root + } + + override fun onBindToolbar(config: ToolbarConfig) { + binding.apply { + tvTitle.text = config.title + + when (config.navBtnType) { + NavBtnType.ICON -> { + config.navIcon?.let { ivLeft.setImageResource(it) } + ivLeft.setOnClickListener(config.onNavClickListener) + tvLeft.visibility = View.GONE + ivLeft.visibility = View.VISIBLE + } + NavBtnType.TEXT -> { + tvLeft.text = config.navText + tvLeft.setOnClickListener(config.onNavClickListener) + tvLeft.visibility = View.VISIBLE + ivLeft.visibility = View.GONE + } + NavBtnType.ICON_TEXT -> { + config.navIcon?.let { ivLeft.setImageResource(it) } + tvLeft.text = config.navText + ivLeft.setOnClickListener(config.onNavClickListener) + tvLeft.setOnClickListener(config.onNavClickListener) + tvLeft.visibility = View.VISIBLE + ivLeft.visibility = View.VISIBLE + } + NavBtnType.NONE -> { + ivLeft.visibility = View.GONE + tvLeft.visibility = View.GONE + } + } + + if (config.rightText != null) { + tvRight.text = config.rightText + tvRight.setOnClickListener(config.onRightClickListener) + tvRight.visibility = View.VISIBLE + config.rightTextColor?.let { tvRight.setTextColor(it) } + } else { + tvRight.visibility = View.GONE + } + + if (config.rightIcon != null) { + ivRight.setImageResource(config.rightIcon!!) + ivRight.setOnClickListener(config.onRightClickListener) + ivRight.visibility = View.VISIBLE + } else { + ivRight.visibility = View.GONE + } + } + } +} \ No newline at end of file diff --git a/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/ui/MainActivity.kt b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/ui/MainActivity.kt new file mode 100644 index 0000000..92ac5b8 --- /dev/null +++ b/sample-kotlin/src/main/java/com/dylanc/loadingstateview/sample/kotlin/ui/MainActivity.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019. Dylan Cai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.dylanc.loadingstateview.sample.kotlin.ui + +import android.graphics.Color +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import com.dylanc.loadingstateview.NavBtnType +import com.dylanc.loadingstateview.sample.kotlin.base.BaseBindingActivity +import com.dylanc.loadingstateview.sample.kotlin.databinding.ActivityMainBinding +import com.dylanc.loadingstateview.sample.kotlin.delegate.rightTextColor + +class MainActivity : BaseBindingActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setToolbar("Home", NavBtnType.NONE) { + rightTextColor = Color.BLUE + rightText("Edit") { onEdit() } + } + showLoadingView() + Handler(Looper.getMainLooper()).postDelayed({ + showErrorView() + }, 2000) + } + + private fun onEdit() { + updateToolbar { + title = "Selected 0" + rightText("Complete") { onComplete() } + } + } + + private fun onComplete() { + updateToolbar { + title = "Home" + rightText("Edit") { onEdit() } + } + } + + override fun onReload() { + showLoadingView() + Handler(Looper.getMainLooper()).postDelayed({ + showContentView() + }, 2000) + } +} diff --git a/sample-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml b/sample-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..5c3bfcd --- /dev/null +++ b/sample-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/drawable-xxhdpi/ic_empty.png b/sample-kotlin/src/main/res/drawable-xxhdpi/ic_empty.png new file mode 100644 index 0000000..26e6ed8 Binary files /dev/null and b/sample-kotlin/src/main/res/drawable-xxhdpi/ic_empty.png differ diff --git a/sample-kotlin/src/main/res/drawable-xxhdpi/ic_error.png b/sample-kotlin/src/main/res/drawable-xxhdpi/ic_error.png new file mode 100644 index 0000000..bf717a5 Binary files /dev/null and b/sample-kotlin/src/main/res/drawable-xxhdpi/ic_error.png differ diff --git a/sample-kotlin/src/main/res/drawable/bg_reload_btn.xml b/sample-kotlin/src/main/res/drawable/bg_reload_btn.xml new file mode 100644 index 0000000..6f8a224 --- /dev/null +++ b/sample-kotlin/src/main/res/drawable/bg_reload_btn.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/drawable/ic_add.xml b/sample-kotlin/src/main/res/drawable/ic_add.xml new file mode 100644 index 0000000..b159e97 --- /dev/null +++ b/sample-kotlin/src/main/res/drawable/ic_add.xml @@ -0,0 +1,5 @@ + + + diff --git a/sample-kotlin/src/main/res/drawable/ic_arrow_back_ios.xml b/sample-kotlin/src/main/res/drawable/ic_arrow_back_ios.xml new file mode 100644 index 0000000..eb7eb83 --- /dev/null +++ b/sample-kotlin/src/main/res/drawable/ic_arrow_back_ios.xml @@ -0,0 +1,10 @@ + + + diff --git a/sample-kotlin/src/main/res/drawable/ic_launcher_background.xml b/sample-kotlin/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..140f829 --- /dev/null +++ b/sample-kotlin/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample-kotlin/src/main/res/drawable/ic_refresh.xml b/sample-kotlin/src/main/res/drawable/ic_refresh.xml new file mode 100644 index 0000000..153ae21 --- /dev/null +++ b/sample-kotlin/src/main/res/drawable/ic_refresh.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/sample-kotlin/src/main/res/layout/activity_main.xml b/sample-kotlin/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..9097a26 --- /dev/null +++ b/sample-kotlin/src/main/res/layout/activity_main.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/layout/layout_empty.xml b/sample-kotlin/src/main/res/layout/layout_empty.xml new file mode 100644 index 0000000..3dba858 --- /dev/null +++ b/sample-kotlin/src/main/res/layout/layout_empty.xml @@ -0,0 +1,36 @@ + + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/layout/layout_error.xml b/sample-kotlin/src/main/res/layout/layout_error.xml new file mode 100644 index 0000000..6339f8b --- /dev/null +++ b/sample-kotlin/src/main/res/layout/layout_error.xml @@ -0,0 +1,54 @@ + + + + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/layout/layout_loading.xml b/sample-kotlin/src/main/res/layout/layout_loading.xml new file mode 100644 index 0000000..875b991 --- /dev/null +++ b/sample-kotlin/src/main/res/layout/layout_loading.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/layout/layout_scrolling_toolbar.xml b/sample-kotlin/src/main/res/layout/layout_scrolling_toolbar.xml new file mode 100644 index 0000000..efcb9e8 --- /dev/null +++ b/sample-kotlin/src/main/res/layout/layout_scrolling_toolbar.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/layout/layout_toolbar.xml b/sample-kotlin/src/main/res/layout/layout_toolbar.xml new file mode 100644 index 0000000..15eae0d --- /dev/null +++ b/sample-kotlin/src/main/res/layout/layout_toolbar.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..03eed25 --- /dev/null +++ b/sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..03eed25 --- /dev/null +++ b/sample-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/mipmap-hdpi/ic_launcher.webp b/sample-kotlin/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/sample-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-mdpi/ic_launcher.webp b/sample-kotlin/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/sample-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.webp b/sample-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/sample-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/sample-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/sample-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/sample-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/sample-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/sample-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/sample-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/sample-kotlin/src/main/res/values-night/themes.xml b/sample-kotlin/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..58e424e --- /dev/null +++ b/sample-kotlin/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/values/colors.xml b/sample-kotlin/src/main/res/values/colors.xml new file mode 100644 index 0000000..5fb06ed --- /dev/null +++ b/sample-kotlin/src/main/res/values/colors.xml @@ -0,0 +1,17 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + + #ddd + #666 + #666 + #666 + #666 + #2196F3 + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/values/strings.xml b/sample-kotlin/src/main/res/values/strings.xml new file mode 100644 index 0000000..f9d246a --- /dev/null +++ b/sample-kotlin/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + LoadingStateView + \ No newline at end of file diff --git a/sample-kotlin/src/main/res/values/themes.xml b/sample-kotlin/src/main/res/values/themes.xml new file mode 100644 index 0000000..e6fe4cc --- /dev/null +++ b/sample-kotlin/src/main/res/values/themes.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/sample-kotlin/src/test/java/com/dylanc/loadingstateview/sample/kotlin/ExampleUnitTest.kt b/sample-kotlin/src/test/java/com/dylanc/loadingstateview/sample/kotlin/ExampleUnitTest.kt new file mode 100644 index 0000000..b21e6fb --- /dev/null +++ b/sample-kotlin/src/test/java/com/dylanc/loadingstateview/sample/kotlin/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.dylanc.loadingstateview.sample.kotlin + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 3306997..66d687a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,5 @@ -include ':app', ':library' +rootProject.name = "LoadingStateView" +include ':loadingstateview' +include ':loadingstateview-ktx' +include ':sample-java' +include ':sample-kotlin'