├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ ├── Apache_v2_0.xml │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── scopes │ └── Shared_Scope.xml └── vcs.xml ├── CHANGELOG.md ├── README.md ├── actionhandler ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── drextended │ │ └── actionhandler │ │ ├── ActionArgs.java │ │ ├── ActionHandler.java │ │ ├── ActionPair.java │ │ ├── ActionParams.java │ │ ├── action │ │ ├── Action.java │ │ ├── ActionFactory.java │ │ ├── BaseAction.java │ │ ├── Cancelable.java │ │ ├── CompositeAction.java │ │ ├── DialogAction.java │ │ ├── IntentAction.java │ │ ├── RequestAction.java │ │ ├── RxRequestAction.java │ │ ├── SingleActionFactory.java │ │ └── SingleActionFactoryAdapter.java │ │ ├── listener │ │ ├── ActionCallback.java │ │ ├── ActionClickListener.java │ │ ├── ActionFireInterceptor.java │ │ ├── ActionInterceptor.java │ │ ├── OnActionDismissListener.java │ │ ├── OnActionErrorListener.java │ │ └── OnActionFiredListener.java │ │ └── util │ │ ├── AUtils.java │ │ ├── AcceptCondition.java │ │ ├── Converters.java │ │ ├── DebounceHelper.java │ │ ├── ProgressBarController.java │ │ └── ViewOnActionClickListener.java │ └── res │ ├── layout │ └── item_menu_composit_action.xml │ └── values │ ├── ids.xml │ └── strings.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── samples ├── databinding │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── drextended │ │ │ └── databinding │ │ │ ├── ActionType.java │ │ │ ├── action │ │ │ ├── OpenSecondActivity.java │ │ │ ├── SampleRequestAction.java │ │ │ ├── SampleRxRequestAction.java │ │ │ ├── ShowToastAction.java │ │ │ ├── SimpleAnimationAction.java │ │ │ └── TrackAction.java │ │ │ ├── view │ │ │ ├── MainActivity.java │ │ │ └── SecondActivity.java │ │ │ └── viewmodel │ │ │ ├── BaseViewModel.java │ │ │ └── MainActivityViewModel.java │ │ └── res │ │ ├── drawable │ │ ├── ic_announcement_black_24dp.xml │ │ ├── ic_cloud_upload_black_24dp.xml │ │ └── ic_touch_app_black_24dp.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── activity_second.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml └── simple-handling │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── drextended │ │ └── actionhandlersample │ │ ├── ActionType.java │ │ ├── action │ │ ├── OpenSecondActivity.java │ │ ├── SampleRequestAction.java │ │ ├── ShowToastAction.java │ │ ├── SimpleAnimationAction.java │ │ └── TrackAction.java │ │ └── activity │ │ ├── MainActivity.java │ │ └── SecondActivity.java │ └── res │ ├── drawable │ ├── ic_announcement_black_24dp.xml │ ├── ic_cloud_upload_black_24dp.xml │ └── ic_touch_app_black_24dp.xml │ ├── layout │ ├── activity_main.xml │ └── activity_second.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/Apache_v2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 42 | 59 | 60 | 61 | 62 | 63 | 64 | 66 | 67 | 68 | 69 | 70 | 71 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/scopes/Shared_Scope.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.1.3 (2018-06-07) 2 | 3 | * add ActionFactory for lazy instantiation actions 4 | 5 | ## 2.1.2 (2018-04-18) 6 | 7 | * fix bug introduced in v2.1.1 8 | 9 | ## 2.1.1 (2018-04-18) 10 | 11 | * add global callback to help you set all listeners and interceptors using just one method. Use `addCallback(callback)`. 12 | * fix: call `interceptActionFire` with action which it was added with. 13 | * fix bug when listeners was called more than once if the same instance of action was added few times in different CompositeActions or DialogWrappers. 14 | 15 | ## 2.1.0 (2018-04-06) 16 | 17 | * Update android support libs version to 27.1.1 18 | * Recompiled with android.databinding.enableV2=true and gradle plugin 3.1.0 19 | 20 | ## 2.0.0 (2018-02-21) 21 | 22 | * Update android support libs version to 25.4.0 and rxjava to 2.1.8 23 | * Recompiled with android.databinding.enableV2=true 24 | 25 | ## 2.0.1 (2018-02-21) 26 | * Fix complation for android.databinding.enableV2=true -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ActionHandler 2 | 3 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-ActionHandler-green.svg?style=true)](https://android-arsenal.com/details/1/3841) 4 | [![Download](https://api.bintray.com/packages/drstranges/android-extended/action-handler/images/download.svg)](https://bintray.com/drstranges/android-extended/action-handler/_latestVersion) 5 | 6 | ## Overview 7 | 8 | This library intended to simplify the work with action handling in android projects. 9 | Just collect actions in a handler and bind them to views. 10 | 11 | Add library as gradle dependency 12 | 13 | ```gradle 14 | repositories { 15 | jcenter() 16 | } 17 | dependencies { 18 | //implement 'com.drextended.actionhandler:actionhandler:1.2.0' // <= compiled with android.databinding.enableV2=false 19 | implement 'com.drextended.actionhandler:actionhandler:2.1.3' // <= compiled with android.databinding.enableV2=true 20 | //implementation "com.android.support:appcompat-v7:27.1.1" 21 | //implementation "io.reactivex.rxjava2:rxandroid:2.0.1" 22 | //implementation "io.reactivex.rxjava2:rxjava:2.1.8" 23 | } 24 | ``` 25 | 26 | ## Features 27 | - `.IntentAction` - Action with Intent: start activity, satrt service, send broadcast. 28 | - `.DialogAction` - Aaction which shows simple dialog before it fired. 29 | - `.RequestAction` - Simple action which makes network request. 30 | - `.RxRequestAction` - Simple action which makes network requests with RxJava observable calls. 31 | - `.CompositeAction` - Composite action which can contain other actions inside and shows simple menu to choose one of them when fired. 32 | - Any custom actions... 33 | 34 | ## Usage 35 | 36 | **MainActivity.java** 37 | ```java 38 | mActionHandler = new ActionHandler.Builder() 39 | .addAction(null, new SimpleAnimationAction()) // Applied for any actionType 40 | .addAction(null, new TrackAction()) // Applied for any actionType 41 | .addAction(ActionType.OPEN_NEW_SCREEN, new OpenSecondActivity()) 42 | .addAction(ActionType.FIRE_ACTION, new ShowToastAction()) 43 | .addAction(ActionType.FIRE_DIALOG_ACTION, DialogAction.wrap(getString(R.string.action_dialog_message), new ShowToastAction())) 44 | .addAction(ActionType.FIRE_REQUEST_ACTION, new SampleRequestAction()) 45 | .addAction(ActionType.MENU, 46 | new CompositeAction(new CompositeAction.TitleProvider() { 47 | @Override 48 | public String getTitle(Context context, String model) { 49 | return "Title (" + model + ")"; 50 | } 51 | }, 52 | new ActionItem(ActionType.OPEN_NEW_SCREEN, new OpenSecondActivity(), R.string.menu_item_1), 53 | new ActionItem(ActionType.FIRE_ACTION, new ShowToastAction(), R.drawable.icon, R.color.tint, R.string.menu_item_2), 54 | )) 55 | //or by lazy 56 | .withFactory(actionType -> { 57 | switch(actionType) { 58 | case ActionType.SOME_ACTION: 59 | return new SomeAction(); 60 | } 61 | return null; 62 | }) 63 | .addActionInterceptor(this) 64 | .addActionFiredListener(this) 65 | .addActionErrorListener(this) 66 | .addActionDismissListener(this) 67 | .build(); 68 | 69 | ... 70 | // and then on view click 71 | mActionHandler.onActionClick(view, ActionType.OPEN_NEW_SCREEN, getSampleModel()); 72 | ``` 73 | with Data Binding 74 | 75 | **item_user.xml** 76 | ``` xml 77 | 78 | 79 | 82 | 83 | 86 | 87 | 88 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | ``` 101 | **Note:** RequestAction and RxRequestAction can show simple progress dialog. By default they use ProgressBarController, which should be initialized with Application instance to avoid WindowLeaked Errors. 102 | 103 | ``` 104 | public class Application extends android.app.Application { 105 | @Override 106 | public void onCreate() { 107 | super.onCreate(); 108 | ProgressBarController.init(this); 109 | } 110 | } 111 | ``` 112 | or 113 | ``` 114 | // Somewhere before first usage 115 | ProgressBarController.init((Application) getApplicationContext()); 116 | ``` 117 | 118 | License 119 | ======= 120 | 121 | Copyright 2016 Roman Donchenko 122 | 123 | Licensed under the Apache License, Version 2.0 (the "License"); 124 | you may not use this file except in compliance with the License. 125 | You may obtain a copy of the License at 126 | 127 | http://www.apache.org/licenses/LICENSE-2.0 128 | 129 | Unless required by applicable law or agreed to in writing, software 130 | distributed under the License is distributed on an "AS IS" BASIS, 131 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132 | See the License for the specific language governing permissions and 133 | limitations under the License. 134 | -------------------------------------------------------------------------------- /actionhandler/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /actionhandler/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | ext { 4 | libraryVersionMajor = 2 5 | libraryVersionMinor = 1 6 | libraryVersionRevision = 3 7 | 8 | libraryVersion = libraryVersionMajor + '.' + libraryVersionMinor + '.' + libraryVersionRevision 9 | 10 | bintrayRepo = 'android-extended' 11 | bintrayName = 'action-handler' 12 | 13 | publishedGroupId = 'com.drextended.actionhandler' 14 | libraryName = 'ActionHandler' 15 | artifact = 'actionhandler' 16 | 17 | libraryDescription = 'Easy action handling in your android project!' 18 | 19 | siteUrl = 'https://github.com/drstranges/ActionHandler' 20 | gitUrl = 'https://github.com/drstranges/ActionHandler.git' 21 | 22 | developerId = 'drstranges' 23 | developerName = 'Roman Donchenko' 24 | developerEmail = 'drstranges@gmail.com' 25 | 26 | licenseName = 'The Apache Software License, Version 2.0' 27 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 28 | allLicenses = ["Apache-2.0"] 29 | } 30 | 31 | android { 32 | compileSdkVersion rootProject.ext.compileSdkVersion 33 | 34 | dataBinding { 35 | enabled = true 36 | } 37 | 38 | defaultConfig { 39 | minSdkVersion 19 40 | targetSdkVersion rootProject.ext.targetSdkVersion 41 | versionCode libraryVersionRevision 42 | versionName libraryVersion 43 | } 44 | buildTypes { 45 | release { 46 | minifyEnabled false 47 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 48 | } 49 | } 50 | 51 | lintOptions { 52 | abortOnError false 53 | } 54 | } 55 | 56 | dependencies { 57 | implementation "androidx.annotation:annotation:$x_annotation_version" 58 | compileOnly "androidx.appcompat:appcompat:$x_appcompat_version" 59 | compileOnly "io.reactivex.rxjava2:rxjava:$rxjava2_version" 60 | compileOnly "io.reactivex.rxjava2:rxandroid:$rxandroid_version" 61 | 62 | } 63 | 64 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' 65 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle' 66 | 67 | task androidJavaDoc (type: Javadoc, dependsOn: "assembleRelease") { 68 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 69 | android.libraryVariants.all { variant -> 70 | if (variant.name == 'release') { 71 | owner.classpath += variant.javaCompile.classpath 72 | } 73 | } 74 | source = android.sourceSets.main.java.srcDirs 75 | exclude '**/R.html', '**/R.*.html', '**/index.html' 76 | } -------------------------------------------------------------------------------- /actionhandler/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android_Env\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /actionhandler/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/ActionArgs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import java.util.Objects; 23 | 24 | public class ActionArgs { 25 | 26 | /** 27 | * The actual action type that fires. If actionType is null, that action match to any actionType 28 | */ 29 | @Nullable 30 | public final String fireActionType; 31 | 32 | @NonNull 33 | public final ActionParams params; 34 | 35 | 36 | public ActionArgs(@NonNull ActionParams params, @Nullable String fireActionType) { 37 | this.params = params; 38 | this.fireActionType = fireActionType; 39 | } 40 | 41 | @Override 42 | public boolean equals(Object o) { 43 | if (this == o) return true; 44 | if (o == null || getClass() != o.getClass()) return false; 45 | ActionArgs that = (ActionArgs) o; 46 | return Objects.equals(fireActionType, that.fireActionType) && 47 | params.equals(that.params); 48 | } 49 | 50 | @Override 51 | public int hashCode() { 52 | return Objects.hash(fireActionType, params); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/ActionPair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.action.Action; 23 | 24 | /** 25 | * Holder for an action and corresponded type 26 | */ 27 | public class ActionPair { 28 | 29 | /** 30 | * If actionType is null, that action match to any actionType 31 | */ 32 | @Nullable 33 | public final String actionType; 34 | 35 | @NonNull 36 | public final Action action; 37 | 38 | public ActionPair(@Nullable String actionType, @NonNull Action action) { 39 | this.actionType = actionType; 40 | this.action = action; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) return true; 46 | if (o == null || getClass() != o.getClass()) return false; 47 | 48 | final ActionPair that = (ActionPair) o; 49 | 50 | if (actionType != null ? !actionType.equals(that.actionType) : that.actionType != null) 51 | return false; 52 | return action.equals(that.action); 53 | 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | int result = actionType != null ? actionType.hashCode() : 0; 59 | result = 31 * result + action.hashCode(); 60 | return result; 61 | } 62 | 63 | @NonNull 64 | @Override 65 | public String toString() { 66 | return "ActionPair{" + 67 | "actionType='" + actionType + '\'' + 68 | ", action=" + action + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/ActionParams.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler; 18 | 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.view.View; 22 | 23 | import androidx.annotation.NonNull; 24 | import androidx.annotation.Nullable; 25 | 26 | import com.drextended.actionhandler.util.ProgressBarController; 27 | import com.drextended.actionhandler.util.AUtils; 28 | 29 | import java.lang.ref.WeakReference; 30 | import java.util.HashMap; 31 | import java.util.Map; 32 | import java.util.Objects; 33 | 34 | public class ActionParams { 35 | 36 | @NonNull 37 | public final Context appContext; 38 | @NonNull 39 | public final WeakReference weakView; 40 | @NonNull 41 | public final String actionType; 42 | @Nullable 43 | public final Object model; 44 | @Nullable 45 | public final Object tag; 46 | @Nullable 47 | private Map payload; 48 | 49 | public ActionParams( 50 | @NonNull Context context, 51 | @Nullable View clickView, 52 | @NonNull String actionType, 53 | @Nullable Object model, 54 | @Nullable Object actionTag 55 | ) { 56 | this.appContext = context.getApplicationContext(); 57 | this.weakView = new WeakReference<>(clickView); 58 | this.actionType = actionType; 59 | this.model = model; 60 | this.tag = actionTag; 61 | } 62 | 63 | @NonNull 64 | public Object requireModel() { 65 | if (model == null) { 66 | throw new IllegalStateException("model is null"); 67 | } 68 | return model; 69 | } 70 | 71 | @Nullable 72 | public View tryGetView() { 73 | return weakView.get(); 74 | } 75 | 76 | @NonNull 77 | public Context getViewOrAppContext() { 78 | View view = weakView.get(); 79 | if (view != null) { 80 | Context viewContext = view.getContext(); 81 | if (viewContext != null) { 82 | Activity activity = AUtils.getActivity(viewContext); 83 | if (activity == null || !(activity.isFinishing() || activity.isDestroyed())) { 84 | return viewContext; 85 | } 86 | } 87 | } 88 | return appContext; 89 | } 90 | 91 | @Nullable 92 | public Activity tryGetActivity() { 93 | View view = weakView.get(); 94 | if (view != null) { 95 | return AUtils.getActivity(view.getContext()); 96 | } 97 | return null; 98 | } 99 | 100 | @Nullable 101 | public T getTag(@NonNull Class clazz) { 102 | if (clazz.isInstance(tag)) { 103 | //noinspection unchecked 104 | return (T) tag; 105 | } 106 | return null; 107 | } 108 | 109 | @Nullable 110 | public Map getPayload() { 111 | return payload; 112 | } 113 | 114 | public void setPayload(@Nullable Map payload) { 115 | this.payload = payload; 116 | } 117 | 118 | public void putPayload(@NonNull Object key, @NonNull String value) { 119 | requirePayload().put(key, value); 120 | } 121 | 122 | public void removePayload(@NonNull Object key) { 123 | if (payload != null) payload.remove(key); 124 | } 125 | 126 | @Nullable 127 | public Object getPayload(@NonNull Object key) { 128 | if (payload != null) { 129 | return payload.get(key); 130 | } 131 | return null; 132 | } 133 | 134 | @Nullable 135 | public T getPayload(@NonNull Object key, @NonNull Class clazz) { 136 | return getPayloadInternal(key, clazz, null); 137 | } 138 | 139 | @NonNull 140 | public T getPayload(@NonNull Object key, @NonNull Class clazz, @NonNull T defaultValue) { 141 | //noinspection ConstantConditions 142 | return getPayloadInternal(key, clazz, defaultValue); 143 | } 144 | 145 | @Nullable 146 | private T getPayloadInternal(@NonNull Object key, @NonNull Class clazz, @Nullable T defaultValue) { 147 | if (payload != null) { 148 | Object value = payload.get(key); 149 | if (value != null && clazz.isInstance(value)) { 150 | //noinspection unchecked 151 | return (T) value; 152 | } 153 | } 154 | return defaultValue; 155 | } 156 | 157 | @NonNull 158 | public Map requirePayload() { 159 | if (payload == null) { 160 | payload = new HashMap<>(); 161 | } 162 | return payload; 163 | } 164 | 165 | @Override 166 | public boolean equals(Object o) { 167 | if (this == o) return true; 168 | if (o == null || getClass() != o.getClass()) return false; 169 | ActionParams that = (ActionParams) o; 170 | return actionType.equals(that.actionType) && 171 | Objects.equals(model, that.model) && 172 | Objects.equals(tag, that.tag) && 173 | Objects.equals(payload, that.payload); 174 | } 175 | 176 | @Override 177 | public int hashCode() { 178 | return Objects.hash(actionType, model, tag); 179 | } 180 | 181 | @Override 182 | @NonNull 183 | public String toString() { 184 | return "ActionParams{" + 185 | "actionType='" + actionType + '\'' + 186 | ", model=" + model + 187 | ", tag=" + tag + 188 | ", payload=" + payload + 189 | '}'; 190 | } 191 | 192 | public T getModel(Class expectedClass) { 193 | if (model != null && expectedClass.isInstance(expectedClass)) { 194 | //noinspection unchecked 195 | return (T) model; 196 | } 197 | return null; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/Action.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.ActionArgs; 23 | 24 | /** 25 | * Base Interface for any action 26 | */ 27 | public interface Action { 28 | 29 | /** 30 | * Check if action can handle given model 31 | * 32 | * @param model The model to check if it can be handled. 33 | * @return true if the action can handle this model, false otherwise. 34 | */ 35 | boolean isModelAccepted(@Nullable Object model); 36 | 37 | 38 | /** 39 | * Executes the action. Should be called only if {@link #isModelAccepted(Object)} return true 40 | * 41 | * @param args The action params, which appointed to the view 42 | * and type of the action which was actually executed. 43 | */ 44 | void onFireAction(@NonNull ActionArgs args); 45 | } 46 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/ActionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | /** 23 | * Used by ActionHandler for lazy instantiating actions. 24 | */ 25 | public interface ActionFactory { 26 | 27 | /** 28 | * Called when ActionHandler have not had the action to handle given actionType yet. 29 | * When ActionHandler already have the action for the actionType, this method will not be called 30 | * 31 | * @param actionType the actionType to handle 32 | * @return actions which can handle given action type 33 | */ 34 | @Nullable 35 | Action[] provideActions(@NonNull String actionType); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/BaseAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.drextended.actionhandler.action; 17 | 18 | import androidx.annotation.NonNull; 19 | import androidx.annotation.Nullable; 20 | 21 | import com.drextended.actionhandler.ActionArgs; 22 | import com.drextended.actionhandler.ActionParams; 23 | import com.drextended.actionhandler.listener.ActionFireInterceptor; 24 | import com.drextended.actionhandler.listener.OnActionDismissListener; 25 | import com.drextended.actionhandler.listener.OnActionErrorListener; 26 | import com.drextended.actionhandler.listener.OnActionFiredListener; 27 | 28 | import java.util.HashSet; 29 | import java.util.Set; 30 | 31 | /** 32 | * Extent from BaseAction all you custom actions. 33 | * BaseAction contain base logic to notify listeners if action fired. 34 | * 35 | */ 36 | public abstract class BaseAction implements Action { 37 | 38 | /** 39 | * Listeners for action fired events. 40 | */ 41 | protected Set mActionFiredListeners = new HashSet<>(1); 42 | 43 | /** 44 | * Listeners for action error events. 45 | */ 46 | protected Set mActionErrorListeners = new HashSet<>(1); 47 | 48 | /** 49 | * Listeners for action dismiss events. 50 | */ 51 | protected Set mActionDismissListeners = new HashSet<>(1); 52 | 53 | /** 54 | * Callbacks to be invoked after a view with an action is clicked and before action handling started. 55 | * Can intercept an action to prevent it to be fired 56 | */ 57 | protected Set mActionFireInterceptors = new HashSet<>(1); 58 | 59 | /** 60 | * Add a listener that will be called when method {@link #notifyOnActionFired(ActionArgs)} 61 | * called. Generally if action fired successfully. 62 | * 63 | * @param listener The listener that will be called when action fired successfully. 64 | */ 65 | public void addActionFiredListener(OnActionFiredListener listener) { 66 | if (listener != null) mActionFiredListeners.add(listener); 67 | } 68 | 69 | /** 70 | * Remove a listener for action fired events. 71 | * 72 | * @param listener The listener for action fired events. 73 | */ 74 | public void removeActionFireListener(OnActionFiredListener listener) { 75 | if (listener != null) mActionFiredListeners.remove(listener); 76 | } 77 | 78 | /** 79 | * Remove all listeners for action fired events. 80 | */ 81 | public void removeAllActionFireListeners() { 82 | mActionFiredListeners.clear(); 83 | } 84 | 85 | 86 | /** 87 | * Add a listener that will be called when method {@link #notifyOnActionError(ActionArgs, Throwable)} 88 | * called. Generally if action fired with error. 89 | * 90 | * @param listener The listener that will be called when action fired with error. 91 | */ 92 | public void addActionErrorListener(OnActionErrorListener listener) { 93 | if (listener != null) mActionErrorListeners.add(listener); 94 | } 95 | 96 | /** 97 | * Remove a listener for action error events. 98 | * 99 | * @param listener The listener for action error events. 100 | */ 101 | public void removeActionErrorListener(OnActionErrorListener listener) { 102 | if (listener != null) mActionErrorListeners.remove(listener); 103 | } 104 | 105 | /** 106 | * Remove all listeners for action error events. 107 | */ 108 | public void removeAllActionErrorListeners() { 109 | mActionErrorListeners.clear(); 110 | } 111 | 112 | /** 113 | * Add a listener that will be called when method {@link #notifyOnActionDismiss(ActionArgs, String)} 114 | * called. Generally if action was dismissed by user. 115 | * 116 | * @param listener The listener that will be called when action dismissed. 117 | */ 118 | public void addActionDismissListener(OnActionDismissListener listener) { 119 | if (listener != null) mActionDismissListeners.add(listener); 120 | } 121 | 122 | /** 123 | * Remove a listener for action dismiss events. 124 | * 125 | * @param listener The listener for action dismiss events. 126 | */ 127 | public void removeActionDismissListener(OnActionDismissListener listener) { 128 | if (listener != null) mActionDismissListeners.remove(listener); 129 | } 130 | 131 | /** 132 | * Remove all listeners for action dismiss events. 133 | */ 134 | public void removeAllActionDismissListeners() { 135 | mActionDismissListeners.clear(); 136 | } 137 | 138 | /** 139 | * Add callback to be invoked right before specific action will be fired. 140 | * Can intercept an action to prevent it to be fired 141 | * 142 | * @param interceptor The interceptor. 143 | */ 144 | public void addActionFireInterceptor(ActionFireInterceptor interceptor) { 145 | if (interceptor != null) mActionFireInterceptors.add(interceptor); 146 | } 147 | 148 | /** 149 | * Remove interceptor. 150 | * 151 | * @param interceptor The interceptor. 152 | */ 153 | public void removeActionFireInterceptor(ActionFireInterceptor interceptor) { 154 | if (interceptor != null) mActionFireInterceptors.remove(interceptor); 155 | } 156 | 157 | /** 158 | * Remove all interceptors. 159 | */ 160 | public void removeAllActionFireInterceptors() { 161 | mActionFireInterceptors.clear(); 162 | } 163 | 164 | /** 165 | * Remove all listeners for action fire, error and dismiss events. 166 | */ 167 | public void removeAllActionListeners() { 168 | mActionFiredListeners.clear(); 169 | mActionErrorListeners.clear(); 170 | mActionDismissListeners.clear(); 171 | mActionFireInterceptors.clear(); 172 | } 173 | 174 | 175 | /** 176 | * Notify any registered listeners that the action has been fired. 177 | * 178 | * @param args The action params, which used while firing action 179 | */ 180 | public void notifyOnActionFired(@NonNull ActionArgs args) { 181 | notifyOnActionFired(args, null); 182 | } 183 | 184 | /** 185 | * Notify any registered listeners that the action has been fired. 186 | * 187 | * @param args The action params, which used while firing action 188 | * @param result The result of action 189 | */ 190 | public void notifyOnActionFired(@NonNull ActionArgs args, @Nullable Object result) { 191 | for (OnActionFiredListener listener : mActionFiredListeners) { 192 | listener.onActionFired(args, result); 193 | } 194 | } 195 | 196 | /** 197 | * Notify any registered listeners that the action has been executed with error. 198 | * 199 | * @param args The action params, which used while firing action 200 | * @param throwable The error 201 | */ 202 | public void notifyOnActionError(@NonNull ActionArgs args, @Nullable Throwable throwable) { 203 | for (OnActionErrorListener listener : mActionErrorListeners) { 204 | listener.onActionError(args, throwable); 205 | } 206 | } 207 | 208 | /** 209 | * Notify any registered listeners that the action has been executed with error. 210 | * 211 | * @param reason The reason to dismiss 212 | * @param args The action params, which used while firing action 213 | */ 214 | public void notifyOnActionDismiss(@NonNull ActionArgs args, @Nullable String reason) { 215 | for (OnActionDismissListener listener : mActionDismissListeners) { 216 | listener.onActionDismiss(args, reason); 217 | } 218 | } 219 | 220 | protected boolean interceptActionFire( 221 | @NonNull ActionParams actionParams, 222 | @NonNull String actionType, 223 | @NonNull Action action 224 | ) { 225 | if (mActionFireInterceptors != null) { 226 | for (ActionFireInterceptor interceptor : mActionFireInterceptors) { 227 | if (interceptor.onInterceptActionFire(actionParams, actionType, action)) 228 | return true; 229 | } 230 | } 231 | return false; 232 | } 233 | } -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/Cancelable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import com.drextended.actionhandler.ActionHandler; 20 | 21 | /** 22 | * Defines an interface for actions that can (or need to) be cancelled. For example, if they 23 | * are not used any longer or if ActionHandler will be recreated and all old actions has to be cancelled. 24 | * For actions collected by {@link ActionHandler} this method can be called by {@link ActionHandler#cancelAll()} 25 | */ 26 | public interface Cancelable { 27 | 28 | /** 29 | * Cancel any action once this method is called. 30 | * For actions collected by {@link ActionHandler} this method can be called by {@link ActionHandler#cancelAll()} 31 | */ 32 | void cancel(); 33 | } 34 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/DialogAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import android.app.Dialog; 20 | import android.content.Context; 21 | import android.content.DialogInterface; 22 | import android.view.View; 23 | 24 | import androidx.annotation.NonNull; 25 | import androidx.appcompat.app.AlertDialog; 26 | 27 | import com.drextended.actionhandler.ActionArgs; 28 | import com.drextended.actionhandler.ActionParams; 29 | import com.drextended.actionhandler.listener.ActionFireInterceptor; 30 | import com.drextended.actionhandler.listener.OnActionDismissListener; 31 | import com.drextended.actionhandler.listener.OnActionErrorListener; 32 | import com.drextended.actionhandler.listener.OnActionFiredListener; 33 | 34 | /** 35 | * Can be used for make an action which show simple dialog before it has been fired. 36 | * You can extend this class for make custom action on just wrap another action 37 | * using {@link #wrap(String, Action)} 38 | * 39 | * @param type of model to handle 40 | */ 41 | @SuppressWarnings("SameParameterValue") 42 | public abstract class DialogAction extends BaseAction { 43 | 44 | @Override 45 | public void onFireAction(@NonNull ActionArgs args) { 46 | final Dialog dialog = createDialog(args); 47 | dialog.show(); 48 | } 49 | 50 | /** 51 | * Creates dialog for showing before call {@link #onDialogActionFire}. 52 | * By default contains: 53 | * - title, obtained by {@link #getDialogTitle(ActionParams)}, 54 | * - message, obtained by {@link #getDialogMessage(ActionParams)}, 55 | * - negative button with label, obtained by {@link #getNegativeButtonTitleResId()}, 56 | * which refuse action by click, 57 | * - positive button with label, obtained by {@link #getPositiveButtonTitleResId()}, 58 | * which call {@link #onDialogActionFire} by click 59 | * 60 | * @param args The action params, which appointed to the view and actually actionType 61 | * @return the dialog to show before call {@link #onDialogActionFire}. 62 | */ 63 | protected Dialog createDialog(@NonNull final ActionArgs args) { 64 | final String title = getDialogTitle(args.params); 65 | final AlertDialog.Builder builder = new AlertDialog.Builder(args.params.getViewOrAppContext()); 66 | if (title != null) builder.setTitle(title); 67 | builder.setMessage(getDialogMessage(args.params)) 68 | .setNegativeButton(getNegativeButtonTitleResId(), new DialogInterface.OnClickListener() { 69 | @Override 70 | public void onClick(DialogInterface dialog, int which) { 71 | notifyOnActionDismiss(args, "Dialog cancelled"); 72 | } 73 | }) 74 | .setPositiveButton(getPositiveButtonTitleResId(), new DialogInterface.OnClickListener() { 75 | @Override 76 | public void onClick(DialogInterface dialog, int which) { 77 | onDialogActionFire(args); 78 | } 79 | }) 80 | .setOnCancelListener(new DialogInterface.OnCancelListener() { 81 | @Override 82 | public void onCancel(DialogInterface dialog) { 83 | notifyOnActionDismiss(args, "Dialog cancelled"); 84 | } 85 | }); 86 | return builder.create(); 87 | } 88 | 89 | /** 90 | * Provides title for dialog 91 | * 92 | * @param params The action params, which appointed to the view 93 | * @return title for dialog 94 | */ 95 | protected String getDialogTitle(@NonNull ActionParams params) { 96 | return null; 97 | } 98 | 99 | /** 100 | * Provides message for dialog 101 | * 102 | * @param params The action params, which appointed to the view 103 | * @return message for dialog 104 | */ 105 | protected abstract String getDialogMessage(@NonNull ActionParams params); 106 | 107 | /** 108 | * Provides resource id of the text to display in the positive button. 109 | * Set android.R.string.ok by default. 110 | * 111 | * @return resource id of the text to display in the positive button. 112 | */ 113 | protected int getPositiveButtonTitleResId() { 114 | return android.R.string.ok; 115 | } 116 | 117 | /** 118 | * Provides resource id of the text to display in the negative button. 119 | * Set android.R.string.cancel by default. 120 | * 121 | * @return resource id of the text to display in the negative button. 122 | */ 123 | protected int getNegativeButtonTitleResId() { 124 | return android.R.string.cancel; 125 | } 126 | 127 | /** 128 | * Executes the action. Called if positive button on a dialog was clicked. 129 | * 130 | * @param args The action params, which appointed to the view and actually actionType 131 | */ 132 | protected void onDialogActionFire(@NonNull final ActionArgs args) { 133 | } 134 | 135 | /** 136 | * Wrap {@link Action} so that it can show dialog before fired. 137 | * 138 | * @param dialogMessage The message for dialog to show on action fire 139 | * @param action The action to fire if positive button on the dialog clicked 140 | * @param Type of model which can be handled 141 | * @return the action which can show dialog before fired. 142 | */ 143 | public static DialogAction wrap(String dialogMessage, Action action) { 144 | return new DialogActionWrapper<>(dialogMessage, action); 145 | } 146 | 147 | /** 148 | * The wrapper class for any type of action so that it can be used as {@link DialogAction} 149 | * 150 | * @param 151 | */ 152 | private static class DialogActionWrapper extends DialogAction { 153 | private final Action mAction; 154 | private final String mDialogMessage; 155 | 156 | /** 157 | * Wrap {@link Action} so that it can show dialog before fired. 158 | * 159 | * @param dialogMessage The message for dialog to show on action fire 160 | * @param action The action to fire if positive button on the dialog clicked 161 | */ 162 | public DialogActionWrapper(String dialogMessage, Action action) { 163 | super(); 164 | mAction = action; 165 | mDialogMessage = dialogMessage; 166 | } 167 | 168 | @Override 169 | protected String getDialogMessage(@NonNull ActionParams params) { 170 | return mDialogMessage; 171 | } 172 | 173 | @Override 174 | protected void onDialogActionFire(@NonNull ActionArgs args) { 175 | if (mAction != null) mAction.onFireAction(args); 176 | } 177 | 178 | @Override 179 | public boolean isModelAccepted(Object model) { 180 | return mAction != null && mAction.isModelAccepted(model); 181 | } 182 | 183 | @Override 184 | public void addActionFiredListener(OnActionFiredListener listener) { 185 | super.addActionFiredListener(listener); 186 | if (mAction instanceof BaseAction) { 187 | ((BaseAction) mAction).addActionFiredListener(listener); 188 | } 189 | } 190 | 191 | @Override 192 | public void addActionErrorListener(OnActionErrorListener listener) { 193 | super.addActionErrorListener(listener); 194 | if (mAction instanceof BaseAction) { 195 | ((BaseAction) mAction).addActionErrorListener(listener); 196 | } 197 | } 198 | 199 | @Override 200 | public void addActionDismissListener(OnActionDismissListener listener) { 201 | super.addActionDismissListener(listener); 202 | if (mAction instanceof BaseAction) { 203 | ((BaseAction) mAction).addActionDismissListener(listener); 204 | } 205 | } 206 | 207 | @Override 208 | public void addActionFireInterceptor(ActionFireInterceptor interceptor) { 209 | super.addActionFireInterceptor(interceptor); 210 | if (mAction instanceof BaseAction) { 211 | ((BaseAction) mAction).addActionFireInterceptor(interceptor); 212 | } 213 | } 214 | 215 | @Override 216 | public void removeActionFireListener(OnActionFiredListener listener) { 217 | super.removeActionFireListener(listener); 218 | if (mAction instanceof BaseAction) { 219 | ((BaseAction) mAction).removeActionFireListener(listener); 220 | } 221 | } 222 | 223 | @Override 224 | public void removeAllActionFireListeners() { 225 | super.removeAllActionFireListeners(); 226 | if (mAction instanceof BaseAction) { 227 | ((BaseAction) mAction).removeAllActionFireListeners(); 228 | } 229 | } 230 | 231 | @Override 232 | public void removeActionErrorListener(OnActionErrorListener listener) { 233 | super.removeActionErrorListener(listener); 234 | if (mAction instanceof BaseAction) { 235 | ((BaseAction) mAction).removeActionErrorListener(listener); 236 | } 237 | } 238 | 239 | @Override 240 | public void removeAllActionErrorListeners() { 241 | super.removeAllActionErrorListeners(); 242 | if (mAction instanceof BaseAction) { 243 | ((BaseAction) mAction).removeAllActionFireListeners(); 244 | } 245 | } 246 | 247 | @Override 248 | public void removeActionDismissListener(OnActionDismissListener listener) { 249 | super.removeActionDismissListener(listener); 250 | if (mAction instanceof BaseAction) { 251 | ((BaseAction) mAction).removeActionDismissListener(listener); 252 | } 253 | } 254 | 255 | @Override 256 | public void removeAllActionDismissListeners() { 257 | super.removeAllActionDismissListeners(); 258 | if (mAction instanceof BaseAction) { 259 | ((BaseAction) mAction).removeAllActionDismissListeners(); 260 | } 261 | } 262 | 263 | @Override 264 | public void removeActionFireInterceptor(ActionFireInterceptor interceptor) { 265 | super.removeActionFireInterceptor(interceptor); 266 | if (mAction instanceof BaseAction) { 267 | ((BaseAction) mAction).removeActionFireInterceptor(interceptor); 268 | } 269 | } 270 | 271 | @Override 272 | public void removeAllActionFireInterceptors() { 273 | super.removeAllActionFireInterceptors(); 274 | if (mAction instanceof BaseAction) { 275 | ((BaseAction) mAction).removeAllActionFireListeners(); 276 | } 277 | } 278 | 279 | @Override 280 | public void removeAllActionListeners() { 281 | super.removeAllActionListeners(); 282 | if (mAction instanceof BaseAction) { 283 | ((BaseAction) mAction).removeAllActionListeners(); 284 | } 285 | } 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/IntentAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import android.content.ActivityNotFoundException; 20 | import android.content.Context; 21 | import android.content.Intent; 22 | import android.os.Bundle; 23 | import android.view.View; 24 | 25 | import androidx.annotation.NonNull; 26 | import androidx.annotation.Nullable; 27 | import androidx.core.app.ActivityOptionsCompat; 28 | import androidx.localbroadcastmanager.content.LocalBroadcastManager; 29 | 30 | import com.drextended.actionhandler.ActionArgs; 31 | import com.drextended.actionhandler.util.AcceptCondition; 32 | 33 | /** 34 | * Base action to fire some intent 35 | * 36 | * @param type of model, which can be handled 37 | */ 38 | public abstract class IntentAction extends BaseAction { 39 | /** 40 | * Type of intent: 41 | * {@link IntentType#START_ACTIVITY}, {@link IntentType#START_SERVICE} 42 | * {@link IntentType#SEND_BROADCAST}, {@link IntentType#SEND_LOCAL_BROADCAST} 43 | */ 44 | protected final IntentType mIntentType; 45 | 46 | public enum IntentType { 47 | START_ACTIVITY, 48 | START_SERVICE, 49 | STOP_SERVICE, 50 | SEND_BROADCAST, 51 | SEND_LOCAL_BROADCAST 52 | } 53 | 54 | public IntentAction() { 55 | mIntentType = IntentType.START_ACTIVITY; 56 | } 57 | 58 | public IntentAction(@NonNull IntentType intentType) { 59 | mIntentType = intentType; 60 | } 61 | 62 | @Override 63 | public void onFireAction(@NonNull final ActionArgs args) { 64 | final Intent intent = getIntent(args); 65 | if (intent == null) { 66 | notifyOnActionDismiss(args, "No intent to fire!"); 67 | return; 68 | } 69 | Context context = args.params.getViewOrAppContext(); 70 | try { 71 | switch (mIntentType) { 72 | case START_ACTIVITY: 73 | startActivity(context, intent, args); 74 | break; 75 | case START_SERVICE: 76 | startService(context, intent, args); 77 | break; 78 | case STOP_SERVICE: 79 | stopService(context, intent, args); 80 | break; 81 | case SEND_BROADCAST: 82 | sendBroadcast(context, intent, args); 83 | break; 84 | case SEND_LOCAL_BROADCAST: 85 | sendLocalBroadcast(context, intent, args); 86 | break; 87 | } 88 | 89 | notifyOnActionFired(args); 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | onError(args, e); 93 | } 94 | } 95 | 96 | /** 97 | * Route exceptions from {@link #startActivity}, {@link #startService(Context, Intent, ActionArgs)} and 98 | * {@link #stopService(Context, Intent, ActionArgs)} 99 | * Generally can be {@link ActivityNotFoundException} or {@link SecurityException} 100 | * 101 | * @param args The action params, which appointed to the view and actually actionType 102 | * @param throwable The exception, which was occurred while {@link #onFireAction(ActionArgs)} 103 | */ 104 | protected void onError(@NonNull ActionArgs args, @Nullable Exception throwable) { 105 | notifyOnActionError(args, throwable); 106 | } 107 | 108 | /** 109 | * If {@link #mIntentType} was set as {@link IntentType#START_ACTIVITY} 110 | * and {@link #getIntent(ActionArgs)} return not null then this method called. 111 | * 112 | * @param context The Context, which generally get from view by {@link View#getContext()} 113 | * @param intent The intent provided by {@link #getIntent(ActionArgs)} 114 | * @param args The action params, which appointed to the view and actually actionType 115 | */ 116 | protected void startActivity( 117 | @NonNull Context context, 118 | @NonNull Intent intent, 119 | @NonNull final ActionArgs args 120 | ) throws ActivityNotFoundException { 121 | context.startActivity(intent); 122 | } 123 | 124 | /** 125 | * Request that a given application service be started. 126 | * Override this method if you need specific behaviour. 127 | * 128 | * @param context The Context, which generally get from view by {@link View#getContext()} 129 | * @param intent The intent to start service, provided by {@link #getIntent(ActionArgs)} 130 | * @param args The action params, which appointed to the view and actually actionType 131 | */ 132 | protected void startService( 133 | @NonNull Context context, 134 | @NonNull Intent intent, 135 | @NonNull final ActionArgs args 136 | ) throws SecurityException { 137 | context.startService(intent); 138 | } 139 | 140 | /** 141 | * Request that a given application service be stopped 142 | * Override this method if you need specific behaviour 143 | * 144 | * @param context The Context, which generally get from view by {@link View#getContext()} 145 | * @param intent The intent to stop service, provided by {@link #getIntent(ActionArgs)} 146 | * @param args The action params, which appointed to the view and actually actionType 147 | */ 148 | protected void stopService( 149 | @NonNull Context context, 150 | @NonNull Intent intent, 151 | @NonNull final ActionArgs args 152 | ) throws SecurityException { 153 | context.stopService(intent); 154 | } 155 | 156 | /** 157 | * Broadcast the given intent to all interested BroadcastReceivers. 158 | * Override this method if you need specific behaviour. 159 | * 160 | * @param context The Context, which generally get from view by {@link View#getContext()} 161 | * @param intent The Intent to broadcast, provided by {@link #getIntent(ActionArgs)} 162 | * @param args The action params, which appointed to the view and actually actionType 163 | */ 164 | protected void sendBroadcast( 165 | @NonNull Context context, 166 | @NonNull Intent intent, 167 | @NonNull final ActionArgs args 168 | ) { 169 | context.sendBroadcast(intent); 170 | } 171 | 172 | /** 173 | * Broadcast the given intent to all interested BroadcastReceivers. 174 | * Override this method if you need specific behaviour. 175 | * 176 | * @param context The Context, which generally get from view by {@link View#getContext()} 177 | * @param intent The Intent to broadcast, provided by {@link #getIntent(ActionArgs)} 178 | * @param args The action params, which appointed to the view and actually actionType 179 | */ 180 | protected void sendLocalBroadcast( 181 | @NonNull Context context, 182 | @NonNull Intent intent, 183 | @NonNull final ActionArgs args 184 | ) { 185 | LocalBroadcastManager.getInstance(context).sendBroadcast(intent); 186 | } 187 | 188 | /** 189 | * Provide an intent for use for start activity, start service or send broadcast. 190 | * You cat define how to use this intent by setting {@link #mIntentType} in {@link #IntentAction(IntentType)} 191 | * 192 | * @param args The action params, which appointed to the view and actually actionType 193 | * @return intent for use in role defined by {@link #mIntentType} in {@link #IntentAction(IntentType)} 194 | * if null action will not be fired. 195 | */ 196 | @Nullable 197 | public abstract Intent getIntent(@NonNull final ActionArgs args); 198 | 199 | /** 200 | * Create simple intent action 201 | * 202 | * @param intent The intent to call 203 | * @param intentType Type of intent: 204 | * {@link IntentType#START_ACTIVITY}, {@link IntentType#START_SERVICE} 205 | * {@link IntentType#SEND_BROADCAST}, {@link IntentType#SEND_LOCAL_BROADCAST} 206 | * @param acceptCondition Condition to check whether model is accepted 207 | * @return The simple intent action 208 | */ 209 | public static IntentAction from(Intent intent, IntentType intentType, AcceptCondition acceptCondition) { 210 | return new SimpleIntentAction(intent, intentType, acceptCondition); 211 | } 212 | 213 | /** 214 | * Create simple intent action to start activity intent 215 | * 216 | * @param intent The intent to start activity. 217 | * Any model is accepted. 218 | * @return The simple intent action to start activity intent 219 | */ 220 | public static IntentAction from(Intent intent) { 221 | return new SimpleIntentAction(intent, IntentType.START_ACTIVITY, null); 222 | } 223 | 224 | /** 225 | * Simple intent action 226 | */ 227 | public static class SimpleIntentAction extends IntentAction { 228 | protected final Intent mIntent; 229 | protected final AcceptCondition mAcceptCondition; 230 | 231 | /** 232 | * @param intent The intent to call 233 | * @param intentType Type of intent: 234 | * {@link IntentType#START_ACTIVITY}, {@link IntentType#START_SERVICE} 235 | * {@link IntentType#SEND_BROADCAST}, {@link IntentType#SEND_LOCAL_BROADCAST} 236 | * @param acceptCondition Condition to check whether model is accepted 237 | */ 238 | public SimpleIntentAction(Intent intent, IntentType intentType, @Nullable AcceptCondition acceptCondition) { 239 | super(intentType != null ? intentType : IntentType.START_ACTIVITY); 240 | mIntent = intent; 241 | mAcceptCondition = acceptCondition; 242 | } 243 | 244 | @Override 245 | public boolean isModelAccepted(Object model) { 246 | return mAcceptCondition == null || mAcceptCondition.isModelAccepted(model); 247 | } 248 | 249 | @Nullable 250 | @Override 251 | public Intent getIntent(@NonNull ActionArgs args) { 252 | return mIntent; 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/RequestAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import androidx.annotation.CallSuper; 20 | import androidx.annotation.NonNull; 21 | import androidx.annotation.Nullable; 22 | 23 | import com.drextended.actionhandler.ActionArgs; 24 | import com.drextended.actionhandler.R; 25 | import com.drextended.actionhandler.util.ProgressBarController; 26 | 27 | /** 28 | * Base action for implementing call a network request 29 | * 30 | * @param The type of network response 31 | * @param The type of model which can be handled 32 | */ 33 | public abstract class RequestAction extends DialogAction { 34 | protected boolean mShowProgressEnabled; 35 | protected boolean mShowDialogEnabled; 36 | protected String mProgressTag; 37 | 38 | public RequestAction() { 39 | } 40 | 41 | /** 42 | * Base action for implementing call a network request 43 | * 44 | * @param showProgressEnabled Set true to show progress dialog while request 45 | * @param showDialogEnabled Set true to show dialog before action fired 46 | */ 47 | public RequestAction(boolean showProgressEnabled, boolean showDialogEnabled) { 48 | mShowProgressEnabled = showProgressEnabled; 49 | mShowDialogEnabled = showDialogEnabled; 50 | if (mShowProgressEnabled) mProgressTag = getClass().getSimpleName(); 51 | } 52 | 53 | /** 54 | * Set progress dialog enabled 55 | * 56 | * @param showProgressEnabled Set true to show progress dialog while request 57 | */ 58 | public void setShowProgressEnabled(boolean showProgressEnabled) { 59 | mShowProgressEnabled = showProgressEnabled; 60 | if (mProgressTag == null && mShowProgressEnabled) mProgressTag = getClass().getSimpleName(); 61 | } 62 | 63 | /** 64 | * Set dialog before action fired enabled 65 | * 66 | * @param showDialogEnabled Set true to show dialog before action fired 67 | */ 68 | public void setShowDialogEnabled(boolean showDialogEnabled) { 69 | mShowDialogEnabled = showDialogEnabled; 70 | } 71 | 72 | @Override 73 | public void onFireAction(@NonNull ActionArgs args) { 74 | if (mShowDialogEnabled) { 75 | super.onFireAction(args); 76 | } else { 77 | makeRequest(args); 78 | } 79 | } 80 | 81 | @Override 82 | protected void onDialogActionFire(@NonNull ActionArgs args) { 83 | makeRequest(args); 84 | } 85 | 86 | /** 87 | * Prepare and call a network request 88 | * 89 | * @param args The action params, which appointed to the view and actually actionType 90 | */ 91 | public void makeRequest(@NonNull ActionArgs args) { 92 | onRequestStarted(args); 93 | onMakeRequest(args); 94 | } 95 | 96 | /** 97 | * Called on request started. Shows progress dialog if enabled. 98 | * 99 | * @param args The action params, which appointed to the view and actually actionType 100 | */ 101 | protected void onRequestStarted(@NonNull ActionArgs args) { 102 | if (mShowProgressEnabled) showProgressDialog(args); 103 | } 104 | 105 | /** 106 | * Provides message for progress dialog 107 | * 108 | * @param args The action params, which appointed to the view and actually actionType 109 | * @return message for progress dialog 110 | */ 111 | protected String getProgressDialogMessage(@NonNull ActionArgs args) { 112 | return args.params.appContext.getString(R.string.action_handler_dialog_message_wait); 113 | } 114 | 115 | /** 116 | * Called on request has been fired successfully. 117 | * Hides progress dialog if enabled and call {@link #notifyOnActionFired} 118 | * Should be called manually in request callback. 119 | * 120 | * @param args The action params, which appointed to the view and actually actionType 121 | * @param response network response 122 | */ 123 | @CallSuper 124 | protected void onResponseSuccess(@NonNull ActionArgs args, @Nullable RM response) { 125 | if (mShowProgressEnabled) hideProgressDialog(); 126 | notifyOnActionFired(args, response); 127 | } 128 | 129 | /** 130 | * Call for show progress dialog 131 | * 132 | * @param args The action params, which appointed to the view and actually actionType 133 | */ 134 | public void showProgressDialog(@NonNull ActionArgs args) { 135 | ProgressBarController.showProgressDialog( 136 | args.params.getViewOrAppContext(), 137 | mProgressTag, 138 | getProgressDialogMessage(args) 139 | ); 140 | } 141 | 142 | /** 143 | * Call for hide progress dialog 144 | */ 145 | public void hideProgressDialog() { 146 | ProgressBarController.hideProgressDialog(mProgressTag); 147 | } 148 | 149 | /** 150 | * Called if request returns error. 151 | * Hides progress dialog if enabled 152 | * Should be called manually in request callback. 153 | * 154 | * @param args The action params, which appointed to the view and actually actionType 155 | * @param e The Error 156 | */ 157 | @CallSuper 158 | protected void onResponseError(@NonNull ActionArgs args, @NonNull Throwable e) { 159 | if (mShowProgressEnabled) hideProgressDialog(); 160 | notifyOnActionError(args, e); 161 | } 162 | 163 | /** 164 | * Implement network request there. 165 | * Note: You should call {@link #onResponseSuccess(ActionArgs, Object)} if request finished successfully 166 | * and {@link #onResponseError(ActionArgs, Throwable)} if it is failed. 167 | * 168 | * @param args The action params, which appointed to the view and actually actionType 169 | */ 170 | protected abstract void onMakeRequest(@NonNull ActionArgs args); 171 | 172 | } 173 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/RxRequestAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.ActionArgs; 23 | import com.drextended.actionhandler.ActionHandler; 24 | 25 | import io.reactivex.Maybe; 26 | import io.reactivex.MaybeSource; 27 | import io.reactivex.MaybeTransformer; 28 | import io.reactivex.android.schedulers.AndroidSchedulers; 29 | import io.reactivex.disposables.CompositeDisposable; 30 | import io.reactivex.disposables.Disposable; 31 | import io.reactivex.observers.DisposableMaybeObserver; 32 | import io.reactivex.schedulers.Schedulers; 33 | 34 | /** 35 | * Base action for implementing call a network request with RxJava Observable (ex. using Retrofit + RxJava) 36 | * 37 | * @param The type of network response 38 | * @param The type of model which can be handled 39 | */ 40 | @SuppressWarnings("SameParameterValue") 41 | public abstract class RxRequestAction extends RequestAction implements Cancelable { 42 | 43 | protected CompositeDisposable mDisposable; 44 | protected boolean mUnsubscribeOnNewRequest = true; 45 | 46 | public RxRequestAction() { 47 | } 48 | 49 | public RxRequestAction(boolean showProgressEnabled, boolean showDialog) { 50 | super(showProgressEnabled, showDialog); 51 | } 52 | 53 | public RxRequestAction(boolean showProgressEnabled, boolean showDialog, boolean unsubscribeOnNewRequest) { 54 | super(showProgressEnabled, showDialog); 55 | this.mUnsubscribeOnNewRequest = unsubscribeOnNewRequest; 56 | } 57 | 58 | @Override 59 | protected void onMakeRequest(@NonNull final ActionArgs args) { 60 | final Maybe observableRequest = getRequest(args); 61 | if (observableRequest == null) { 62 | if (mShowProgressEnabled) hideProgressDialog(); 63 | return; 64 | } 65 | if (mUnsubscribeOnNewRequest) { 66 | dispose(mDisposable); 67 | } 68 | if (mDisposable == null || mDisposable.isDisposed()) { 69 | mDisposable = new CompositeDisposable(); 70 | } 71 | mDisposable.add(observableRequest 72 | .compose(applySchedulers()) 73 | .subscribeWith(new DisposableMaybeObserver() { 74 | private volatile boolean hasResponse = false; 75 | 76 | @Override 77 | public void onSuccess(RM response) { 78 | hasResponse = true; 79 | onResponseSuccess(args, response); 80 | } 81 | 82 | @Override 83 | public void onError(Throwable e) { 84 | onResponseError(args, e); 85 | } 86 | 87 | @Override 88 | public void onComplete() { 89 | if (!hasResponse) { 90 | onResponseSuccess(args, null); 91 | } 92 | } 93 | })); 94 | } 95 | 96 | /** 97 | * Override this method if you want to apply custom schedulers for request flow. 98 | * By default {@code Schedulers.io()} applied for subscribeOn, 99 | * and {@code AndroidSchedulers.mainThread()} for observeOn. 100 | * 101 | * @return transformer for apply schedulers 102 | */ 103 | @NonNull 104 | protected MaybeTransformer applySchedulers() { 105 | return new MaybeTransformer() { 106 | @Override 107 | public MaybeSource apply(Maybe upstream) { 108 | return upstream.subscribeOn(Schedulers.io()) 109 | .observeOn(AndroidSchedulers.mainThread()); 110 | } 111 | }; 112 | } 113 | 114 | /** 115 | * Helper method to dispose the call 116 | * 117 | * @param disposable disposable to dispose 118 | */ 119 | protected void dispose(Disposable disposable) { 120 | if (disposable != null && !disposable.isDisposed()) disposable.dispose(); 121 | } 122 | 123 | /** 124 | * Unsubscribes from request observable once this method is called. 125 | * Override this if you need other behaviour. 126 | * For actions collected by {@link ActionHandler} this method can be called by {@link ActionHandler#cancelAll()} 127 | */ 128 | @Override 129 | public void cancel() { 130 | dispose(mDisposable); 131 | } 132 | 133 | /** 134 | * Implement network request observable there. 135 | * By default {@code Schedulers.io()} applied for subscribeOn, 136 | * and {@code AndroidSchedulers.mainThread()} for observeOn. If you want to apply custom schedulers 137 | * override {@link #applySchedulers()} 138 | * 139 | * @param args The action params, which appointed to the view and actually actionType 140 | * @return request observable. 141 | */ 142 | @Nullable 143 | protected abstract Maybe getRequest(@NonNull ActionArgs args); 144 | 145 | } 146 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/SingleActionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | /** 23 | * Used by ActionHandler for lazy instantiating actions. 24 | */ 25 | public interface SingleActionFactory { 26 | 27 | /** 28 | * Called when ActionHandler have not had the action to handle given actionType yet. 29 | * When ActionHandler already have the action for the actionType, this method will not be called 30 | * 31 | * @param actionType the actionType to handle 32 | * @return action which can handle given action type 33 | */ 34 | @Nullable 35 | Action provideAction(@NonNull String actionType); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/action/SingleActionFactoryAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.action; 18 | 19 | import androidx.annotation.NonNull; 20 | 21 | /** 22 | * Adapter for use {@link SingleActionFactory} as {@link ActionFactory} 23 | */ 24 | public class SingleActionFactoryAdapter implements ActionFactory { 25 | 26 | private final SingleActionFactory mFactory; 27 | 28 | public SingleActionFactoryAdapter(@NonNull SingleActionFactory factory) { 29 | mFactory = factory; 30 | } 31 | 32 | @Override 33 | public Action[] provideActions(@NonNull String actionType) { 34 | Action action = mFactory.provideAction(actionType); 35 | return action == null ? null : new Action[]{action}; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.listener; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.ActionArgs; 23 | import com.drextended.actionhandler.ActionParams; 24 | import com.drextended.actionhandler.action.Action; 25 | 26 | /** 27 | * One interface for all listeners and interceptors. 28 | */ 29 | public interface ActionCallback extends ActionInterceptor, ActionFireInterceptor, 30 | OnActionFiredListener, OnActionDismissListener, OnActionErrorListener { 31 | 32 | abstract class SimpleActionCallback implements ActionCallback { 33 | 34 | /** 35 | * @inheritDocs 36 | */ 37 | @Override 38 | public boolean onInterceptActionFire(@NonNull ActionParams actionParams, @Nullable String actionType, @NonNull Action action) { 39 | return false; 40 | } 41 | 42 | /** 43 | * @inheritDocs 44 | */ 45 | @Override 46 | public boolean onInterceptAction(@NonNull ActionParams params) { 47 | return false; 48 | } 49 | 50 | /** 51 | * @inheritDocs 52 | */ 53 | @Override 54 | public void onActionDismiss(@NonNull ActionArgs args, @Nullable String reason) { 55 | } 56 | 57 | /** 58 | * @inheritDocs 59 | */ 60 | @Override 61 | public void onActionError(@NonNull ActionArgs args, @Nullable Throwable throwable) { 62 | } 63 | 64 | /** 65 | * @inheritDocs 66 | */ 67 | @Override 68 | public void onActionFired(@NonNull ActionArgs args, @Nullable Object result) { 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionClickListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.listener; 18 | 19 | import android.view.View; 20 | 21 | import androidx.annotation.NonNull; 22 | import androidx.annotation.Nullable; 23 | 24 | /** 25 | * Interface definition for a callback to be invoked when a view with an action is clicked. 26 | */ 27 | public interface ActionClickListener { 28 | /** 29 | * Called when a view with an action is clicked. 30 | * 31 | * @param view The view that was clicked. 32 | * @param actionType The action type, which appointed to the view 33 | * @param model The model, which appointed to the view and should be handled 34 | * @param actionTag The tag, which can be used to distinct click source or etc. 35 | */ 36 | void onActionClick( 37 | @NonNull final View view, 38 | @Nullable final String actionType, 39 | @Nullable final Object model, 40 | @Nullable final Object actionTag 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionFireInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.listener; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.ActionPair; 23 | import com.drextended.actionhandler.ActionParams; 24 | import com.drextended.actionhandler.action.Action; 25 | 26 | /** 27 | * Interface definition for a callback to be invoked right before specific action will be fired. 28 | * If {@link #onInterceptActionFire(ActionParams, String, Action)} return true 29 | * then this action will not be fired. 30 | */ 31 | public interface ActionFireInterceptor { 32 | /** 33 | * Called right before specific action will be fired 34 | * If return true then this action will not be fired. 35 | * 36 | * @param actionParams The action params, which appointed to the view 37 | * @param actionType The action type, which is prepared to fire. 38 | * May be different from actionParams.actionType 39 | * when intercepted actionItem in CompositeAction 40 | * or when actionType of fired action is null that match to any 41 | * @param action The action, which is prepared to fire. 42 | * @return true for intercept the action, false to handle the action in normal way. 43 | */ 44 | boolean onInterceptActionFire( 45 | @NonNull ActionParams actionParams, 46 | @Nullable String actionType, 47 | @NonNull Action action 48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.listener; 18 | 19 | import androidx.annotation.NonNull; 20 | 21 | import com.drextended.actionhandler.ActionParams; 22 | 23 | /** 24 | * Interface definition for a callback to be invoked after a view with an action is clicked 25 | * and before action type handling started. If {@link #onInterceptAction(ActionParams)} return true 26 | * then this action type will not be handled. 27 | */ 28 | public interface ActionInterceptor { 29 | /** 30 | * Called after a view with an action is clicked 31 | * and before action handling started. If return true then this action will not be handled. 32 | * 33 | * @param params The actionParams 34 | * @return true for intercept the action, false to handle the action in normal way. 35 | */ 36 | boolean onInterceptAction(@NonNull ActionParams params); 37 | } 38 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/listener/OnActionDismissListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.listener; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.ActionArgs; 23 | 24 | /** 25 | * Interface definition for a callback to be invoked when an action was dismissed. 26 | */ 27 | public interface OnActionDismissListener { 28 | 29 | /** 30 | * Called when error occurred while an action is executing. 31 | * 32 | * @param args The action params, which appointed to the view 33 | * and actual fired action type 34 | * @param reason The reason to dismiss 35 | */ 36 | void onActionDismiss( 37 | @NonNull ActionArgs args, 38 | @Nullable String reason 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/listener/OnActionErrorListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.listener; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.ActionArgs; 23 | 24 | /** 25 | * Interface definition for a callback to be invoked when an action is executed with error. 26 | */ 27 | public interface OnActionErrorListener { 28 | 29 | /** 30 | * Called when error occurred while an action is executing. 31 | * 32 | * @param args The action params, which appointed to the view and actually actionType 33 | * @param throwable The error 34 | */ 35 | void onActionError( 36 | @NonNull ActionArgs args, 37 | @Nullable Throwable throwable 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/listener/OnActionFiredListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.listener; 18 | 19 | import androidx.annotation.NonNull; 20 | import androidx.annotation.Nullable; 21 | 22 | import com.drextended.actionhandler.ActionArgs; 23 | 24 | /** 25 | * Interface definition for a callback to be invoked when an action is executed successfully. 26 | */ 27 | public interface OnActionFiredListener { 28 | 29 | /** 30 | * Called after an action is executed successfully. 31 | * 32 | * @param args The action params, which used while firing action 33 | * @param result The result of action 34 | */ 35 | void onActionFired( 36 | @NonNull ActionArgs args, 37 | @Nullable Object result 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/util/AUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.util; 18 | 19 | import android.app.Activity; 20 | import android.app.Dialog; 21 | import android.content.Context; 22 | import android.content.ContextWrapper; 23 | import android.os.Build; 24 | 25 | import androidx.annotation.Nullable; 26 | 27 | public class AUtils { 28 | 29 | 30 | public static Activity getAliveActivity(@Nullable final Context context) { 31 | if (context != null) { 32 | Context baseContext = context; 33 | while (!(baseContext instanceof Activity) && baseContext instanceof ContextWrapper) { 34 | baseContext = ((ContextWrapper) baseContext).getBaseContext(); 35 | } 36 | if (baseContext instanceof Activity) { 37 | Activity activity = (Activity) baseContext; 38 | if (isAlive(activity) && !activity.isFinishing()) { 39 | return activity; 40 | } 41 | } 42 | } 43 | return null; 44 | } 45 | 46 | public static Activity getActivity(@Nullable final Context context) { 47 | if (context != null) { 48 | Context baseContext = context; 49 | while (!(baseContext instanceof Activity) && baseContext instanceof ContextWrapper) { 50 | baseContext = ((ContextWrapper) baseContext).getBaseContext(); 51 | } 52 | if (baseContext instanceof Activity) { 53 | return (Activity) baseContext; 54 | } 55 | } 56 | return null; 57 | } 58 | 59 | public static boolean isAlive(Dialog dialog) { 60 | return dialog != null && isAlive(getActivity(dialog.getContext())); 61 | } 62 | 63 | public static boolean isAlive(final Activity activity) { 64 | if (activity == null) return false; 65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 66 | return !activity.isDestroyed(); 67 | } 68 | return true; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/util/AcceptCondition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.util; 18 | 19 | /** 20 | * Provides interface to implement condition for checking whether model is accepted 21 | * Created by roman.donchenko on 22.02.2017. 22 | */ 23 | 24 | public interface AcceptCondition { 25 | boolean isModelAccepted(Object model); 26 | } 27 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/util/Converters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.util; 18 | 19 | import android.view.View; 20 | 21 | import androidx.databinding.BindingAdapter; 22 | 23 | import com.drextended.actionhandler.listener.ActionClickListener; 24 | 25 | /** 26 | * Helper class for collect all data binding adapters in one place 27 | */ 28 | public class Converters { 29 | 30 | /** 31 | * Binding adapter to assign an action to a view using android data binding approach. 32 | * Sample: 33 | *
34 |      * <Button
35 |      *     android:layout_width="wrap_content"
36 |      *     android:layout_height="wrap_content"
37 |      *
38 |      *     android:actionHandler="@{someActionHandler}"
39 |      *     android:actionType='@{"send_message"}'
40 |      *     android:actionTypeLongClick='@{"show_menu"}'
41 |      *     android:model="@{user}"
42 |      *     android:modelLongClick="@{userSettings}"
43 |      *     android:actionTag='@{"analytics_tag_1"}'
44 |      *
45 |      *     android:text="@string/my_button_text"/>
46 |      * 
47 | * 48 | * @param view The View to bind an action 49 | * @param actionHandler The action handler which will handle an action 50 | * @param actionType The action type, which will be handled on view clicked 51 | * @param actionTypeLongClick The action type, which will be handled on view long clicked 52 | * @param model The model which will be handled 53 | * @param modelLongClick The model which will be handled for long click. If null, {@code model} will be used 54 | * @param actionTag The tag. CAn be used to distinct click source 55 | */ 56 | @BindingAdapter( 57 | value = { 58 | "actionHandler", 59 | "actionType", 60 | "actionTypeLongClick", 61 | "model", 62 | "modelLongClick", 63 | "actionTag" 64 | }, 65 | requireAll = false 66 | ) 67 | public static void setActionHandler( 68 | final View view, 69 | final ActionClickListener actionHandler, 70 | final String actionType, 71 | final String actionTypeLongClick, 72 | final Object model, 73 | final Object modelLongClick, 74 | final Object actionTag 75 | ) { 76 | if (actionHandler != null) { 77 | ViewOnActionClickListener clickListener = new ViewOnActionClickListener( 78 | actionHandler, 79 | actionType, 80 | actionTypeLongClick, 81 | model, 82 | modelLongClick == null ? model : modelLongClick, 83 | actionTag 84 | ); 85 | if (actionType != null) view.setOnClickListener(clickListener); 86 | if (actionTypeLongClick != null) view.setOnLongClickListener(clickListener); 87 | } else { 88 | if (actionType != null) view.setOnClickListener(null); 89 | if (actionTypeLongClick != null) view.setOnLongClickListener(null); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/util/DebounceHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.util; 18 | 19 | import java.util.HashMap; 20 | import java.util.concurrent.locks.ReentrantReadWriteLock; 21 | 22 | /** 23 | * Helper to handle debounce time 24 | * Created on 25.07.2017. 25 | */ 26 | 27 | public class DebounceHelper { 28 | private final HashMap mDebounceMap = new HashMap<>(); 29 | private final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock(); 30 | 31 | /** 32 | * Check if time "debounceMillis" elapsed since last timer reset by call {@link #resetTime} 33 | * or {@link #checkTimeAndResetIfElapsed(String, long)} 34 | * 35 | * @param tag the tag 36 | * @param debounceMillis the debounce time for defined tag 37 | * @return true if debounce time has been elapsed since last call, false otherwise 38 | */ 39 | public boolean checkTimeElapsed(String tag, long debounceMillis) { 40 | mLock.readLock().lock(); 41 | Long lastCallMillis = this.mDebounceMap.get(tag); 42 | mLock.readLock().unlock(); 43 | long nowMillis = System.currentTimeMillis(); 44 | return lastCallMillis == null 45 | || nowMillis - lastCallMillis > debounceMillis; 46 | } 47 | 48 | /** 49 | * Reset timer for specific tag 50 | * 51 | * @param tag the tag 52 | */ 53 | public void resetTime(String tag){ 54 | mLock.writeLock().lock(); 55 | this.mDebounceMap.put(tag, System.currentTimeMillis()); 56 | mLock.writeLock().unlock(); 57 | } 58 | 59 | /** 60 | * Check if time "debounceMillis" elapsed since last timer reset by call {@link #resetTime} 61 | * or {@link #checkTimeAndResetIfElapsed(String, long)} 62 | * 63 | * @param tag the tag 64 | * @param debounceMillis the debounce time for defined tag 65 | * @return true if debounce time has been elapsed since last call, false otherwise 66 | */ 67 | public boolean checkTimeAndResetIfElapsed(String tag, long debounceMillis) { 68 | mLock.readLock().lock(); 69 | Long lastCallMillis = this.mDebounceMap.get(tag); 70 | mLock.readLock().unlock(); 71 | long nowMillis = System.currentTimeMillis(); 72 | if(lastCallMillis == null || nowMillis - lastCallMillis > debounceMillis) { 73 | mLock.writeLock().lock(); 74 | this.mDebounceMap.put(tag, nowMillis); 75 | mLock.writeLock().unlock(); 76 | return true; 77 | } 78 | return false; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/util/ProgressBarController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.util; 18 | 19 | import android.app.Activity; 20 | import android.app.Application; 21 | import android.app.ProgressDialog; 22 | import android.content.Context; 23 | import android.os.Bundle; 24 | import android.view.Window; 25 | 26 | import androidx.annotation.NonNull; 27 | 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | import java.util.Map; 31 | import java.util.WeakHashMap; 32 | 33 | /** 34 | * This class used to show progress bar for asynchronous requests 35 | */ 36 | public class ProgressBarController { 37 | public static final String DEFAULT_TAG = "default_tag"; 38 | 39 | private static final Object sLock = new Object(); 40 | private static Application.ActivityLifecycleCallbacks sLifecycleCallbacks; 41 | private static WeakHashMap sDialogs = new WeakHashMap<>(); 42 | 43 | /** 44 | * Call this before first call of {@link #showProgressDialog} 45 | * 46 | * @param app application 47 | */ 48 | public static void init(Application app) { 49 | if (sLifecycleCallbacks != null) { 50 | app.unregisterActivityLifecycleCallbacks(sLifecycleCallbacks); 51 | } 52 | sLifecycleCallbacks = new OnDestroyActivityCallback() { 53 | @Override 54 | public void onActivityDestroyed(Activity activity) { 55 | final int hashCode = activity.hashCode(); 56 | synchronized (sLock) { 57 | final List dialogs = findDialogs(hashCode); 58 | for (ProgressDialog dialog : dialogs) { 59 | dialog.dismiss(); 60 | sDialogs.remove(dialog); 61 | } 62 | } 63 | } 64 | }; 65 | app.registerActivityLifecycleCallbacks(sLifecycleCallbacks); 66 | } 67 | 68 | /** 69 | * Hides all dialogs and unregisters activity lifecycle callbacks 70 | * 71 | * @param app application instance 72 | */ 73 | public static void release(Application app) { 74 | if (sLifecycleCallbacks != null) { 75 | app.unregisterActivityLifecycleCallbacks(sLifecycleCallbacks); 76 | } 77 | hideProgressDialogsAll(); 78 | } 79 | 80 | /** 81 | * Shows default progress dialog without any message 82 | * 83 | * @param context context 84 | */ 85 | public static void showProgressDialog(final Context context) { 86 | showProgressDialog(context, DEFAULT_TAG, null); 87 | } 88 | 89 | /** 90 | * Shows default dialog with a message 91 | * 92 | * @param context context 93 | * @param message the message to show in a dialog 94 | */ 95 | public static void showProgressDialog(final Context context, final String message) { 96 | showProgressDialog(context, DEFAULT_TAG, message); 97 | } 98 | 99 | /** 100 | * Shows a new dialog with a message for each different tag. 101 | * 102 | * @param context context 103 | * @param tag the tag for determining specific dialog 104 | * @param message the message to show in a dialog 105 | */ 106 | public static void showProgressDialog(final Context context, String tag, final String message) { 107 | final Activity activity = AUtils.getActivity(context); 108 | if (!AUtils.isAlive(activity) || activity.isFinishing()) return; 109 | if (tag == null) tag = DEFAULT_TAG; 110 | ProgressDialog dialog; 111 | synchronized (sLock) { 112 | dialog = findDialog(tag); 113 | 114 | if (!AUtils.isAlive(dialog)) { 115 | if (dialog != null) sDialogs.remove(dialog); 116 | dialog = new ProgressDialog(context); 117 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); 118 | dialog.setCancelable(false); 119 | sDialogs.put(dialog, new Tag(tag, activity.hashCode())); 120 | } 121 | } 122 | dialog.setMessage(message); 123 | dialog.show(); 124 | } 125 | 126 | /** 127 | * Hide default dialog 128 | */ 129 | public static void hideProgressDialog() { 130 | hideProgressDialog(DEFAULT_TAG); 131 | } 132 | 133 | /** 134 | * Hide dialog with specific tag 135 | * 136 | * @param tag the tag to determine specific dialog 137 | */ 138 | public static void hideProgressDialog(String tag) { 139 | if (tag == null) return; 140 | synchronized (sLock) { 141 | ProgressDialog dialog = findDialog(tag); 142 | if (dialog != null) { 143 | if (AUtils.isAlive(dialog) && dialog.isShowing()) dialog.dismiss(); 144 | sDialogs.remove(dialog); 145 | } 146 | } 147 | } 148 | 149 | /** 150 | * Hide all dialogs 151 | */ 152 | public static void hideProgressDialogsAll() { 153 | synchronized (sLock) { 154 | for (ProgressDialog dialog : sDialogs.keySet()) { 155 | if (AUtils.isAlive(dialog) && dialog.isShowing()) dialog.dismiss(); 156 | } 157 | sDialogs.clear(); 158 | } 159 | } 160 | 161 | private static ProgressDialog findDialog(@NonNull String tag) { 162 | for (Map.Entry entry : sDialogs.entrySet()) { 163 | if (tag.equals(entry.getValue().tag)) { 164 | return entry.getKey(); 165 | } 166 | } 167 | return null; 168 | } 169 | 170 | private static List findDialogs(long activityHashcode) { 171 | List result = new ArrayList<>(); 172 | for (Map.Entry entry : sDialogs.entrySet()) { 173 | if (activityHashcode == entry.getValue().activityHashcode) { 174 | result.add(entry.getKey()); 175 | } 176 | } 177 | return result; 178 | } 179 | 180 | private static class Tag { 181 | final String tag; 182 | final long activityHashcode; 183 | 184 | private Tag(String tag, long activityHashcode) { 185 | this.tag = tag; 186 | this.activityHashcode = activityHashcode; 187 | } 188 | } 189 | 190 | private static abstract class OnDestroyActivityCallback implements Application.ActivityLifecycleCallbacks { 191 | @Override 192 | public void onActivityCreated(Activity activity, Bundle bundle) { 193 | } 194 | 195 | @Override 196 | public void onActivityStarted(Activity activity) { 197 | } 198 | 199 | @Override 200 | public void onActivityResumed(Activity activity) { 201 | } 202 | 203 | @Override 204 | public void onActivityPaused(Activity activity) { 205 | } 206 | 207 | @Override 208 | public void onActivityStopped(Activity activity) { 209 | } 210 | 211 | @Override 212 | public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /actionhandler/src/main/java/com/drextended/actionhandler/util/ViewOnActionClickListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.actionhandler.util; 18 | 19 | import android.view.View; 20 | 21 | import androidx.annotation.NonNull; 22 | import androidx.annotation.Nullable; 23 | 24 | import com.drextended.actionhandler.listener.ActionClickListener; 25 | 26 | public class ViewOnActionClickListener implements View.OnClickListener, View.OnLongClickListener { 27 | 28 | @NonNull 29 | private final ActionClickListener actionHandler; 30 | @Nullable 31 | private final String actionType; 32 | @Nullable 33 | private final String actionTypeLongClick; 34 | @Nullable 35 | private final Object model; 36 | @Nullable 37 | private final Object modelLongClick; 38 | @Nullable 39 | private final Object actionTypeTag; 40 | 41 | public ViewOnActionClickListener( 42 | @NonNull ActionClickListener actionHandler, 43 | @Nullable String actionType, 44 | @Nullable String actionTypeLongClick, 45 | @Nullable Object model, 46 | @Nullable Object modelLongClick, 47 | @Nullable Object actionTypeTag 48 | ) { 49 | 50 | this.actionHandler = actionHandler; 51 | this.actionType = actionType; 52 | this.actionTypeLongClick = actionTypeLongClick; 53 | this.model = model; 54 | this.modelLongClick = modelLongClick; 55 | this.actionTypeTag = actionTypeTag; 56 | } 57 | 58 | public ViewOnActionClickListener( 59 | @NonNull ActionClickListener actionHandler, 60 | @Nullable Object model, 61 | @Nullable String actionType 62 | ) { 63 | this(actionHandler, actionType, actionType, model, model, null); 64 | } 65 | 66 | public ViewOnActionClickListener( 67 | @NonNull ActionClickListener actionHandler, 68 | @Nullable Object model, 69 | @Nullable String actionType, 70 | @Nullable String actionTypeLongClick 71 | ) { 72 | this(actionHandler, actionType, actionTypeLongClick, model, model, null); 73 | } 74 | 75 | @Override 76 | public void onClick(View v) { 77 | if (actionType != null) { 78 | actionHandler.onActionClick(v, actionType, model, actionTypeTag); 79 | } 80 | } 81 | 82 | @Override 83 | public boolean onLongClick(View v) { 84 | if (actionTypeLongClick != null) { 85 | actionHandler.onActionClick(v, actionTypeLongClick, modelLongClick, actionTypeTag); 86 | return true; 87 | } 88 | return false; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /actionhandler/src/main/res/layout/item_menu_composit_action.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 23 | 24 | 34 | 35 | 51 | -------------------------------------------------------------------------------- /actionhandler/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /actionhandler/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Wait please… 3 | 4 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | compileSdkVersion = 28 4 | targetSdkVersion = 28 5 | 6 | kotlin_version = '1.3.31' 7 | 8 | x_appcompat_version = '1.0.2' 9 | x_annotation_version = '1.1.0' 10 | 11 | rxjava2_version = '2.2.10' 12 | rxandroid_version = '2.1.1' 13 | 14 | } 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | dependencies { 20 | classpath 'com.android.tools.build:gradle:3.5.0-beta04' 21 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 22 | classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4" //1.7.2 23 | classpath "com.github.dcendents:android-maven-gradle-plugin:2.1" //1.4.1 24 | } 25 | } 26 | 27 | allprojects { 28 | repositories { 29 | google() 30 | jcenter() 31 | } 32 | } 33 | 34 | task clean(type: Delete) { 35 | delete rootProject.buildDir 36 | } 37 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.databinding.enableV2=true 2 | android.useAndroidX=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drstranges/ActionHandler/5ee1c61883e5e9e5039522788324a57fd51ac71e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Jun 22 13:52:34 EEST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /samples/databinding/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /samples/databinding/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.compileSdkVersion 5 | 6 | dataBinding { 7 | enabled = true 8 | } 9 | 10 | defaultConfig { 11 | applicationId "com.example.databinding" 12 | minSdkVersion 21 13 | targetSdkVersion rootProject.ext.targetSdkVersion 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | lintOptions { 25 | abortOnError false 26 | } 27 | compileOptions { 28 | sourceCompatibility 1.8 29 | targetCompatibility 1.8 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation project(path: ':actionhandler') 35 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 36 | 37 | implementation "androidx.annotation:annotation:$x_annotation_version" 38 | implementation "androidx.appcompat:appcompat:$x_appcompat_version" 39 | implementation "io.reactivex.rxjava2:rxjava:$rxjava2_version" 40 | implementation "io.reactivex.rxjava2:rxandroid:$rxandroid_version" 41 | } 42 | -------------------------------------------------------------------------------- /samples/databinding/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Android_Env\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /samples/databinding/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/ActionType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding; 18 | 19 | public class ActionType { 20 | public static final String OPEN_NEW_SCREEN = "open_new_screen"; 21 | public static final String FIRE_ACTION = "fire_action"; 22 | public static final String FIRE_DIALOG_ACTION = "fire_dialog_action"; 23 | public static final String FIRE_REQUEST_ACTION = "fire_request_action"; 24 | public static final String FIRE_RX_REQUEST_ACTION = "fire_rx_request_action"; 25 | public static final String FIRE_COMPOSITE_ACTION = "composite_action"; 26 | } 27 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/action/OpenSecondActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.action; 18 | 19 | import android.app.Activity; 20 | import android.content.ActivityNotFoundException; 21 | import android.content.Context; 22 | import android.content.ContextWrapper; 23 | import android.content.Intent; 24 | 25 | import androidx.annotation.NonNull; 26 | import androidx.annotation.Nullable; 27 | import androidx.core.app.ActivityOptionsCompat; 28 | import android.view.View; 29 | 30 | import com.drextended.actionhandler.ActionArgs; 31 | import com.drextended.actionhandler.action.IntentAction; 32 | import com.drextended.databinding.view.SecondActivity; 33 | 34 | 35 | public class OpenSecondActivity extends IntentAction { 36 | @Override 37 | public boolean isModelAccepted(Object model) { 38 | return model instanceof String; 39 | } 40 | 41 | @Nullable 42 | @Override 43 | public Intent getIntent(@NonNull ActionArgs args) { 44 | return SecondActivity.getIntent(args.params.getViewOrAppContext(), args.params.getModel(String.class)); 45 | } 46 | 47 | @Override 48 | protected void startActivity(@NonNull Context context, @NonNull Intent intent, @NonNull ActionArgs args) throws ActivityNotFoundException { 49 | ActivityOptionsCompat transition = prepareTransition(args); 50 | if (transition != null) { 51 | context.startActivity(intent, transition.toBundle()); 52 | } else { 53 | super.startActivity(context, intent, args); 54 | } 55 | } 56 | 57 | private ActivityOptionsCompat prepareTransition(@NonNull ActionArgs args) { 58 | View view = args.params.tryGetView(); 59 | Activity activity = args.params.tryGetActivity(); 60 | 61 | if (activity == null || view == null) return null; 62 | return ActivityOptionsCompat 63 | .makeSceneTransitionAnimation(activity, view, SecondActivity.TRANSITION_NAME); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/action/SampleRequestAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.action; 18 | 19 | import android.app.Activity; 20 | import android.os.Handler; 21 | import android.widget.Toast; 22 | 23 | import androidx.annotation.NonNull; 24 | import androidx.annotation.Nullable; 25 | 26 | import com.drextended.actionhandler.ActionArgs; 27 | import com.drextended.actionhandler.ActionParams; 28 | import com.drextended.actionhandler.action.RequestAction; 29 | import com.drextended.databinding.R; 30 | 31 | public class SampleRequestAction extends RequestAction { 32 | 33 | private int mCount; 34 | 35 | public SampleRequestAction() { 36 | super(true, true); 37 | } 38 | 39 | @Override 40 | public boolean isModelAccepted(Object model) { 41 | return model instanceof String; 42 | } 43 | 44 | @Override 45 | protected String getDialogMessage(@NonNull ActionParams params) { 46 | return params.appContext.getString(R.string.action_request_dialog_message, params.model); 47 | } 48 | 49 | @Override 50 | protected void onMakeRequest(@NonNull ActionArgs args) { 51 | final Handler handler = new Handler(); 52 | handler.postDelayed(() -> { 53 | Activity activity = args.params.tryGetActivity(); 54 | if (activity != null && (activity.isFinishing() || activity.isDestroyed())) return; 55 | if (mCount++ % 3 == 0) { 56 | onResponseError(args, new Exception("Test Error!:) Just repeat this request!")); 57 | } else { 58 | onResponseSuccess(args, "Request has been done successfully"); 59 | } 60 | }, 3000); 61 | } 62 | 63 | @Override 64 | protected void onResponseSuccess(@NonNull ActionArgs args, @Nullable String response) { 65 | super.onResponseSuccess(args, response); 66 | Toast.makeText(args.params.appContext, response, Toast.LENGTH_SHORT).show(); 67 | } 68 | 69 | @Override 70 | protected void onResponseError(@NonNull ActionArgs args, @NonNull Throwable e) { 71 | super.onResponseError(args, e); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/action/SampleRxRequestAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.action; 18 | 19 | import android.content.Context; 20 | 21 | import androidx.annotation.NonNull; 22 | import androidx.annotation.Nullable; 23 | import android.view.View; 24 | import android.widget.Toast; 25 | 26 | import com.drextended.actionhandler.ActionArgs; 27 | import com.drextended.actionhandler.ActionParams; 28 | import com.drextended.actionhandler.action.RxRequestAction; 29 | import com.drextended.databinding.R; 30 | 31 | import java.util.concurrent.TimeUnit; 32 | 33 | import io.reactivex.Maybe; 34 | import io.reactivex.MaybeSource; 35 | import io.reactivex.functions.Function; 36 | 37 | public class SampleRxRequestAction extends RxRequestAction { 38 | 39 | private int mCount; 40 | 41 | public SampleRxRequestAction() { 42 | super(true, true); 43 | } 44 | 45 | @Nullable 46 | @Override 47 | protected Maybe getRequest(@NonNull ActionArgs args) { 48 | if (mCount++ % 3 == 0) { 49 | return Maybe.just("") 50 | .delay(2000, TimeUnit.MILLISECONDS) 51 | .flatMap(s -> Maybe.error(new Throwable("Request has failed"))); 52 | } else { 53 | return Maybe.just("Request has been done successfully") 54 | .delay(2000, TimeUnit.MILLISECONDS); 55 | } 56 | } 57 | 58 | @Override 59 | public boolean isModelAccepted(Object model) { 60 | return model instanceof String; 61 | } 62 | 63 | @Override 64 | protected String getDialogMessage(@NonNull ActionParams params) { 65 | return params.appContext.getString(R.string.action_request_dialog_message, params.model); 66 | } 67 | 68 | @Override 69 | protected void onResponseSuccess(@NonNull ActionArgs args, @Nullable String response) { 70 | super.onResponseSuccess(args, response); 71 | Toast.makeText(args.params.appContext, response, Toast.LENGTH_SHORT).show(); 72 | } 73 | 74 | @Override 75 | protected void onResponseError(@NonNull ActionArgs args, @NonNull Throwable e) { 76 | super.onResponseError(args, e); 77 | Toast.makeText(args.params.appContext, e.getMessage(), Toast.LENGTH_SHORT).show(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/action/ShowToastAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.action; 18 | 19 | import android.content.Context; 20 | import android.widget.Toast; 21 | 22 | import androidx.annotation.NonNull; 23 | 24 | import com.drextended.actionhandler.ActionArgs; 25 | import com.drextended.actionhandler.action.BaseAction; 26 | import com.drextended.databinding.R; 27 | 28 | public class ShowToastAction extends BaseAction { 29 | 30 | @Override 31 | public boolean isModelAccepted(Object model) { 32 | return model instanceof String; 33 | } 34 | 35 | @Override 36 | public void onFireAction(@NonNull ActionArgs args) { 37 | Context appContext = args.params.appContext; 38 | 39 | Toast.makeText( 40 | appContext, 41 | appContext.getString(R.string.toast_message, args.params.model), 42 | Toast.LENGTH_SHORT 43 | ).show(); 44 | 45 | notifyOnActionFired(args); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/action/SimpleAnimationAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.action; 18 | 19 | import android.animation.ObjectAnimator; 20 | import android.view.View; 21 | 22 | import androidx.annotation.NonNull; 23 | 24 | import com.drextended.actionhandler.ActionArgs; 25 | import com.drextended.actionhandler.action.BaseAction; 26 | 27 | public class SimpleAnimationAction extends BaseAction { 28 | 29 | @Override 30 | public boolean isModelAccepted(Object model) { 31 | return true; 32 | } 33 | 34 | @Override 35 | public void onFireAction(@NonNull ActionArgs args) { 36 | View view = args.params.tryGetView(); 37 | if (view == null) { 38 | notifyOnActionDismiss(args, "No view"); 39 | return; 40 | } 41 | ObjectAnimator 42 | .ofFloat(view, "translationX", 0, 25, -25, 25, -25, 15, -15, 6, -6, 0) 43 | .setDuration(200) 44 | .start(); 45 | notifyOnActionFired(args); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/action/TrackAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.action; 18 | 19 | import android.content.Context; 20 | 21 | import androidx.annotation.NonNull; 22 | import androidx.annotation.Nullable; 23 | import android.util.Log; 24 | import android.view.View; 25 | 26 | import com.drextended.actionhandler.ActionArgs; 27 | import com.drextended.actionhandler.action.Action; 28 | 29 | public class TrackAction implements Action { 30 | 31 | @Override 32 | public boolean isModelAccepted(Object model) { 33 | return true; 34 | } 35 | 36 | @Override 37 | public void onFireAction(@NonNull ActionArgs args) { 38 | Log.d("tagTrackAction", "onFireAction: " + args.fireActionType + ", model: " + args.params.model); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/view/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.view; 18 | 19 | import androidx.databinding.DataBindingUtil; 20 | import android.os.Bundle; 21 | import androidx.appcompat.app.AppCompatActivity; 22 | import android.widget.Toast; 23 | 24 | import com.drextended.databinding.R; 25 | import com.drextended.databinding.databinding.ActivityMainBinding; 26 | import com.drextended.databinding.viewmodel.MainActivityViewModel; 27 | 28 | public class MainActivity extends AppCompatActivity implements MainActivityViewModel.Callback { 29 | 30 | private MainActivityViewModel mViewModel; 31 | @SuppressWarnings("FieldCanBeLocal") 32 | private ActivityMainBinding mBinding; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | 38 | mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); 39 | mViewModel = new MainActivityViewModel(this, this); 40 | mBinding.setViewModel(mViewModel); 41 | } 42 | 43 | @Override 44 | protected void onSaveInstanceState(Bundle outState) { 45 | super.onSaveInstanceState(outState); 46 | mViewModel.onSaveInstanceState(outState); 47 | } 48 | 49 | @Override 50 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 51 | super.onRestoreInstanceState(savedInstanceState); 52 | mViewModel.onRestoreInstanceState(savedInstanceState); 53 | } 54 | 55 | @Override 56 | public void showMessage(String message) { 57 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/view/SecondActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.view; 18 | 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.os.Bundle; 22 | import androidx.appcompat.app.AppCompatActivity; 23 | import android.view.MenuItem; 24 | 25 | import com.drextended.databinding.R; 26 | 27 | 28 | public class SecondActivity extends AppCompatActivity { 29 | 30 | private static final String ARG_TITLE = "arg_title"; 31 | public static final String TRANSITION_NAME = "transition_name"; 32 | private String mTitle; 33 | 34 | public static Intent getIntent(Context context, String title) { 35 | final Intent intent = new Intent(context, SecondActivity.class); 36 | intent.putExtra(ARG_TITLE, title); 37 | return intent; 38 | } 39 | 40 | private void initArgs() { 41 | final Bundle args = getIntent().getExtras(); 42 | if (args != null) mTitle = args.getString(ARG_TITLE); 43 | } 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_second); 49 | initArgs(); 50 | setTitle(mTitle); 51 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 52 | } 53 | 54 | @Override 55 | public boolean onOptionsItemSelected(MenuItem item) { 56 | // Respond to the action bar's Up/Home button 57 | if (item.getItemId() == android.R.id.home) { 58 | supportFinishAfterTransition(); 59 | return true; 60 | } 61 | return super.onOptionsItemSelected(item); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/viewmodel/BaseViewModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.viewmodel; 18 | 19 | import android.content.Context; 20 | import androidx.annotation.StringRes; 21 | 22 | public class BaseViewModel { 23 | private Context mContext; 24 | 25 | public BaseViewModel(Context context) { 26 | mContext = context; 27 | } 28 | 29 | public Context getContext() { 30 | return mContext; 31 | } 32 | 33 | public String getString(@StringRes int resId) { 34 | return mContext.getString(resId); 35 | } 36 | 37 | public void onDestroy() { 38 | mContext = null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/databinding/src/main/java/com/drextended/databinding/viewmodel/MainActivityViewModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Roman Donchenko. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.drextended.databinding.viewmodel; 18 | 19 | import android.content.Context; 20 | import android.os.Bundle; 21 | 22 | import androidx.annotation.NonNull; 23 | import androidx.annotation.Nullable; 24 | import androidx.databinding.ObservableField; 25 | 26 | import com.drextended.actionhandler.ActionArgs; 27 | import com.drextended.actionhandler.ActionHandler; 28 | import com.drextended.actionhandler.ActionParams; 29 | import com.drextended.actionhandler.action.Action; 30 | import com.drextended.actionhandler.action.CompositeAction; 31 | import com.drextended.actionhandler.action.CompositeAction.ActionItem; 32 | import com.drextended.actionhandler.action.DialogAction; 33 | import com.drextended.actionhandler.action.SingleActionFactory; 34 | import com.drextended.actionhandler.listener.ActionCallback; 35 | import com.drextended.databinding.ActionType; 36 | import com.drextended.databinding.R; 37 | import com.drextended.databinding.action.OpenSecondActivity; 38 | import com.drextended.databinding.action.SampleRequestAction; 39 | import com.drextended.databinding.action.SampleRxRequestAction; 40 | import com.drextended.databinding.action.ShowToastAction; 41 | import com.drextended.databinding.action.SimpleAnimationAction; 42 | import com.drextended.databinding.action.TrackAction; 43 | 44 | /** 45 | * Created on 15.06.2016. 46 | */ 47 | 48 | public class MainActivityViewModel extends BaseViewModel implements ActionCallback { 49 | 50 | private static final String EXTRA_LAST_ACTION_TEXT = "EXTRA_LAST_ACTION_TEXT"; 51 | 52 | public ObservableField lastActionText = new ObservableField<>(); 53 | public ObservableField model = new ObservableField<>(); 54 | public ActionHandler actionHandler; 55 | 56 | private int mClickCount; 57 | private Callback mCallback; 58 | 59 | public MainActivityViewModel(Context context, Callback callback) { 60 | super(context); 61 | mCallback = callback != null ? callback : Callback.EMPTY_CALLBACK; 62 | actionHandler = buildActionHandler(); 63 | refreshModel(); 64 | } 65 | 66 | private void refreshModel() { 67 | model.set("Model (" + System.currentTimeMillis() + ")"); 68 | } 69 | 70 | private ActionHandler buildActionHandler() { 71 | 72 | final ShowToastAction showToastAction = new ShowToastAction(); 73 | 74 | return new ActionHandler.Builder() 75 | .addAction(null, new SimpleAnimationAction()) // Applied for any actionType 76 | .addAction(null, new TrackAction()) // Applied for any actionType 77 | .addAction(ActionType.FIRE_ACTION, showToastAction) 78 | .withFactory(new SingleActionFactory() { 79 | @Nullable 80 | @Override 81 | public Action provideAction(@NonNull String actionType) { 82 | switch (actionType) { 83 | case ActionType.OPEN_NEW_SCREEN: 84 | return new OpenSecondActivity(); 85 | case ActionType.FIRE_DIALOG_ACTION: 86 | return DialogAction.wrap(getString(R.string.action_dialog_message), showToastAction); 87 | case ActionType.FIRE_REQUEST_ACTION: 88 | return new SampleRequestAction(); 89 | case ActionType.FIRE_COMPOSITE_ACTION: 90 | return buildMenuAction(showToastAction); 91 | } 92 | return null; 93 | } 94 | }) 95 | .addCallback(this) 96 | .setDefaultDebounce(1000) 97 | .setDebounce(2000, ActionType.FIRE_ACTION) 98 | .build(); 99 | } 100 | 101 | private Action buildMenuAction(ShowToastAction showToastAction) { 102 | CompositeAction menuAction = new CompositeAction<>(( 103 | context, model) -> "Title (" + model + ")", 104 | true, 105 | true, 106 | new ActionItem<>(ActionType.OPEN_NEW_SCREEN, new OpenSecondActivity(), R.drawable.ic_touch_app_black_24dp, 0, 107 | (context, model) -> { 108 | // There you can return any title for menu item using some fields from model 109 | return context.getString(R.string.fire_intent_action); 110 | }), 111 | new ActionItem(ActionType.FIRE_ACTION, showToastAction, R.drawable.ic_announcement_black_24dp, R.color.greenLight, R.string.fire_simple_action), 112 | new ActionItem(ActionType.FIRE_DIALOG_ACTION, DialogAction.wrap(getString(R.string.action_dialog_message), showToastAction), R.drawable.ic_announcement_black_24dp, R.color.amber, R.string.fire_dialog_action), 113 | new ActionItem(ActionType.FIRE_REQUEST_ACTION, new SampleRequestAction() { 114 | @Override 115 | public boolean isModelAccepted(Object model) { 116 | return super.isModelAccepted(model) && mClickCount % 3 == 0; 117 | } 118 | }, R.drawable.ic_cloud_upload_black_24dp, R.color.red, R.string.fire_request_action), 119 | new ActionItem(ActionType.FIRE_RX_REQUEST_ACTION, new SampleRxRequestAction(), 0, 0, R.string.fire_rx_request_action) 120 | ); 121 | menuAction.setShowAsPopupMenuEnabled(false); 122 | return menuAction; 123 | } 124 | 125 | @Override 126 | public boolean onInterceptAction(@NonNull ActionParams params) { 127 | switch (params.actionType) { 128 | case ActionType.OPEN_NEW_SCREEN: 129 | case ActionType.FIRE_ACTION: 130 | final boolean consumed = mClickCount++ % 7 == 0; 131 | if (consumed) { 132 | mCallback.showMessage(getString(R.string.message_action_intercepted)); 133 | } 134 | return consumed; 135 | // case ActionType.FIRE_ACTION: 136 | // case ActionType.FIRE_DIALOG_ACTION: 137 | // case ActionType.FIRE_REQUEST_ACTION: 138 | } 139 | return false; 140 | } 141 | 142 | @Override 143 | public boolean onInterceptActionFire(@NonNull ActionParams actionParams, @Nullable String actionType, @NonNull Action action) { 144 | return false; 145 | } 146 | 147 | @Override 148 | public void onActionFired(@NonNull ActionArgs args, @Nullable Object result) { 149 | switch (args.params.actionType) { 150 | case ActionType.OPEN_NEW_SCREEN: 151 | lastActionText.set("Intent Action"); 152 | break; 153 | case ActionType.FIRE_ACTION: 154 | lastActionText.set("Simple Action"); 155 | break; 156 | case ActionType.FIRE_DIALOG_ACTION: 157 | lastActionText.set("Dialog Action"); 158 | break; 159 | case ActionType.FIRE_REQUEST_ACTION: 160 | lastActionText.set("Request Action"); 161 | break; 162 | } 163 | } 164 | 165 | @Override 166 | public void onActionError(@NonNull ActionArgs args, @Nullable Throwable throwable) { 167 | mCallback.showMessage("TestError: " + (throwable != null ? throwable.getMessage() : null)); 168 | } 169 | 170 | @Override 171 | public void onActionDismiss(@NonNull ActionArgs args, @Nullable String reason) { 172 | mCallback.showMessage("Action dismissed. Reason: " + reason); 173 | } 174 | 175 | public void onSaveInstanceState(Bundle outState) { 176 | outState.putString(EXTRA_LAST_ACTION_TEXT, lastActionText.get()); 177 | } 178 | 179 | public void onRestoreInstanceState(Bundle savedInstanceState) { 180 | lastActionText.set(savedInstanceState.getString(EXTRA_LAST_ACTION_TEXT)); 181 | } 182 | 183 | @Override 184 | public void onDestroy() { 185 | super.onDestroy(); 186 | actionHandler.cancelAll(); 187 | } 188 | 189 | public interface Callback { 190 | 191 | void showMessage(String message); 192 | 193 | Callback EMPTY_CALLBACK = message -> { }; 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /samples/databinding/src/main/res/drawable/ic_announcement_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /samples/databinding/src/main/res/drawable/ic_cloud_upload_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /samples/databinding/src/main/res/drawable/ic_touch_app_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /samples/databinding/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 37 | 38 | 43 | 44 | 48 | 49 |