diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..61a9130 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..48740c8 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..d2ce72d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..314fdcd --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3538998 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Marsad Maqsood + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e948bcd --- /dev/null +++ b/README.md @@ -0,0 +1,360 @@ + +[![](https://jitpack.io/v/MarsadMaqsood/StylishDialogs.svg)](https://jitpack.io/#MarsadMaqsood/StylishDialogs) + + +Stylish Alert Dialog +=================== +Stylish Alert Dialogs for Android. + +### Features +- Ability to set custom view +- More convenient interface to bind listeners (like in AlertDialog) +- Third neutral button with own listener, colors, methods and etc. +- Ability to disable buttons +- Ability to set buttons stroke width +- Dark style of dialogs +- Ability to make dialogs without buttons +- Support of HTML tags +- Ability to set text size +- Ability to set color of buttons + +### Upcoming Dialog Designs +- Text Bouncing Dialog + +### Screenshot +![image](https://github.com/MarsadMaqsood/StylishDialogs/blob/master/assets/sample_1.gif) + +**Maven** + + + + jitpack.io + https://jitpack.io + + + + + com.github.MarsadMaqsood + StylishDialogs + 0.1.+ + + +**Gradle** + + allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } + } + + dependencies { + implementation 'com.github.MarsadMaqsood:StylishDialogs:0.1.+' + } + +## How to Usage + +Show simple material progress + +**Java** + + StylishAlertDialog pDialog = new StylishAlertDialog(this, StylishAlertDialog.PROGRESS); + pDialog.getProgressHelper().setBarColor(Color.parseColor("#A5DC86")); + pDialog.setTitleText("Loading"); + pDialog.setCancelable(false); + pDialog.show(); +--- +**Kotlin** + + val pDialog = StylishAlertDialog(this, StylishAlertDialog.PROGRESS) + pDialog.progressHelper.barColor = Color.parseColor("#A5DC86") + pDialog.titleText = "Loading" + pDialog.setCancelable(false) + pDialog.show() + + +You can customize progress bar dynamically with the materialish-progress methods via + ```StylishAlertDialog.getProgressHelper();``` + + resetCount() + isSpinning() + spin() + stopSpinning() + getProgress() + setProgress(float progress) + setInstantProgress(float progress) + getCircleRadius() + setCircleRadius(int circleRadius) + getBarWidth() + setBarWidth(int barWidth) + getBarColor() + setBarColor(int barColor) + getRimWidth() + setRimWidth(int rimWidth) + getRimColor() + setRimColor(int rimColor) + getSpinSpeed() + setSpinSpeed(float spinSpeed) + getButton(/*StylishAlertDialog.Button)Type*/) + getButton(/*StylishAlertDialog.Button)Type*/).setBackgroundTintList() + +thanks to the project [materialish-progress](https://github.com/pnikosis/materialish-progress) + +Code Samples + +Simple basic message: + +**Java** + + new StylishAlertDialog(this) + .setTitleText("Here's a message!") + .show(); + +___ +**Kotlin** + + StylishAlertDialog(this) + .setTitleText("Here's a message!") + .show() + +Title with a text under: + +**Java** + + new StylishAlertDialog(this) + .setTitleText("Here's a message!") + .setContentText("It's pretty, isn't it?") + .show(); + +___ +**Kotlin** + + StylishAlertDialog(this) + .setTitleText("Here's a message!") + .setContentText("It's pretty, isn't it?") + .show() + +Error message: + +**Java** + + new StylishAlertDialog(this, StylishAlertDialog.ERROR) + .setTitleText("Oops...") + .setContentText("Something went wrong!") + .show(); +--- +**Kotlin** + + StylishAlertDialog(this, StylishAlertDialog.ERROR) + .setTitleText("Oops...") + .setContentText("Something went wrong!") + .show() + + +Warning message: + +**Java** + + new StylishAlertDialog(this, StylishAlertDialog.WARNING) + .setTitleText("Are you sure?") + .setContentText("Won't be able to recover this file!") + .setConfirmText("Yes, delete it!") + .show(); + +--- +**Kotlin** + + StylishAlertDialog(this, StylishAlertDialog.WARNING) + .setTitleText("Are you sure?") + .setContentText("Won't be able to recover this file!") + .setConfirmText("Yes, delete it!") + .show() + +Success message: + +**Java** + + new StylishAlertDialog(this, StylishAlertDialog.SUCCESS) + .setTitleText("Good job!") + .setContentText("You clicked the button!") + .show(); + +--- +**Kotlin** + + StylishAlertDialog(this, StylishAlertDialog.SUCCESS) + .setTitleText("Good job!") + .setContentText("You clicked the button!") + .show() + +Message with a custom icon: + +**Java** + + new StylishAlertDialog(this, StylishAlertDialog.CUSTOM_IMAGE) + .setTitleText("Stylish!") + .setContentText("Here's a custom image.") + .setCustomImage(R.drawable.custom_img) + .show(); + +--- +**Kotlin** + + StylishAlertDialog(this, StylishAlertDialog.CUSTOM_IMAGE) + .setTitleText("Stylish!") + .setContentText("Here's a custom image.") + .setCustomImage(R.drawable.custom_img) + .show() + +Message with a custom view: + +**Java** + + final EditText editText = new EditText(this); + new StylishAlertDialog(this, StylishAlertDialog.NORMAL) + .setTitleText("Custom view") + .setConfirmText("Ok") + .setCustomView(editText) + .show(); +--- +**Kotlin** + + val editText = EditText(this) + StylishAlertDialog(this, StylishAlertDialog.NORMAL) + .setTitleText("Custom view") + .setConfirmText("Ok") + .setCustomView(editText) + .show() + + +Different ways to bind the listener to button: + +**Java** + + new StylishAlertDialog(this, StylishAlertDialog.WARNING) + .setTitleText("Are you sure?") + .setContentText("Won't be able to recover this file!") + .setConfirmText("Yes,delete it!") + .setConfirmClickListener(new StylishAlertDialog.OnStylishClickListener() { + @Override + public void onClick(StylishAlertDialog sDialog) { + sDialog.dismissWithAnimation(); + } + }) + .setCancelButton("Cancel", new StylishAlertDialog.OnStylishClickListener() { + @Override + public void onClick(StylishAlertDialog sDialog) { + sDialog.dismissWithAnimation(); + } + }) + .show(); +--- +**Kotlin** + + StylishAlertDialog(this, StylishAlertDialog.WARNING) + .setTitleText("Are you sure?") + .setContentText("Won't be able to recover this file!") + .setConfirmText("Yes,delete it!") + .setConfirmClickListener(StylishAlertDialog::dismissWithAnimation) + .setCancelButton("Cancel",StylishAlertDialog::dismissWithAnimation) + .show() + +Disable button + +**Java** + + final StylishAlertDialog disabledBtnDialog = new StylishAlertDialog(this, StylishAlertDialog.NORMAL) + .setTitleText("Title") + .setContentText("Disabled button dialog") + .setConfirmText("Confirm") + .setCancelText("Cancel") + + disabledBtnDialog.setOnShowListener(new DialogInterface.OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + disabledBtnDialog.getButton(StylishAlertDialog.BUTTON_CONFIRM).setEnabled(false); + } + }); + disabledBtnDialog.show(); +--- +**Kotlin** + + val disabledBtnDialog = StylishAlertDialog(this, StylishAlertDialog.NORMAL) + .setTitleText("Title") + .setContentText("Disabled button dialog") + .setConfirmText("Confirm") + .setCancelText("Cancel") + disabledBtnDialog.setOnShowListener { + disabledBtnDialog.getButton(StylishAlertDialog.BUTTON_CONFIRM).isEnabled = false + } + disabledBtnDialog.show() + + +**Change** the dialog style upon confirming: + +**Java** + + new StylishAlertDialog(this, StylishAlertDialog.WARNING) + .setTitleText("Are you sure?") + .setContentText("Won't be able to recover this file!") + .setConfirmText("Yes, delete it!") + .setConfirmClickListener(new StylishAlertDialog.OnStylishClickListener() { + @Override + public void onClick(StylishAlertDialog sDialog) { + sDialog + .setTitleText("Deleted!") + .setContentText("Your imaginary file has been deleted!") + .setConfirmText("OK") + .setConfirmClickListener(null) + .changeAlertType(StylishAlertDialog.SUCCESS); + } + }) + .show(); +--- +**Kotlin** + + StylishAlertDialog(this, StylishAlertDialog.WARNING) + .setTitleText("Are you sure?") + .setContentText("Won't be able to recover this file!") + .setConfirmText("Yes, delete it!") + .setConfirmClickListener { sDialog -> + sDialog.setTitleText("Deleted!") + .setContentText("Your imaginary file has been deleted!") + .setConfirmText("OK") + .setConfirmClickListener(null) + .changeAlertType(StylishAlertDialog.SUCCESS) + } + .show() + + +**Proguard-Rules** + + -keep class com.marsad.stylishdialogs.RotatingAnimation { + public (...); + } + + + +## License + + The MIT License (MIT) + + Copyright (c) 2021 Marsad Maqsood + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..5b47736 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,42 @@ +plugins { + id 'com.android.application' +} + +android { + compileSdkVersion 31 + buildToolsVersion "30.0.3" + + defaultConfig { + applicationId "com.marsad.stylishdialogs" + minSdkVersion 16 + targetSdkVersion 31 + multiDexEnabled true + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation project(path: ':stylishdialogs') + implementation "androidx.multidex:multidex:2.0.1" + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..c2c4e6c --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,24 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile +-keep class com.marsad.stylishdialogs.RotatingAnimation { + public (...); +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/marsad/stylishdialogs/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/marsad/stylishdialogs/ExampleInstrumentedTest.java new file mode 100644 index 0000000..733a459 --- /dev/null +++ b/app/src/androidTest/java/com/marsad/stylishdialogs/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.marsad.stylishdialogs; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.marsad.stylishdialogs", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7c242b5 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/marsad/stylishdialogs/MainActivity.java b/app/src/main/java/com/marsad/stylishdialogs/MainActivity.java new file mode 100644 index 0000000..83d7814 --- /dev/null +++ b/app/src/main/java/com/marsad/stylishdialogs/MainActivity.java @@ -0,0 +1,76 @@ +package com.marsad.stylishdialogs; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; + +import androidx.appcompat.app.AppCompatActivity; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + findViewById(R.id.simpleMsgDialog) + .setOnClickListener(v -> + new StylishAlertDialog(this, StylishAlertDialog.NORMAL) + .setContentText("Hey, You try me") + .show() + ); + + findViewById(R.id.titleWTextDialog) + .setOnClickListener(v -> + new StylishAlertDialog(this, StylishAlertDialog.PROGRESS) + .setTitleText("Hey, This is title") + .setContentText("Content text") + .show() + ); + + findViewById(R.id.successMsgDialog) + .setOnClickListener(v -> + new StylishAlertDialog(this, StylishAlertDialog.SUCCESS) + .setContentText("Hey, You try me") + .show() + ); + + findViewById(R.id.errorMsgDialog) + .setOnClickListener(v -> + new StylishAlertDialog(this, StylishAlertDialog.ERROR) + .setContentText("Hey, You try me") + .show() + ); + + findViewById(R.id.successWithNormalDialog) + .setOnClickListener(v -> { + + StylishAlertDialog alertDialog = new StylishAlertDialog(this, StylishAlertDialog.PROGRESS); + alertDialog.setContentText("Processing...") + .show(); + + new Handler(Looper.getMainLooper()) + .postDelayed((Runnable) () -> { + alertDialog.changeAlertType(StylishAlertDialog.SUCCESS); + alertDialog.setContentText("Task Completed"); + alertDialog.setConfirmButton("OK", StylishAlertDialog::dismissWithAnimation); + alertDialog.setNeutralButton("OK n", StylishAlertDialog::dismissWithAnimation); + alertDialog.setCancelButton("Cancel", StylishAlertDialog::dismissWithAnimation); + }, 2500); + + }); + + findViewById(R.id.warnWithConfirmBtn) + .setOnClickListener(v -> { + StylishAlertDialog alertDialog = new StylishAlertDialog(this, StylishAlertDialog.WARNING); + alertDialog.setContentText("Are you sure you want to proceed") + .setConfirmButton("Yes, Proceed", StylishAlertDialog -> { + alertDialog.changeAlertType(com.marsad.stylishdialogs.StylishAlertDialog.SUCCESS); + alertDialog.setContentText("Job Done"); + alertDialog.setConfirmButton("OK", com.marsad.stylishdialogs.StylishAlertDialog::dismissWithAnimation); + }) + .show(); + }); + + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..6f79d55 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..c209e78 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..b2dfe3d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4f0f1d6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..62b611d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..948a307 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..1b9a695 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..28d4b77 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9287f50 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..aa7d642 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9126ae3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..feaabde --- /dev/null +++ b/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..8d365c6 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Stylish Dialogs + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..dd87dc3 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/app/src/test/java/com/marsad/stylishdialogs/ExampleUnitTest.java b/app/src/test/java/com/marsad/stylishdialogs/ExampleUnitTest.java new file mode 100644 index 0000000..819bca7 --- /dev/null +++ b/app/src/test/java/com/marsad/stylishdialogs/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.marsad.stylishdialogs; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/assets/sample_1.gif b/assets/sample_1.gif new file mode 100644 index 0000000..c8b2764 Binary files /dev/null and b/assets/sample_1.gif differ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..095a996 --- /dev/null +++ b/build.gradle @@ -0,0 +1,25 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + google() + mavenCentral() + maven{url 'https://jitpack.io'} + } + dependencies { + classpath 'com.android.tools.build:gradle:4.2.2' + classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..52f5917 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..5a8cb9e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Feb 17 17:44:55 PKT 2021 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/install.Unix.sh b/install.Unix.sh new file mode 100644 index 0000000..e69de29 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..a9fbda1 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,3 @@ +include ':stylishdialogs' +include ':app' +rootProject.name = "StylishDialogs" \ No newline at end of file diff --git a/stylishdialogs/.gitignore b/stylishdialogs/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/stylishdialogs/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/stylishdialogs/build.gradle b/stylishdialogs/build.gradle new file mode 100644 index 0000000..51894cf --- /dev/null +++ b/stylishdialogs/build.gradle @@ -0,0 +1,24 @@ +plugins { + id 'com.android.library' +} + +android { + compileSdkVersion 31 + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 31 + versionCode 1 + versionName "1.0" + } + + lintOptions { + abortOnError false + } + +} + +dependencies { + implementation 'com.pnikosis:materialish-progress:1.7' + implementation 'androidx.appcompat:appcompat:1.3.1' +} \ No newline at end of file diff --git a/stylishdialogs/src/androidTest/java/com/marsad/stylishdialogs/ExampleInstrumentedTest.java b/stylishdialogs/src/androidTest/java/com/marsad/stylishdialogs/ExampleInstrumentedTest.java new file mode 100644 index 0000000..cd1e134 --- /dev/null +++ b/stylishdialogs/src/androidTest/java/com/marsad/stylishdialogs/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.marsad.stylishdialogs; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.marsad.stylishdialogs.test", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/stylishdialogs/src/main/AndroidManifest.xml b/stylishdialogs/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c4b4ec6 --- /dev/null +++ b/stylishdialogs/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/java/com/marsad/stylishdialogs/AnimLoader.java b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/AnimLoader.java new file mode 100644 index 0000000..5715b97 --- /dev/null +++ b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/AnimLoader.java @@ -0,0 +1,104 @@ +package com.marsad.stylishdialogs; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.AnimationSet; +import android.view.animation.RotateAnimation; +import android.view.animation.ScaleAnimation; +import android.view.animation.TranslateAnimation; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +public class AnimLoader { + + public static Animation loadAnimation(Context context, int id) + throws Resources.NotFoundException { + + XmlResourceParser parser = null; + try { + parser = context.getResources().getAnimation(id); + return createAnimationFromXml(context, parser); + } catch (XmlPullParserException ex) { + Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(ex); + throw rnf; + } catch (IOException ex) { + Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(ex); + throw rnf; + } finally { + if (parser != null) parser.close(); + } + } + + private static Animation createAnimationFromXml(Context c, XmlPullParser parser) + throws XmlPullParserException, IOException { + + return createAnimationFromXml(c, parser, null, Xml.asAttributeSet(parser)); + } + + private static Animation createAnimationFromXml(Context c, XmlPullParser parser, + AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException { + + Animation anim = null; + + int type; + int depth = parser.getDepth(); + + while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) + && type != XmlPullParser.END_DOCUMENT) { + + if (type != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + + switch (name) { + case "set": + anim = new AnimationSet(c, attrs); + createAnimationFromXml(c, parser, (AnimationSet) anim, attrs); + break; + case "alpha": + anim = new AlphaAnimation(c, attrs); + break; + case "scale": + anim = new ScaleAnimation(c, attrs); + break; + case "rotate": + anim = new RotateAnimation(c, attrs); + break; + case "translate": + anim = new TranslateAnimation(c, attrs); + break; + default: + Log.d("ANIM_NAME", name); + try { + anim = (Animation) Class.forName(name).getConstructor(Context.class, AttributeSet.class).newInstance(c, attrs); + } catch (Exception te) { + throw new RuntimeException("Unknown animation name: " + parser.getName() + " error:" + te.getMessage()); + } + break; + } + + if (parent != null) { + parent.addAnimation(anim); + } + } + + return anim; + + } + +} diff --git a/stylishdialogs/src/main/java/com/marsad/stylishdialogs/Constants.java b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/Constants.java new file mode 100644 index 0000000..a86e384 --- /dev/null +++ b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/Constants.java @@ -0,0 +1,32 @@ +package com.marsad.stylishdialogs; + +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.view.MotionEvent; +import android.view.View; + +public class Constants { + public static final View.OnTouchListener FOCUS_TOUCH_LISTENER = new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + Drawable drawable = v.getBackground(); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_BUTTON_PRESS: + + drawable.setColorFilter(0x20000000, PorterDuff.Mode.SRC_ATOP); + v.invalidate(); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + drawable.clearColorFilter(); + v.invalidate(); + break; + } + return false; + } + + }; + + +} diff --git a/stylishdialogs/src/main/java/com/marsad/stylishdialogs/PGHelper.java b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/PGHelper.java new file mode 100644 index 0000000..29d2c05 --- /dev/null +++ b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/PGHelper.java @@ -0,0 +1,169 @@ +package com.marsad.stylishdialogs; + +import android.content.Context; + +import com.pnikosis.materialishprogress.ProgressWheel; + +public class PGHelper { + + private ProgressWheel mProgressWheel; + private boolean mToSpin; + private float mSpinSpeed; + private int mBarWidth; + private int mBarColor; + private int mRimWidth; + private int mRimColor; + private boolean mIsInstantProgress; + private float mProgressVal; + private int mCircleRadius; + + public PGHelper(Context context) { + mToSpin = true; + mSpinSpeed = 0.75f; + mBarWidth = context.getResources().getDimensionPixelSize(R.dimen.common_circle_width) + 1; + mBarColor = context.getResources().getColor(R.color.success_stroke_color); + mRimWidth = 0; + mRimColor = 0x00000000; + mIsInstantProgress = false; + mProgressVal = -1; + mCircleRadius = context.getResources().getDimensionPixelOffset(R.dimen.progress_circle_radius); + } + + public ProgressWheel getProgressWheel() { + return mProgressWheel; + } + + public void setProgressWheel(ProgressWheel progressWheel) { + mProgressWheel = progressWheel; + updatePropsIfNeed(); + } + + private void updatePropsIfNeed() { + if (mProgressWheel != null) { + if (!mToSpin && mProgressWheel.isSpinning()) { + mProgressWheel.stopSpinning(); + } else if (mToSpin && !mProgressWheel.isSpinning()) { + mProgressWheel.spin(); + } + if (mSpinSpeed != mProgressWheel.getSpinSpeed()) { + mProgressWheel.setSpinSpeed(mSpinSpeed); + } + if (mBarWidth != mProgressWheel.getBarWidth()) { + mProgressWheel.setBarWidth(mBarWidth); + } + if (mBarColor != mProgressWheel.getBarColor()) { + mProgressWheel.setBarColor(mBarColor); + } + if (mRimWidth != mProgressWheel.getRimWidth()) { + mProgressWheel.setRimWidth(mRimWidth); + } + if (mRimColor != mProgressWheel.getRimColor()) { + mProgressWheel.setRimColor(mRimColor); + } + if (mProgressVal != mProgressWheel.getProgress()) { + if (mIsInstantProgress) { + mProgressWheel.setInstantProgress(mProgressVal); + } else { + mProgressWheel.setProgress(mProgressVal); + } + } + if (mCircleRadius != mProgressWheel.getCircleRadius()) { + mProgressWheel.setCircleRadius(mCircleRadius); + } + } + } + + public void resetCount() { + if (mProgressWheel != null) { + mProgressWheel.resetCount(); + } + } + + public boolean isSpinning() { + return mToSpin; + } + + public void spin() { + mToSpin = true; + updatePropsIfNeed(); + } + + public void stopSpinning() { + mToSpin = false; + updatePropsIfNeed(); + } + + public float getProgress() { + return mProgressVal; + } + + public void setProgress(float progress) { + mIsInstantProgress = false; + mProgressVal = progress; + updatePropsIfNeed(); + } + + public void setInstantProgress(float progress) { + mProgressVal = progress; + mIsInstantProgress = true; + updatePropsIfNeed(); + } + + public int getCircleRadius() { + return mCircleRadius; + } + + /** + * @param circleRadius units using pixel + **/ + public void setCircleRadius(int circleRadius) { + mCircleRadius = circleRadius; + updatePropsIfNeed(); + } + + public int getBarWidth() { + return mBarWidth; + } + + public void setBarWidth(int barWidth) { + mBarWidth = barWidth; + updatePropsIfNeed(); + } + + public int getBarColor() { + return mBarColor; + } + + public void setBarColor(int barColor) { + mBarColor = barColor; + updatePropsIfNeed(); + } + + public int getRimWidth() { + return mRimWidth; + } + + public void setRimWidth(int rimWidth) { + mRimWidth = rimWidth; + updatePropsIfNeed(); + } + + public int getRimColor() { + return mRimColor; + } + + public void setRimColor(int rimColor) { + mRimColor = rimColor; + updatePropsIfNeed(); + } + + public float getSpinSpeed() { + return mSpinSpeed; + } + + public void setSpinSpeed(float spinSpeed) { + mSpinSpeed = spinSpeed; + updatePropsIfNeed(); + } + +} diff --git a/stylishdialogs/src/main/java/com/marsad/stylishdialogs/RotatingAnimation.java b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/RotatingAnimation.java new file mode 100644 index 0000000..66ea441 --- /dev/null +++ b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/RotatingAnimation.java @@ -0,0 +1,157 @@ +package com.marsad.stylishdialogs; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Camera; +import android.graphics.Matrix; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +public class RotatingAnimation extends Animation { + public static final int ROLL_BY_X = 0; + public static final int ROLL_BY_Y = 1; + public static final int ROLL_BY_Z = 2; + private int mPivotXType = ABSOLUTE; + private int mPivotYType = ABSOLUTE; + private float mPivotXValue = 0.0f; + private float mPivotYValue = 0.0f; + private float mFromDegrees; + private float mToDegrees; + private float mPivotX; + private float mPivotY; + private Camera mCamera; + private int mRollType; + + public RotatingAnimation(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RotatingAnimation); + + mFromDegrees = a.getFloat(R.styleable.RotatingAnimation_fromDeg, 0.0f); + mToDegrees = a.getFloat(R.styleable.RotatingAnimation_toDeg, 0.0f); + mRollType = a.getInt(R.styleable.RotatingAnimation_rollType, ROLL_BY_X); + Description d = parseValue(a.peekValue(R.styleable.RotatingAnimation_customPivotX)); + mPivotXType = d.type; + mPivotXValue = d.value; + + d = parseValue(a.peekValue(R.styleable.RotatingAnimation_customPivotY)); + mPivotYType = d.type; + mPivotYValue = d.value; + + a.recycle(); + + initializePivotPoint(); + } + + public RotatingAnimation(int rollType, float fromDegrees, float toDegrees) { + mRollType = rollType; + mFromDegrees = fromDegrees; + mToDegrees = toDegrees; + mPivotX = 0.0f; + mPivotY = 0.0f; + } + + public RotatingAnimation(int rollType, float fromDegrees, float toDegrees, float pivotX, float pivotY) { + mRollType = rollType; + mFromDegrees = fromDegrees; + mToDegrees = toDegrees; + + mPivotXType = ABSOLUTE; + mPivotYType = ABSOLUTE; + mPivotXValue = pivotX; + mPivotYValue = pivotY; + initializePivotPoint(); + } + + public RotatingAnimation(int rollType, float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) { + mRollType = rollType; + mFromDegrees = fromDegrees; + mToDegrees = toDegrees; + + mPivotXValue = pivotXValue; + mPivotXType = pivotXType; + mPivotYValue = pivotYValue; + mPivotYType = pivotYType; + initializePivotPoint(); + } + + Description parseValue(TypedValue value) { + Description d = new Description(); + if (value == null) { + d.type = ABSOLUTE; + d.value = 0; + } else { + if (value.type == TypedValue.TYPE_FRACTION) { + d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == + TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? + RELATIVE_TO_PARENT : RELATIVE_TO_SELF; + d.value = TypedValue.complexToFloat(value.data); + return d; + } else if (value.type == TypedValue.TYPE_FLOAT) { + d.type = ABSOLUTE; + d.value = value.getFloat(); + return d; + } else if (value.type >= TypedValue.TYPE_FIRST_INT && + value.type <= TypedValue.TYPE_LAST_INT) { + d.type = ABSOLUTE; + d.value = value.data; + return d; + } + } + + d.type = ABSOLUTE; + d.value = 0.0f; + + return d; + } + + private void initializePivotPoint() { + if (mPivotXType == ABSOLUTE) { + mPivotX = mPivotXValue; + } + if (mPivotYType == ABSOLUTE) { + mPivotY = mPivotYValue; + } + } + + @Override + public void initialize(int width, int height, int parentWidth, int parentHeight) { + super.initialize(width, height, parentWidth, parentHeight); + mCamera = new Camera(); + mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth); + mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight); + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + final float fromDegrees = mFromDegrees; + float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); + + final Matrix matrix = t.getMatrix(); + + mCamera.save(); + switch (mRollType) { + case ROLL_BY_X: + mCamera.rotateX(degrees); + break; + case ROLL_BY_Y: + mCamera.rotateY(degrees); + break; + case ROLL_BY_Z: + mCamera.rotateZ(degrees); + break; + } + mCamera.getMatrix(matrix); + mCamera.restore(); + + matrix.preTranslate(-mPivotX, -mPivotY); + matrix.postTranslate(mPivotX, mPivotY); + } + + protected static class Description { + public int type; + public float value; + } +} diff --git a/stylishdialogs/src/main/java/com/marsad/stylishdialogs/StylishAlertDialog.java b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/StylishAlertDialog.java new file mode 100644 index 0000000..382a863 --- /dev/null +++ b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/StylishAlertDialog.java @@ -0,0 +1,712 @@ +package com.marsad.stylishdialogs; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.os.Bundle; +import android.text.Html; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.AnimationSet; +import android.view.animation.Transformation; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.pnikosis.materialishprogress.ProgressWheel; + +import java.util.List; + +public class StylishAlertDialog extends Dialog implements View.OnClickListener { + public static final int NORMAL = 0; + public static final int ERROR = 1; + public static final int SUCCESS = 2; + public static final int WARNING = 3; + public static final int CUSTOM_IMAGE = 4; + public static final int PROGRESS = 5; + //aliases + public final static int BUTTON_CONFIRM = DialogInterface.BUTTON_POSITIVE; + public final static int BUTTON_CANCEL = DialogInterface.BUTTON_NEGATIVE; + public static boolean DARK_STYLE = false; + private final float defStrokeWidth; + private View mDialogView; + private AnimationSet mModalInAnim; + private AnimationSet mModalOutAnim; + private Animation mOverlayOutAnim; + private Animation mErrorInAnim; + private AnimationSet mErrorXInAnim; + private AnimationSet mSuccessLayoutAnimSet; + private Animation mSuccessBowAnim; + private TextView mTitleTextView; + private TextView mContentTextView; + private FrameLayout mCustomViewContainer; + private View mCustomView; + private String mTitleText; + private String mContentText; + private boolean mShowCancel; + private boolean mShowContent; + private String mCancelText; + private String mConfirmText; + private String mNeutralText; + private int mAlertType; + private FrameLayout mErrorFrame; + private FrameLayout mSuccessFrame; + private FrameLayout mProgressFrame; + private SuccessView mSuccessTick; + private ImageView mErrorX; + private View mSuccessLeftMask; + private View mSuccessRightMask; + private Drawable mCustomImgDrawable; + private ImageView mCustomImage; + private LinearLayout mButtonsContainer; + private Button mConfirmButton; + private boolean mHideConfirmButton = false; + private Button mCancelButton; + private Button mNeutralButton; + private Integer mConfirmButtonBackgroundColor; + private Integer mConfirmButtonTextColor; + private Integer mNeutralButtonBackgroundColor; + private Integer mNeutralButtonTextColor; + private Integer mCancelButtonBackgroundColor; + private Integer mCancelButtonTextColor; + private PGHelper mProgressHelper; + private FrameLayout mWarningFrame; + private OnStylishClickListener mCancelClickListener; + private OnStylishClickListener mConfirmClickListener; + private OnStylishClickListener mNeutralClickListener; + private boolean mCloseFromCancel; + private boolean mHideKeyBoardOnDismiss = true; + private int contentTextSize = 0; + private float strokeWidth = 0; + + + public StylishAlertDialog(Context context) { + this(context, NORMAL); + } + + public StylishAlertDialog(Context context, int alertType) { + super(context, DARK_STYLE ? R.style.alert_dialog_dark : R.style.alert_dialog_light); + setCancelable(true); + setCanceledOnTouchOutside(true); //TODO was false + + defStrokeWidth = getContext().getResources().getDimension(R.dimen.buttons_stroke_width); + strokeWidth = defStrokeWidth; + + mProgressHelper = new PGHelper(context); + mAlertType = alertType; + mErrorInAnim = AnimLoader.loadAnimation(getContext(), R.anim.error_layout_in); + mErrorXInAnim = (AnimationSet) AnimLoader.loadAnimation(getContext(), R.anim.error_in); + // 2.3.x system don't support alpha-animation on layer-list drawable + // remove it from animation set + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { + List childAnim = mErrorXInAnim.getAnimations(); + int idx = 0; + for (; idx < childAnim.size(); idx++) { + if (childAnim.get(idx) instanceof AlphaAnimation) { + break; + } + } + if (idx < childAnim.size()) { + childAnim.remove(idx); + } + } + mSuccessBowAnim = AnimLoader.loadAnimation(getContext(), R.anim.success_rotate); + mSuccessLayoutAnimSet = (AnimationSet) AnimLoader.loadAnimation(getContext(), R.anim.success_layout_rotate); + mModalInAnim = (AnimationSet) AnimLoader.loadAnimation(getContext(), R.anim.model_in); + mModalOutAnim = (AnimationSet) AnimLoader.loadAnimation(getContext(), R.anim.model_out); + mModalOutAnim.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + mDialogView.setVisibility(View.GONE); + if (mHideKeyBoardOnDismiss) { + hideSoftKeyboard(); + } + mDialogView.post(new Runnable() { + @Override + public void run() { + if (mCloseFromCancel) { + StylishAlertDialog.super.cancel(); + } else { + StylishAlertDialog.super.dismiss(); + } + } + }); + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + // dialog overlay fade out + mOverlayOutAnim = new Animation() { + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + WindowManager.LayoutParams wlp = getWindow().getAttributes(); + wlp.alpha = 1 - interpolatedTime; + getWindow().setAttributes(wlp); + } + }; + mOverlayOutAnim.setDuration(120); + } + + public static int spToPx(float sp, Context context) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics()); + } + + public StylishAlertDialog hideConfirmButton() { + this.mHideConfirmButton = true; + return this; + } + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.stylish_dialogs); + + mDialogView = getWindow().getDecorView().findViewById(android.R.id.content); + mTitleTextView = findViewById(R.id.title_text); + mContentTextView = findViewById(R.id.content_text); + mCustomViewContainer = findViewById(R.id.custom_view_container); + mErrorFrame = findViewById(R.id.error_frame); + mErrorX = mErrorFrame.findViewById(R.id.error_x); + mSuccessFrame = findViewById(R.id.success_frame); + mProgressFrame = findViewById(R.id.progress_dialog); + mSuccessTick = mSuccessFrame.findViewById(R.id.success_tick); + mSuccessLeftMask = mSuccessFrame.findViewById(R.id.mask_left); + mSuccessRightMask = mSuccessFrame.findViewById(R.id.mask_right); + mCustomImage = findViewById(R.id.custom_image); + mWarningFrame = findViewById(R.id.warning_frame); + mButtonsContainer = findViewById(R.id.buttons_container); + mConfirmButton = findViewById(R.id.confirm_button); + mConfirmButton.setOnClickListener(this); + mConfirmButton.setOnTouchListener(Constants.FOCUS_TOUCH_LISTENER); + mCancelButton = findViewById(R.id.cancel_button); + mCancelButton.setOnClickListener(this); + mCancelButton.setOnTouchListener(Constants.FOCUS_TOUCH_LISTENER); + mNeutralButton = findViewById(R.id.neutral_button); + mNeutralButton.setOnClickListener(this); + mNeutralButton.setOnTouchListener(Constants.FOCUS_TOUCH_LISTENER); + mProgressHelper.setProgressWheel((ProgressWheel) findViewById(R.id.progressWheel)); + + setTitleText(mTitleText); + setContentText(mContentText); + setCustomView(mCustomView); + setCancelText(mCancelText); + setConfirmText(mConfirmText); + setNeutralText(mNeutralText); + applyStroke(); + setConfirmButtonBackgroundColor(mConfirmButtonBackgroundColor); + setConfirmButtonTextColor(mConfirmButtonTextColor); + setCancelButtonBackgroundColor(mCancelButtonBackgroundColor); + setCancelButtonTextColor(mCancelButtonTextColor); + setNeutralButtonBackgroundColor(mNeutralButtonBackgroundColor); + setNeutralButtonTextColor(mNeutralButtonTextColor); + changeAlertType(mAlertType, true); + + } + + private void restore() { + mCustomImage.setVisibility(View.GONE); + mErrorFrame.setVisibility(View.GONE); + mSuccessFrame.setVisibility(View.GONE); + mWarningFrame.setVisibility(View.GONE); + mProgressFrame.setVisibility(View.GONE); + + mConfirmButton.setVisibility(mHideConfirmButton ? View.GONE : View.VISIBLE); + + adjustButtonContainerVisibility(); + + mConfirmButton.setBackgroundResource(R.drawable.btn_bg_green); + mErrorFrame.clearAnimation(); + mErrorX.clearAnimation(); + mSuccessTick.clearAnimation(); + mSuccessLeftMask.clearAnimation(); + mSuccessRightMask.clearAnimation(); + } + + /** + * Hides buttons container if all buttons are invisible or gone. + * This deletes useless margins + */ + private void adjustButtonContainerVisibility() { + boolean showButtonsContainer = false; + for (int i = 0; i < mButtonsContainer.getChildCount(); i++) { + View view = mButtonsContainer.getChildAt(i); + if (view instanceof Button && view.getVisibility() == View.VISIBLE) { + showButtonsContainer = true; + break; + } + } + mButtonsContainer.setVisibility(showButtonsContainer ? View.VISIBLE : View.GONE); + } + + private void playAnimation() { + if (mAlertType == ERROR) { + mErrorFrame.startAnimation(mErrorInAnim); + mErrorX.startAnimation(mErrorXInAnim); + } else if (mAlertType == SUCCESS) { + mSuccessTick.startTickAnim(); + mSuccessRightMask.startAnimation(mSuccessBowAnim); + } + } + + private void changeAlertType(int alertType, boolean fromCreate) { + mAlertType = alertType; + // call after created views + if (mDialogView != null) { + if (!fromCreate) { + // restore all of views state before switching alert type + restore(); + } + mConfirmButton.setVisibility(mHideConfirmButton ? View.GONE : View.VISIBLE); + switch (mAlertType) { + case ERROR: + mErrorFrame.setVisibility(View.VISIBLE); + break; + case SUCCESS: + mSuccessFrame.setVisibility(View.VISIBLE); + // initial rotate layout of success mask + mSuccessLeftMask.startAnimation(mSuccessLayoutAnimSet.getAnimations().get(0)); + mSuccessRightMask.startAnimation(mSuccessLayoutAnimSet.getAnimations().get(1)); + break; + case WARNING: +// mConfirmButton.setBackgroundResource(R.drawable.red_button_background); + mWarningFrame.setVisibility(View.VISIBLE); + break; + case CUSTOM_IMAGE: + setCustomImage(mCustomImgDrawable); + break; + case PROGRESS: + mProgressFrame.setVisibility(View.VISIBLE); + mConfirmButton.setVisibility(View.GONE); +// mButtonsContainer.setVisibility(View.GONE); + break; + } + adjustButtonContainerVisibility(); + if (!fromCreate) { + playAnimation(); + } + } + } + + public int getAlertType() { + return mAlertType; + } + + public void changeAlertType(int alertType) { + changeAlertType(alertType, false); + } + + public String getTitleText() { + return mTitleText; + } + + public StylishAlertDialog setTitleText(String text) { + mTitleText = text; + if (mTitleTextView != null && mTitleText != null) { + if (text.isEmpty()) { + mTitleTextView.setVisibility(View.GONE); + } else { + mTitleTextView.setVisibility(View.VISIBLE); + mTitleTextView.setText(Html.fromHtml(mTitleText)); + } + } + return this; + } + + public StylishAlertDialog setTitleText(int resId) { + return setTitleText(getContext().getResources().getString(resId)); + } + + public StylishAlertDialog setCustomImage(Drawable drawable) { + mCustomImgDrawable = drawable; + if (mCustomImage != null && mCustomImgDrawable != null) { + mCustomImage.setVisibility(View.VISIBLE); + mCustomImage.setImageDrawable(mCustomImgDrawable); + } + return this; + } + + public StylishAlertDialog setCustomImage(int resourceId) { + return setCustomImage(getContext().getResources().getDrawable(resourceId)); + } + + public String getContentText() { + return mContentText; + } + + /** + * @param text text which can contain html tags. + */ + public StylishAlertDialog setContentText(String text) { + mContentText = text; + if (mContentTextView != null && mContentText != null) { + showContentText(true); + if (contentTextSize != 0) { + mContentTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, spToPx(contentTextSize, getContext())); + } + mContentTextView.setText(Html.fromHtml(mContentText)); + mContentTextView.setVisibility(View.VISIBLE); + mCustomViewContainer.setVisibility(View.GONE); + } + return this; + } + + /** + * @param width in SP + */ + public StylishAlertDialog setStrokeWidth(float width) { + this.strokeWidth = spToPx(width, getContext()); + return this; + } + + private void applyStroke() { + if (Float.compare(defStrokeWidth, strokeWidth) != 0) { + Resources r = getContext().getResources(); + setButtonBackgroundColor(mConfirmButton, r.getColor(R.color.main_green_color)); + setButtonBackgroundColor(mNeutralButton, r.getColor(R.color.main_disabled_color)); + setButtonBackgroundColor(mCancelButton, r.getColor(R.color.red_btn_bg_color)); + } + } + + public boolean isShowCancelButton() { + return mShowCancel; + } + + public StylishAlertDialog showCancelButton(boolean isShow) { + mShowCancel = isShow; + if (mCancelButton != null) { + mCancelButton.setVisibility(mShowCancel ? View.VISIBLE : View.GONE); + } + return this; + } + + public boolean isShowContentText() { + return mShowContent; + } + + public StylishAlertDialog showContentText(boolean isShow) { + mShowContent = isShow; + if (mContentTextView != null) { + mContentTextView.setVisibility(mShowContent ? View.VISIBLE : View.GONE); + } + return this; + } + + public String getCancelText() { + return mCancelText; + } + + public StylishAlertDialog setCancelText(String text) { + mCancelText = text; + if (mCancelButton != null && mCancelText != null) { + showCancelButton(true); + mCancelButton.setText(mCancelText); + } + return this; + } + + public String getConfirmText() { + return mConfirmText; + } + + public StylishAlertDialog setConfirmText(String text) { + mConfirmText = text; + if (mConfirmButton != null && mConfirmText != null) { + mConfirmButton.setText(mConfirmText); + } + return this; + } + + public Integer getConfirmButtonBackgroundColor() { + return mConfirmButtonBackgroundColor; + } + + public StylishAlertDialog setConfirmButtonBackgroundColor(Integer color) { + mConfirmButtonBackgroundColor = color; + setButtonBackgroundColor(mConfirmButton, color); + return this; + } + + public Integer getNeutralButtonBackgroundColor() { + return mNeutralButtonBackgroundColor; + } + + public StylishAlertDialog setNeutralButtonBackgroundColor(Integer color) { + mNeutralButtonBackgroundColor = color; + setButtonBackgroundColor(mNeutralButton, color); + return this; + } + + public Integer getCancelButtonBackgroundColor() { + return mCancelButtonBackgroundColor; + } + + public StylishAlertDialog setCancelButtonBackgroundColor(Integer color) { + mCancelButtonBackgroundColor = color; + setButtonBackgroundColor(mCancelButton, color); + return this; + } + + private void setButtonBackgroundColor(Button btn, Integer color) { + if (btn != null && color != null) { + Drawable[] drawableItems = ViewUtils.getDrawable(btn); + if (drawableItems != null) { + GradientDrawable gradientDrawableUnChecked = (GradientDrawable) drawableItems[1]; + //solid color + gradientDrawableUnChecked.setColor(color); + //stroke + gradientDrawableUnChecked.setStroke((int) strokeWidth, genStrokeColor(color)); + } + } + } + + private int genStrokeColor(int color) { + float[] hsv = new float[3]; + Color.colorToHSV(color, hsv); + hsv[2] *= 0.7f; // decrease value component + return Color.HSVToColor(hsv); + } + + public Integer getConfirmButtonTextColor() { + return mConfirmButtonTextColor; + } + + public StylishAlertDialog setConfirmButtonTextColor(Integer color) { + mConfirmButtonTextColor = color; + if (mConfirmButton != null && color != null) { + mConfirmButton.setTextColor(mConfirmButtonTextColor); + } + return this; + } + + public Integer getNeutralButtonTextColor() { + return mNeutralButtonTextColor; + } + + public StylishAlertDialog setNeutralButtonTextColor(Integer color) { + mNeutralButtonTextColor = color; + if (mNeutralButton != null && color != null) { + mNeutralButton.setTextColor(mNeutralButtonTextColor); + } + return this; + } + + public Integer getCancelButtonTextColor() { + return mCancelButtonTextColor; + } + + public StylishAlertDialog setCancelButtonTextColor(Integer color) { + mCancelButtonTextColor = color; + if (mCancelButton != null && color != null) { + mCancelButton.setTextColor(mCancelButtonTextColor); + } + return this; + } + + public StylishAlertDialog setCancelClickListener(OnStylishClickListener listener) { + mCancelClickListener = listener; + return this; + } + + public StylishAlertDialog setConfirmClickListener(OnStylishClickListener listener) { + mConfirmClickListener = listener; + return this; + } + + public StylishAlertDialog setNeutralText(String text) { + mNeutralText = text; + if (mNeutralButton != null && mNeutralText != null && !text.isEmpty()) { + mNeutralButton.setVisibility(View.VISIBLE); + mNeutralButton.setText(mNeutralText); + } + return this; + } + + public StylishAlertDialog setNeutralClickListener(OnStylishClickListener listener) { + mNeutralClickListener = listener; + return this; + } + + @Override + public void setTitle(CharSequence title) { + this.setTitleText(title.toString()); + } + + @Override + public void setTitle(int titleId) { + this.setTitleText(getContext().getResources().getString(titleId)); + } + + public Button getButton(int buttonType) { + switch (buttonType) { + default: + case BUTTON_CONFIRM: + return mConfirmButton; + case BUTTON_CANCEL: + return mCancelButton; + case BUTTON_NEUTRAL: + return mNeutralButton; + } + } + + public StylishAlertDialog setConfirmButton(String text, OnStylishClickListener listener) { + this.setConfirmText(text); + this.setConfirmClickListener(listener); + return this; + } + + public StylishAlertDialog setConfirmButton(int resId, OnStylishClickListener listener) { + String text = getContext().getResources().getString(resId); + setConfirmButton(text, listener); + return this; + } + + public StylishAlertDialog setCancelButton(String text, OnStylishClickListener listener) { + this.setCancelText(text); + this.setCancelClickListener(listener); + return this; + } + + public StylishAlertDialog setCancelButton(int resId, OnStylishClickListener listener) { + String text = getContext().getResources().getString(resId); + setCancelButton(text, listener); + return this; + } + + public StylishAlertDialog setNeutralButton(String text, OnStylishClickListener listener) { + this.setNeutralText(text); + this.setNeutralClickListener(listener); + return this; + } + + public StylishAlertDialog setNeutralButton(int resId, OnStylishClickListener listener) { + String text = getContext().getResources().getString(resId); + setNeutralButton(text, listener); + return this; + } + + public int getContentTextSize() { + return contentTextSize; + } + + /** + * Set content text size + * + * @param value text size in sp + */ + public StylishAlertDialog setContentTextSize(int value) { + this.contentTextSize = value; + return this; + } + + protected void onStart() { + mDialogView.startAnimation(mModalInAnim); + playAnimation(); + } + + /** + * set custom view instead of message + * + * @param view + */ + public StylishAlertDialog setCustomView(View view) { + mCustomView = view; + if (mCustomView != null && mCustomViewContainer != null) { + mCustomViewContainer.addView(view); + mCustomViewContainer.setVisibility(View.VISIBLE); + mContentTextView.setVisibility(View.GONE); + } + return this; + } + + /** + * The real Dialog.cancel() will be invoked async-ly after the animation finishes. + */ + @Override + public void cancel() { + dismissWithAnimation(true); + } + + /** + * The real Dialog.dismiss() will be invoked async-ly after the animation finishes. + */ + public void dismissWithAnimation() { + dismissWithAnimation(false); + } + + private void dismissWithAnimation(boolean fromCancel) { + mCloseFromCancel = fromCancel; + //several view animations can't be launched at one view, that's why apply alpha animation on child + ((ViewGroup) mDialogView).getChildAt(0).startAnimation(mOverlayOutAnim); //alpha animation + mDialogView.startAnimation(mModalOutAnim); //scale animation + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.cancel_button) { + if (mCancelClickListener != null) { + mCancelClickListener.onClick(StylishAlertDialog.this); + } else { + dismissWithAnimation(); + } + } else if (v.getId() == R.id.confirm_button) { + if (mConfirmClickListener != null) { + mConfirmClickListener.onClick(StylishAlertDialog.this); + } else { + dismissWithAnimation(); + } + } else if (v.getId() == R.id.neutral_button) { + if (mNeutralClickListener != null) { + mNeutralClickListener.onClick(StylishAlertDialog.this); + } else { + dismissWithAnimation(); + } + } + } + + public PGHelper getProgressHelper() { + return mProgressHelper; + } + + public boolean isHideKeyBoardOnDismiss() { + return this.mHideKeyBoardOnDismiss; + } + + public StylishAlertDialog setHideKeyBoardOnDismiss(boolean hide) { + this.mHideKeyBoardOnDismiss = hide; + return this; + } + + private void hideSoftKeyboard() { + Activity activity = getOwnerActivity(); + if (activity != null) { + InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); + if (inputMethodManager != null && activity.getCurrentFocus() != null) { + inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0); + } + } + } + + public interface OnStylishClickListener { + void onClick(StylishAlertDialog StylishAlertDialog); + } +} diff --git a/stylishdialogs/src/main/java/com/marsad/stylishdialogs/SuccessView.java b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/SuccessView.java new file mode 100644 index 0000000..fbc3f03 --- /dev/null +++ b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/SuccessView.java @@ -0,0 +1,123 @@ +package com.marsad.stylishdialogs; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +public class SuccessView extends View { + private float mDensity = -1; + private final float CONST_RADIUS = dip2px(1.2f); + private final float CONST_RECT_WEIGHT = dip2px(3); + private final float CONST_LEFT_RECT_W = dip2px(15); + private final float CONST_RIGHT_RECT_W = dip2px(25); + private final float MIN_LEFT_RECT_W = dip2px(3.3f); + private final float MAX_RIGHT_RECT_W = CONST_RIGHT_RECT_W + dip2px(6.7f); + private Paint mPaint; + private float mMaxLeftRectWidth; + private float mLeftRectWidth; + private float mRightRectWidth; + private boolean mLeftRectGrowMode; + + public SuccessView(Context context) { + super(context); + init(); + } + + public SuccessView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + mPaint = new Paint(); + mPaint.setColor(getResources().getColor(R.color.success_stroke_color)); + mLeftRectWidth = CONST_LEFT_RECT_W; + mRightRectWidth = CONST_RIGHT_RECT_W; + mLeftRectGrowMode = false; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); +// todo: changed int to float + float totalW = getWidth(); + float totalH = getHeight(); + // rotate canvas first + canvas.rotate(45, totalW / 2, totalH / 2); + + totalW /= 1.2; + totalH /= 1.4; + mMaxLeftRectWidth = (totalW + CONST_LEFT_RECT_W) / 2 + CONST_RECT_WEIGHT - 1; + + RectF leftRect = new RectF(); + if (mLeftRectGrowMode) { + leftRect.left = 0; + leftRect.right = leftRect.left + mLeftRectWidth; + } else { + leftRect.right = (totalW + CONST_LEFT_RECT_W) / 2 + CONST_RECT_WEIGHT - 1; + leftRect.left = leftRect.right - mLeftRectWidth; + } + //todo; extracted common part from if + leftRect.top = (totalH + CONST_RIGHT_RECT_W) / 2; + leftRect.bottom = leftRect.top + CONST_RECT_WEIGHT; + //todo: and else + canvas.drawRoundRect(leftRect, CONST_RADIUS, CONST_RADIUS, mPaint); + + RectF rightRect = new RectF(); + rightRect.bottom = (totalH + CONST_RIGHT_RECT_W) / 2 + CONST_RECT_WEIGHT - 1; + rightRect.left = (totalW + CONST_LEFT_RECT_W) / 2; + rightRect.right = rightRect.left + CONST_RECT_WEIGHT; + rightRect.top = rightRect.bottom - mRightRectWidth; + canvas.drawRoundRect(rightRect, CONST_RADIUS, CONST_RADIUS, mPaint); + } + + public float dip2px(float dpValue) { + if (mDensity == -1) { + mDensity = getResources().getDisplayMetrics().density; + } + return dpValue * mDensity + 0.5f; + } + + public void startTickAnim() { + // hide tick + mLeftRectWidth = 0; + mRightRectWidth = 0; + invalidate(); + Animation tickAnim = new Animation() { + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + super.applyTransformation(interpolatedTime, t); + if (0.54 < interpolatedTime && 0.7 >= interpolatedTime) { // grow left and right rect to right + mLeftRectGrowMode = true; + mLeftRectWidth = mMaxLeftRectWidth * ((interpolatedTime - 0.54f) / 0.16f); + if (0.65 < interpolatedTime) { + mRightRectWidth = MAX_RIGHT_RECT_W * ((interpolatedTime - 0.65f) / 0.19f); + } + invalidate(); + } else if (0.7 < interpolatedTime && 0.84 >= interpolatedTime) { // shorten left rect from right, still grow right rect + mLeftRectGrowMode = false; + mLeftRectWidth = mMaxLeftRectWidth * (1 - ((interpolatedTime - 0.7f) / 0.14f)); + mLeftRectWidth = Math.max(mLeftRectWidth, MIN_LEFT_RECT_W); +// todo:changes//upper line with +// Math.max// +// mLeftRectWidth = mLeftRectWidth < MIN_LEFT_RECT_W ? MIN_LEFT_RECT_W : mLeftRectWidth; + mRightRectWidth = MAX_RIGHT_RECT_W * ((interpolatedTime - 0.65f) / 0.19f); + invalidate(); + } else if (0.84 < interpolatedTime && 1 >= interpolatedTime) { // restore left rect width, shorten right rect to const + mLeftRectGrowMode = false; + mLeftRectWidth = MIN_LEFT_RECT_W + (CONST_LEFT_RECT_W - MIN_LEFT_RECT_W) * ((interpolatedTime - 0.84f) / 0.16f); + mRightRectWidth = CONST_RIGHT_RECT_W + (MAX_RIGHT_RECT_W - CONST_RIGHT_RECT_W) * (1 - ((interpolatedTime - 0.84f) / 0.16f)); + invalidate(); + } + } + }; + tickAnim.setDuration(750); + tickAnim.setStartOffset(100); + startAnimation(tickAnim); + } +} \ No newline at end of file diff --git a/stylishdialogs/src/main/java/com/marsad/stylishdialogs/ViewUtils.java b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/ViewUtils.java new file mode 100644 index 0000000..29c1701 --- /dev/null +++ b/stylishdialogs/src/main/java/com/marsad/stylishdialogs/ViewUtils.java @@ -0,0 +1,17 @@ +package com.marsad.stylishdialogs; + +import android.graphics.drawable.Drawable; +import android.graphics.drawable.DrawableContainer; +import android.graphics.drawable.StateListDrawable; +import android.view.View; + +public class ViewUtils { + static Drawable[] getDrawable(View view) { + StateListDrawable drawable = (StateListDrawable) view.getBackground(); + DrawableContainer.DrawableContainerState dcs = (DrawableContainer.DrawableContainerState) drawable.getConstantState(); + if (dcs != null) { + return dcs.getChildren(); + } + return null; + } +} diff --git a/stylishdialogs/src/main/res/anim/error_in.xml b/stylishdialogs/src/main/res/anim/error_in.xml new file mode 100644 index 0000000..27c2845 --- /dev/null +++ b/stylishdialogs/src/main/res/anim/error_in.xml @@ -0,0 +1,31 @@ + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/anim/error_layout_in.xml b/stylishdialogs/src/main/res/anim/error_layout_in.xml new file mode 100644 index 0000000..5952dc6 --- /dev/null +++ b/stylishdialogs/src/main/res/anim/error_layout_in.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/anim/model_in.xml b/stylishdialogs/src/main/res/anim/model_in.xml new file mode 100644 index 0000000..c16301e --- /dev/null +++ b/stylishdialogs/src/main/res/anim/model_in.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/anim/model_out.xml b/stylishdialogs/src/main/res/anim/model_out.xml new file mode 100644 index 0000000..add960f --- /dev/null +++ b/stylishdialogs/src/main/res/anim/model_out.xml @@ -0,0 +1,15 @@ + + + + + + diff --git a/stylishdialogs/src/main/res/anim/success_layout_rotate.xml b/stylishdialogs/src/main/res/anim/success_layout_rotate.xml new file mode 100644 index 0000000..93978d7 --- /dev/null +++ b/stylishdialogs/src/main/res/anim/success_layout_rotate.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/anim/success_rotate.xml b/stylishdialogs/src/main/res/anim/success_rotate.xml new file mode 100644 index 0000000..73692b5 --- /dev/null +++ b/stylishdialogs/src/main/res/anim/success_rotate.xml @@ -0,0 +1,10 @@ + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/btn_bg.xml b/stylishdialogs/src/main/res/drawable/btn_bg.xml new file mode 100644 index 0000000..393b89f --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/btn_bg.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/btn_bg_gray.xml b/stylishdialogs/src/main/res/drawable/btn_bg_gray.xml new file mode 100644 index 0000000..0304923 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/btn_bg_gray.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/btn_bg_green.xml b/stylishdialogs/src/main/res/drawable/btn_bg_green.xml new file mode 100644 index 0000000..67238b9 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/btn_bg_green.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/btn_bg_red.xml b/stylishdialogs/src/main/res/drawable/btn_bg_red.xml new file mode 100644 index 0000000..c8a6fe1 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/btn_bg_red.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/center_error_x.xml b/stylishdialogs/src/main/res/drawable/center_error_x.xml new file mode 100644 index 0000000..9cd66b1 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/center_error_x.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/dialog_bg.xml b/stylishdialogs/src/main/res/drawable/dialog_bg.xml new file mode 100644 index 0000000..f6f2ed5 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/dialog_bg.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/dialog_bg_dark.xml b/stylishdialogs/src/main/res/drawable/dialog_bg_dark.xml new file mode 100644 index 0000000..dfa4401 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/dialog_bg_dark.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/dialog_bg_light.xml b/stylishdialogs/src/main/res/drawable/dialog_bg_light.xml new file mode 100644 index 0000000..522e323 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/dialog_bg_light.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/error_circle.xml b/stylishdialogs/src/main/res/drawable/error_circle.xml new file mode 100644 index 0000000..2df0e56 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/error_circle.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/success_circle.xml b/stylishdialogs/src/main/res/drawable/success_circle.xml new file mode 100644 index 0000000..675ccad --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/success_circle.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/success_circle2.xml b/stylishdialogs/src/main/res/drawable/success_circle2.xml new file mode 100644 index 0000000..9c86143 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/success_circle2.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/warn_circle.xml b/stylishdialogs/src/main/res/drawable/warn_circle.xml new file mode 100644 index 0000000..44c6ccd --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/warn_circle.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/drawable/warn_sign.xml b/stylishdialogs/src/main/res/drawable/warn_sign.xml new file mode 100644 index 0000000..b16a832 --- /dev/null +++ b/stylishdialogs/src/main/res/drawable/warn_sign.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/layout/simple_dialog.xml b/stylishdialogs/src/main/res/layout/simple_dialog.xml new file mode 100644 index 0000000..0f31942 --- /dev/null +++ b/stylishdialogs/src/main/res/layout/simple_dialog.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/layout/stylish_dialogs.xml b/stylishdialogs/src/main/res/layout/stylish_dialogs.xml new file mode 100644 index 0000000..50bf4f8 --- /dev/null +++ b/stylishdialogs/src/main/res/layout/stylish_dialogs.xml @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/values/attrs.xml b/stylishdialogs/src/main/res/values/attrs.xml new file mode 100644 index 0000000..f38e98f --- /dev/null +++ b/stylishdialogs/src/main/res/values/attrs.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/values/colors.xml b/stylishdialogs/src/main/res/values/colors.xml new file mode 100644 index 0000000..1cd8753 --- /dev/null +++ b/stylishdialogs/src/main/res/values/colors.xml @@ -0,0 +1,53 @@ + + + #00000000 + + #F36868 + + #FFFFFF + + #e6222222 + + #FFFFFF + #D0D0D0 + #B6B6B6 + #AEDEF4 + #96BFD2 + #E86A52 + #C5534D + #F36868 + #A5DC86 + #33A5DC86 + #F8BB86 + #575757 + #ff37474f + #ff263238 + #ff21272b + #ff80cbc4 + #ff009688 + + #575757 + #fff + #797979 + #fff + + + #6bd505 + #60bf04 + #f77805 + #e66f04 + #F6B606 + #D8A106 + #2469df + #205ec7 + #05d9f7 + #05c7e2 + + #838383 + #707070 + + #009688 + #018579 + + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/values/dimens.xml b/stylishdialogs/src/main/res/values/dimens.xml new file mode 100644 index 0000000..87ff4bf --- /dev/null +++ b/stylishdialogs/src/main/res/values/dimens.xml @@ -0,0 +1,9 @@ + + + 290dp + 3dp + 34dp + + 53dp + 0sp + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/values/strings.xml b/stylishdialogs/src/main/res/values/strings.xml new file mode 100644 index 0000000..71b2708 --- /dev/null +++ b/stylishdialogs/src/main/res/values/strings.xml @@ -0,0 +1,9 @@ + + + StylishAlertDialog + Here is the message! + OK + Cancel + Loading… + + \ No newline at end of file diff --git a/stylishdialogs/src/main/res/values/style.xml b/stylishdialogs/src/main/res/values/style.xml new file mode 100644 index 0000000..27ba631 --- /dev/null +++ b/stylishdialogs/src/main/res/values/style.xml @@ -0,0 +1,40 @@ + + + + + + + + + + \ No newline at end of file diff --git a/stylishdialogs/src/test/java/com/marsad/stylishdialogs/ExampleUnitTest.java b/stylishdialogs/src/test/java/com/marsad/stylishdialogs/ExampleUnitTest.java new file mode 100644 index 0000000..819bca7 --- /dev/null +++ b/stylishdialogs/src/test/java/com/marsad/stylishdialogs/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package com.marsad.stylishdialogs; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file