├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── custom_snackbar │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── custom_snackbar │ │ │ ├── ui │ │ │ ├── CoordinatorLayoutAct.kt │ │ │ ├── CustomViewAct.kt │ │ │ ├── DrawableAct.kt │ │ │ ├── MainActivity.kt │ │ │ └── SimpleAct.kt │ │ │ └── utils │ │ │ └── Const.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_border.xml │ │ ├── ic_gradient.xml │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_coordinator_layout.xml │ │ ├── activity_custom_view.xml │ │ ├── activity_drawable.xml │ │ ├── activity_main.xml │ │ ├── activity_simple.xml │ │ ├── content_app.xml │ │ └── snack_layout.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── custom_snackbar │ └── ExampleUnitTest.kt ├── build.gradle ├── csbx ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kishandonga │ │ └── csbx │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── kishandonga │ │ │ └── csbx │ │ │ └── CustomSnackbar.kt │ └── res │ │ └── values │ │ └── colors.xml │ └── test │ └── java │ └── com │ └── kishandonga │ └── csbx │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── img_1.png ├── img_2.png ├── img_3.png └── img_4.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea 38 | 39 | # Keystore files 40 | # Uncomment the following line if you do not want to check your keystore files in. 41 | #*.jks 42 | 43 | # External native build folder generated in Android Studio 2.2 and later 44 | .externalNativeBuild 45 | 46 | # Google Services (e.g. APIs or Firebase) 47 | google-services.json 48 | 49 | # Freeline 50 | freeline.py 51 | freeline/ 52 | freeline_project_description.json 53 | 54 | # fastlane 55 | fastlane/report.xml 56 | fastlane/Preview.html 57 | fastlane/screenshots 58 | fastlane/test_output 59 | fastlane/readme.md 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android Custom Snackbar 2 | 3 | [![](https://jitpack.io/v/kishandonga/custom-snackbar.svg)](https://jitpack.io/#kishandonga/custom-snackbar) 4 | 5 | Android custom snackbar is derived from the Android default snackbar control 6 | - Use it in Activity or Fragment 7 | - Change the background and text color easily 8 | - Custom view applies in the snackbar control 9 | - Typeface applies easily to text 10 | - Corner radius and Padding apply 11 | - Androidx supported 12 | - More to find out yourself 13 | 14 | ## Installation 15 | Gradle: 16 | 17 | ```groovy 18 | repositories { 19 | maven { url 'https://jitpack.io' } 20 | } 21 | 22 | dependencies { 23 | implementation 'com.github.kishandonga:custom-snackbar:1.3' 24 | } 25 | 26 | ``` 27 | 28 | ## Screenshots 29 | 30 |
31 | Custom snackbar same as Default Control of the android Snackbar
32 |

33 | Make the background semi-transparent and add a corner radius for a better look
34 |

35 | Custom view according to your requirements
36 |

37 | Apply gradient in the snackbar background
38 |

39 |
40 | 41 | ## Examples 42 | 43 | #### Refer to This Sample Code 44 | For, more information refer this sample code [here](app/src/main/java/com/example/custom_snackbar/ui/) 45 | 46 | #### With Coordinator Layout 47 | Passing the activity context and coordinator layout as view in the custom snackbar constructor as shown below 48 | ```kotlin 49 | CustomSnackbar(this, ****).show {...} 50 | ``` 51 | 52 | #### Without Coordinator Layout 53 | Only pass the activity context in the custom snackbar constructor as shown below 54 | ```kotlin 55 | CustomSnackbar(this).show {...} 56 | ``` 57 | Kotlin 58 | ```kotlin 59 | CustomSnackbar(this, root).show { 60 | textTypeface(BOLD | BOLD_ITALIC | ITALIC | NORMAL | CUSTOM) 61 | actionTypeface(BOLD | BOLD_ITALIC | ITALIC | NORMAL | CUSTOM) 62 | textColor(...) 63 | backgroundColor(...) 64 | border(..., ...) 65 | cornerRadius(...) 66 | padding(...) 67 | duration(LENGTH_INDEFINITE | LENGTH_LONG | LENGTH_SHORT) 68 | actionTextColor(...) 69 | message(...) 70 | withAction(android.R.string.ok) { 71 | it.dismiss() 72 | } 73 | } 74 | ``` 75 | Java 76 | ```java 77 | CustomSnackbar sb = new CustomSnackbar(MainActivity.this); 78 | sb.message("Testing Message..."); 79 | sb.padding(15); 80 | sb.cornerRadius(15); 81 | sb.duration(Snackbar.LENGTH_LONG); 82 | sb.withAction(android.R.string.ok, new Function1() { 83 | @Override 84 | public Unit invoke(Snackbar snackbar) { 85 | snackbar.dismiss(); 86 | return null; 87 | } 88 | }); 89 | sb.show(); 90 | ``` 91 | 92 | #### Custom View 93 | 94 | Kotlin 95 | ```kotlin 96 | CustomSnackbar(this).show { 97 | customView(R.layout.snack_layout) 98 | padding(...) 99 | duration(LENGTH_INDEFINITE | LENGTH_LONG | LENGTH_SHORT) 100 | withCustomView { 101 | it.findViewById(R.id.btnUndo).setOnClickListener { 102 | dismiss() 103 | } 104 | } 105 | } 106 | ``` 107 | Java 108 | ```java 109 | final CustomSnackbar sb = new CustomSnackbar(MainActivity.this); 110 | sb.customView(R.layout.snack_layout); 111 | sb.duration(Snackbar.LENGTH_INDEFINITE); 112 | sb.withCustomView(new Function1() { 113 | @Override 114 | public Unit invoke(View view) { 115 | view.findViewById(R.id.btnUndo).setOnClickListener(new View.OnClickListener() { 116 | @Override 117 | public void onClick(View view) { 118 | sb.dismiss(); 119 | } 120 | }); 121 | return null; 122 | } 123 | }); 124 | sb.show(); 125 | 126 | // OR Use Like This Way 127 | 128 | // View v = sb.getView(); 129 | // if(v != null){ 130 | // v.findViewById(R.id.btnUndo).setOnClickListener(new View.OnClickListener() { 131 | // @Override 132 | // public void onClick(View view) { 133 | // sb.dismiss(); 134 | // } 135 | // }); 136 | // } 137 | ``` 138 | 139 | #### With Drawable 140 | 141 | Kotlin 142 | ```kotlin 143 | CustomSnackbar(this).show { 144 | drawableRes(R.drawable.ic_gradient) 145 | ... 146 | } 147 | ``` 148 | Java 149 | ```java 150 | CustomSnackbar sb = new CustomSnackbar(MainActivity.this); 151 | sb.drawableRes(R.drawable.ic_gradient); 152 | sb.message("Test Message..."); 153 | sb.padding(15); 154 | sb.duration(Snackbar.LENGTH_LONG); 155 | sb.show(); 156 | ``` 157 | 158 | ## API Documents 159 | 160 | |Function |Parameter |Description | 161 | |:-------------------:|:-------------------:|:-------------------:| 162 | |actionTextColor | Integer Color Value | Change the action button text color, the default value is colorAccent 163 | |actionTextColorRes | Color Resource | Refer actionTextColor function description 164 | |textColor | Integer Color Value | Change the message text color, the default value is a white color 165 | |textColorRes | Color Resource | Refer textColor function description 166 | |backgroundColor | Integer Color Value | Change the background color of the snackbar, The default value is the same as snackbar background also you can't make it transparent 167 | |backgroundColorRes | Color Resource | Refer backgroundColor function description 168 | |cornerRadius | Float Value | Apply corner radius on all the sides (Left, Top, Right, Bottom), default value is 0 169 | |cornerRadiusRes | Dimension Resource | Refer cornerRadius function description 170 | |border | Width as Integer and Integer Color Value | Apply border width and color around the snackbar, the default value of the width is 0 and the color is transparent 171 | |borderRes | Width as Dimension Resource and Color Resource | Refer border function description 172 | |customView | View or Layout Resource | Set your customized view as snackbar, the default value is null also when you apply custom view then other API are not in use as shown in the example code 173 | |message | String | Set the message as string and the default value is an empty string 174 | |messageRes | String Resource | Refer message function description 175 | |duration | Integer Value | set the time duration default value is Snackbar.LENGTH_SHORT 176 | |padding | Integer Value | Apply the padding at the (Left, Right, Bottom) side, the default value is 0 177 | |paddingRes | Dimension Resource | Refer padding function description 178 | |textTypeface | Typeface | Change the message text Typeface, default value is Typeface.NORMAL 179 | |actionTypeface | Typeface | Change the action button text Typeface, default value is Typeface.NORMAL 180 | |withAction | String Resource or String and Snackbar as anonymous function | pass the first argument as action button name and the default value is an empty string, second argument as lambda function with snackbar reference 181 | |withCustomView | View as anonymous function | when custom view initialized then passing here for your further use 182 | |drawable | GradientDrawable | Set the gradient drawable as snackbar background, the default value is null also when you apply drawable then background color, cornerRadius, border width, and color API are not in used as shown in the example code 183 | |drawableRes | Drawable Resource| Refer drawable function description 184 | |show | Void Or Koltin DSL | Show the snackbar view 185 | |dismiss | Void Or Unit | Dismiss the snackbar view 186 | |getView | Void and return View? | Same as withCustomView but it will return a null value too 187 | 188 | 189 | ### About me 190 | 191 | I'm Kishan Donga and you can connect with me via the below links, I am a developer and love to create innovations. 192 | 193 | LinkedIn [@ikd96](https://www.linkedin.com/in/ikd96/) 194 | Email [kishandonga.92@gmail.com](mailto:kishandonga.92@gmail.com) 195 | Twitter [@ikishan96](https://twitter.com/ikishan96) 196 | Instagram [@ikishan96](https://www.instagram.com/ikishan96/) 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | namespace 'com.example.custom_snackbar' 6 | compileSdkVersion 33 7 | 8 | defaultConfig { 9 | applicationId "com.example.custom_snackbar" 10 | minSdkVersion 19 11 | targetSdkVersion 33 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | buildFeatures { 24 | viewBinding = true 25 | } 26 | 27 | kotlinOptions { 28 | jvmTarget = '1.8' 29 | } 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(dir: 'libs', include: ['*.jar']) 34 | implementation project(path: ':csbx') 35 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 36 | implementation 'androidx.appcompat:appcompat:1.6.1' 37 | implementation 'com.google.android.material:material:1.9.0' 38 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 39 | implementation 'com.github.skydoves:colorpickerview:2.2.4' 40 | } 41 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in show.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/custom_snackbar/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar 2 | 3 | class ExampleInstrumentedTest 4 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/custom_snackbar/ui/CoordinatorLayoutAct.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar.ui 2 | 3 | import android.content.DialogInterface 4 | import android.graphics.Color 5 | import android.graphics.Typeface 6 | import android.os.Bundle 7 | import android.widget.SeekBar 8 | import androidx.appcompat.app.AppCompatActivity 9 | import androidx.core.content.ContextCompat 10 | import com.example.custom_snackbar.R 11 | import com.example.custom_snackbar.databinding.ActivityCoordinatorLayoutBinding 12 | import com.example.custom_snackbar.utils.themeConst 13 | import com.google.android.material.snackbar.Snackbar 14 | import com.kishandonga.csbx.CustomSnackbar 15 | import com.skydoves.colorpickerview.ColorPickerDialog 16 | import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener 17 | 18 | class CoordinatorLayoutAct : AppCompatActivity() { 19 | 20 | private lateinit var binding: ActivityCoordinatorLayoutBinding 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | val themeConst = intent.getIntExtra(themeConst, 0) 25 | setTheme(if (themeConst == 0) R.style.AppCompat_NoActionBar else R.style.Material_NoActionBar) 26 | 27 | binding = ActivityCoordinatorLayoutBinding.inflate(layoutInflater) 28 | setContentView(binding.root) 29 | setSupportActionBar(binding.toolbarLayout) 30 | title = getString(R.string.lbl_with_coordinator_layout) 31 | 32 | var textColor = Color.WHITE 33 | var bgColor = Color.TRANSPARENT 34 | var borderColor = Color.TRANSPARENT 35 | var actionTxtColor = ContextCompat.getColor(this, R.color.colorAccent) 36 | 37 | binding.content.btnActionTextColor.setOnClickListener { 38 | ColorPickerDialog.Builder(this) 39 | .setTitle("ColorPicker Dialog") 40 | .setPositiveButton( 41 | getString(android.R.string.ok), 42 | ColorEnvelopeListener { envelope, _ -> 43 | binding.content.llActionTextColor.setBackgroundColor(envelope.color) 44 | actionTxtColor = envelope.color 45 | }) 46 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 47 | di.cancel() 48 | } 49 | .show() 50 | } 51 | 52 | binding.content.btnTextColor.setOnClickListener { 53 | ColorPickerDialog.Builder(this) 54 | .setTitle("ColorPicker Dialog") 55 | .setPositiveButton( 56 | getString(android.R.string.ok), 57 | ColorEnvelopeListener { envelope, _ -> 58 | binding.content.llTextColor.setBackgroundColor(envelope.color) 59 | textColor = envelope.color 60 | }) 61 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 62 | di.cancel() 63 | } 64 | .show() 65 | } 66 | 67 | binding.content.btnBgColor.setOnClickListener { 68 | ColorPickerDialog.Builder(this) 69 | .setTitle("ColorPicker Dialog") 70 | .setPositiveButton( 71 | getString(android.R.string.ok), 72 | ColorEnvelopeListener { envelope, _ -> 73 | binding.content.llBgColor.setBackgroundColor(envelope.color) 74 | bgColor = envelope.color 75 | }) 76 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 77 | di.cancel() 78 | } 79 | .show() 80 | } 81 | 82 | binding.content.btnBorderColor.setOnClickListener { 83 | ColorPickerDialog.Builder(this) 84 | .setTitle("ColorPicker Dialog") 85 | .setPositiveButton( 86 | getString(android.R.string.ok), 87 | ColorEnvelopeListener { envelope, _ -> 88 | binding.content.llBorderColor.setBackgroundColor(envelope.color) 89 | borderColor = envelope.color 90 | }) 91 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 92 | di.cancel() 93 | } 94 | .show() 95 | } 96 | 97 | binding.content.sbPadding.setOnSeekBarChangeListener(object : 98 | SeekBar.OnSeekBarChangeListener { 99 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 100 | binding.content.tvPaddingIndicator.text = p0?.progress.toString() 101 | } 102 | 103 | override fun onStartTrackingTouch(p0: SeekBar?) { 104 | } 105 | 106 | override fun onStopTrackingTouch(p0: SeekBar?) { 107 | } 108 | }) 109 | 110 | binding.content.sbCornerRadius.setOnSeekBarChangeListener(object : 111 | SeekBar.OnSeekBarChangeListener { 112 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 113 | binding.content.tvCornerRadiusIndicator.text = p0?.progress.toString() 114 | } 115 | 116 | override fun onStartTrackingTouch(p0: SeekBar?) { 117 | } 118 | 119 | override fun onStopTrackingTouch(p0: SeekBar?) { 120 | } 121 | }) 122 | 123 | binding.content.sbBorderWidth.setOnSeekBarChangeListener(object : 124 | SeekBar.OnSeekBarChangeListener { 125 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 126 | binding.content.tvBorderIndicator.text = p0?.progress.toString() 127 | } 128 | 129 | override fun onStartTrackingTouch(p0: SeekBar?) { 130 | } 131 | 132 | override fun onStopTrackingTouch(p0: SeekBar?) { 133 | } 134 | }) 135 | 136 | var snackbar: CustomSnackbar? = null 137 | 138 | binding.content.btnShow.setOnClickListener { 139 | 140 | val msg = binding.content.edMessage.text?.trim().toString() 141 | if (msg.isBlank() || msg.isEmpty()) { 142 | binding.content.edMessage.error = "Please Enter Message" 143 | return@setOnClickListener 144 | } 145 | 146 | val timeDuration: Int = when { 147 | binding.content.rbLengthIndefinite.isChecked -> Snackbar.LENGTH_INDEFINITE 148 | binding.content.rbLengthLong.isChecked -> Snackbar.LENGTH_LONG 149 | else -> Snackbar.LENGTH_SHORT 150 | } 151 | 152 | val typeface: Typeface = when { 153 | binding.content.rbBold.isChecked -> Typeface.defaultFromStyle(Typeface.BOLD) 154 | binding.content.rbBoldItalic.isChecked -> Typeface.defaultFromStyle(Typeface.BOLD_ITALIC) 155 | binding.content.rbItalic.isChecked -> Typeface.defaultFromStyle(Typeface.ITALIC) 156 | else -> Typeface.defaultFromStyle(Typeface.NORMAL) 157 | } 158 | 159 | snackbar = CustomSnackbar(this, binding.root).show { 160 | textTypeface(typeface) 161 | actionTypeface(typeface) 162 | textColor(textColor) 163 | backgroundColor(bgColor) 164 | border(binding.content.sbBorderWidth.progress, borderColor) 165 | padding(binding.content.sbPadding.progress) 166 | cornerRadius(binding.content.sbCornerRadius.progress.toFloat()) 167 | duration(timeDuration) 168 | actionTextColor(actionTxtColor) 169 | message(msg) 170 | if (binding.content.rbWithAction.isChecked) { 171 | withAction(android.R.string.ok) { 172 | it.dismiss() 173 | } 174 | } 175 | } 176 | } 177 | 178 | binding.content.btnHide.setOnClickListener { 179 | snackbar?.dismiss() 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/custom_snackbar/ui/CustomViewAct.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar.ui 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.widget.SeekBar 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.example.custom_snackbar.R 8 | import com.example.custom_snackbar.databinding.ActivityCustomViewBinding 9 | import com.example.custom_snackbar.utils.themeConst 10 | import com.google.android.material.snackbar.Snackbar 11 | import com.kishandonga.csbx.CustomSnackbar 12 | 13 | class CustomViewAct : AppCompatActivity() { 14 | 15 | private lateinit var binding: ActivityCustomViewBinding 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | val themeConst = intent.getIntExtra(themeConst, 0) 20 | setTheme(if (themeConst == 0) R.style.AppCompat_ActionBar else R.style.Material_ActionBar) 21 | 22 | binding = ActivityCustomViewBinding.inflate(layoutInflater) 23 | setContentView(binding.root) 24 | title = "Custom View" 25 | 26 | var snackbar: CustomSnackbar? = null 27 | 28 | binding.sbPadding.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { 29 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 30 | binding.tvPaddingIndicator.text = p0?.progress.toString() 31 | } 32 | 33 | override fun onStartTrackingTouch(p0: SeekBar?) { 34 | } 35 | 36 | override fun onStopTrackingTouch(p0: SeekBar?) { 37 | } 38 | }) 39 | 40 | binding.btnShowCustomView.setOnClickListener { 41 | 42 | val timeDuration: Int = when { 43 | binding.rbLengthIndefinite.isChecked -> Snackbar.LENGTH_INDEFINITE 44 | binding.rbLengthLong.isChecked -> Snackbar.LENGTH_LONG 45 | else -> Snackbar.LENGTH_SHORT 46 | } 47 | 48 | snackbar = CustomSnackbar(this).show { 49 | customView(R.layout.snack_layout) 50 | padding(binding.sbPadding.progress) 51 | duration(timeDuration) 52 | withCustomView { 53 | it.findViewById(R.id.btnUndo).setOnClickListener { 54 | dismiss() 55 | } 56 | } 57 | } 58 | } 59 | 60 | binding.btnHideCustomView.setOnClickListener { 61 | snackbar?.dismiss() 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/custom_snackbar/ui/DrawableAct.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar.ui 2 | 3 | import android.content.DialogInterface 4 | import android.graphics.Color 5 | import android.graphics.Typeface 6 | import android.os.Bundle 7 | import android.widget.SeekBar 8 | import androidx.appcompat.app.AppCompatActivity 9 | import androidx.core.content.ContextCompat 10 | import com.example.custom_snackbar.R 11 | import com.example.custom_snackbar.databinding.ActivityDrawableBinding 12 | import com.example.custom_snackbar.utils.themeConst 13 | import com.google.android.material.snackbar.Snackbar 14 | import com.kishandonga.csbx.CustomSnackbar 15 | import com.skydoves.colorpickerview.ColorPickerDialog 16 | import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener 17 | 18 | class DrawableAct : AppCompatActivity() { 19 | 20 | private lateinit var binding: ActivityDrawableBinding 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | val themeConst = intent.getIntExtra(themeConst, 0) 25 | setTheme(if (themeConst == 0) R.style.AppCompat_ActionBar else R.style.Material_ActionBar) 26 | 27 | binding = ActivityDrawableBinding.inflate(layoutInflater) 28 | setContentView(binding.root) 29 | title = "Custom Drawable" 30 | 31 | var textColor = Color.WHITE 32 | var actionTxtColor = ContextCompat.getColor(this, R.color.colorAccent) 33 | 34 | binding.btnActionTextColor.setOnClickListener { 35 | ColorPickerDialog.Builder(this) 36 | .setTitle("ColorPicker Dialog") 37 | .setPositiveButton( 38 | getString(android.R.string.ok), 39 | ColorEnvelopeListener { envelope, _ -> 40 | binding.llActionTextColor.setBackgroundColor(envelope.color) 41 | actionTxtColor = envelope.color 42 | }) 43 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 44 | di.cancel() 45 | } 46 | .show() 47 | } 48 | 49 | binding.btnTextColor.setOnClickListener { 50 | ColorPickerDialog.Builder(this) 51 | .setTitle("ColorPicker Dialog") 52 | .setPositiveButton( 53 | getString(android.R.string.ok), 54 | ColorEnvelopeListener { envelope, _ -> 55 | binding.llTextColor.setBackgroundColor(envelope.color) 56 | textColor = envelope.color 57 | }) 58 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 59 | di.cancel() 60 | } 61 | .show() 62 | } 63 | 64 | binding.sbPadding.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { 65 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 66 | binding.tvPaddingIndicator.text = p0?.progress.toString() 67 | } 68 | 69 | override fun onStartTrackingTouch(p0: SeekBar?) { 70 | } 71 | 72 | override fun onStopTrackingTouch(p0: SeekBar?) { 73 | } 74 | }) 75 | 76 | var snackbar: CustomSnackbar? = null 77 | 78 | binding.btnShow.setOnClickListener { 79 | 80 | val timeDuration: Int = when { 81 | binding.rbLengthIndefinite.isChecked -> Snackbar.LENGTH_INDEFINITE 82 | binding.rbLengthLong.isChecked -> Snackbar.LENGTH_LONG 83 | else -> Snackbar.LENGTH_SHORT 84 | } 85 | 86 | val typeface: Typeface = when { 87 | binding.rbBold.isChecked -> Typeface.defaultFromStyle(Typeface.BOLD) 88 | binding.rbBoldItalic.isChecked -> Typeface.defaultFromStyle(Typeface.BOLD_ITALIC) 89 | binding.rbItalic.isChecked -> Typeface.defaultFromStyle(Typeface.ITALIC) 90 | else -> Typeface.defaultFromStyle(Typeface.NORMAL) 91 | } 92 | 93 | snackbar = CustomSnackbar(this).show { 94 | drawableRes(R.drawable.ic_gradient) 95 | textColor(textColor) 96 | actionTextColor(actionTxtColor) 97 | textTypeface(typeface) 98 | actionTypeface(typeface) 99 | padding(binding.sbPadding.progress) 100 | duration(timeDuration) 101 | message("Testing Message...") 102 | if (binding.rbWithAction.isChecked) { 103 | withAction(android.R.string.ok) { 104 | it.dismiss() 105 | } 106 | } 107 | } 108 | } 109 | 110 | binding.btnHide.setOnClickListener { 111 | snackbar?.dismiss() 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/custom_snackbar/ui/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar.ui 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import com.example.custom_snackbar.databinding.ActivityMainBinding 7 | import com.example.custom_snackbar.utils.themeConst 8 | 9 | class MainActivity : AppCompatActivity() { 10 | 11 | private lateinit var binding: ActivityMainBinding 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | binding = ActivityMainBinding.inflate(layoutInflater) 16 | setContentView(binding.root) 17 | 18 | binding.btnWithCL.setOnClickListener { 19 | startNewActivity(CoordinatorLayoutAct::class.java) 20 | } 21 | 22 | binding.btnWithoutCL.setOnClickListener { 23 | startNewActivity(SimpleAct::class.java) 24 | } 25 | 26 | binding.btnCustomView.setOnClickListener { 27 | startNewActivity(CustomViewAct::class.java) 28 | } 29 | 30 | binding.btnDrawableAct.setOnClickListener { 31 | startNewActivity(DrawableAct::class.java) 32 | } 33 | } 34 | 35 | private fun startNewActivity(cls: Class<*>) { 36 | val theme = if (binding.rbAppCompact.isChecked) 0 else 1 37 | val intent = Intent(this, cls).apply { 38 | putExtra(themeConst, theme) 39 | } 40 | startActivity(intent) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/custom_snackbar/ui/SimpleAct.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar.ui 2 | 3 | import android.content.DialogInterface 4 | import android.graphics.Color 5 | import android.graphics.Typeface 6 | import android.os.Bundle 7 | import android.widget.SeekBar 8 | import androidx.appcompat.app.AppCompatActivity 9 | import androidx.core.content.ContextCompat 10 | import com.example.custom_snackbar.R 11 | import com.example.custom_snackbar.databinding.ActivitySimpleBinding 12 | import com.example.custom_snackbar.utils.themeConst 13 | import com.google.android.material.snackbar.Snackbar 14 | import com.kishandonga.csbx.CustomSnackbar 15 | import com.skydoves.colorpickerview.ColorPickerDialog 16 | import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener 17 | 18 | class SimpleAct : AppCompatActivity() { 19 | 20 | private lateinit var binding: ActivitySimpleBinding 21 | 22 | override fun onCreate(savedInstanceState: Bundle?) { 23 | super.onCreate(savedInstanceState) 24 | val themeConst = intent.getIntExtra(themeConst, 0) 25 | setTheme(if (themeConst == 0) R.style.AppCompat_ActionBar else R.style.Material_ActionBar) 26 | 27 | binding = ActivitySimpleBinding.inflate(layoutInflater) 28 | setContentView(binding.root) 29 | 30 | title = getString(R.string.lbl_without_coordinator_layout) 31 | 32 | var textColor = Color.WHITE 33 | var bgColor = Color.TRANSPARENT 34 | var borderColor = Color.TRANSPARENT 35 | var actionTxtColor = ContextCompat.getColor(this, R.color.colorAccent) 36 | 37 | binding.content.btnActionTextColor.setOnClickListener { 38 | ColorPickerDialog.Builder(this).setTitle("ColorPicker Dialog").setPositiveButton( 39 | getString(android.R.string.ok), 40 | ColorEnvelopeListener { envelope, _ -> 41 | binding.content.llActionTextColor.setBackgroundColor(envelope.color) 42 | actionTxtColor = envelope.color 43 | }) 44 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 45 | di.cancel() 46 | }.show() 47 | } 48 | 49 | binding.content.btnTextColor.setOnClickListener { 50 | ColorPickerDialog.Builder(this).setTitle("ColorPicker Dialog").setPositiveButton( 51 | getString(android.R.string.ok), 52 | ColorEnvelopeListener { envelope, _ -> 53 | binding.content.llTextColor.setBackgroundColor(envelope.color) 54 | textColor = envelope.color 55 | }) 56 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 57 | di.cancel() 58 | }.show() 59 | } 60 | 61 | binding.content.btnBgColor.setOnClickListener { 62 | ColorPickerDialog.Builder(this).setTitle("ColorPicker Dialog").setPositiveButton( 63 | getString(android.R.string.ok), 64 | ColorEnvelopeListener { envelope, _ -> 65 | binding.content.llBgColor.setBackgroundColor(envelope.color) 66 | bgColor = envelope.color 67 | }) 68 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 69 | di.cancel() 70 | }.show() 71 | } 72 | 73 | binding.content.btnBorderColor.setOnClickListener { 74 | ColorPickerDialog.Builder(this).setTitle("ColorPicker Dialog").setPositiveButton( 75 | getString(android.R.string.ok), 76 | ColorEnvelopeListener { envelope, _ -> 77 | binding.content.llBorderColor.setBackgroundColor(envelope.color) 78 | borderColor = envelope.color 79 | }) 80 | .setNegativeButton(getString(android.R.string.cancel)) { di: DialogInterface, _: Int -> 81 | di.cancel() 82 | }.show() 83 | } 84 | 85 | binding.content.sbPadding.setOnSeekBarChangeListener(object : 86 | SeekBar.OnSeekBarChangeListener { 87 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 88 | binding.content.tvPaddingIndicator.text = p0?.progress.toString() 89 | } 90 | 91 | override fun onStartTrackingTouch(p0: SeekBar?) { 92 | } 93 | 94 | override fun onStopTrackingTouch(p0: SeekBar?) { 95 | } 96 | }) 97 | 98 | binding.content.sbCornerRadius.setOnSeekBarChangeListener(object : 99 | SeekBar.OnSeekBarChangeListener { 100 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 101 | binding.content.tvCornerRadiusIndicator.text = p0?.progress.toString() 102 | } 103 | 104 | override fun onStartTrackingTouch(p0: SeekBar?) { 105 | } 106 | 107 | override fun onStopTrackingTouch(p0: SeekBar?) { 108 | } 109 | }) 110 | 111 | binding.content.sbBorderWidth.setOnSeekBarChangeListener(object : 112 | SeekBar.OnSeekBarChangeListener { 113 | override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) { 114 | binding.content.tvBorderIndicator.text = p0?.progress.toString() 115 | } 116 | 117 | override fun onStartTrackingTouch(p0: SeekBar?) { 118 | } 119 | 120 | override fun onStopTrackingTouch(p0: SeekBar?) { 121 | } 122 | }) 123 | 124 | var snackbar: CustomSnackbar? = null 125 | 126 | binding.content.btnShow.setOnClickListener { 127 | 128 | val msg = binding.content.edMessage.text?.trim().toString() 129 | if (msg.isBlank() || msg.isEmpty()) { 130 | binding.content.edMessage.error = "Please Enter Message" 131 | return@setOnClickListener 132 | } 133 | 134 | val timeDuration: Int = when { 135 | binding.content.rbLengthIndefinite.isChecked -> Snackbar.LENGTH_INDEFINITE 136 | binding.content.rbLengthLong.isChecked -> Snackbar.LENGTH_LONG 137 | else -> Snackbar.LENGTH_SHORT 138 | } 139 | 140 | val typeface: Typeface = when { 141 | binding.content.rbBold.isChecked -> Typeface.defaultFromStyle(Typeface.BOLD) 142 | binding.content.rbBoldItalic.isChecked -> Typeface.defaultFromStyle(Typeface.BOLD_ITALIC) 143 | binding.content.rbItalic.isChecked -> Typeface.defaultFromStyle(Typeface.ITALIC) 144 | else -> Typeface.defaultFromStyle(Typeface.NORMAL) 145 | } 146 | 147 | snackbar = CustomSnackbar(this).show { 148 | textTypeface(typeface) 149 | actionTypeface(typeface) 150 | textColor(textColor) 151 | backgroundColor(bgColor) 152 | border(binding.content.sbBorderWidth.progress, borderColor) 153 | padding(binding.content.sbPadding.progress) 154 | cornerRadius(binding.content.sbCornerRadius.progress.toFloat()) 155 | duration(timeDuration) 156 | actionTextColor(actionTxtColor) 157 | message(msg) 158 | if (binding.content.rbWithAction.isChecked) { 159 | withAction(android.R.string.ok) { 160 | it.dismiss() 161 | } 162 | } 163 | } 164 | } 165 | 166 | binding.content.btnHide.setOnClickListener { 167 | snackbar?.dismiss() 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/custom_snackbar/utils/Const.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar.utils 2 | 3 | const val themeConst: String = "themeConst" -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_coordinator_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_custom_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 21 | 22 | 26 | 27 | 33 | 34 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 61 | 62 | 66 | 67 | 71 | 72 | 77 | 78 | 79 | 80 | 86 | 87 | 88 | 89 | 94 | 95 | 100 | 101 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 22 | 23 | 29 | 30 | 36 | 37 | 38 | 39 | 43 | 44 | 49 | 50 | 54 | 55 | 61 | 62 | 67 | 68 | 73 | 74 | 75 | 76 | 77 | 78 | 83 | 84 | 89 | 90 | 94 | 95 | 99 | 100 | 105 | 106 | 107 | 108 | 114 | 115 | 116 | 117 | 121 | 122 | 127 | 128 | 132 | 133 | 139 | 140 | 145 | 146 | 147 | 148 | 149 | 150 | 155 | 156 | 160 | 161 | 165 | 166 | 172 | 173 | 178 | 179 | 184 | 185 | 190 | 191 | 192 | 193 | 194 | 195 | 200 | 201 | 206 | 207 | 213 | 214 | 218 | 219 | 220 | 221 | 222 | 228 | 229 | 234 | 235 | 241 | 242 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 22 | 23 | 28 | 29 | 30 | 31 | 37 | 38 | 44 | 45 | 51 | 52 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_simple.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 20 | 21 | 27 | 28 | 29 | 30 | 35 | 36 | 41 | 42 | 46 | 47 | 51 | 52 | 53 | 54 | 58 | 59 | 64 | 65 | 69 | 70 | 76 | 77 | 82 | 83 | 88 | 89 | 90 | 91 | 92 | 93 | 98 | 99 | 104 | 105 | 109 | 110 | 114 | 115 | 120 | 121 | 122 | 123 | 129 | 130 | 131 | 132 | 136 | 137 | 142 | 143 | 147 | 148 | 154 | 155 | 160 | 161 | 162 | 163 | 164 | 165 | 170 | 171 | 175 | 176 | 180 | 181 | 187 | 188 | 193 | 194 | 199 | 200 | 205 | 206 | 207 | 208 | 209 | 210 | 215 | 216 | 221 | 222 | 228 | 229 | 233 | 234 | 235 | 236 | 237 | 242 | 243 | 248 | 249 | 255 | 256 | 260 | 261 | 262 | 263 | 264 | 270 | 271 | 276 | 277 | 283 | 284 | 288 | 289 | 290 | 291 | 292 | 297 | 298 | 303 | 304 | 308 | 309 | 313 | 314 | 319 | 320 | 321 | 322 | 328 | 329 | 330 | 331 | 336 | 337 | 342 | 343 | 349 | 350 | 354 | 355 | 356 | 357 | 358 | 363 | 364 | 369 | 370 | 374 | 375 | 379 | 380 | 385 | 386 | 387 | 388 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | -------------------------------------------------------------------------------- /app/src/main/res/layout/snack_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 23 | 24 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | #80E7E7E7 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Custom Snackbar 3 | AppCompat Theme 4 | Material Theme 5 | With Coordinator Layout 6 | Without Coordinator Layout 7 | Enter Message 8 | Text Color 9 | Background Color 10 | Corner Radius 11 |   -   12 | 0 13 | Border Color 14 | Border Width 15 | LENGTH_INDEFINITE 16 | LENGTH_SHORT 17 | LENGTH_LONG 18 | Time Duration 19 | Select Typeface 20 | BOLD_ITALIC 21 | ITALIC 22 | BOLD 23 | NORMAL 24 | Show 25 | Hide 26 | Show Custom View 27 | Show Action Button 28 | Hide Action Button 29 | With Action 30 | Hide Custom View 31 | With Custom View 32 | Action Button Text Color 33 | With Drawable 34 | Padding 35 | UNDO 36 | Are you sure? do you want to undo this operation? 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | 24 | 25 | 32 | 33 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/custom_snackbar/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.custom_snackbar 2 | 3 | class ExampleUnitTest 4 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.8.22' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:7.3.1' 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | maven { url "https://jitpack.io" } 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /csbx/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /csbx/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | namespace 'com.kishandonga.csbx' 6 | compileSdkVersion 33 7 | 8 | defaultConfig { 9 | minSdkVersion 19 10 | targetSdkVersion 33 11 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' 12 | } 13 | 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | kotlinOptions { 22 | jvmTarget = '1.8' 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 29 | implementation 'androidx.appcompat:appcompat:1.6.1' 30 | implementation 'com.google.android.material:material:1.9.0' 31 | } -------------------------------------------------------------------------------- /csbx/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in show.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /csbx/src/androidTest/java/com/kishandonga/csbx/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.kishandonga.csbx; 2 | 3 | public class ExampleInstrumentedTest { 4 | } 5 | -------------------------------------------------------------------------------- /csbx/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /csbx/src/main/java/com/kishandonga/csbx/CustomSnackbar.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("MemberVisibilityCanBePrivate", "unused") 2 | 3 | package com.kishandonga.csbx 4 | 5 | import android.app.Activity 6 | import android.content.Context 7 | import android.graphics.Color 8 | import android.graphics.Typeface 9 | import android.graphics.drawable.GradientDrawable 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import android.widget.LinearLayout 13 | import androidx.annotation.ColorInt 14 | import androidx.annotation.ColorRes 15 | import androidx.annotation.DimenRes 16 | import androidx.annotation.DrawableRes 17 | import androidx.annotation.LayoutRes 18 | import androidx.annotation.StringRes 19 | import androidx.appcompat.widget.AppCompatButton 20 | import androidx.appcompat.widget.AppCompatTextView 21 | import androidx.coordinatorlayout.widget.CoordinatorLayout 22 | import androidx.core.content.ContextCompat 23 | import com.google.android.material.snackbar.Snackbar 24 | import com.google.android.material.snackbar.SnackbarContentLayout 25 | 26 | class CustomSnackbar(private val context: Context) { 27 | 28 | private var textColor: Int = ContextCompat.getColor(context, R.color.csb_white) 29 | private var actionTextColor: Int = ContextCompat.getColor(context, R.color.colorAccent) 30 | private var duration: Int = Snackbar.LENGTH_SHORT 31 | private var drawable = GradientDrawable() 32 | private var message: String = "" 33 | private var padding: Int = 0.toPx(context).toInt() 34 | private var customView: View? = null 35 | private var action: ((Snackbar) -> Unit)? = null 36 | private var customViewAction: ((View) -> Unit)? = null 37 | private var buttonName: String = "" 38 | private val inflater: LayoutInflater = LayoutInflater.from(context) 39 | private var backgroundColor: Int = Color.TRANSPARENT 40 | private var borderWidth: Int = 0 41 | private var borderColor: Int = Color.TRANSPARENT 42 | private var cornerRadius: Float = 0f 43 | private var coordinateView: View? = null 44 | private var tfTextView: Typeface? = null 45 | private var tfActionBtn: Typeface? = null 46 | private var customDrawable: GradientDrawable? = null 47 | private lateinit var snackbar: Snackbar 48 | 49 | constructor(context: Context, view: View) : this(context) { 50 | coordinateView = view 51 | } 52 | 53 | fun drawableRes(@DrawableRes drawableId: Int) { 54 | val drw = ContextCompat.getDrawable(context, drawableId) 55 | if (drw is GradientDrawable) { 56 | drawable(drw) 57 | } 58 | } 59 | 60 | fun drawable(drawable: GradientDrawable?) { 61 | this.customDrawable = drawable 62 | } 63 | 64 | fun textTypeface(textTypeface: Typeface) { 65 | tfTextView = textTypeface 66 | } 67 | 68 | fun actionTypeface(actionTypeface: Typeface) { 69 | tfActionBtn = actionTypeface 70 | } 71 | 72 | fun withCustomView(customViewAction: ((View) -> Unit)?) { 73 | this.customViewAction = customViewAction 74 | } 75 | 76 | fun withAction(@StringRes resId: Int, action: (Snackbar) -> Unit) { 77 | withAction(context.getString(resId), action) 78 | } 79 | 80 | fun withAction(actionText: String, action: (Snackbar) -> Unit) { 81 | this.action = action 82 | this.buttonName = actionText 83 | } 84 | 85 | fun paddingRes(@DimenRes dimenId: Int) { 86 | padding(context.resources.getDimension(dimenId).toInt()) 87 | } 88 | 89 | fun padding(padding: Int) { 90 | this.padding = padding 91 | } 92 | 93 | fun duration(duration: Int) { 94 | this.duration = duration 95 | } 96 | 97 | fun messageRes(@StringRes message: Int) { 98 | message(context.getString(message)) 99 | } 100 | 101 | fun message(message: String) { 102 | this.message = message 103 | } 104 | 105 | fun customView(@LayoutRes layoutResource: Int) { 106 | customView(inflater.inflate(layoutResource, LinearLayout(context), false)) 107 | } 108 | 109 | fun customView(view: View) { 110 | this.customView = view 111 | } 112 | 113 | fun borderRes(@DimenRes dimenId: Int, @ColorRes colorId: Int) { 114 | border( 115 | context.resources.getDimension(dimenId).toInt(), ContextCompat.getColor( 116 | context, 117 | colorId 118 | ) 119 | ) 120 | } 121 | 122 | fun border(width: Int, @ColorInt color: Int) { 123 | this.borderWidth = width 124 | this.borderColor = color 125 | } 126 | 127 | fun cornerRadiusRes(@DimenRes dimenId: Int) { 128 | cornerRadius(context.resources.getDimension(dimenId)) 129 | } 130 | 131 | fun cornerRadius(cornerRadius: Float) { 132 | this.cornerRadius = cornerRadius 133 | } 134 | 135 | fun backgroundColorRes(@ColorRes colorId: Int) { 136 | backgroundColor(ContextCompat.getColor(context, colorId)) 137 | } 138 | 139 | fun backgroundColor(@ColorInt color: Int) { 140 | this.backgroundColor = color 141 | } 142 | 143 | fun textColorRes(@ColorRes colorId: Int) { 144 | textColor(ContextCompat.getColor(context, colorId)) 145 | } 146 | 147 | fun textColor(@ColorInt color: Int) { 148 | this.textColor = color 149 | } 150 | 151 | fun actionTextColorRes(@ColorRes colorId: Int) { 152 | actionTextColor(ContextCompat.getColor(context, colorId)) 153 | } 154 | 155 | fun actionTextColor(@ColorInt actionTextColor: Int) { 156 | this.actionTextColor = actionTextColor 157 | } 158 | 159 | fun show(): CustomSnackbar { 160 | if (coordinateView != null && coordinateView is CoordinatorLayout) { 161 | makeSnackbar(coordinateView!!) 162 | } else { 163 | (context as Activity).findViewById(android.R.id.content)?.apply { 164 | makeSnackbar(this) 165 | } 166 | } 167 | snackbar.show() 168 | return this 169 | } 170 | 171 | private fun makeSnackbar(view: View) { 172 | snackbar = Snackbar.make(view, message, duration) 173 | val snackbarView = snackbar.view 174 | val snackbarLayout = snackbarView as Snackbar.SnackbarLayout // Frame Layout 175 | val snackContentLayout = 176 | snackbarLayout.getChildAt(0) as SnackbarContentLayout // Linear Layout 177 | 178 | if (customDrawable == null) { 179 | if (backgroundColor != 0) { 180 | drawable.setColor(backgroundColor) 181 | } else { 182 | drawable = snackbarLayout.background as GradientDrawable 183 | } 184 | drawable.cornerRadius = cornerRadius 185 | drawable.setStroke(borderWidth, borderColor) 186 | } else { 187 | drawable = customDrawable as GradientDrawable 188 | } 189 | 190 | val pLeft = snackbarLayout.paddingLeft 191 | val pRight = snackbarLayout.paddingRight 192 | 193 | snackbarLayout.setBackgroundColor(Color.TRANSPARENT) 194 | snackbarLayout.setPadding(0, 0, 0, 0) 195 | snackContentLayout.setPadding(pLeft, 0, pRight, 0) 196 | snackContentLayout.background = drawable 197 | 198 | if (padding > 0) { 199 | snackbarLayout.setPadding(padding, 0, padding, padding) 200 | } 201 | 202 | if (customView == null) { 203 | val tvSnackbarTextView = snackContentLayout.getChildAt(0) as AppCompatTextView 204 | tvSnackbarTextView.setTextColor(textColor) 205 | if (tfTextView != null) { 206 | tvSnackbarTextView.typeface = tfTextView 207 | } 208 | val btnSnackbarActionButton = snackContentLayout.getChildAt(1) as AppCompatButton 209 | btnSnackbarActionButton.setTextColor(actionTextColor) 210 | if (tfActionBtn != null) { 211 | btnSnackbarActionButton.typeface = tfActionBtn 212 | } 213 | 214 | if (action != null) { 215 | snackbar.setAction(buttonName) { 216 | action?.invoke(snackbar) 217 | } 218 | } 219 | } else { 220 | snackContentLayout.visibility = View.GONE 221 | snackbarLayout.addView(customView) 222 | customViewAction?.invoke(customView!!) 223 | } 224 | } 225 | 226 | inline fun show(func: CustomSnackbar.() -> Unit): CustomSnackbar { 227 | this.func() 228 | return this.show() 229 | } 230 | 231 | private fun Int.toPx(context: Context): Float { 232 | return this * context.resources.displayMetrics.density 233 | } 234 | 235 | fun getView(): View? { 236 | return customView 237 | } 238 | 239 | fun dismiss() { 240 | if (::snackbar.isInitialized) { 241 | snackbar.dismiss() 242 | } 243 | } 244 | } -------------------------------------------------------------------------------- /csbx/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | #FFFFFF 7 | 8 | -------------------------------------------------------------------------------- /csbx/src/test/java/com/kishandonga/csbx/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.kishandonga.csbx; 2 | 3 | public class ExampleUnitTest { 4 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | # Kotlin code style for this project: "official" or "obsolete": 18 | kotlin.code.style=official 19 | android.useAndroidX=true 20 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Feb 13 15:55:23 IST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /images/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/images/img_1.png -------------------------------------------------------------------------------- /images/img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/images/img_2.png -------------------------------------------------------------------------------- /images/img_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/images/img_3.png -------------------------------------------------------------------------------- /images/img_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kishandonga/custom-snackbar/fb9fe9f7c0ba0626520b510f545633581726fd06/images/img_4.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':csbx' 2 | --------------------------------------------------------------------------------