mirror of
				https://codeberg.org/tom79/Fedilab.git
				synced 2025-10-20 11:20:16 +03:00 
			
		
		
		
	Fix issue #745 - Update library for bottom buttons.
This commit is contained in:
		
							parent
							
								
									d70c285bea
								
							
						
					
					
						commit
						107ac13e15
					
				
					 21 changed files with 865 additions and 35 deletions
				
			
		|  | @ -78,7 +78,7 @@ allprojects { | |||
| } | ||||
| dependencies { | ||||
|     implementation project(':autoimageslider') | ||||
|     implementation 'androidx.appcompat:appcompat:1.5.1' | ||||
|     implementation 'androidx.appcompat:appcompat:1.6.0' | ||||
| 
 | ||||
|     implementation 'com.google.android.material:material:1.7.0' | ||||
| 
 | ||||
|  | @ -94,7 +94,6 @@ dependencies { | |||
|     implementation "org.conscrypt:conscrypt-android:2.5.2" | ||||
|     implementation 'com.vanniktech:emoji-one:0.6.0' | ||||
|     implementation 'com.github.GrenderG:Toasty:1.5.2' | ||||
|     implementation 'org.framagit.tom79:SparkButton:1.0.13' | ||||
|     implementation "com.github.bumptech.glide:glide:4.14.2" | ||||
|     implementation "com.github.bumptech.glide:okhttp3-integration:4.14.2" | ||||
|     implementation("com.github.bumptech.glide:recyclerview-integration:4.14.2") { | ||||
|  | @ -107,7 +106,7 @@ dependencies { | |||
|     implementation 'com.github.mergehez:ArgPlayer:v3.1' | ||||
|     implementation project(path: ':mytransl') | ||||
|     implementation project(path: ':ratethisapp') | ||||
| 
 | ||||
|     implementation project(path: ':sparkbutton') | ||||
| 
 | ||||
|     implementation 'com.burhanrashid52:photoeditor:1.5.1' | ||||
|     implementation("com.vanniktech:android-image-cropper:4.3.3") | ||||
|  |  | |||
|  | @ -638,21 +638,13 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> | |||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         holder.binding.actionButtonFavorite.pressOnTouch(false); | ||||
|         holder.binding.actionButtonBoost.pressOnTouch(false); | ||||
|         holder.binding.actionButtonBookmark.pressOnTouch(false); | ||||
| 
 | ||||
|         holder.binding.actionButtonFavorite.setActiveImage(R.drawable.ic_round_star_24); | ||||
|         holder.binding.actionButtonFavorite.setInactiveImage(R.drawable.ic_round_star_border_24); | ||||
|         holder.binding.actionButtonBookmark.setActiveImage(R.drawable.ic_round_bookmark_24); | ||||
|         holder.binding.actionButtonBookmark.setInactiveImage(R.drawable.ic_round_bookmark_border_24); | ||||
|         holder.binding.actionButtonBoost.setActiveImage(R.drawable.ic_round_repeat_24); | ||||
|         holder.binding.actionButtonBoost.setInactiveImage(R.drawable.ic_round_repeat_24); | ||||
|         holder.binding.actionButtonFavorite.setDisableCircle(true); | ||||
|         holder.binding.actionButtonBoost.setDisableCircle(true); | ||||
|         holder.binding.actionButtonBookmark.setDisableCircle(true); | ||||
|         holder.binding.actionButtonFavorite.setActiveImageTint(R.color.marked_icon); | ||||
|         holder.binding.actionButtonBoost.setActiveImageTint(R.color.boost_icon); | ||||
|         holder.binding.actionButtonBookmark.setActiveImageTint(R.color.marked_icon); | ||||
|         applyColor(context, holder); | ||||
| 
 | ||||
|         if (status.pinned) { | ||||
|  | @ -2319,9 +2311,6 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> | |||
|             Helper.changeDrawableColor(context, R.drawable.ic_bot, theme_icons_color); | ||||
|             Helper.changeDrawableColor(context, R.drawable.ic_round_reply_24, theme_icons_color); | ||||
|             Helper.changeDrawableColor(context, holder.binding.actionButtonTranslate, theme_icons_color); | ||||
|             holder.binding.actionButtonFavorite.setInActiveImageTintColor(theme_icons_color); | ||||
|             holder.binding.actionButtonBookmark.setInActiveImageTintColor(theme_icons_color); | ||||
|             holder.binding.actionButtonBoost.setInActiveImageTintColor(theme_icons_color); | ||||
|             holder.binding.replyCount.setTextColor(theme_icons_color); | ||||
|         } | ||||
|         if (theme_statuses_color != -1) { | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:tint="?attr/colorControlNormal" | ||||
|     android:tint="@color/marked_icon" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     <path | ||||
|  |  | |||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_round_repeat_active_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/drawable/ic_round_repeat_active_24.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:tint="@color/boost_icon" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     <path | ||||
|         android:fillColor="?attr/colorControlNormal" | ||||
|         android:pathData="M7,7h10v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L17,5L6,5c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1s1,-0.45 1,-1L7,7zM17,17L7,17v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.36L7,19h11c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3z" /> | ||||
| </vector> | ||||
|  | @ -1,7 +1,7 @@ | |||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:tint="?attr/colorControlNormal" | ||||
|     android:tint="@color/marked_icon" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     <path | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     xmlns:sparkbutton="http://schemas.android.com/apk/res-auto" | ||||
|     android:id="@+id/cardview_container" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|  | @ -655,12 +656,11 @@ | |||
|                 android:layout_height="48dp" | ||||
|                 android:adjustViewBounds="true" | ||||
|                 android:contentDescription="@string/reblog_add" | ||||
|                 app:sparkbutton_activeImage="@drawable/ic_round_repeat_24" | ||||
|                 app:sparkbutton_animationSpeed="1.5" | ||||
|                 app:sparkbutton_iconSize="24dp" | ||||
|                 app:sparkbutton_inActiveImage="@drawable/ic_round_repeat_24" | ||||
|                 app:sparkbutton_primaryColor="@color/boost_icon" | ||||
|                 app:sparkbutton_secondaryColor="@color/boost_icon" /> | ||||
|                 app:activeImage="@drawable/ic_round_repeat_active_24" | ||||
|                 app:iconSize="28dp" | ||||
|                 app:inactiveImage="@drawable/ic_round_repeat_24" | ||||
|                 app:primaryColor="@color/boost_icon" | ||||
|                 app:secondaryColor="@color/boost_icon" /> | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageButton | ||||
|                 android:id="@+id/action_button_quote" | ||||
|  | @ -691,12 +691,12 @@ | |||
|                 android:layout_gravity="center" | ||||
|                 android:adjustViewBounds="true" | ||||
|                 android:contentDescription="@string/favourite_add" | ||||
|                 app:sparkbutton_activeImage="@drawable/ic_round_star_24" | ||||
|                 app:sparkbutton_animationSpeed="1.5" | ||||
|                 app:sparkbutton_iconSize="24dp" | ||||
|                 app:sparkbutton_inActiveImage="@drawable/ic_round_star_border_24" | ||||
|                 app:sparkbutton_primaryColor="@color/marked_icon" | ||||
|                 app:sparkbutton_secondaryColor="@color/marked_icon" /> | ||||
|                 app:activeImage="@drawable/ic_round_star_24" | ||||
|                 app:animationSpeed="1.5" | ||||
|                 app:inactiveImage="@drawable/ic_round_star_border_24" | ||||
|                 app:primaryColor="@color/marked_icon" | ||||
|                 app:secondaryColor="@color/marked_icon" | ||||
|                 sparkbutton:iconSize="28dp" /> | ||||
| 
 | ||||
|             <com.varunest.sparkbutton.SparkButton | ||||
|                 android:id="@+id/action_button_bookmark" | ||||
|  | @ -709,12 +709,12 @@ | |||
|                 android:layout_gravity="center" | ||||
|                 android:adjustViewBounds="true" | ||||
|                 android:contentDescription="@string/bookmark_add" | ||||
|                 app:sparkbutton_activeImage="@drawable/ic_round_bookmark_24" | ||||
|                 app:sparkbutton_animationSpeed="1.5" | ||||
|                 app:sparkbutton_iconSize="24dp" | ||||
|                 app:sparkbutton_inActiveImage="@drawable/ic_round_bookmark_border_24" | ||||
|                 app:sparkbutton_primaryColor="@color/marked_icon" | ||||
|                 app:sparkbutton_secondaryColor="@color/marked_icon" /> | ||||
|                 app:activeImage="@drawable/ic_round_bookmark_24" | ||||
|                 app:animationSpeed="1.5" | ||||
|                 app:inactiveImage="@drawable/ic_round_bookmark_border_24" | ||||
|                 app:primaryColor="@color/marked_icon" | ||||
|                 app:secondaryColor="@color/marked_icon" | ||||
|                 sparkbutton:iconSize="28dp" /> | ||||
| 
 | ||||
| 
 | ||||
|             <androidx.appcompat.widget.AppCompatImageButton | ||||
|  |  | |||
|  | @ -3,3 +3,4 @@ include ':app' | |||
| include ':autoimageslider' | ||||
| include ':mytransl' | ||||
| include ':ratethisapp' | ||||
| include ':sparkbutton' | ||||
|  |  | |||
							
								
								
									
										1
									
								
								sparkbutton/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								sparkbutton/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| /build | ||||
							
								
								
									
										27
									
								
								sparkbutton/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								sparkbutton/build.gradle
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| apply plugin: 'com.android.library' | ||||
| 
 | ||||
| group = 'com.github.tom79' | ||||
| 
 | ||||
| android { | ||||
|     compileSdkVersion 33 | ||||
| 
 | ||||
|     defaultConfig { | ||||
|         minSdkVersion 15 | ||||
|         targetSdkVersion 33 | ||||
|         versionCode 3 | ||||
|         versionName "1.0.12" | ||||
|     } | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
|     lintOptions { | ||||
|         abortOnError false | ||||
|     } | ||||
| } | ||||
| dependencies { | ||||
|     implementation fileTree(dir: 'libs', include: ['*.jar']) | ||||
|     implementation 'androidx.appcompat:appcompat:1.6.0' | ||||
| } | ||||
							
								
								
									
										3
									
								
								sparkbutton/gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								sparkbutton/gradle.properties
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| POM_NAME=SparkButton | ||||
| POM_ARTIFACT_ID=sparkbutton | ||||
| POM_PACKAGING=aar | ||||
							
								
								
									
										96
									
								
								sparkbutton/maven-push.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								sparkbutton/maven-push.gradle
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | |||
| apply plugin: 'maven' | ||||
| apply plugin: 'signing' | ||||
| 
 | ||||
| def isReleaseBuild() { | ||||
|     return VERSION_NAME.contains("SNAPSHOT") == false | ||||
| } | ||||
| 
 | ||||
| def getReleaseRepositoryUrl() { | ||||
|     return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL | ||||
|             : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" | ||||
| } | ||||
| 
 | ||||
| def getSnapshotRepositoryUrl() { | ||||
|     return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL | ||||
|             : "https://oss.sonatype.org/content/repositories/snapshots/" | ||||
| } | ||||
| 
 | ||||
| def getRepositoryUsername() { | ||||
|     return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" | ||||
| } | ||||
| 
 | ||||
| def getRepositoryPassword() { | ||||
|     return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" | ||||
| } | ||||
| 
 | ||||
| afterEvaluate { project -> | ||||
|     uploadArchives { | ||||
|         repositories { | ||||
|             mavenDeployer { | ||||
|                 beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } | ||||
| 
 | ||||
|                 pom.groupId = GROUP | ||||
|                 pom.artifactId = POM_ARTIFACT_ID | ||||
|                 pom.version = VERSION_NAME | ||||
| 
 | ||||
|                 repository(url: getReleaseRepositoryUrl()) { | ||||
|                     authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) | ||||
|                 } | ||||
|                 snapshotRepository(url: getSnapshotRepositoryUrl()) { | ||||
|                     authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) | ||||
|                 } | ||||
| 
 | ||||
|                 pom.project { | ||||
|                     name POM_NAME | ||||
|                     packaging POM_PACKAGING | ||||
|                     description POM_DESCRIPTION | ||||
|                     url POM_URL | ||||
| 
 | ||||
|                     scm { | ||||
|                         url POM_SCM_URL | ||||
|                         connection POM_SCM_CONNECTION | ||||
|                         developerConnection POM_SCM_DEV_CONNECTION | ||||
|                     } | ||||
| 
 | ||||
|                     licenses { | ||||
|                         license { | ||||
|                             name POM_LICENCE_NAME | ||||
|                             url POM_LICENCE_URL | ||||
|                             distribution POM_LICENCE_DIST | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     developers { | ||||
|                         developer { | ||||
|                             id POM_DEVELOPER_ID | ||||
|                             name POM_DEVELOPER_NAME | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     signing { | ||||
|         required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } | ||||
|         sign configurations.archives | ||||
|     } | ||||
| 
 | ||||
|     //task androidJavadocs(type: Javadoc) { | ||||
|     //source = android.sourceSets.main.allJava | ||||
|     //} | ||||
| 
 | ||||
|     //task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { | ||||
|     //classifier = 'javadoc' | ||||
|     //from androidJavadocs.destinationDir | ||||
|     //} | ||||
| 
 | ||||
|     task androidSourcesJar(type: Jar) { | ||||
|         classifier = 'sources' | ||||
|         from android.sourceSets.main.java.sourceFiles | ||||
|     } | ||||
| 
 | ||||
|     artifacts { | ||||
|         archives androidSourcesJar | ||||
|     } | ||||
| } | ||||
							
								
								
									
										17
									
								
								sparkbutton/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								sparkbutton/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| # Add project specific ProGuard rules here. | ||||
| # By default, the flags in this file are appended to flags specified | ||||
| # in /android-sdk/tools/proguard/proguard-android.txt | ||||
| # You can edit the include path and order by changing the proguardFiles | ||||
| # directive in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
| 
 | ||||
| # Add any project specific keep options here: | ||||
| 
 | ||||
| # If your project uses WebView with JS, uncomment the following | ||||
| # and specify the fully qualified class name to the JavaScript interface | ||||
| # class: | ||||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||||
| #   public *; | ||||
| #} | ||||
							
								
								
									
										4
									
								
								sparkbutton/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								sparkbutton/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| <manifest package="com.varunest.sparkbutton"> | ||||
| 
 | ||||
|     <application /> | ||||
| </manifest> | ||||
|  | @ -0,0 +1,313 @@ | |||
| package com.varunest.sparkbutton; | ||||
| 
 | ||||
| import android.animation.Animator; | ||||
| import android.animation.AnimatorListenerAdapter; | ||||
| import android.animation.AnimatorSet; | ||||
| import android.animation.ObjectAnimator; | ||||
| import android.annotation.TargetApi; | ||||
| import android.content.Context; | ||||
| import android.content.res.TypedArray; | ||||
| import android.os.Build; | ||||
| import android.util.AttributeSet; | ||||
| import android.view.Gravity; | ||||
| import android.view.MotionEvent; | ||||
| import android.view.View; | ||||
| import android.view.animation.AccelerateDecelerateInterpolator; | ||||
| import android.view.animation.DecelerateInterpolator; | ||||
| import android.view.animation.OvershootInterpolator; | ||||
| import android.widget.FrameLayout; | ||||
| import android.widget.ImageView; | ||||
| 
 | ||||
| import androidx.annotation.ColorInt; | ||||
| import androidx.annotation.DrawableRes; | ||||
| import androidx.annotation.Px; | ||||
| import androidx.appcompat.widget.AppCompatImageView; | ||||
| import androidx.core.content.ContextCompat; | ||||
| 
 | ||||
| import com.varunest.sparkbutton.helpers.SparkAnimationView; | ||||
| import com.varunest.sparkbutton.helpers.Utils; | ||||
| 
 | ||||
| /** | ||||
|  * @author varun 7th July 2016 | ||||
|  */ | ||||
| public class SparkButton extends FrameLayout implements View.OnClickListener { | ||||
|     private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); | ||||
|     private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator(); | ||||
|     private static final OvershootInterpolator OVERSHOOT_INTERPOLATOR = new OvershootInterpolator(4); | ||||
| 
 | ||||
|     private static final int INVALID_RESOURCE_ID = -1; | ||||
|     private static final float ANIMATIONVIEW_SIZE_FACTOR = 3; | ||||
|     private static final float DOTS_SIZE_FACTOR = .08f; | ||||
|     int activeImageTint; | ||||
|     int inActiveImageTint; | ||||
|     private @DrawableRes | ||||
|     int imageResourceIdActive = INVALID_RESOURCE_ID; | ||||
|     private @DrawableRes | ||||
|     int imageResourceIdInactive = INVALID_RESOURCE_ID; | ||||
|     private @Px | ||||
|     int imageSize; | ||||
|     private @ColorInt | ||||
|     int primaryColor; | ||||
|     private @ColorInt | ||||
|     int secondaryColor; | ||||
|     private SparkAnimationView sparkAnimationView; | ||||
|     private ImageView imageView; | ||||
|     private float animationSpeed = 1; | ||||
|     private boolean isChecked = false; | ||||
|     private AnimatorSet animatorSet; | ||||
|     private SparkEventListener listener; | ||||
| 
 | ||||
|     SparkButton(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
| 
 | ||||
|     public SparkButton(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|         initFromXML(attrs); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     public SparkButton(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|         initFromXML(attrs); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     @TargetApi(Build.VERSION_CODES.LOLLIPOP) | ||||
|     public SparkButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | ||||
|         super(context, attrs, defStyleAttr, defStyleRes); | ||||
|         initFromXML(attrs); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     void init() { | ||||
|         int animationViewSize = (int) (imageSize * ANIMATIONVIEW_SIZE_FACTOR); | ||||
| 
 | ||||
|         sparkAnimationView = new SparkAnimationView(getContext()); | ||||
|         LayoutParams dotsViewLayoutParams = new LayoutParams(animationViewSize, animationViewSize, Gravity.CENTER); | ||||
|         sparkAnimationView.setLayoutParams(dotsViewLayoutParams); | ||||
| 
 | ||||
|         sparkAnimationView.setColors(secondaryColor, primaryColor); | ||||
|         sparkAnimationView.setMaxDotSize((int) (imageSize * DOTS_SIZE_FACTOR)); | ||||
| 
 | ||||
|         addView(sparkAnimationView); | ||||
| 
 | ||||
|         imageView = new AppCompatImageView(getContext()); | ||||
|         LayoutParams imageViewLayoutParams = new LayoutParams(imageSize, imageSize, Gravity.CENTER); | ||||
|         imageView.setLayoutParams(imageViewLayoutParams); | ||||
| 
 | ||||
|         addView(imageView); | ||||
| 
 | ||||
|         if (imageResourceIdInactive != INVALID_RESOURCE_ID) { | ||||
|             // should load inactive img first | ||||
|             imageView.setImageResource(imageResourceIdInactive); | ||||
|         } else if (imageResourceIdActive != INVALID_RESOURCE_ID) { | ||||
|             imageView.setImageResource(imageResourceIdActive); | ||||
|         } else { | ||||
|             throw new IllegalArgumentException("One of Inactive/Active Image Resources is required!"); | ||||
|         } | ||||
|         setOnTouchListener(); | ||||
|         setOnClickListener(this); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Call this function to start spark animation | ||||
|      */ | ||||
|     public void playAnimation() { | ||||
|         if (animatorSet != null) { | ||||
|             animatorSet.cancel(); | ||||
|         } | ||||
| 
 | ||||
|         imageView.animate().cancel(); | ||||
|         imageView.setScaleX(0); | ||||
|         imageView.setScaleY(0); | ||||
|         sparkAnimationView.setInnerCircleRadiusProgress(0); | ||||
|         sparkAnimationView.setOuterCircleRadiusProgress(0); | ||||
|         sparkAnimationView.setCurrentProgress(0); | ||||
| 
 | ||||
|         animatorSet = new AnimatorSet(); | ||||
| 
 | ||||
|         ObjectAnimator outerCircleAnimator = ObjectAnimator.ofFloat(sparkAnimationView, SparkAnimationView.OUTER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f); | ||||
|         outerCircleAnimator.setDuration((long) (250 / animationSpeed)); | ||||
|         outerCircleAnimator.setInterpolator(DECELERATE_INTERPOLATOR); | ||||
| 
 | ||||
|         ObjectAnimator innerCircleAnimator = ObjectAnimator.ofFloat(sparkAnimationView, SparkAnimationView.INNER_CIRCLE_RADIUS_PROGRESS, 0.1f, 1f); | ||||
|         innerCircleAnimator.setDuration((long) (200 / animationSpeed)); | ||||
|         innerCircleAnimator.setStartDelay((long) (200 / animationSpeed)); | ||||
|         innerCircleAnimator.setInterpolator(DECELERATE_INTERPOLATOR); | ||||
| 
 | ||||
|         ObjectAnimator starScaleYAnimator = ObjectAnimator.ofFloat(imageView, ImageView.SCALE_Y, 0.2f, 1f); | ||||
|         starScaleYAnimator.setDuration((long) (350 / animationSpeed)); | ||||
|         starScaleYAnimator.setStartDelay((long) (250 / animationSpeed)); | ||||
|         starScaleYAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR); | ||||
| 
 | ||||
|         ObjectAnimator starScaleXAnimator = ObjectAnimator.ofFloat(imageView, ImageView.SCALE_X, 0.2f, 1f); | ||||
|         starScaleXAnimator.setDuration((long) (350 / animationSpeed)); | ||||
|         starScaleXAnimator.setStartDelay((long) (250 / animationSpeed)); | ||||
|         starScaleXAnimator.setInterpolator(OVERSHOOT_INTERPOLATOR); | ||||
| 
 | ||||
|         ObjectAnimator dotsAnimator = ObjectAnimator.ofFloat(sparkAnimationView, SparkAnimationView.DOTS_PROGRESS, 0, 1f); | ||||
|         dotsAnimator.setDuration((long) (900 / animationSpeed)); | ||||
|         dotsAnimator.setStartDelay((long) (50 / animationSpeed)); | ||||
|         dotsAnimator.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR); | ||||
| 
 | ||||
|         animatorSet.playTogether( | ||||
|                 outerCircleAnimator, | ||||
|                 innerCircleAnimator, | ||||
|                 starScaleYAnimator, | ||||
|                 starScaleXAnimator, | ||||
|                 dotsAnimator | ||||
|         ); | ||||
| 
 | ||||
|         animatorSet.addListener(new AnimatorListenerAdapter() { | ||||
|             @Override | ||||
|             public void onAnimationCancel(Animator animation) { | ||||
|                 sparkAnimationView.setInnerCircleRadiusProgress(0); | ||||
|                 sparkAnimationView.setOuterCircleRadiusProgress(0); | ||||
|                 sparkAnimationView.setCurrentProgress(0); | ||||
|                 imageView.setScaleX(1); | ||||
|                 imageView.setScaleY(1); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onAnimationEnd(Animator animation) { | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onAnimationStart(Animator animation) { | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         animatorSet.start(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public @Px | ||||
|     int getImageSize() { | ||||
|         return imageSize; | ||||
|     } | ||||
| 
 | ||||
|     public void setImageSize(@Px int imageSize) { | ||||
|         this.imageSize = imageSize; | ||||
|     } | ||||
| 
 | ||||
|     public @ColorInt | ||||
|     int getPrimaryColor() { | ||||
|         return primaryColor; | ||||
|     } | ||||
| 
 | ||||
|     public void setPrimaryColor(@ColorInt int primaryColor) { | ||||
|         this.primaryColor = primaryColor; | ||||
|     } | ||||
| 
 | ||||
|     public @ColorInt | ||||
|     int getSecondaryColor() { | ||||
|         return secondaryColor; | ||||
|     } | ||||
| 
 | ||||
|     public void setSecondaryColor(@ColorInt int secondaryColor) { | ||||
|         this.secondaryColor = secondaryColor; | ||||
|     } | ||||
| 
 | ||||
|     public void setAnimationSpeed(float animationSpeed) { | ||||
|         this.animationSpeed = animationSpeed; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @return Returns whether the button is checked (Active) or not. | ||||
|      */ | ||||
|     public boolean isChecked() { | ||||
|         return isChecked; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Change Button State (Works only if both active and disabled image resource is defined) | ||||
|      * | ||||
|      * @param flag desired checked state of the button | ||||
|      */ | ||||
|     public void setChecked(boolean flag) { | ||||
|         isChecked = flag; | ||||
|         imageView.setImageResource(isChecked ? imageResourceIdActive : imageResourceIdInactive); | ||||
|     } | ||||
| 
 | ||||
|     public void setInactiveImage(int inactiveResource) { | ||||
|         this.imageResourceIdInactive = inactiveResource; | ||||
|         imageView.setImageResource(isChecked ? imageResourceIdActive : imageResourceIdInactive); | ||||
|     } | ||||
| 
 | ||||
|     public void setActiveImage(int activeResource) { | ||||
|         this.imageResourceIdActive = activeResource; | ||||
|         imageView.setImageResource(isChecked ? imageResourceIdActive : imageResourceIdInactive); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onClick(View v) { | ||||
|         boolean shouldPlayAnimation = listener == null || listener.onEvent(this, isChecked); | ||||
| 
 | ||||
|         if (shouldPlayAnimation) { | ||||
|             if (imageResourceIdInactive != INVALID_RESOURCE_ID) { | ||||
|                 isChecked = !isChecked; | ||||
| 
 | ||||
|                 imageView.setImageResource(isChecked ? imageResourceIdActive : imageResourceIdInactive); | ||||
| 
 | ||||
|                 if (animatorSet != null) { | ||||
|                     animatorSet.cancel(); | ||||
|                 } | ||||
|                 if (isChecked) { | ||||
|                     sparkAnimationView.setVisibility(VISIBLE); | ||||
|                     playAnimation(); | ||||
|                 } else { | ||||
|                     sparkAnimationView.setVisibility(INVISIBLE); | ||||
|                 } | ||||
|             } else { | ||||
|                 playAnimation(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private void setOnTouchListener() { | ||||
|         setOnTouchListener((v, event) -> { | ||||
|             switch (event.getAction()) { | ||||
|                 case MotionEvent.ACTION_DOWN: | ||||
|                     imageView.animate().scaleX(0.8f).scaleY(0.8f).setDuration(150).setInterpolator(DECELERATE_INTERPOLATOR); | ||||
|                     setPressed(true); | ||||
|                     break; | ||||
| 
 | ||||
|                 case MotionEvent.ACTION_MOVE: | ||||
|                     break; | ||||
| 
 | ||||
|                 case MotionEvent.ACTION_UP: | ||||
|                     imageView.animate().scaleX(1).scaleY(1).setInterpolator(DECELERATE_INTERPOLATOR); | ||||
|                     if (isPressed()) { | ||||
|                         performClick(); | ||||
|                         setPressed(false); | ||||
|                     } | ||||
|                     break; | ||||
| 
 | ||||
|                 case MotionEvent.ACTION_CANCEL: | ||||
|                     imageView.animate().scaleX(1).scaleY(1).setInterpolator(DECELERATE_INTERPOLATOR); | ||||
|                     break; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private int getColor(int id) { | ||||
|         return ContextCompat.getColor(getContext(), id); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private void initFromXML(AttributeSet attr) { | ||||
|         TypedArray a = getContext().obtainStyledAttributes(attr, R.styleable.SparkButton); | ||||
|         imageSize = a.getDimensionPixelOffset(R.styleable.SparkButton_iconSize, Utils.dpToPx(getContext(), 50)); | ||||
|         imageResourceIdActive = a.getResourceId(R.styleable.SparkButton_activeImage, INVALID_RESOURCE_ID); | ||||
|         imageResourceIdInactive = a.getResourceId(R.styleable.SparkButton_inactiveImage, INVALID_RESOURCE_ID); | ||||
|         primaryColor = ContextCompat.getColor(getContext(), a.getResourceId(R.styleable.SparkButton_primaryColor, R.color.spark_primary_color)); | ||||
|         secondaryColor = ContextCompat.getColor(getContext(), a.getResourceId(R.styleable.SparkButton_secondaryColor, R.color.spark_secondary_color)); | ||||
|         animationSpeed = a.getFloat(R.styleable.SparkButton_animationSpeed, 1); | ||||
|         // recycle typedArray | ||||
|         a.recycle(); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,61 @@ | |||
| package com.varunest.sparkbutton; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| 
 | ||||
| import androidx.annotation.ColorInt; | ||||
| import androidx.annotation.DrawableRes; | ||||
| 
 | ||||
| import com.varunest.sparkbutton.helpers.Utils; | ||||
| 
 | ||||
| /** | ||||
|  * @author varun on 07/07/16. | ||||
|  */ | ||||
| public class SparkButtonBuilder { | ||||
|     private final SparkButton sparkButton; | ||||
|     private final Context context; | ||||
| 
 | ||||
|     public SparkButtonBuilder(Context context) { | ||||
|         this.context = context; | ||||
|         sparkButton = new SparkButton(context); | ||||
|     } | ||||
| 
 | ||||
|     public SparkButtonBuilder setActiveImage(@DrawableRes int resourceId) { | ||||
|         sparkButton.setActiveImage(resourceId); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SparkButtonBuilder setInactiveImage(@DrawableRes int resourceId) { | ||||
|         sparkButton.setInactiveImage(resourceId); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SparkButtonBuilder setPrimaryColor(@ColorInt int color) { | ||||
|         sparkButton.setPrimaryColor(color); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SparkButtonBuilder setSecondaryColor(int color) { | ||||
|         sparkButton.setSecondaryColor(color); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SparkButtonBuilder setImageSizePx(int px) { | ||||
|         sparkButton.setImageSize(px); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SparkButtonBuilder setImageSizeDp(int dp) { | ||||
|         sparkButton.setImageSize(Utils.dpToPx(context, dp)); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SparkButtonBuilder setAnimationSpeed(float speed) { | ||||
|         sparkButton.setAnimationSpeed(speed); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public SparkButton build() { | ||||
|         sparkButton.init(); | ||||
|         return sparkButton; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,10 @@ | |||
| package com.varunest.sparkbutton; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| /** | ||||
|  * @author varun on 07/07/16. | ||||
|  */ | ||||
| public interface SparkEventListener { | ||||
|     boolean onEvent(@NonNull SparkButton button, boolean buttonState); | ||||
| } | ||||
|  | @ -0,0 +1,249 @@ | |||
| package com.varunest.sparkbutton.helpers; | ||||
| 
 | ||||
| import android.animation.ArgbEvaluator; | ||||
| import android.annotation.TargetApi; | ||||
| import android.content.Context; | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.PorterDuff; | ||||
| import android.graphics.PorterDuffXfermode; | ||||
| import android.os.Build; | ||||
| import android.util.AttributeSet; | ||||
| import android.util.Property; | ||||
| import android.view.View; | ||||
| 
 | ||||
| 
 | ||||
| public class SparkAnimationView extends View { | ||||
|     public static final Property<SparkAnimationView, Float> INNER_CIRCLE_RADIUS_PROGRESS = | ||||
|             new Property<SparkAnimationView, Float>(Float.class, "innerCircleRadiusProgress") { | ||||
|                 @Override | ||||
|                 public Float get(SparkAnimationView object) { | ||||
|                     return object.getInnerCircleRadiusProgress(); | ||||
|                 } | ||||
| 
 | ||||
|                 @Override | ||||
|                 public void set(SparkAnimationView object, Float value) { | ||||
|                     object.setInnerCircleRadiusProgress(value); | ||||
|                 } | ||||
|             }; | ||||
|     private static final int DOTS_COUNT = 12; | ||||
|     private static final int OUTER_DOTS_POSITION_ANGLE = 360 / DOTS_COUNT; | ||||
|     private static final ArgbEvaluator argbEvaluator = new ArgbEvaluator(); | ||||
|     public static final Property<SparkAnimationView, Float> DOTS_PROGRESS = new Property<SparkAnimationView, Float>(Float.class, "dotsProgress") { | ||||
|         @Override | ||||
|         public Float get(SparkAnimationView object) { | ||||
|             return object.getCurrentProgress(); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public void set(SparkAnimationView object, Float value) { | ||||
|             object.setCurrentProgress(value); | ||||
|         } | ||||
|     }; | ||||
|     public static final Property<SparkAnimationView, Float> OUTER_CIRCLE_RADIUS_PROGRESS = | ||||
|             new Property<SparkAnimationView, Float>(Float.class, "outerCircleRadiusProgress") { | ||||
|                 @Override | ||||
|                 public Float get(SparkAnimationView object) { | ||||
|                     return object.getOuterCircleRadiusProgress(); | ||||
|                 } | ||||
| 
 | ||||
|                 @Override | ||||
|                 public void set(SparkAnimationView object, Float value) { | ||||
|                     object.setOuterCircleRadiusProgress(value); | ||||
|                 } | ||||
|             }; | ||||
|     private final Paint[] dotsPaints = new Paint[4]; | ||||
|     private final Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); | ||||
|     private final Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); | ||||
|     private int primaryColor = 0xFFFFC107; | ||||
|     private int primaryColorDark = 0xFFFF9800; | ||||
|     private int secondaryColor = 0xFFFF5722; | ||||
|     private int secondaryColorDark = 0xFFF44336; | ||||
|     private int centerX; | ||||
|     private int centerY; | ||||
|     private float maxOuterDotsRadius; | ||||
|     private float maxInnerDotsRadius; | ||||
|     private float maxDotSize; | ||||
|     private float currentProgress = 0; | ||||
|     private float currentRadius1 = 0; | ||||
|     private float currentDotSize1 = 0; | ||||
|     private float currentDotSize2 = 0; | ||||
|     private float currentRadius2 = 0; | ||||
|     private float outerCircleRadiusProgress = 0f; | ||||
|     private float innerCircleRadiusProgress = 0f; | ||||
|     private float maxCircleSize; | ||||
| 
 | ||||
|     public SparkAnimationView(Context context) { | ||||
|         super(context); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     public SparkAnimationView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     public SparkAnimationView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     @TargetApi(Build.VERSION_CODES.LOLLIPOP) | ||||
|     public SparkAnimationView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | ||||
|         super(context, attrs, defStyleAttr, defStyleRes); | ||||
|         init(); | ||||
|     } | ||||
| 
 | ||||
|     private void init() { | ||||
|         setLayerType(View.LAYER_TYPE_HARDWARE, null); | ||||
| 
 | ||||
|         maxDotSize = Utils.dpToPx(getContext(), 4); | ||||
|         for (int i = 0; i < dotsPaints.length; i++) { | ||||
|             dotsPaints[i] = new Paint(Paint.ANTI_ALIAS_FLAG); | ||||
|         } | ||||
| 
 | ||||
|         maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onSizeChanged(int w, int h, int oldw, int oldh) { | ||||
|         centerX = w / 2; | ||||
|         centerY = h / 2; | ||||
|         maxOuterDotsRadius = w / 2 - maxDotSize * 2; | ||||
|         maxInnerDotsRadius = 0.8f * maxOuterDotsRadius; | ||||
|         maxCircleSize = w / 4.3f; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onDraw(Canvas canvas) { | ||||
|         drawOuterDotsFrame(canvas); | ||||
|         drawInnerDotsFrame(canvas); | ||||
| 
 | ||||
|         canvas.drawCircle(getWidth() / 2, getHeight() / 2, outerCircleRadiusProgress * maxCircleSize, circlePaint); | ||||
|         canvas.drawCircle(getWidth() / 2, getHeight() / 2, innerCircleRadiusProgress * (maxCircleSize + 1), maskPaint); | ||||
|     } | ||||
| 
 | ||||
|     public void setMaxDotSize(int pxUnits) { | ||||
|         maxDotSize = pxUnits; | ||||
|     } | ||||
| 
 | ||||
|     private void drawOuterDotsFrame(Canvas canvas) { | ||||
|         for (int i = 0; i < DOTS_COUNT; i++) { | ||||
|             int cX = (int) (centerX + currentRadius1 * Math.cos(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180)); | ||||
|             int cY = (int) (centerY + currentRadius1 * Math.sin(i * OUTER_DOTS_POSITION_ANGLE * Math.PI / 180)); | ||||
|             canvas.drawCircle(cX, cY, currentDotSize1, dotsPaints[i % dotsPaints.length]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void drawInnerDotsFrame(Canvas canvas) { | ||||
|         for (int i = 0; i < DOTS_COUNT; i++) { | ||||
|             int cX = (int) (centerX + currentRadius2 * Math.cos((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180)); | ||||
|             int cY = (int) (centerY + currentRadius2 * Math.sin((i * OUTER_DOTS_POSITION_ANGLE - 10) * Math.PI / 180)); | ||||
|             canvas.drawCircle(cX, cY, currentDotSize2, dotsPaints[(i + 1) % dotsPaints.length]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public float getCurrentProgress() { | ||||
|         return currentProgress; | ||||
|     } | ||||
| 
 | ||||
|     public void setCurrentProgress(float currentProgress) { | ||||
|         this.currentProgress = currentProgress; | ||||
| 
 | ||||
|         updateInnerDotsPosition(); | ||||
|         updateOuterDotsPosition(); | ||||
|         updateDotsPaints(); | ||||
|         updateDotsAlpha(); | ||||
| 
 | ||||
|         postInvalidate(); | ||||
|     } | ||||
| 
 | ||||
|     private void updateInnerDotsPosition() { | ||||
|         if (currentProgress < 0.3f) { | ||||
|             this.currentRadius2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0, 0.3f, 0.f, maxInnerDotsRadius); | ||||
|         } else { | ||||
|             this.currentRadius2 = maxInnerDotsRadius; | ||||
|         } | ||||
| 
 | ||||
|         if (currentProgress < 0.2) { | ||||
|             this.currentDotSize2 = maxDotSize; | ||||
|         } else if (currentProgress < 0.5) { | ||||
|             this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.2f, 0.5f, maxDotSize, 0.3 * maxDotSize); | ||||
|         } else { | ||||
|             this.currentDotSize2 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, maxDotSize * 0.3f, 0); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private void updateOuterDotsPosition() { | ||||
|         if (currentProgress < 0.3f) { | ||||
|             this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.0f, 0.3f, 0, maxOuterDotsRadius * 0.8f); | ||||
|         } else { | ||||
|             this.currentRadius1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.3f, 1f, 0.8f * maxOuterDotsRadius, maxOuterDotsRadius); | ||||
|         } | ||||
| 
 | ||||
|         if (currentProgress < 0.7) { | ||||
|             this.currentDotSize1 = maxDotSize; | ||||
|         } else { | ||||
|             this.currentDotSize1 = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.7f, 1f, maxDotSize, 0); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void updateDotsPaints() { | ||||
|         if (currentProgress < 0.5f) { | ||||
|             float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0f, 0.5f, 0, 1f); | ||||
|             dotsPaints[0].setColor((Integer) argbEvaluator.evaluate(progress, primaryColor, primaryColorDark)); | ||||
|             dotsPaints[1].setColor((Integer) argbEvaluator.evaluate(progress, primaryColorDark, secondaryColor)); | ||||
|             dotsPaints[2].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColor, secondaryColorDark)); | ||||
|             dotsPaints[3].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColorDark, primaryColor)); | ||||
|         } else { | ||||
|             float progress = (float) Utils.mapValueFromRangeToRange(currentProgress, 0.5f, 1f, 0, 1f); | ||||
|             dotsPaints[0].setColor((Integer) argbEvaluator.evaluate(progress, primaryColorDark, secondaryColor)); | ||||
|             dotsPaints[1].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColor, secondaryColorDark)); | ||||
|             dotsPaints[2].setColor((Integer) argbEvaluator.evaluate(progress, secondaryColorDark, primaryColor)); | ||||
|             dotsPaints[3].setColor((Integer) argbEvaluator.evaluate(progress, primaryColor, primaryColorDark)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void updateDotsAlpha() { | ||||
|         float progress = (float) Utils.clamp(currentProgress, 0.6f, 1f); | ||||
|         int alpha = (int) Utils.mapValueFromRangeToRange(progress, 0.6f, 1f, 255, 0); | ||||
|         dotsPaints[0].setAlpha(alpha); | ||||
|         dotsPaints[1].setAlpha(alpha); | ||||
|         dotsPaints[2].setAlpha(alpha); | ||||
|         dotsPaints[3].setAlpha(alpha); | ||||
|     } | ||||
| 
 | ||||
|     public void setColors(int primaryColor, int secondaryColor) { | ||||
|         this.primaryColor = primaryColor; | ||||
|         this.primaryColorDark = Utils.darkenColor(primaryColor, 1.1f); | ||||
|         this.secondaryColor = secondaryColor; | ||||
|         this.secondaryColorDark = Utils.darkenColor(secondaryColor, 1.1f); | ||||
|     } | ||||
| 
 | ||||
|     public float getInnerCircleRadiusProgress() { | ||||
|         return innerCircleRadiusProgress; | ||||
|     } | ||||
| 
 | ||||
|     public void setInnerCircleRadiusProgress(float innerCircleRadiusProgress) { | ||||
|         this.innerCircleRadiusProgress = innerCircleRadiusProgress; | ||||
|         postInvalidate(); | ||||
|     } | ||||
| 
 | ||||
|     private void updateCircleColor() { | ||||
|         float colorProgress = (float) Utils.clamp(outerCircleRadiusProgress, 0.5, 1); | ||||
|         colorProgress = (float) Utils.mapValueFromRangeToRange(colorProgress, 0.5f, 1f, 0f, 1f); | ||||
|         this.circlePaint.setColor((Integer) argbEvaluator.evaluate(colorProgress, primaryColor, secondaryColor)); | ||||
|     } | ||||
| 
 | ||||
|     public float getOuterCircleRadiusProgress() { | ||||
|         return outerCircleRadiusProgress; | ||||
|     } | ||||
| 
 | ||||
|     public void setOuterCircleRadiusProgress(float outerCircleRadiusProgress) { | ||||
|         this.outerCircleRadiusProgress = outerCircleRadiusProgress; | ||||
|         updateCircleColor(); | ||||
|         postInvalidate(); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,30 @@ | |||
| package com.varunest.sparkbutton.helpers; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.graphics.Color; | ||||
| import android.util.DisplayMetrics; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| public class Utils { | ||||
|     public static double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { | ||||
|         return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); | ||||
|     } | ||||
| 
 | ||||
|     public static double clamp(double value, double low, double high) { | ||||
|         return Math.min(Math.max(value, low), high); | ||||
|     } | ||||
| 
 | ||||
|     public static int darkenColor(int color, float multiplier) { | ||||
|         float[] hsv = new float[3]; | ||||
| 
 | ||||
|         Color.colorToHSV(color, hsv); | ||||
|         hsv[2] *= multiplier; // value component | ||||
|         return Color.HSVToColor(hsv); | ||||
|     } | ||||
| 
 | ||||
|     public static int dpToPx(@NonNull Context context, int dp) { | ||||
|         DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); | ||||
|         return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								sparkbutton/src/main/res/values/attrs.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								sparkbutton/src/main/res/values/attrs.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <declare-styleable name="SparkButton"> | ||||
|         <attr name="iconSize" format="dimension|reference" /> | ||||
|         <attr name="activeImage" format="reference" /> | ||||
|         <attr name="inactiveImage" format="reference" /> | ||||
|         <attr name="primaryColor" format="reference" /> | ||||
|         <attr name="secondaryColor" format="reference" /> | ||||
|         <attr name="animationSpeed" format="float" /> | ||||
|     </declare-styleable> | ||||
| </resources> | ||||
							
								
								
									
										6
									
								
								sparkbutton/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								sparkbutton/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <color name="spark_primary_color">#FFFFC107</color> | ||||
|     <color name="spark_secondary_color">#FFFF5722</color> | ||||
|     <color name="spark_image_tint">#00000000</color> | ||||
| </resources> | ||||
							
								
								
									
										3
									
								
								sparkbutton/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								sparkbutton/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| <resources> | ||||
|     <string name="app_name">SparkButton</string> | ||||
| </resources> | ||||
		Loading…
	
		Reference in a new issue