diff --git a/README.md b/README.md index 9443197..e19e83e 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,31 @@ -## AndroidSampleLibrary +[![Version]() +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) -> During the very critical moment. I made a plan for learning other computer languages. I was realized that I've lost a lot of source code.
- After I finished one project or finished one part of the project. I forgot it immediately. That's why I was keep working on the Sample Library. Here is the fourth or fifth version of a test project.
- I must say it's my favorite
+## android-sample-library -After one week of hard working. I've finished some functions: -* [Sample component](document/component/sampleCompoent.md) -* [Sample function](document/function/sampleFunction.md) -* [Action processor](document/actionprocessor/actionProcessor.md) +> A powerful library to help you demonstrate your android app. -### Annotations -The [Annotations](document/annotations/sampleAnnotation.md) +## Table of content -#### [中文文档](document/readme-cn.md) +- [Compile](#Compile) + - [Compile-with-groovy](#Compile-with-groovy) + - [Compile-with-kts](#Compile-with-kts) + - [Using one script to configure the library](#Using-one-script-to-configure-the-library) +- [Project structure](#Project-structure) +- [Usage](#How-to-use-it) + - [Using the package to generate the category](#Using-the-package-to-generate-the-category) + - [Custom the title and category](#Custom-the-title-and-category) + - [Working with testcase](#Working-with-testcase) + - [Working with extension](#Working-with-extension) +- [Design](#Design) +- [Sample file](#Sample) -### Sample -[APK FILE](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/file/app-debug.apk?raw=true) +### Compile -### Better ways for you to simplify your samples. -[Usage](document/usage.md) +#### Compile with groovy -### Gradle +
+Groovy ``` //Project:build.gradle --------------- @@ -48,106 +53,166 @@ dependencies { ... implementation "com.github.momodae.AndroidSampleLibrary:library:$sample_version" } +``` + +
+ + +#### Compile with kts + +
+Kotlin ``` +//Project:build.gradle --------------- +buildscript { + ext.sample_version = '1.3.0' + repositories { + ... + maven { url 'https://jitpack.io' } + } + dependencies { + ... + //Here is our plugin. + classpath "com.github.momodae.AndroidSampleLibrary:plugin:$sample_version" +} -### Pictures +allprojects { + repositories { + maven { url 'https://jitpack.io' } + } +} -![Image1](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/image/image1.gif?raw=true)
-![Image2](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/image/image2.gif?raw=true)
+//Project:app ------------- +apply plugin: 'sample' +dependencies { + ... + implementation "com.github.momodae.AndroidSampleLibrary:library:$sample_version" +} +``` +
-### How to use this library. +#### Using one script to configure the library -* The simplest way to use this library. -If you want to use this library as simple as possible. The only thing you have to do is configure all the dependency and plugin. That's it. -I will help you generate all the categories and the sample information. -For example +We highly recommend you use one script to configure this library. ``` -|--test1 - |-- Sample1Activity - |-- Sample2Activity -|--test2 - |-- Sample1Activity - |-- Sample2Activity +... ``` -From the package and class. I will help you generate all the demonstrate structure. Noticed that this is only for Activity and Fragment. -Because we collect all the Activity/Fragment, If you have other classes that you use them for special purposes. Use the annotation class:@Exclude. +### Project structure -* The other way, configure the category and sample by yourself. +- api: Common api for both library and plugin +- app: the demo app +- core: The core library. It supports the basic action processor and extension. +- extension: Based on the core. It helps us implements all the extensions, such as components and functions. +- sample-plugin: This Gradle plugin helps us collect all the sample, testcases, extensions. -* For an activity sample +It will generate a class file while compiling. (Without source code). The class file has a string field containing a JSON string so you can parse it to get all the components and extensions. - You could use either @Register or @RefRegister to set this sample up
+### Design - ``` - @RefRegister(title=R.string.component_sample3,desc=R.string.component_sample3_desc,category = R.string.component_category,priority = 2) - class ComponentSourceSampleActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_component_source_code_sample) - } - } - ``` - -* For an fragment sample - You could use either @Register or @RefRegister to set this sample up
- - ``` - @RefRegister(title=R.string.component_sample5,desc = R.string.component_sample5_desc,category = R.string.component_category) - class ComponentSampleFragment : Fragment() { - private var index=0 - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_component_sample, container, false); - } - } - ``` +* [Sample component](document/sample-compoent.md) +* [Action processor](document/sample-processor.md) -* How to organize each samples - First every samples belong to root. But if you setup your sample like this:
- You actually changed the category of this sample
- ``` - @RefRegister(xxx,category = R.string.component_category)
- class Sample{ - ... - } - ``` +### How to use it - But if this category does not exist. The sample will be lost. +#### Using the package to generate the category -* How to use different kinds of components +We try to simplify the demo classification. So what's the simplest way to category the demon? It should be the package name and component class. +That's it. - ``` - //Mark each component annotation to this sample - @SampleMessage - @SampleMemory - ... - class Sample{ - ... - } - ``` +For example. this is your project structure -* Setup an exception handler. If your sample does not works properly and you want see the details. Here you could trace the exception and check it out -. But if you do not have an exception handler. When the exception occurred. The application will crash. For a demo, It is usually not a problem. +``` +com.andorid.test.fragment + FragmentDemo1.kt + FragmentDemo2.kt +com.android.test.ui + ViewDemo1.kt + ViewDemo2.kt +``` - ``` - val projectApplication = SampleApplication.getProjectApplication() - projectApplication.androidSample.registerExceptionHandler { context, e, sampleItem, item -> - Log.e(TAG, "Exception occurs:" + e.message) - } - ``` +Your demo will look like this list. +``` +|-- fragment + |-- FragmentDemo1 + |-- FragmentDemo2 +|-- ui + |-- ViewDemo1 + |-- ViewDemo2 +``` -* The different between RefCategory and Category. -> We use R.string to support i18n. If you want to support that. The Category is more convenient. +That's all, You don't need to do anything. +#### Custom the title and category -### About me +If you want to customize your demo. You have to use this annotation `@Register` -A programmer in mainland China. +For example: -If you have any new idea about this project, feel free to contact me with this email:bingo110@126.com +``` +@Register(title="Demo1",desc="This is your demo",path="") +class DemoActivity:AppcompatActivity{ + ... +} +``` + +* the field title is the demo's title... +* the field desc is the demo's description... +* path: this one is your category. You can use it this way: ui/list or ui/text. + +Tips: + +For the field path, you can either make it empty or use a specific path. I will collect all the paths and help you generate a tree. + +#### Working with testcase +Imagine you have a vast demonstration app, and finding one demo is hard. So you may want to open it directly whenever you launch your app. + +The solution is to annotate your component with `@TestCase` + +``` +@TestCase +@Register(title="Demo1",desc="This is your demo",path="") +class DemoActivity:AppcompatActivity{ + ... +} +``` + +For more testcases I will help you pop up a dialog, and you can choose your demo. + +#### Working with extension + +This is a simple case to use all kinds of extensions. +When you use `SampleSourceCode,` it will help you generate a ViewPager and put your source code as a list. + +``` +@SampleMemory +@SampleMessage +@SampleSourceCode +@SampleDocument("documentSample.md") +@Register(title = "组件集", desc = "展示当前己扩展的组件") +class ComponentListSampleActivity : AppCompatActivity() { + ... +} +``` + +Now we support several extensions. + +* Component + * SampleDocument: display the related document + * SampleMemory: display the runtime memory. + * SampleSourceCode: display the source file + * SampleMessage: display the test message. + +### Sample +[APK FILE](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/file/app-debug.apk?raw=true) + +### Pictures + +![Image1](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/image/image1.gif?raw=true)
+![Image2](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/image/image2.gif?raw=true)
diff --git a/document/actionprocessor/actionProcessor.md b/document/actionprocessor/actionProcessor.md deleted file mode 100644 index b4dd355..0000000 --- a/document/actionprocessor/actionProcessor.md +++ /dev/null @@ -1,79 +0,0 @@ -## ActionProcessor -For a sample library. We are not going to just demonstrate Activity or Fragment. But sometimes display a dialog or something just print a message. -Long before this version. I believe this is good enough. But one day one of my friends tells me. I have a Dialog library. All I want is to click the title and display the dialog. -Then that makes me start try to abstract the action. How to support this function dynamically. - - -``` -public abstract class AbsActionProcessor { - /** - * consider if you want to process this item. usually is class object. HowEver It will be an custom object. - */ - public abstract boolean isInstance(Class clazz); - - /** - * Get object instance from class object - * @param context - * @param clazz - * @return - */ - public abstract T getInstance(FragmentActivity context,RegisterItem item,Class clazz) throws Exception; - - /** - * process the register configuration - * @param context Android context object. Here you is an FragmentActivity. - * @param sampleItem the one that you register which is all the information you could use - * @throws Exception when you execute an action failed throw an exception - */ - public abstract void run(FragmentActivity context, RegisterItem sampleItem,T item) throws Exception; -} - -``` - -The abstract class was the basic class for us to use. For a Activity. We got an implementation. - -``` -@ActionProcessor -public class ActivityClassActionProcessor extends ClassActionProcessor { - @Override - public boolean isInstance(Class item) { - //Test if the sample class is available for the processor. - return super.isInstance(item)&& Activity.class.isAssignableFrom(item); - } - - @Override - public void run(FragmentActivity context, RegisterItem sampleItem, Class clazz){ - //How the activity processor handle the class. - Intent intent = new Intent(context, clazz); - intent.putExtra("title",sampleItem.title); - intent.putExtra("desc",sampleItem.desc); - context.startActivity(intent); - } -} -``` - -Here is another one to support Dialog - -``` -@ActionProcessor -public class DialogClassActionProcessor extends ClassActionProcessor { - @Override - public boolean isInstance(Class item) { - return super.isInstance(item)&& Dialog.class.isAssignableFrom(item); - } - - @Override - public void run(FragmentActivity context, RegisterItem sampleItem, Class clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException { - Constructor constructor = (Constructor) clazz.getConstructor(Context.class); - Dialog dialog = constructor.newInstance(context); - dialog.show(); - } -} -``` -You may aware of the Annotation: @ActionProcessor. This is for the plugin to collect all the action processor together. -Because of the abstraction. Now we could easily support all kinds of demos. - - - - - diff --git a/document/annotations/sampleAnnotation.md b/document/annotations/sampleAnnotation.md deleted file mode 100644 index 2c2125d..0000000 --- a/document/annotations/sampleAnnotation.md +++ /dev/null @@ -1,124 +0,0 @@ -## Annotations -| Annotation | Note | -| ------ | ------ | -| Register | register a sample | -| RefRegister | Same as @Register but only use R.string | -| Category | register a category | -| RefCategory | Same as @Register but only use R.string | -| ActionProcessor | | -| Component | | -| Function | | -| MainComponent | | -| TestCase | | - - -* *Register* -> If you want to support i18n then use the RefRegister instead - -``` -@Register(title="SampleTitle",desc="SampleDescription",category = "Which category this sample belong") -class Sample { - ... -} - -``` - -* *Category* -> If you want to support i18n then use the RefRegister instead - -``` -@Category(title="category title",desc = "category description") -class Object{ - ... -} -``` - -Make sure that all your samples has an exact category or it will lose from nowhere - -* *ActonProcessor* -> If you got a special sample that I do not support. You could implement your own sample action processor - -For instance: -* I am not support alertDialog. Then I write some code like this. - -``` -//With this annotation. this class will register to the action processor manager automatically -@ActionProcessor -public class AlertDialogActionProcessor extends AbsActionProcessor { - //Check is this class object you want to take - @Override - public boolean isInstance(Class clazz) { - return SampleObject.class.isAssignableFrom(clazz); - } - - //Then after you get this register sample. Here use the information to do what you want. - @Override - public AlertDialog getInstance(FragmentActivity context, RegisterItem item, Class clazz) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { - SampleObject object; - try{ - object= (SampleObject) clazz.newInstance(); - } catch (InstantiationException e){ - } - return (AlertDialog) object.getObject(context); - } - - @Override - public void run(FragmentActivity context, RegisterItem sampleItem, AlertDialog item) { - item.show(); - } -} - -//Now I can show you all different kinds of AlertDialog - @RefRegister(title = R.string.dialog_sample1,desc =R.string.dialog_sample1_desc,category = R.string.dialog) -public class DialogSample1 implements SampleObject { - @Override - public Object getObject(final Context context) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Login Alert") - .setMessage("Are you sure, you want to continue ?") - .setCancelable(false) - .setPositiveButton("Yes", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Toast.makeText(context,"Selected Option: YES",Toast.LENGTH_SHORT).show(); - } - }) - .setNegativeButton("No", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Toast.makeText(context,"Selected Option: No",Toast.LENGTH_SHORT).show(); - } - }); - //Creating dialog box - return builder.create(); - } -} - -``` - -Make sure after you have your own ActionProcessor. mark as ActionProcessor - - -* *Component* - - If you want to inject a common view into some specific samples. You should check this out [More detail](https://github.com/momodae/AndroidSampleLibrary/blob/master/document/component/sampleCompoent.md) - -* *Function* - - If you want to do something every time when you open a sample. You should check this out [More detail](https://github.com/momodae/AndroidSampleLibrary/blob/master/document/function/sampleFunction.md) - -* *MainComponent* - - This is an annotation that register a main component. Actually you don't have to implement your own main component.
- The component is for the programmer who want to have their own home page. I will give you all the information that you registered in. - - -Take a look at [MainSampleFragment](https://github.com/momodae/AndroidSampleLibrary/blob/master/app/src/main/java/com/cz/sample/custom/main/MainSampleFragment.java) - -* *TestCase* - - This one is when you want to run a sample immediately. But you have a lot of samples. - You can mark your sample as @TestCase. Then I will start your sample at home page. - However, if you have more than one @TestCase, I will alert a dialog for you to choose which one you want to demonstrate. - -![](image/https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/image/test_case_image.png?raw=true) diff --git a/document/function/sampleFunction.md b/document/function/sampleFunction.md deleted file mode 100644 index 0f9dbac..0000000 --- a/document/function/sampleFunction.md +++ /dev/null @@ -1,129 +0,0 @@ -## Sample Function - -> After I start a sample. However, I want to do something.
-Such as request runtime permission, or collect all the use time and sort samples dynamically.
-But I can't just update my project every time when the time when I want to change something. That why we have this.
- - -##### *Related Source File* - -``` -//SourceCode:library/com.cz.android.sample.library.function.permission - |-- Permission - |-- PermissionObserver - |-- @SamplePermission - |-- SamplePermissionFunction (This is the implementation of the Function) - |-- SamplePermissoinsFragment -``` - -#### SamplePermissionFunction - -``` -@Function -public class SamplePermissionFunction implements SampleFunction { - /** - * If your function wants to do some initial work. Here we inject the fragment. - * But if we don't we this function, call SamplePermissionsFragment.injectIfNeededIn(context); - * and then try to get fragment from the FragmentManager It just didn't exist - * @param context - */ - @Override - public void init(FragmentActivity context) { - //inject permission fragment - SamplePermissionsFragment.injectIfNeededIn(context); - } - - /** - * Check this class and determined this class needs to run this function - * @param clazz - * @return - */ - @Override - public boolean isAvailable(Class clazz) { - SamplePermission samplePermission = clazz.getAnnotation(SamplePermission.class); - return (null!=samplePermission&& - null!=samplePermission.value()&& - 0 < samplePermission.value().length); - } - - @Override - public void run(FragmentActivity context, final Object object, RegisterItem item) { - [...] - final SamplePermissionsFragment permissionsFragment=SamplePermissionsFragment.get(activity); - PermissionObserver permissionObserverWrapper = new PermissionObserver() { - @Override - public void onAccepted(PermissionResult permission) { - PermissionViewModel viewModel = PermissionViewModelProviders.getViewModel(activity); - PermissionObserver observer = viewModel.getObserver(); - if(null!=observer){ - observer.onAccepted(permission); - } - } - }; - //add permission observer - permissionsFragment.addPermissionObserver(permissions,permissionObserverWrapper); - //Request permission - permissionsFragment.requestPermissions(permissions); - } -} - -``` - -> How we use this function - -``` - -@SamplePermission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE) -@RefRegister(title=R.string.function_permission_sample1,desc = R.string.function_permission_sample1_desc,category = R.string.sample_function) -class SamplePermissionActivity : AppCompatActivity(),PermissionObserver{ - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_function_permission_sample) - PermissionViewModelProviders.getViewModel(this).addObserver { result-> - if(result.granted){ - val text = getString(R.string.permission_granted, result.name) - Toast.makeText(applicationContext,text, Toast.LENGTH_SHORT).show() - } else { - val text = getString(R.string.permission_denied, result.name) - Toast.makeText(applicationContext,text, Toast.LENGTH_SHORT).show() - } - } - } -} -``` - -### How to implement your own function - -1. Mark class as a function -2. Have a class implements from the interface:SampleFunction - -``` -// -@Function -public class VisitRecordFunction implements SampleFunction { - private static final String TAG="VisitRecordFunction"; - - @Override - public void init(FragmentActivity context) { - } - @Override - public boolean isAvailable(Class clazz) { - // when you return false. It won't call run method below. - return true; - } - @Override - public void run(FragmentActivity context, Object object, RegisterItem item) { - // do something... - Log.e(TAG,"Title:"+item.getTitle()+" class:"+object.toString()); - } -} - -``` - - - -### The problems - -* I do know that my fragment request permission with call the method OnActivityForResult. I will fix this in next version - diff --git a/document/help.md b/document/help.md deleted file mode 100644 index bd05624..0000000 --- a/document/help.md +++ /dev/null @@ -1,16 +0,0 @@ -## Help - -* The command of debug processor - -``` -./gradlew compileDebugJavaWithJavac -Dorg.gradle.daemon=false -Dorg.gradle.debug=true -``` - -sudo lsof -t -i tcp:5005 | xargs kill -9 - -* The command of debug plugin task - -``` -./gradlew :app:transformClassesWithSampleForDebug -Dorg.gradle.daemon=false -Dorg.gradle.debug=true -./gradlew :app:jar -Dorg.gradle.daemon=false -Dorg.gradle.debug=true -``` diff --git a/document/readme-cn.md b/document/readme-cn.md deleted file mode 100644 index a9a2274..0000000 --- a/document/readme-cn.md +++ /dev/null @@ -1,108 +0,0 @@ -## AndroidSampleLibrary - -> 春节特殊时期,本来打算学点其他的,发现.以前有很多库,写了可能都挺长时间没更新了.也没有一个足够方便的基础扩展演示库.于是带着这种想法.便着手设计了此库 - -* #### 已经完成的基本功能为: -* [扩展组件](component/sampleCompoent.md) -* [扩展功能](function/sampleFunction.md) -* [演示处理器](actionprocessor/actionProcessor.md) - -#### [英文文档](../README.md) - -### 示例下载 -[apk file](https://github.com/momodae/AndroidSampleLibrary/raw/master/apk/app-debug.apk) - -### 演示图片 - -![Image1](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/image/image1.gif?raw=true)
-![Image2](https://github.com/momodae/LibraryResources/blob/master/AndroidSampleLibrary/image/image2.gif?raw=true)
- -### 所有常用注解 -The [Annotations](document/annotations/sampleAnnotation.md) - -### 如何使用 -最简单的使用是直接引入库与插件后,什么也不做。我会自动根据包信息,与Activity/Fragment的类名称等生成演示结果。

-此处,因为会自动扫描所有的Activity/Fragment,所以如果有不是演示的Activity/Fragment,请自行加上注解@Exclude. -另外发生冲突的,会自行合并。 -``` -|--test1 - |-- Sample1Activity - |-- Sample2Activity -|--test2 - |-- Sample1Activity - |-- Sample2Activity -``` - -正常使用需要自己配置使用示例。以及层级结构。好处是,可以支持国际化,示例描述,以及层级展示优先级等等。具体可以根据需求自行选择。 - -* Activity 演示 - - 可以使用 @Register 或者 @RefRegister标志一个类为演示对象
- - ``` - @RefRegister(title=R.string.component_sample3,desc=R.string.component_sample3_desc,category = R.string.component_category,priority = 2) - class ComponentSourceSampleActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_component_source_code_sample) - } - } - ``` - -* Fragment 演示 - 可以使用 @Register 或者 @RefRegister标志一个类为演示对象
- - ``` - @RefRegister(title=R.string.component_sample5,desc = R.string.component_sample5_desc,category = R.string.component_category) - class ComponentSampleFragment : Fragment() { - private var index=0 - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_component_sample, container, false); - } - } - ``` - -* 如何组织层级 - - 所以演示,默认放在根目录,但是如果在指定 category,则会自动关联到此分类下
- ``` - @RefRegister(xxx,category = R.string.component_category)
- class Sample{ - ... - } - ``` - - 一定要注意,如果此分类不存在了. 这个演示会丢失. - -* 设置异常处理类,如果在启动示例时,发生一些未知异常,会回调到此处. - - ``` - - val projectApplication = SampleApplication.getProjectApplication() - projectApplication.androidSample.registerExceptionHandler { context, e, sampleItem, item -> - Log.e(TAG, "Exception occurs:" + e.message) - } - ``` - -* 使用不同的组件,扩展演示. 非常重要!默认实现了4个组件,通过上面Component 文档介绍.只需要在每一个演示处,使用注解标志即可. - - ``` - //Mark each component annotation to this sample - @SampleMessage - @SampleMemory - ... - class Sample{ - ... - } - ``` - - -### 问题 - -这个项目花费了一周时间. 时间也比较有限.而且是第一个版本,所以会有很多问题. - -一些我确认的问题如下: - -* 权限申请工作不正常. -* 源码查看视图应该为一个树级,当前只是一个列表 - diff --git a/document/component/sampleCompoent.md b/document/sample-compoent.md similarity index 65% rename from document/component/sampleCompoent.md rename to document/sample-compoent.md index 229cd6d..c283c7a 100644 --- a/document/component/sampleCompoent.md +++ b/document/sample-compoent.md @@ -11,44 +11,55 @@ As a result:It's all about how to add additional view to each samples ### Here are the solution. * First I have an abstract component container. It an interface. - ``` - //SourceCode:core/com.cz.android.sample.component.CompanionComponentContainer - - public interface ComponentContainer { - /** - * if there was a condition that make this component available or not - * @return - */ - boolean isComponentAvailable(@NonNull Object object); - - /** - * Get component view by view. If you want to maintain the original view just return it back; - * @return - */ - View getComponentView(@NonNull FragmentActivity context,@NonNull Object object,@NonNull ViewGroup parentView,@NonNull View view); - - /** - * When component is already. This method will call - * @see ComponentContainer#isComponentAvailable(java.lang.Object) - * @param context - * @param view - */ - void onCreatedView(@NonNull FragmentActivity context,@NonNull Object object,@NonNull View view); - - /** - * This will put this component to top or bottom in stack - * @return - */ - int getComponentPriority(); - } - ``` +``` +interface ComponentContainer { + /** + * We check if this object has Annotation:SampleBorder. + * If this sample object doesn't have this annotation. It won't call the other functions + * + * @return + */ + fun isComponentAvailable(component: Any): Boolean + + /** + * This function is an critical function. It's move like a chain. Each component will call this function + * And return a new view for the next. + * Tips: + * 1. If the sample is not a activity or fragment. Take a look on [AppcompatWindowDelegate] + * + * @param context activity context + * @param component the instance of the sample. It depends on which one that you registered + * @param parentView The parent view of your original view. + * @param view your fragment/activity content view + * @return + */ + fun getComponentView(context: AppCompatActivity, component: Any, parentView: ViewGroup, view: View): View + + /** + * After this component created a new view. This function will call automatically. + * The view is the one you created. You only have this chance to initialize your code here or it will be changed by the other component. + * + * @param context + * @param object + * @param view + */ + fun onCreatedView(context: AppCompatActivity, `object`: Any, view: View) + + /** + * The priority in the component queue. If you want your component run before others + * + * @return + */ + fun getComponentPriority(): Int = 0 +} +``` #### Here is a sample for ComponentContainer ##### *Sample File* ``` -//SourceCode:app/com.cz.sample.custom.component +//SourceCode:app/com.github.jackchen.sample.custom.component |-- BorderComponent |-- BorderLayout |-- SampleBorder @@ -59,61 +70,50 @@ It comes with the annotation: SampleBorder. That's your custom annotation to che
``` -@Component -public class BorderComponent implements ComponentContainer { +@Extension +class BorderComponent : ComponentContainer { /** * We check if this object has Annotation:SampleBorder. * If this sample object doesn't have this annotation. It won't call the other functions - * @param object + * @param component * @return */ - @Override - public boolean isComponentAvailable(@NonNull Object object) { - SampleBorder sampleBorder = object.getClass().getAnnotation(SampleBorder.class); - return null!=sampleBorder&&sampleBorder.value(); + override fun isComponentAvailable(component: Any): Boolean { + val sampleBorder = component.javaClass.getAnnotation(SampleBorder::class.java) + return null != sampleBorder && sampleBorder.value } /** * This function is an critical function. It's move like a chain. Each component will call this function * And return a new view for the next. - * * Tips: - * 1. If the sample is not a activity or fragment. Take a look on {@link ComponentWindowDelegate} + * 1. If the sample is not a activity or fragment. Take a look on [com.github.jackchen.android.core.window.AppcompatWindowDelegate] * - * @param context activity context - * @param object the instance of the sample. It depends on which one that you registered + * @param context activity context + * @param component the instance of the sample. It depends on which one that you registered * @param parentView The parent view of your original view. - * @param view your fragment/activity content view + * @param view your fragment/activity content view * @return */ - @Override - public View getComponentView(@NonNull FragmentActivity context, @NonNull Object object, @NonNull ViewGroup parentView, @NonNull View view) { - BorderLayout borderLayout=new BorderLayout(context); - borderLayout.addView(view); - return borderLayout; + override fun getComponentView( + context: AppCompatActivity, component: Any, + parentView: ViewGroup, view: View + ): View { + val borderLayout = BorderLayout(context) + borderLayout.addView(view) + return borderLayout } /** * After this component created a new view. This function will call automatically. * The view is the one you created. You only have this chance to initialize your code here or it will be changed by the other component. + * * @param context * @param object * @param view */ - @Override - public void onCreatedView(@NonNull FragmentActivity context, @NonNull Object object, @NonNull View view) { - } - - /** - * The priority in the component queue. If you want your component run before others - * @return - */ - @Override - public int getComponentPriority() { - return 0; - } + override fun onCreatedView(context: AppCompatActivity, `object`: Any, view: View) {} } - ``` ### Some component We already have @@ -121,7 +121,7 @@ public class BorderComponent implements ComponentContainer { #### *Component List* ``` -//SourceCode:library/com.cz.android.sample.library.component +//SourceCode:extension/com.github.jackchen.sample.library.component |-- code |-- document |-- memory diff --git a/document/sample-processor.md b/document/sample-processor.md new file mode 100644 index 0000000..5deb5f1 --- /dev/null +++ b/document/sample-processor.md @@ -0,0 +1,63 @@ +## ActionProcessor +For a sample library. We are not going to just demonstrate Activity or Fragment. But sometimes display a dialog or something just print a message. +Long before this version. I believe this is good enough. But one day one of my friends told me. I have a Dialog library. All I want is to click the title and display the dialog. +Then that makes me start try to abstract the action. Here is how we support this function. + + +``` +public abstract class ActionProcessor { + /** + * consider if you want to process this item. usually is class object. HowEver It will be an custom object. + */ + public abstract boolean isAvailable(Class clazz); + + /** + * process the register configuration + * + * @param context Android context object. Here you is an FragmentActivity. + * @param sampleItem the one that you register which is all the information you could use + * @throws Exception when you execute an action failed throw an exception + */ + public abstract void execute(AppCompatActivity context, SampleItem sampleItem) throws SampleFailedException; +} +``` + +This is how we support `Activity` + +``` +public class ActivityClassActionProcessor extends ActionProcessor { + @Override public boolean isAvailable(final Class clazz) { + return Activity.class.isAssignableFrom(clazz); + } + + @Override public void execute(final AppCompatActivity context, final SampleItem sampleItem) + throws SampleFailedException { + Class clazz = sampleItem.clazz(); + Intent intent = new Intent(context, clazz); + intent.putExtra(SampleConstants.PARAMETER_TITLE, sampleItem.title); + intent.putExtra(SampleConstants.PARAMETER_DESC, sampleItem.desc); + context.startActivity(intent); + } +} + +``` + +Quite easy, right? + +Here is a demo to support AlertDialog instance + +``` +@Extension +public class AlertDialogActionProcessor extends SampleInterfaceProcessor { + @Override public void execute(final AppCompatActivity context, final AlertDialog dialog) + throws SampleFailedException { + dialog.show(); + } +} +``` + +You can check the [demo](../app/src/main/java/com/github/jackchen/sample/dialog/DialogSample.kt) for more details. + +The annotation class `Extension` is to register this processor as an extension. + + diff --git a/document/todo.md b/document/todo.md deleted file mode 100644 index 802ac1f..0000000 --- a/document/todo.md +++ /dev/null @@ -1 +0,0 @@ -## TODO diff --git a/document/usage.md b/document/usage.md deleted file mode 100644 index 61923d8..0000000 --- a/document/usage.md +++ /dev/null @@ -1,113 +0,0 @@ -## Usage - -* About runtime permission request - -``` -//What kind of permission you would like to have. -@SamplePermission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE) -class SamplePermissionActivity : AppCompatActivity(){ - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_function_permission_sample) - - //Add an observer, when the permission request got a response you will receive the result. - //Because we use ViewModel, So you do not have to release the resources mannally. - PermissionViewModelProviders.getViewModel(this).addObserver { result-> - if(result.granted){ - val text = getString(R.string.permission_granted, result.name) - Toast.makeText(applicationContext,text, Toast.LENGTH_SHORT).show() - } else { - val text = getString(R.string.permission_denied, result.name) - Toast.makeText(applicationContext,text, Toast.LENGTH_SHORT).show() - } - } - } -} -``` - -* Display a list - -``` -//Simple list adapter for RecyclerView -val dataProvider = DataManager.getDataProvider(this) -val simpleArrayAdapter = SimpleArrayAdapter(this, dataProvider.wordList) - -//Simple fragment adapter for ViewPager. -val fragmentList=mutableListOf(...) -val adapter=SimpleFragmentPagerAdapter(fragmentList) - -``` - -* About the test data -``` -val dataProvider = DataManager.getDataProvider(this) -//Noticed we only have about 600 English test words. -//Ask for one word -dataProvider.word -//Ask for a bunch of word. -dataProvider.getWordList(10) -//From index ten return on hundred testing word. -dataProvider.getWordList(10,100) - -//local image urls. -val imageArray = dataProvider.imageArray -//another way to fetch image urls. -val imageAnalyzer=ImageAnalyzer() -imageAnalyzer.setDataSource(HtmlSource()) -val imageUrlList=imageAnalyzer.analysis(this,"http://xxx") - -//For color resources. -val color = DataProvider.getColor() -//All the material blue color. -val colorArray = dataProvider.getColorArray(DataProvider.COLOR_BLUE_GREY) -``` - -* About color resources -I already defined all of the martial color resources. -``` - - -#FFEBEE -#FFCDD2 -#EF9A9A -#E57373 -#EF5350 -#F44336 -#E53935 -#D32F2F -#C62828 -#B71C1C -#FF8A80 -#FF5252 -#FF1744 -#D50000 - - -#FCE4EC -#F8BBD0 -#F48FB1 -#F06292 -#EC407A -#E91E63 -#D81B60 -#C2185B -#AD1457 -#880E4F -#FF80AB -#FF4081 -#F50057 -#C51162 -[...] -``` - -* Display the output message. -Firstly, Configure the annotation: @SampleMessage in your sample class. -Than, Use the System.out.println("xxx) instead of Log. You will have your own panel to display the message. - - -* Display the source code use @SampleSourceCode - -* Display the memory panel. Maybe is not correct. use @SampleMemory -