├── .github └── workflows │ └── android.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── art └── demoScratchCardLayout.gif ├── build.gradle ├── demoscratchcardlayout ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ └── output.json └── src │ ├── androidTest │ └── java │ │ └── dev │ │ └── skymansandy │ │ └── scratchcardlayoutexample │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── dev │ │ │ └── skymansandy │ │ │ └── scratchcardlayoutexample │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ └── main │ │ │ │ │ └── MainActivity.kt │ │ │ └── fragment │ │ │ │ ├── aboutdev │ │ │ │ └── AboutDevFragment.kt │ │ │ │ ├── demoscreen │ │ │ │ └── DemoFragment.kt │ │ │ │ └── webpagescreen │ │ │ │ ├── WebPageContent.kt │ │ │ │ └── WebPageFragment.kt │ │ │ └── util │ │ │ ├── AppConstants.kt │ │ │ └── AppUtils.kt │ └── res │ │ ├── drawable │ │ ├── ic_menu_about_library.png │ │ ├── ic_menu_about_me.png │ │ ├── ic_menu_donate_beer.png │ │ ├── ic_menu_github_source.png │ │ ├── ic_menu_home.png │ │ ├── ic_menu_issues_and_feedback.png │ │ ├── ic_menu_rate_app.png │ │ ├── ic_menu_share.png │ │ ├── scratch.png │ │ └── trophy.png │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_about_dev.xml │ │ ├── fragment_demo.xml │ │ ├── fragment_webpage.xml │ │ └── nav_header.xml │ │ ├── menu │ │ └── menu_nav_drawer.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-ldpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── dev │ └── skymansandy │ └── scratchcardlayoutexample │ └── ExampleUnitTest.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── index.html ├── javadoc ├── allclasses-frame.html ├── allclasses-noframe.html ├── constant-values.html ├── deprecated-list.html ├── help-doc.html ├── in │ └── codeshuffle │ │ └── scratchcardlayout │ │ ├── listener │ │ ├── ScratchListener.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ ├── ui │ │ ├── ScratchCardLayout.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ └── util │ │ ├── ScratchCardUtils.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html ├── index-files │ ├── index-1.html │ ├── index-2.html │ ├── index-3.html │ ├── index-4.html │ └── index-5.html ├── index.html ├── overview-frame.html ├── overview-summary.html ├── overview-tree.html ├── package-list ├── script.js └── stylesheet.css ├── scratchcardlayout ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── dev │ │ └── skymansandy │ │ └── scratchcardlayout │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── dev │ │ │ └── skymansandy │ │ │ └── scratchcardlayout │ │ │ ├── listener │ │ │ └── ScratchListener.kt │ │ │ ├── ui │ │ │ ├── ScratchCard.kt │ │ │ └── ScratchCardLayout.kt │ │ │ └── util │ │ │ └── ScratchCardUtils.kt │ └── res │ │ ├── layout │ │ └── default_scratch_view.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ └── strings.xml │ └── test │ └── java │ └── dev │ └── skymansandy │ └── scratchcardlayout │ └── ExampleUnitTest.kt └── settings.gradle /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: set up JDK 1.8 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 1.8 20 | - name: Build with Gradle 21 | run: ./gradlew build 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea/ 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | - build-tools-28.0.3 8 | - android-28 9 | - extra-android-m2repository 10 | - extra-android-support 11 | 12 | before_script: 13 | - touch local.properties 14 | 15 | script: 16 | - ./gradlew build 17 | 18 | before_install: 19 | - chmod +x gradlew 20 | - mkdir "$ANDROID_HOME/licenses" || true 21 | - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license" 22 | - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license" 23 | -------------------------------------------------------------------------------- /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 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScratchCardLayout 2 | 3 | [![License](https://img.shields.io/badge/License%20-Apache%202-337ab7.svg)](https://www.apache.org/licenses/LICENSE-2.0) 4 | [![MinSDK](https://img.shields.io/badge/API-14%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=14) 5 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-ScratchCardLayout-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/7597) 6 | [![Download](https://api.bintray.com/packages/skymansandy/ScratchCard/ScratchCardLayout/images/download.svg) ](https://bintray.com/skymansandy/ScratchCard/ScratchCardLayout/_latestVersion) 7 | 8 | ## A simple Android library for scratch card reveal kind of effect 9 | 10 | 11 | ## Features: 12 | 13 | - Scratch card effect to ANY view. 14 | - Just wrap your existing complex Layout with ScratchCardLayout. 15 | - CardView based library. So All styling of CardView is available. 16 | - Set scratch brush width. 17 | - Enable/Disable scratching effect 18 | - Set Drawable to be scratched (color / image). 19 | - Set the percentage of scratch when you should be revealing full layout. 20 | - Get callbacks when scratching starts, progresses (with a percentage) and when stops.. 21 | 22 | 23 | # Demonstration 24 | |Demo scratchCardLayout| 25 | |:---:| 26 | |![](art/demoScratchCardLayout.gif)| 27 | 28 | 29 | # Usage 30 | ## Dependency: 31 | 32 | 33 | ``` 34 | dependencies { 35 | implementation 'in.codeshuffle.scratchcardlayout:ScratchCardLayout:1.0.8' 36 | } 37 | ``` 38 | 39 | ## XML Usage 40 | ```xml 41 | 50 | 51 | 52 | 53 | ``` 54 | 55 | ## Java Usage 56 | ```java 57 | //Get view reference 58 | ScratchCardLayout scratchCardLayout = findViewById(R.id.scratchCard); 59 | 60 | //Set the drawable (programmatically) 61 | scratchCardLayout.setScratchDrawable(getResources().getDrawable(R.drawable.car)); 62 | 63 | //Set scratch brush width 64 | scratchCardLayout.setScratchWidth(30f); 65 | 66 | //Reveal full layout when some percent of the view is scratched 67 | scratchCardLayout.setRevealFullAtPercent(40); 68 | 69 | //Scratching enable/disable 70 | scratchCardLayout.setScratchEnabled(true); 71 | 72 | //Remove all scratch made till now 73 | scratchCardLayout.resetScratch(); 74 | 75 | //Reveal scratch card (Shows the layout underneath the scratch) 76 | scratchCardLayout.revealScratch(); 77 | ``` 78 | 79 | ### Listeners available 80 | 81 | Implement the given interface and override these stuff: 82 | 83 | ```java 84 | 85 | //Implement this to your class 86 | yourClass extends someBaseClass implements ScratchListener 87 | 88 | //Set the listener 89 | scratchCardLayout.setScratchListener(this); 90 | 91 | //You'll have three main callback methods as scratch listeners 92 | //Scratch started 93 | void onScratchStarted(); 94 | 95 | //Scracth progress (NOTE: not guaranteed to be exact percent. consider it like atleast this much percent has been scratched) 96 | void onScratchProgress(ScratchCardLayout scratchCardLayout, int atLeastScratchedPercent); 97 | 98 | //Scratch completed 99 | void onScratchComplete(); 100 | ``` 101 | 102 | ## PlayStore app 103 | 104 | https://play.google.com/store/apps/details?id=in.codeshuffle.scratchcardlayoutexample 105 | 106 | ## Note 107 | ``` 108 | - The progress is the value guaranteeing that the mentioned percent is atleast scratched. NOT THE EXACT PERCENTAGE (for performance reasaons) 109 | ``` 110 | 111 | License 112 | ------- 113 | 114 | Copyright 2019 SkyManSandy 115 | 116 | Licensed under the Apache License, Version 2.0 (the "License"); 117 | you may not use this file except in compliance with the License. 118 | You may obtain a copy of the License at 119 | 120 | http://www.apache.org/licenses/LICENSE-2.0 121 | 122 | Unless required by applicable law or agreed to in writing, software 123 | distributed under the License is distributed on an "AS IS" BASIS, 124 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 125 | See the License for the specific language governing permissions and 126 | limitations under the License. 127 | -------------------------------------------------------------------------------- /art/demoScratchCardLayout.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/art/demoScratchCardLayout.gif -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.71' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.6.3' 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | 11 | classpath 'com.novoda:bintray-release:0.9.1' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | google() 18 | jcenter() 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } 25 | -------------------------------------------------------------------------------- /demoscratchcardlayout/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /demoscratchcardlayout/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 29 7 | defaultConfig { 8 | applicationId "in.codeshuffle.scratchcardview" 9 | minSdkVersion 19 10 | targetSdkVersion 29 11 | versionCode 3 12 | versionName "1.1" 13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | compileOptions { 22 | sourceCompatibility JavaVersion.VERSION_1_8 23 | targetCompatibility JavaVersion.VERSION_1_8 24 | } 25 | viewBinding { 26 | enabled = true 27 | } 28 | } 29 | 30 | dependencies { 31 | testImplementation 'junit:junit:4.13' 32 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 33 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 34 | 35 | implementation fileTree(dir: 'libs', include: ['*.jar']) 36 | implementation 'com.google.android.material:material:1.1.0' 37 | implementation 'androidx.appcompat:appcompat:1.1.0' 38 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 39 | 40 | //Glide 41 | implementation 'com.github.bumptech.glide:glide:4.11.0' 42 | annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' 43 | 44 | //Circular image view 45 | implementation 'de.hdodenhof:circleimageview:3.1.0' 46 | 47 | //Scratch card view 48 | implementation project(':scratchcardlayout') 49 | } 50 | -------------------------------------------------------------------------------- /demoscratchcardlayout/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 build.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 | -------------------------------------------------------------------------------- /demoscratchcardlayout/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"demoscratchcardlayout-release.apk","fullName":"release","baseName":"release"},"path":"demoscratchcardlayout-release.apk","properties":{}}] -------------------------------------------------------------------------------- /demoscratchcardlayout/src/androidTest/java/dev/skymansandy/scratchcardlayoutexample/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample 2 | 3 | import android.content.Context 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | import androidx.test.platform.app.InstrumentationRegistry 6 | import org.junit.Assert 7 | import org.junit.Test 8 | import org.junit.runner.RunWith 9 | 10 | /** 11 | * Instrumented test, which will execute on an Android device. 12 | * 13 | * @see [Testing documentation](http://d.android.com/tools/testing) 14 | */ 15 | @RunWith(AndroidJUnit4::class) 16 | class ExampleInstrumentedTest { 17 | @Test 18 | fun useAppContext() { 19 | // Context of the app under test. 20 | val appContext: Context = InstrumentationRegistry.getTargetContext() 21 | Assert.assertEquals("in.codeshuffle.scratchcardview", appContext.packageName) 22 | } 23 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/java/dev/skymansandy/scratchcardlayoutexample/ui/activity/main/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample.ui.activity.main 2 | 3 | import dev.skymansandy.scratchcardlayoutexample.ui.fragment.aboutdev.AboutDevFragment 4 | import dev.skymansandy.scratchcardlayoutexample.ui.fragment.demoscreen.DemoFragment 5 | import dev.skymansandy.scratchcardlayoutexample.ui.fragment.webpagescreen.WebPageContent 6 | import dev.skymansandy.scratchcardlayoutexample.ui.fragment.webpagescreen.WebPageFragment 7 | import dev.skymansandy.scratchcardlayoutexample.util.AppUtils 8 | import dev.skymansandy.scratchcardviewexample.R 9 | import dev.skymansandy.scratchcardviewexample.databinding.ActivityMainBinding 10 | import android.os.Bundle 11 | import android.os.Handler 12 | import android.view.MenuItem 13 | import androidx.appcompat.app.ActionBarDrawerToggle 14 | import androidx.appcompat.app.AppCompatActivity 15 | import androidx.core.view.GravityCompat 16 | import androidx.fragment.app.Fragment 17 | import com.google.android.material.navigation.NavigationView 18 | 19 | class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { 20 | 21 | private val demoFragment by lazy { DemoFragment.getInstance() } 22 | private val aboutLibraryFragment by lazy { WebPageFragment.getInstance(WebPageContent.PAGE_VIEW_ABOUT_LIBRARY) } 23 | private val githubFragment by lazy { WebPageFragment.getInstance(WebPageContent.PAGE_VIEW_IN_GITHUB) } 24 | private val issueFeedBackFragment by lazy { WebPageFragment.getInstance(WebPageContent.PAGE_ISSUE_AND_FEEDBACK) } 25 | private val donateBeerFragment by lazy { WebPageFragment.getInstance(WebPageContent.PAGE_DONATE_BEER) } 26 | 27 | private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) } 28 | 29 | private var doubleBackToExitPressedOnce = false 30 | 31 | override fun onCreate(savedInstanceState: Bundle?) { 32 | super.onCreate(savedInstanceState) 33 | setContentView(binding.root) 34 | 35 | replaceFragment(demoFragment) 36 | 37 | setupNavDrawer() 38 | setupActionbarWithToggle() 39 | } 40 | 41 | private fun setupActionbarWithToggle() { 42 | setSupportActionBar(binding.toolbar) 43 | binding.toolbar.title = getString(R.string.app_name) 44 | supportActionBar?.let { 45 | val mDrawerToggle = ActionBarDrawerToggle( 46 | this, binding.drawerLayout, binding.toolbar, 47 | R.string.navigation_drawer_open, R.string.navigation_drawer_close 48 | ) 49 | binding.drawerLayout.setDrawerListener(mDrawerToggle) 50 | it.setDisplayHomeAsUpEnabled(true) 51 | it.setHomeButtonEnabled(true) 52 | mDrawerToggle.syncState() 53 | } 54 | } 55 | 56 | private fun setupNavDrawer() { 57 | binding.navView.setNavigationItemSelectedListener(this) 58 | } 59 | 60 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 61 | if (item.itemId == R.id.home) { 62 | binding.drawerLayout.openDrawer(GravityCompat.START) 63 | return true 64 | } 65 | return super.onOptionsItemSelected(item) 66 | } 67 | 68 | override fun onNavigationItemSelected(menuItem: MenuItem): Boolean { 69 | when (menuItem.itemId) { 70 | R.id.navMenuHome -> { 71 | replaceFragment(demoFragment) 72 | binding.toolbar.title = getString(R.string.app_name) 73 | menuItem.isChecked = true 74 | } 75 | R.id.navMenuAboutLibrary -> { 76 | replaceFragment(aboutLibraryFragment) 77 | binding.toolbar.title = getString(R.string.about_library) 78 | menuItem.isChecked = true 79 | } 80 | R.id.navMenuGithub -> { 81 | replaceFragment(githubFragment) 82 | binding.toolbar.title = getString(R.string.source_code) 83 | menuItem.isChecked = true 84 | } 85 | R.id.navMenuIssueFeedback -> { 86 | replaceFragment(issueFeedBackFragment) 87 | binding.toolbar.title = getString(R.string.issues_and_feedback) 88 | menuItem.isChecked = true 89 | } 90 | R.id.navMenuDonateBeer -> { 91 | replaceFragment(donateBeerFragment) 92 | binding.toolbar.title = getString(R.string.thanks_for_the_beer) 93 | AppUtils.showShortToast(this, 94 | getString(R.string.thats_so_nice_of_you)) 95 | } 96 | R.id.navMenuAbout -> { 97 | val aboutDevFragment: AboutDevFragment = AboutDevFragment.getInstance() 98 | aboutDevFragment.show(supportFragmentManager, aboutDevFragment.tag) 99 | } 100 | R.id.navMenuRateApp -> { 101 | AppUtils.openPlayStoreForApp(this) 102 | AppUtils.showShortToast(this, 103 | getString(R.string.thanks_for_the_support)) 104 | } 105 | R.id.navMenuShareApp -> AppUtils.shareLibraryApp(this) 106 | } 107 | binding.drawerLayout.closeDrawers() 108 | return true 109 | } 110 | 111 | override fun onBackPressed() { 112 | if (doubleBackToExitPressedOnce) { 113 | super.onBackPressed() 114 | return 115 | } 116 | doubleBackToExitPressedOnce = true 117 | AppUtils.showShortToast(this, getString(R.string.press_back_to_exit)) 118 | Handler().postDelayed({ doubleBackToExitPressedOnce = false }, 2000) 119 | } 120 | 121 | private fun replaceFragment(instance: Fragment) { 122 | val fragmentTransaction = supportFragmentManager.beginTransaction() 123 | fragmentTransaction.replace(R.id.container, instance) 124 | fragmentTransaction.commit() 125 | } 126 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/java/dev/skymansandy/scratchcardlayoutexample/ui/fragment/aboutdev/AboutDevFragment.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample.ui.fragment.aboutdev 2 | 3 | import dev.skymansandy.scratchcardviewexample.databinding.FragmentAboutDevBinding 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.fragment.app.DialogFragment 9 | 10 | class AboutDevFragment : DialogFragment() { 11 | 12 | companion object { 13 | fun getInstance(): AboutDevFragment { 14 | val bundle = Bundle() 15 | val aboutDevFragment = AboutDevFragment() 16 | aboutDevFragment.arguments = bundle 17 | return aboutDevFragment 18 | } 19 | } 20 | 21 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 22 | return FragmentAboutDevBinding.inflate(inflater).root 23 | } 24 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/java/dev/skymansandy/scratchcardlayoutexample/ui/fragment/demoscreen/DemoFragment.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample.ui.fragment.demoscreen 2 | 3 | import dev.skymansandy.scratchcardlayout.listener.ScratchListener 4 | import dev.skymansandy.scratchcardlayout.ui.ScratchCardLayout 5 | import dev.skymansandy.scratchcardlayout.util.ScratchCardUtils 6 | import dev.skymansandy.scratchcardlayoutexample.util.AppUtils 7 | import dev.skymansandy.scratchcardviewexample.R 8 | import dev.skymansandy.scratchcardviewexample.databinding.FragmentDemoBinding 9 | import android.os.Bundle 10 | import android.util.Log 11 | import android.view.LayoutInflater 12 | import android.view.View 13 | import android.view.ViewGroup 14 | import android.widget.CompoundButton 15 | import android.widget.SeekBar 16 | import android.widget.SeekBar.OnSeekBarChangeListener 17 | import androidx.fragment.app.DialogFragment 18 | 19 | class DemoFragment : DialogFragment(), ScratchListener { 20 | 21 | companion object { 22 | private val TAG: String? = DemoFragment::class.java.simpleName 23 | 24 | fun getInstance(): DemoFragment { 25 | val bundle = Bundle() 26 | val demoFragment = DemoFragment() 27 | demoFragment.arguments = bundle 28 | return demoFragment 29 | } 30 | } 31 | 32 | private lateinit var binding: FragmentDemoBinding 33 | 34 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 35 | binding = FragmentDemoBinding.inflate(inflater) 36 | return binding.root 37 | } 38 | 39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 40 | super.onViewCreated(view, savedInstanceState) 41 | resetLibraryView() 42 | resetControlPanelView() 43 | setControlPanelListeners() 44 | } 45 | 46 | private fun resetLibraryView() { 47 | binding.scratchCard.setScratchListener(this) 48 | 49 | binding.reveal.setOnClickListener { binding.scratchCard.revealScratch() } 50 | binding.reset.setOnClickListener { 51 | binding.scratchCard.resetScratch() 52 | resetControlPanelView() 53 | } 54 | } 55 | 56 | private fun resetControlPanelView() { 57 | binding.brushSizeSeekBar.progress = 40 58 | binding.revealFullAtSeekBar.progress = 40 59 | binding.scratchEffectToggle.isChecked = true 60 | binding.scratchEffectToggle.text = getString(R.string.enabled) 61 | } 62 | 63 | private fun setControlPanelListeners() { 64 | //Scratch Brush size config 65 | binding.brushSizeSeekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { 66 | override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {} 67 | override fun onStartTrackingTouch(seekBar: SeekBar?) {} 68 | override fun onStopTrackingTouch(seekBar: SeekBar?) { 69 | context?.let { 70 | binding.scratchCard.setScratchWidthDip(ScratchCardUtils.dipToPx(it, seekBar!!.progress.toFloat())) 71 | } 72 | } 73 | }) 74 | 75 | //Scratch effect config 76 | binding.scratchEffectToggle.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> 77 | binding.scratchCard.setScratchEnabled(isChecked) 78 | binding.scratchEffectToggle.text = getString(if (isChecked) R.string.enabled else R.string.disabled) 79 | } 80 | 81 | //Scratch reveal at percent 82 | binding.revealFullAtSeekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { 83 | override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {} 84 | override fun onStartTrackingTouch(seekBar: SeekBar?) {} 85 | override fun onStopTrackingTouch(seekBar: SeekBar?) { 86 | AppUtils.showShortToast(activity, getString(R.string.resetting_view_since_reveal_percent_was_changed)) 87 | binding.scratchCard.setRevealFullAtPercent(seekBar!!.progress) 88 | binding.scratchCard.resetScratch() 89 | } 90 | }) 91 | } 92 | 93 | override fun onScratchStarted() { 94 | Log.d(TAG, "Scratch started") 95 | } 96 | 97 | override fun onScratchProgress(scratchCardLayout: ScratchCardLayout, atLeastScratchedPercent: Int) { 98 | Log.d(TAG, "Progress = $atLeastScratchedPercent") 99 | } 100 | 101 | override fun onScratchComplete() { 102 | Log.d(TAG, "Scratch ended") 103 | } 104 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/java/dev/skymansandy/scratchcardlayoutexample/ui/fragment/webpagescreen/WebPageContent.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample.ui.fragment.webpagescreen 2 | 3 | enum class WebPageContent { 4 | PAGE_VIEW_ABOUT_LIBRARY, 5 | PAGE_VIEW_IN_GITHUB, 6 | PAGE_ISSUE_AND_FEEDBACK, 7 | PAGE_DONATE_BEER 8 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/java/dev/skymansandy/scratchcardlayoutexample/ui/fragment/webpagescreen/WebPageFragment.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample.ui.fragment.webpagescreen 2 | 3 | import dev.skymansandy.scratchcardlayoutexample.util.AppConstants.URLs 4 | import dev.skymansandy.scratchcardviewexample.databinding.FragmentWebpageBinding 5 | import android.annotation.SuppressLint 6 | import android.graphics.Bitmap 7 | import android.os.Bundle 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.webkit.WebChromeClient 12 | import android.webkit.WebView 13 | import android.webkit.WebViewClient 14 | import androidx.fragment.app.DialogFragment 15 | 16 | class WebPageFragment : DialogFragment() { 17 | 18 | companion object { 19 | private val CONTENT_TYPE: String? = "contentType" 20 | 21 | fun getInstance(content: WebPageContent): WebPageFragment { 22 | val bundle = Bundle() 23 | val webPageFragment = WebPageFragment() 24 | bundle.putSerializable(CONTENT_TYPE, content) 25 | webPageFragment.arguments = bundle 26 | return webPageFragment 27 | } 28 | } 29 | 30 | private lateinit var binding: FragmentWebpageBinding 31 | 32 | private val mChromeClient: WebChromeClient? = object : WebChromeClient() { 33 | override fun onProgressChanged(view: WebView?, newProgress: Int) { 34 | super.onProgressChanged(view, newProgress) 35 | if (!isAdded) return 36 | binding.progressBar.progress = newProgress 37 | } 38 | } 39 | 40 | private val mWebClient: WebViewClient? = object : WebViewClient() { 41 | override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { 42 | super.onPageStarted(view, url, favicon) 43 | if (!isAdded) return 44 | binding.progressBar.visibility = View.VISIBLE 45 | } 46 | 47 | override fun onPageFinished(view: WebView?, url: String?) { 48 | super.onPageFinished(view, url) 49 | if (!isAdded) return 50 | binding.progressBar.visibility = View.GONE 51 | } 52 | } 53 | 54 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 55 | binding = FragmentWebpageBinding.inflate(inflater) 56 | return binding.root 57 | } 58 | 59 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 60 | super.onViewCreated(view, savedInstanceState) 61 | if (savedInstanceState == null) { 62 | setupWebViewDefaults() 63 | val bundle = arguments 64 | if (bundle != null) { 65 | val content = bundle.getSerializable(CONTENT_TYPE) as? WebPageContent 66 | ?: WebPageContent.PAGE_VIEW_IN_GITHUB 67 | when (content) { 68 | WebPageContent.PAGE_VIEW_ABOUT_LIBRARY -> binding.webView.loadUrl(URLs.VIEW_READ_ME) 69 | WebPageContent.PAGE_VIEW_IN_GITHUB -> binding.webView.loadUrl(URLs.GITHUB_REPO_URL) 70 | WebPageContent.PAGE_ISSUE_AND_FEEDBACK -> binding.webView.loadUrl(URLs.ISSUE_FEEDBACK_URL) 71 | WebPageContent.PAGE_DONATE_BEER -> binding.webView.loadUrl(URLs.DONATE_BEER_URL) 72 | } 73 | } 74 | } 75 | } 76 | 77 | @SuppressLint("SetJavaScriptEnabled") 78 | private fun setupWebViewDefaults() { 79 | binding.webView.apply { 80 | webChromeClient = mChromeClient 81 | webViewClient = mWebClient 82 | 83 | settings.displayZoomControls = false 84 | settings.setSupportZoom(false) 85 | settings.builtInZoomControls = false 86 | settings.javaScriptEnabled = true 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/java/dev/skymansandy/scratchcardlayoutexample/util/AppConstants.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample.util 2 | 3 | object AppConstants { 4 | object URLs { 5 | val GITHUB_REPO_URL: String? = "https://github.com/skymansandy/scratchCardLayout" 6 | val ISSUE_FEEDBACK_URL: String? = "https://github.com/skymansandy/scratchCardLayout/issues" 7 | val DONATE_BEER_URL: String? = "https://beerpay.io/skymansandy/scratchCardLayout" 8 | val VIEW_READ_ME: String? = "https://github.com/skymansandy/scratchCardLayout/blob/master/README.md" 9 | } 10 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/java/dev/skymansandy/scratchcardlayoutexample/util/AppUtils.kt: -------------------------------------------------------------------------------- 1 | package dev.skymansandy.scratchcardlayoutexample.util 2 | 3 | import dev.skymansandy.scratchcardviewexample.R 4 | import android.content.ActivityNotFoundException 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.net.Uri 8 | import android.widget.Toast 9 | import java.text.MessageFormat 10 | 11 | object AppUtils { 12 | fun openPlayStoreForApp(context: Context?) { 13 | context?.let { 14 | val appPackageName = it.packageName 15 | try { 16 | it.startActivity(Intent(Intent.ACTION_VIEW, 17 | Uri.parse(it.resources.getString(R.string.app_market_link) + appPackageName))) 18 | } catch (e: ActivityNotFoundException) { 19 | it.startActivity(Intent(Intent.ACTION_VIEW, 20 | Uri.parse(it.resources.getString(R.string.app_google_play_store_link) + appPackageName))) 21 | } 22 | } 23 | } 24 | 25 | fun shareLibraryApp(context: Context?) { 26 | context?.let { 27 | try { 28 | val shareBody = MessageFormat.format("{0}: {1}\n\n{2}", 29 | it.getString(R.string.here_is_an_interesting_library), 30 | it.getString(R.string.library_app_name), 31 | it.getString(R.string.library_app_description)) 32 | val sharingIntent = Intent(Intent.ACTION_SEND) 33 | sharingIntent.type = "text/plain" 34 | sharingIntent.putExtra(Intent.EXTRA_SUBJECT, it.getString(R.string.library_app_name)) 35 | sharingIntent.putExtra(Intent.EXTRA_TEXT, shareBody) 36 | it.startActivity(Intent.createChooser(sharingIntent, it.resources.getString(R.string.share_using))) 37 | } catch (e: Exception) { 38 | e.printStackTrace() 39 | showShortToast(it, "Something went wrong!") 40 | } 41 | } 42 | } 43 | 44 | fun showShortToast(context: Context?, message: String?) { 45 | Toast.makeText(context, message, Toast.LENGTH_SHORT).show() 46 | } 47 | } -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_about_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_about_library.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_about_me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_about_me.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_donate_beer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_donate_beer.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_github_source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_github_source.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_home.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_issues_and_feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_issues_and_feedback.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_rate_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_rate_app.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/ic_menu_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/ic_menu_share.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/scratch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/scratch.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/drawable/trophy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skymansandy/scratchCardLayout/f0d346e3e717e5d4ff29bea803c7c9b4de7f4bd2/demoscratchcardlayout/src/main/res/drawable/trophy.png -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 22 | 23 | 27 | 28 | 29 | 30 | 38 | 39 | -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/layout/fragment_about_dev.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 19 | 20 | 21 | 28 | 29 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /demoscratchcardlayout/src/main/res/layout/fragment_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 24 | 25 | 26 | 31 | 32 | 41 | 42 | 48 | 49 | 50 | 51 | 52 | 53 | 57 | 58 | 63 | 64 | 70 | 71 | 76 | 77 | 82 | 83 | 89 | 90 | 91 | 92 | 93 | 94 | 100 | 101 | 107 | 108 | 113 | 114 | 120 | 121 | 122 | 123 | 124 | 130 | 131 | 136 | 137 | 142 | 143 | 144 | 150 | 151 | 152 | 153 | 154 | 160 | 161 |