├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── RELEASE-NOTES.md ├── build.gradle ├── config ├── bintray.gradle ├── checkstyle │ ├── checkstyle.xml │ └── suppressions.xml ├── findbugs │ └── excludeFilter.xml ├── jacoco.gradle ├── maven.gradle └── static_analysis.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── prism-palette ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── stylingandroid │ │ └── prism │ │ ├── filter │ │ └── PaletteFilter.java │ │ └── palette │ │ └── PaletteTrigger.java │ └── test │ └── java │ ├── android │ └── support │ │ └── v7 │ │ └── graphics │ │ ├── DummyGenerator.java │ │ └── PaletteFactory.java │ └── com │ └── stylingandroid │ └── prism │ └── palette │ ├── MockUtils.java │ └── PaletteTriggerTest.java ├── prism-viewpager ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── stylingandroid │ │ └── prism │ │ ├── setter │ │ ├── GlowSetterIcs.java │ │ ├── GlowSetterLollipop.java │ │ ├── ViewPagerGlowSetter.java │ │ ├── ViewPagerGlowSetterLegacy.java │ │ └── ViewPagerSetterFactory.java │ │ └── viewpager │ │ ├── ColorProvider.java │ │ ├── ColorProviderAdapter.java │ │ ├── ColourAnimator.java │ │ ├── ColourProvider.java │ │ ├── ViewPagerTrigger.java │ │ └── compat │ │ └── ArgbEvaluatorCompat.java │ └── test │ └── java │ └── com │ └── stylingandroid │ └── prism │ └── viewpager │ ├── ColorProviderAdapterTest.java │ └── compat │ ├── ArgbEvaluatorCompatTest.java │ ├── ArgbEvaluatorHoneycombTest.java │ └── ArgbEvaluatorLegacyTest.java ├── prism ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── stylingandroid │ │ └── prism │ │ ├── BaseTrigger.java │ │ ├── ColorSetter.java │ │ ├── Prism.java │ │ ├── Setter.java │ │ ├── SetterAdapter.java │ │ ├── Trigger.java │ │ ├── filter │ │ ├── CompoundFilter.java │ │ ├── Filter.java │ │ ├── GenericFilter.java │ │ ├── IdentityFilter.java │ │ ├── RepeatableFilter.java │ │ ├── ShadeFilter.java │ │ ├── SystemChromeFilter.java │ │ └── TintFilter.java │ │ └── setter │ │ ├── BaseSetter.java │ │ ├── ColourSetterFactory.java │ │ ├── FabSetter.java │ │ ├── FieldAccessor.java │ │ ├── MethodInvoker.java │ │ ├── ReflectiveCache.java │ │ ├── SetterFactory.java │ │ ├── SystemChromeSetter.java │ │ ├── TextSetter.java │ │ └── ViewBackgroundSetter.java │ └── test │ └── java │ ├── android │ └── support │ │ └── design │ │ └── widget │ │ └── FloatingActionButton.java │ └── com │ └── stylingandroid │ └── prism │ ├── BuilderTest.java │ ├── MockUtils.java │ ├── SetterAdapterTest.java │ ├── filter │ ├── IdentityFilterTest.java │ ├── RepeatableFilterTest.java │ ├── ShadeFilterTest.java │ ├── SystemChromeFilterTest.java │ └── TintFilterTest.java │ └── setter │ ├── BaseSetterTest.java │ ├── FabSetterTest.java │ ├── FieldAccessorTest.java │ ├── SetterFactoryTest.java │ ├── StatusBarSetterAccessor.java │ ├── SystemChromeSetterTest.java │ ├── TextSetterTest.java │ └── ViewBackgroundSetterTest.java ├── sample-palette ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── stylingandroid │ │ └── prism │ │ └── sample │ │ └── palette │ │ ├── ImageLoadTask.java │ │ └── MainActivity.java │ └── res │ ├── drawable-hdpi │ └── ic_image.png │ ├── drawable-mdpi │ └── ic_image.png │ ├── drawable-xhdpi │ └── ic_image.png │ ├── drawable-xxhdpi │ └── ic_image.png │ ├── drawable-xxxhdpi │ └── ic_image.png │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── sample-viewpager ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── stylingandroid │ │ └── prism │ │ └── sample │ │ └── viewpager │ │ ├── ColourFragment.java │ │ ├── MainActivity.java │ │ └── RainbowPagerAdapter.java │ └── res │ ├── drawable-hdpi │ ├── ic_block.png │ └── ic_menu.png │ ├── drawable-mdpi │ ├── ic_block.png │ └── ic_menu.png │ ├── drawable-xhdpi │ ├── ic_block.png │ └── ic_menu.png │ ├── drawable-xxhdpi │ ├── ic_block.png │ └── ic_menu.png │ ├── drawable-xxxhdpi │ ├── ic_block.png │ └── ic_menu.png │ ├── layout │ ├── activity_main.xml │ ├── fragment_colour.xml │ ├── include_main.xml │ └── nav_header.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── stylingandroid │ │ └── prismpalette │ │ └── MainActivityTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── stylingandroid │ │ └── prism │ │ └── sample │ │ └── MainActivity.java │ └── res │ ├── drawable-hdpi │ └── ic_image.png │ ├── drawable-mdpi │ └── ic_image.png │ ├── drawable-xhdpi │ └── ic_image.png │ ├── drawable-xxhdpi │ └── ic_image.png │ ├── drawable-xxxhdpi │ └── ic_image.png │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── settings.gradle └── test-lib ├── .gitignore ├── build.gradle └── src └── main └── java └── com └── stylingandroid └── prism └── ColourUtils.java /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Pull requests are not being accepted at this time. Please see the README for further details. 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2015 Styling Android Limited 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Prism 2 | 3 | It is with an extremely heavy heart that I must announce that updates to Prism have been suspended indefinitely. This also means that I will be unable accept any pull requests until further notice. 4 | 5 | The reason for this suspension is an infringement of my intellectual property and I have been advised to suspend updates in an attempt to minimise any further infringements whilst I pursue the matter through legal channels. I would dearly like to share details of those responsible, but have been advised that this may prejudice any legal process. 6 | 7 | It is such a shame that I have been forced in to this position as there are some really exciting features that were going to be added. But I now cannot see when, or even if, these will ever be released. 8 | 9 | Some trolls are stupid enough to destroy the bridge they choose to live under. 10 | 11 | Au revoir, Prism. 12 | 13 | Mark Allison 14 | 22nd July 2015 15 | -------------------------------------------------------------------------------- /RELEASE-NOTES.md: -------------------------------------------------------------------------------- 1 | 1.0.1 2 | ------- 3 | 4 | - Now sets NavigationBar colour as well as StatusBar colour 5 | - Palette API tweaks 6 | - BUGFIX: DarkVibrantFilter was incorrect 7 | 8 | 1.0.0 9 | ------- 10 | 11 | - Initial release 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | maven { url 'https://repos.zeroturnaround.com/nexus/content/repositories/zt-public-releases' } 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:1.2.3' 10 | classpath 'com.zeroturnaround.jrebel.android:jr-android-gradle:0.8.+' 11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2' 12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | jcenter() 22 | } 23 | } 24 | 25 | def isDryRun() { 26 | if (project.hasProperty('dryrun')) { 27 | return project.dryrun.toBoolean() 28 | } 29 | return true 30 | } 31 | -------------------------------------------------------------------------------- /config/bintray.gradle: -------------------------------------------------------------------------------- 1 | apply from: '../config/maven.gradle' 2 | apply plugin: 'com.jfrog.bintray' 3 | 4 | version = libraryVersion 5 | 6 | task sourcesJar(type: Jar) { 7 | from android.sourceSets.main.java.srcDirs 8 | classifier = 'sources' 9 | } 10 | 11 | task javadoc(type: Javadoc) { 12 | source = android.sourceSets.main.java.srcDirs 13 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 14 | } 15 | 16 | task javadocJar(type: Jar, dependsOn: javadoc) { 17 | classifier = 'javadoc' 18 | from javadoc.destinationDir 19 | } 20 | artifacts { 21 | archives javadocJar 22 | archives sourcesJar 23 | } 24 | 25 | Properties properties = new Properties() 26 | File localProperties = project.rootProject.file('local.properties'); 27 | if (localProperties.exists()) { 28 | properties.load(localProperties.newDataInputStream()) 29 | } else { 30 | properties.put("bintray.user", project.bintrayUser) 31 | properties.put("bintray.apikey", project.bintrayApikey) 32 | } 33 | 34 | bintray { 35 | user = properties.getProperty("bintray.user") 36 | key = properties.getProperty("bintray.apikey") 37 | dryRun = bintrayDryRun 38 | publish = true 39 | 40 | configurations = ['archives'] 41 | pkg { 42 | repo = 'maven' 43 | name = libraryName 44 | desc = libraryDescription 45 | websiteUrl = 'https://github.com/StylingAndroid/Prism' 46 | vcsUrl = 'https://github.com/StylingAndroid/Prism.git' 47 | licenses = ["Apache-2.0"] 48 | version { 49 | name = libraryVersion 50 | desc = libraryDescription 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /config/checkstyle/checkstyle.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /config/checkstyle/suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /config/findbugs/excludeFilter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /config/jacoco.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'jacoco' 2 | 3 | //jacoco { 4 | // toolVersion "0.7.1.201405082137" 5 | //} 6 | // 7 | //def coverageSourceDirs = [ 8 | // "$projectDir/src/main/java", 9 | //] 10 | // 11 | //task jacocoTestReport(type: JacocoReport, dependsOn: "testDebug") { 12 | // group = "Reporting" 13 | // description = "Generate Jacoco coverage reports after running tests." 14 | // reports { 15 | // xml.enabled = true 16 | // html.enabled = true 17 | // } 18 | // classDirectories = fileTree( 19 | // dir: './build/intermediates/classes/debug', 20 | // excludes: ['**/R*.class', 21 | // '**/*$InjectAdapter.class', 22 | // '**/*$ModuleAdapter.class', 23 | // '**/*$ViewInjector*.class' 24 | // ] 25 | // ) 26 | // sourceDirectories = files(coverageSourceDirs) 27 | // executionData = files("$buildDir/jacoco/testDebug.exec") 28 | // // Bit hacky but fixes https://code.google.com/p/android/issues/detail?id=69174. 29 | // // We iterate through the compiled .class tree and rename $$ to $. 30 | // doFirst { 31 | // new File("$buildDir/intermediates/classes/").eachFileRecurse { file -> 32 | // if (file.name.contains('$$')) { 33 | // file.renameTo(file.path.replace('$$', '$')) 34 | // } 35 | // } 36 | // } 37 | //} 38 | 39 | android.libraryVariants.all { variant -> 40 | task("test${variant.name.capitalize()}WithCoverage", type: JacocoReport, dependsOn: "test${variant.name.capitalize()}") { 41 | group = 'verification' 42 | description = "Run unit test for the ${variant.name} build with Jacoco code coverage reports." 43 | 44 | classDirectories = fileTree( 45 | dir: variant.javaCompile.destinationDir, 46 | excludes: ['**/R*.class', 47 | '**/*$InjectAdapter.class', 48 | '**/*$ModuleAdapter.class', 49 | '**/*$ViewInjector*.class', 50 | '**/*BuildConfig*.class' 51 | ] 52 | ) 53 | sourceDirectories = files(variant.javaCompile.source) 54 | executionData = files("build/jacoco/test${variant.name.capitalize()}.exec") 55 | 56 | reports { 57 | xml.enabled true 58 | xml.destination "${buildDir}/reports/jacoco/${variant.name}/${variant.name}.xml" 59 | html.destination "${buildDir}/reports/jacoco/${variant.name}/html" 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /config/maven.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | 3 | group = 'com.stylingandroid.prism' 4 | 5 | install { 6 | repositories.mavenInstaller { 7 | pom { 8 | project { 9 | packaging 'aar' 10 | groupId 'com.stylingandroid.prism' 11 | artifactId libraryName 12 | version libraryVersion 13 | 14 | // Add your description here 15 | name libraryName 16 | description libraryDescription 17 | url 'https://github.com/StylingAndroid/Prism' 18 | 19 | // Set your license 20 | licenses { 21 | license { 22 | name 'The Apache Software License, Version 2.0' 23 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 24 | } 25 | } 26 | developers { 27 | developer { 28 | id 'Styling Android' 29 | name 'Mark Allison' 30 | email 'mark@stylingandroid.com' 31 | } 32 | } 33 | scm { 34 | connection 'https://github.com/StylingAndroid/Prism.git' 35 | developerConnection 'https://github.com/StylingAndroid/Prism.git' 36 | url 'https://github.com/StylingAndroid/Prism' 37 | 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /config/static_analysis.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'checkstyle' 2 | apply plugin: 'findbugs' 3 | apply plugin: 'pmd' 4 | 5 | check.dependsOn 'checkstyle', 'pmd', 'findbugs' 6 | 7 | task pmd(type: Pmd) { 8 | ignoreFailures = true 9 | 10 | source 'src' 11 | include '**/*.java' 12 | exclude '**/gen/**' 13 | 14 | reports { 15 | xml.enabled = true 16 | html.enabled = false 17 | } 18 | } 19 | 20 | task checkstyle(type: Checkstyle) { 21 | ignoreFailures = true 22 | configFile file("${project(':').projectDir}/config/checkstyle/checkstyle.xml") 23 | 24 | source 'src/main' 25 | include '**/*.java' 26 | exclude '**/packageName/**', '**/utils/MyFile.java' 27 | classpath = files() 28 | } 29 | 30 | task findbugs(type: FindBugs, dependsOn: assembleDebug) { 31 | ignoreFailures = true 32 | classes = fileTree("$projectDir/build/intermediates/classes/debug/") 33 | source = fileTree("$projectDir/src/main/java/") 34 | classpath = files() 35 | excludeFilter = file("${project(':').projectDir}/config/findbugs/excludeFilter.xml") 36 | effort = 'max' 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | dryrun=true 20 | libraryVersion=1.0.1 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 19 12:20:05 BST 2015 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-2.5-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /prism-palette/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /prism-palette/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | minSdkVersion 7 9 | targetSdkVersion 22 10 | } 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 15 | } 16 | debug { 17 | testCoverageEnabled = true 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.android.support:palette-v7:22.2.0' 24 | compile project(':prism') 25 | 26 | testCompile 'junit:junit:4.12' 27 | testCompile 'org.mockito:mockito-core:1.10.19' 28 | testCompile 'org.easytesting:fest-assert-core:2.0M10' 29 | testCompile 'org.powermock:powermock-module-junit4:1.6.2' 30 | testCompile 'org.powermock:powermock-api-mockito:1.6.2' 31 | testCompile project(':test-lib') 32 | } 33 | 34 | ext { 35 | libraryName = 'prism-palette' 36 | libraryDescription = 'A trigger for Prism to change colours based on the Palette colours from an image' 37 | libraryVersion = project.libraryVersion 38 | bintrayDryRun = isDryRun() 39 | } 40 | 41 | apply from: '../config/bintray.gradle' 42 | apply from: '../config/jacoco.gradle' 43 | apply from: '../config/static_analysis.gradle' 44 | -------------------------------------------------------------------------------- /prism-palette/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/markallison/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /prism-palette/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /prism-palette/src/main/java/com/stylingandroid/prism/filter/PaletteFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import android.support.v7.graphics.Palette; 4 | 5 | public class PaletteFilter extends CompoundFilter { 6 | 7 | public PaletteFilter(GenericFilter firstFilter, GenericFilter secondFilter) { 8 | super(firstFilter, secondFilter); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /prism-palette/src/main/java/com/stylingandroid/prism/palette/PaletteTrigger.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.palette; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.graphics.Palette; 7 | 8 | import com.stylingandroid.prism.BaseTrigger; 9 | import com.stylingandroid.prism.filter.Filter; 10 | import com.stylingandroid.prism.filter.CompoundFilter; 11 | import com.stylingandroid.prism.filter.GenericFilter; 12 | 13 | import java.lang.ref.WeakReference; 14 | 15 | public class PaletteTrigger extends BaseTrigger { 16 | private Palette palette; 17 | 18 | public PaletteTrigger() { 19 | } 20 | 21 | public void setBitmap(@NonNull Bitmap bitmap) { 22 | new Palette.Builder(bitmap).generate(listener); 23 | } 24 | 25 | public Filter getVibrantFilter() { 26 | return getVibrantFilter(getColour()); 27 | } 28 | 29 | public Filter getVibrantFilter(GenericFilter nextFilter) { 30 | return new CompoundFilter<>(new VibrantFilter(this), nextFilter); 31 | } 32 | 33 | public Filter getLightVibrantFilter() { 34 | return getLightVibrantFilter(getColour()); 35 | } 36 | 37 | public Filter getLightVibrantFilter(GenericFilter nextFilter) { 38 | return new CompoundFilter<>(new LightVibrantFilter(this), nextFilter); 39 | } 40 | 41 | public Filter getDarkVibrantFilter() { 42 | return getDarkVibrantFilter(getColour()); 43 | } 44 | 45 | public Filter getDarkVibrantFilter(GenericFilter nextFilter) { 46 | return new CompoundFilter<>(new DarkVibrantFilter(this), nextFilter); 47 | } 48 | 49 | public Filter getMutedFilter() { 50 | return getMutedFilter(getColour()); 51 | } 52 | 53 | public Filter getMutedFilter(GenericFilter nextFilter) { 54 | return new CompoundFilter<>(new MutedFilter(this), nextFilter); 55 | } 56 | 57 | public Filter getLightMutedFilter() { 58 | return getLightMutedFilter(getColour()); 59 | } 60 | 61 | public Filter getLightMutedFilter(GenericFilter nextFilter) { 62 | return new CompoundFilter<>(new LightMutedFilter(this), nextFilter); 63 | } 64 | 65 | public Filter getDarkMutedFilter() { 66 | return getDarkMutedFilter(getColour()); 67 | } 68 | 69 | public Filter getDarkMutedFilter(GenericFilter nextFilter) { 70 | return new CompoundFilter<>(new DarkMutedFilter(this), nextFilter); 71 | } 72 | 73 | public GenericFilter getColour() { 74 | return rgbColour; 75 | } 76 | 77 | public GenericFilter getColor() { 78 | return rgbColour; 79 | } 80 | 81 | public GenericFilter getTitleTextColour() { 82 | return titleTextColour; 83 | } 84 | 85 | public GenericFilter getTitleTextColor() { 86 | return getTitleTextColour(); 87 | } 88 | 89 | public GenericFilter getBodyTextColour() { 90 | return bodyTextColour; 91 | } 92 | 93 | public GenericFilter getBodyTextColor() { 94 | return getBodyTextColour(); 95 | } 96 | 97 | private Palette.PaletteAsyncListener listener = new Palette.PaletteAsyncListener() { 98 | @Override 99 | public void onGenerated(Palette newPalette) { 100 | setPalette(newPalette); 101 | } 102 | }; 103 | 104 | private abstract static class BasePaletteFilter implements GenericFilter { 105 | private final WeakReference parentWeakReference; 106 | 107 | protected BasePaletteFilter(PaletteTrigger parent) { 108 | this.parentWeakReference = new WeakReference<>(parent); 109 | } 110 | 111 | @Override 112 | public Palette.Swatch filter(Integer noValue) { 113 | Palette palette = getPalette(); 114 | if (palette != null) { 115 | return doFilter(palette); 116 | } 117 | return null; 118 | } 119 | 120 | protected abstract Palette.Swatch doFilter(Palette palette); 121 | 122 | protected Palette getPalette() { 123 | PaletteTrigger paletteTrigger = parentWeakReference.get(); 124 | if (paletteTrigger != null) { 125 | return paletteTrigger.getPalette(); 126 | } 127 | return null; 128 | } 129 | } 130 | 131 | private static class VibrantFilter extends BasePaletteFilter { 132 | VibrantFilter(PaletteTrigger parent) { 133 | super(parent); 134 | } 135 | 136 | @Override 137 | protected Palette.Swatch doFilter(Palette palette) { 138 | return palette.getVibrantSwatch(); 139 | } 140 | } 141 | 142 | private static class LightVibrantFilter extends BasePaletteFilter { 143 | LightVibrantFilter(PaletteTrigger parent) { 144 | super(parent); 145 | } 146 | 147 | @Override 148 | protected Palette.Swatch doFilter(Palette palette) { 149 | return palette.getLightVibrantSwatch(); 150 | } 151 | } 152 | 153 | private static class DarkVibrantFilter extends BasePaletteFilter { 154 | DarkVibrantFilter(PaletteTrigger parent) { 155 | super(parent); 156 | } 157 | 158 | @Override 159 | protected Palette.Swatch doFilter(Palette palette) { 160 | return palette.getDarkVibrantSwatch(); 161 | } 162 | } 163 | 164 | private static class MutedFilter extends BasePaletteFilter { 165 | MutedFilter(PaletteTrigger parent) { 166 | super(parent); 167 | } 168 | 169 | @Override 170 | protected Palette.Swatch doFilter(Palette palette) { 171 | return palette.getMutedSwatch(); 172 | } 173 | } 174 | 175 | private static class LightMutedFilter extends BasePaletteFilter { 176 | LightMutedFilter(PaletteTrigger parent) { 177 | super(parent); 178 | } 179 | 180 | @Override 181 | protected Palette.Swatch doFilter(Palette palette) { 182 | return palette.getLightMutedSwatch(); 183 | } 184 | } 185 | 186 | private static class DarkMutedFilter extends BasePaletteFilter { 187 | DarkMutedFilter(PaletteTrigger parent) { 188 | super(parent); 189 | } 190 | 191 | @Override 192 | protected Palette.Swatch doFilter(android.support.v7.graphics.Palette palette) { 193 | return palette.getDarkMutedSwatch(); 194 | } 195 | } 196 | 197 | private GenericFilter rgbColour = new GenericFilter() { 198 | @Override 199 | public Integer filter(Palette.Swatch colour) { 200 | if (colour == null) { 201 | return Color.TRANSPARENT; 202 | } 203 | return colour.getRgb(); 204 | } 205 | }; 206 | 207 | private GenericFilter titleTextColour = new GenericFilter() { 208 | @Override 209 | public Integer filter(Palette.Swatch colour) { 210 | if (colour == null) { 211 | return Color.TRANSPARENT; 212 | } 213 | return colour.getTitleTextColor(); 214 | } 215 | }; 216 | 217 | private GenericFilter bodyTextColour = new GenericFilter() { 218 | @Override 219 | public Integer filter(Palette.Swatch colour) { 220 | if (colour == null) { 221 | return Color.TRANSPARENT; 222 | } 223 | return colour.getBodyTextColor(); 224 | } 225 | }; 226 | 227 | Palette getPalette() { 228 | return palette; 229 | } 230 | 231 | void setPalette(Palette palette) { 232 | this.palette = palette; 233 | setColour(palette.getVibrantColor(0)); 234 | } 235 | 236 | } 237 | -------------------------------------------------------------------------------- /prism-palette/src/test/java/android/support/v7/graphics/DummyGenerator.java: -------------------------------------------------------------------------------- 1 | package android.support.v7.graphics; 2 | 3 | import java.util.List; 4 | 5 | public class DummyGenerator extends Palette.Generator { 6 | private static final int VIBRANT = 0; 7 | private static final int LIGHT_VIBRANT = 1; 8 | private static final int DARK_VIBRANT = 2; 9 | private static final int MUTED = 3; 10 | private static final int LIGHT_MUTED = 4; 11 | private static final int DARK_MUTED = 5; 12 | 13 | private List swatches; 14 | 15 | @Override 16 | public void generate(List swatches) { 17 | this.swatches = swatches; 18 | } 19 | 20 | @Override 21 | public Palette.Swatch getVibrantSwatch() { 22 | return getSwatch(VIBRANT); 23 | } 24 | 25 | @Override 26 | public Palette.Swatch getLightVibrantSwatch() { 27 | return getSwatch(LIGHT_VIBRANT); 28 | } 29 | 30 | @Override 31 | public Palette.Swatch getDarkVibrantSwatch() { 32 | return getSwatch(DARK_VIBRANT); 33 | } 34 | 35 | @Override 36 | public Palette.Swatch getMutedSwatch() { 37 | return getSwatch(MUTED); 38 | } 39 | 40 | @Override 41 | public Palette.Swatch getLightMutedSwatch() { 42 | return getSwatch(LIGHT_MUTED); 43 | } 44 | 45 | @Override 46 | public Palette.Swatch getDarkMutedSwatch() { 47 | return getSwatch(DARK_MUTED); 48 | } 49 | 50 | private Palette.Swatch getSwatch(int index) { 51 | if(index < swatches.size()) { 52 | return swatches.get(index); 53 | } 54 | return null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /prism-palette/src/test/java/android/support/v7/graphics/PaletteFactory.java: -------------------------------------------------------------------------------- 1 | package android.support.v7.graphics; 2 | 3 | import java.util.List; 4 | 5 | public final class PaletteFactory { 6 | private PaletteFactory() { 7 | //NO-OP 8 | } 9 | 10 | public static Palette createPalette(List swatches, Palette.Generator generator) { 11 | return new Palette.Builder(swatches).generator(generator).generate(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /prism-palette/src/test/java/com/stylingandroid/prism/palette/MockUtils.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.palette; 2 | 3 | import android.graphics.Color; 4 | 5 | import com.stylingandroid.prism.ColourUtils; 6 | 7 | import org.mockito.invocation.InvocationOnMock; 8 | import org.mockito.stubbing.Answer; 9 | 10 | import static org.mockito.Matchers.anyInt; 11 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 12 | import static org.powermock.api.mockito.PowerMockito.when; 13 | 14 | public final class MockUtils { 15 | public static void mockColor() { 16 | mockStatic(Color.class); 17 | when(Color.argb(anyInt(), anyInt(), anyInt(), anyInt())).thenAnswer( 18 | new Answer() { 19 | @Override 20 | public Integer answer(InvocationOnMock invocation) throws Throwable { 21 | Object[] args = invocation.getArguments(); 22 | return ColourUtils.argb((int) args[0], (int) args[1], (int) args[2], (int) args[3]); 23 | } 24 | }); 25 | when(Color.rgb(anyInt(), anyInt(), anyInt())).thenAnswer( 26 | new Answer() { 27 | @Override 28 | public Integer answer(InvocationOnMock invocation) throws Throwable { 29 | Object[] args = invocation.getArguments(); 30 | return ColourUtils.rgb((int) args[0], (int) args[1], (int) args[2]); 31 | } 32 | }); 33 | when(Color.alpha(anyInt())).thenAnswer( 34 | new Answer() { 35 | @Override 36 | public Integer answer(InvocationOnMock invocation) throws Throwable { 37 | Object[] args = invocation.getArguments(); 38 | return (int) args[0] >>> ColourUtils.TWENTY_FOUR_BITS; 39 | } 40 | }); 41 | when(Color.red(anyInt())).thenAnswer( 42 | new Answer() { 43 | @Override 44 | public Integer answer(InvocationOnMock invocation) throws Throwable { 45 | Object[] args = invocation.getArguments(); 46 | return ((int)args[0] >> ColourUtils.SIXTEEN_BITS) & 0xFF; 47 | } 48 | }); 49 | when(Color.green(anyInt())).thenAnswer( 50 | new Answer() { 51 | @Override 52 | public Integer answer(InvocationOnMock invocation) throws Throwable { 53 | Object[] args = invocation.getArguments(); 54 | return ((int) args[0] >> ColourUtils.EIGHT_BITS) & 0xFF; 55 | } 56 | }); 57 | when(Color.blue(anyInt())).thenAnswer( 58 | new Answer() { 59 | @Override 60 | public Integer answer(InvocationOnMock invocation) throws Throwable { 61 | Object[] args = invocation.getArguments(); 62 | return (int) args[0] & 0xFF; 63 | } 64 | }); 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /prism-palette/src/test/java/com/stylingandroid/prism/palette/PaletteTriggerTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.palette; 2 | 3 | import android.graphics.Color; 4 | import android.support.v7.graphics.DummyGenerator; 5 | import android.support.v7.graphics.Palette; 6 | import android.support.v7.graphics.PaletteFactory; 7 | 8 | import com.stylingandroid.prism.ColourUtils; 9 | import com.stylingandroid.prism.filter.Filter; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.junit.runner.RunWith; 17 | import org.mockito.MockitoAnnotations; 18 | import org.powermock.core.classloader.annotations.PrepareForTest; 19 | import org.powermock.modules.junit4.PowerMockRunner; 20 | 21 | import static org.fest.assertions.api.Assertions.assertThat; 22 | 23 | @RunWith(PowerMockRunner.class) 24 | @PrepareForTest(Color.class) 25 | public class PaletteTriggerTest { 26 | private static final int VIBRANT = ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_000, ColourUtils.HEX_000); 27 | private static final int LIGHT_VIBRANT = ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_255, ColourUtils.HEX_000); 28 | private static final int DARK_VIBRANT = ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_000, ColourUtils.HEX_255); 29 | private static final int MUTED = ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_255, ColourUtils.HEX_000); 30 | private static final int LIGHT_MUTED = ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_000, ColourUtils.HEX_255); 31 | private static final int DARK_MUTED = ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_255, ColourUtils.HEX_255); 32 | private PaletteTrigger paletteTrigger; 33 | 34 | @Before 35 | public void setUp() throws Exception { 36 | MockitoAnnotations.initMocks(this); 37 | MockUtils.mockColor(); 38 | List swatches = new ArrayList<>(); 39 | swatches.add(new Palette.Swatch(VIBRANT, 100)); 40 | swatches.add(new Palette.Swatch(LIGHT_VIBRANT, 100)); 41 | swatches.add(new Palette.Swatch(DARK_VIBRANT, 100)); 42 | swatches.add(new Palette.Swatch(MUTED, 100)); 43 | swatches.add(new Palette.Swatch(LIGHT_MUTED, 100)); 44 | swatches.add(new Palette.Swatch(DARK_MUTED, 100)); 45 | Palette palette = PaletteFactory.createPalette(swatches, new DummyGenerator()); 46 | paletteTrigger = new PaletteTrigger(); 47 | paletteTrigger.setPalette(palette); 48 | } 49 | 50 | @Test 51 | public void givenADummyPaletteVibrantColourIsCorrect() { 52 | Filter filter = paletteTrigger.getVibrantFilter(); 53 | int output = filter.filter(null); 54 | assertThat(output).isEqualTo(VIBRANT); 55 | } 56 | 57 | @Test 58 | public void givenADummyPaletteLightVibrantColourIsCorrect() { 59 | Filter filter = paletteTrigger.getLightVibrantFilter(); 60 | int output = filter.filter(null); 61 | assertThat(output).isEqualTo(LIGHT_VIBRANT); 62 | } 63 | 64 | @Test 65 | public void givenADummyPaletteDarkVibrantColourIsCorrect() { 66 | Filter filter = paletteTrigger.getDarkVibrantFilter(); 67 | int output = filter.filter(null); 68 | assertThat(output).isEqualTo(DARK_VIBRANT); 69 | } 70 | 71 | @Test 72 | public void givenADummyPaletteMutedColourIsCorrect() { 73 | Filter filter = paletteTrigger.getMutedFilter(); 74 | int output = filter.filter(null); 75 | assertThat(output).isEqualTo(MUTED); 76 | } 77 | 78 | @Test 79 | public void givenADummyPaletteLightMutedColourIsCorrect() { 80 | Filter filter = paletteTrigger.getLightMutedFilter(); 81 | int output = filter.filter(null); 82 | assertThat(output).isEqualTo(LIGHT_MUTED); 83 | } 84 | 85 | @Test 86 | public void givenADummyPaletteDarkMutedColourIsCorrect() { 87 | Filter filter = paletteTrigger.getDarkMutedFilter(); 88 | int output = filter.filter(null); 89 | assertThat(output).isEqualTo(DARK_MUTED); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /prism-viewpager/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /prism-viewpager/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | minSdkVersion 7 9 | targetSdkVersion 22 10 | } 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 15 | } 16 | debug { 17 | testCoverageEnabled = true 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.android.support:support-v4:22.2.0' 24 | compile project(':prism') 25 | 26 | testCompile 'junit:junit:4.12' 27 | testCompile 'org.mockito:mockito-core:1.10.19' 28 | testCompile 'org.easytesting:fest-assert-core:2.0M10' 29 | } 30 | 31 | ext { 32 | libraryName = 'prism-viewpager' 33 | libraryDescription = 'A trigger for Prism to change colours based on a ViewPager' 34 | libraryVersion = project.libraryVersion 35 | bintrayDryRun = isDryRun() 36 | } 37 | 38 | apply from: '../config/bintray.gradle' 39 | apply from: '../config/jacoco.gradle' 40 | apply from: '../config/static_analysis.gradle' 41 | -------------------------------------------------------------------------------- /prism-viewpager/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/markallison/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/setter/GlowSetterIcs.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.ColorFilter; 8 | import android.graphics.Paint; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuffColorFilter; 11 | import android.graphics.drawable.BitmapDrawable; 12 | import android.graphics.drawable.Drawable; 13 | import android.os.Build; 14 | import android.support.annotation.ColorInt; 15 | import android.support.annotation.DrawableRes; 16 | import android.widget.EdgeEffect; 17 | 18 | import com.stylingandroid.prism.filter.Filter; 19 | 20 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 21 | final class GlowSetterIcs extends ViewPagerGlowSetter { 22 | private static final String GLOW = "mGlow"; 23 | private static final String EDGE = "mEdge"; 24 | 25 | private final Resources resources; 26 | private final int glowDrawableId; 27 | private final int edgeDrawableId; 28 | private final Setter left; 29 | private final Setter right; 30 | 31 | GlowSetterIcs(Filter filter, Resources resources, int glowId, int edgeId, EdgeEffect leftEdgeEffect, EdgeEffect rightEdgeEffect) { 32 | super(filter); 33 | this.resources = resources; 34 | glowDrawableId = glowId; 35 | edgeDrawableId = edgeId; 36 | this.left = new Setter(leftEdgeEffect); 37 | this.right = new Setter(rightEdgeEffect); 38 | } 39 | 40 | @Override 41 | public void onSetColour(@ColorInt int colour) { 42 | left.setColour(colour); 43 | right.setColour(colour); 44 | } 45 | 46 | private void setDrawableColour(FieldAccessor drawableFieldAccessor, @DrawableRes int drawableId, @ColorInt int colour) { 47 | Drawable drawable = getDrawable(drawableId); 48 | if (drawable != null && drawable instanceof BitmapDrawable) { 49 | Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); 50 | Bitmap coloured = colourise(bitmap, colour); 51 | drawable = new BitmapDrawable(resources, coloured); 52 | drawableFieldAccessor.set(drawable); 53 | } 54 | 55 | } 56 | 57 | @SuppressWarnings("deprecation") 58 | private Drawable getDrawable(int id) { 59 | return resources.getDrawable(id); 60 | } 61 | 62 | private Bitmap colourise(Bitmap bitmap, @ColorInt int colour) { 63 | Bitmap coloured = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); 64 | ColorFilter cf = new PorterDuffColorFilter(colour, PorterDuff.Mode.SRC_IN); 65 | Canvas canvas = new Canvas(coloured); 66 | Paint paint = new Paint(); 67 | paint.setColorFilter(cf); 68 | canvas.drawBitmap(bitmap, 0, 0, paint); 69 | return coloured; 70 | } 71 | 72 | private final class Setter { 73 | private final FieldAccessor glowAccessor; 74 | private final FieldAccessor edgeAccessor; 75 | 76 | private Setter(EdgeEffect edgeEffect) { 77 | this.glowAccessor = getDrawableAccessor(edgeEffect, GLOW); 78 | this.edgeAccessor = getDrawableAccessor(edgeEffect, EDGE); 79 | } 80 | 81 | public void setColour(@ColorInt int colour) { 82 | setDrawableColour(glowAccessor, glowDrawableId, colour); 83 | setDrawableColour(edgeAccessor, edgeDrawableId, colour); 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/setter/GlowSetterLollipop.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.annotation.ColorInt; 6 | import android.widget.EdgeEffect; 7 | 8 | import com.stylingandroid.prism.filter.Filter; 9 | 10 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 11 | final class GlowSetterLollipop extends ViewPagerGlowSetter { 12 | private final EdgeEffect leftEdgeEffect; 13 | private final EdgeEffect rightEdgeEffect; 14 | 15 | public GlowSetterLollipop(Filter filter, EdgeEffect leftEdgeEffect, EdgeEffect rightEdgeEffect) { 16 | super(filter); 17 | this.leftEdgeEffect = leftEdgeEffect; 18 | this.rightEdgeEffect = rightEdgeEffect; 19 | } 20 | 21 | @Override 22 | public void onSetColour(@ColorInt int colour) { 23 | leftEdgeEffect.setColor(colour); 24 | rightEdgeEffect.setColor(colour); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/setter/ViewPagerGlowSetter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.res.Resources; 5 | import android.graphics.drawable.Drawable; 6 | import android.os.Build; 7 | import android.support.annotation.NonNull; 8 | import android.support.annotation.Nullable; 9 | import android.support.v4.view.ViewPager; 10 | import android.support.v4.widget.EdgeEffectCompat; 11 | import android.widget.EdgeEffect; 12 | 13 | import com.stylingandroid.prism.filter.Filter; 14 | import com.stylingandroid.prism.filter.IdentityFilter; 15 | 16 | public abstract class ViewPagerGlowSetter extends BaseSetter { 17 | private static final IdentityFilter IDENTITY_FILTER = new IdentityFilter(); 18 | private static final String LEFT_EDGE = "mLeftEdge"; 19 | private static final String RIGHT_EDGE = "mRightEdge"; 20 | private static final String EDGE_EFFECT = "mEdgeEffect"; 21 | private static final String OVERSCROLL_GLOW = "overscroll_glow"; 22 | private static final String OVERSCROLL_EDGE = "overscroll_edge"; 23 | private static final String DRAWABLE = "drawable"; 24 | private static final String ANDROID = "android"; 25 | 26 | ViewPagerGlowSetter(Filter filter) { 27 | super(filter, false); 28 | } 29 | 30 | public static ViewPagerGlowSetter newInstance(@NonNull ViewPager view) { 31 | return newInstance(view, IDENTITY_FILTER); 32 | } 33 | 34 | public static ViewPagerGlowSetter newInstance(@NonNull ViewPager view, @Nullable Filter filter) { 35 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 36 | return newInstanceLollipop(view, filter); 37 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 38 | return newInstanceIcs(view, filter); 39 | } else { 40 | return new ViewPagerGlowSetterLegacy(filter); 41 | } 42 | } 43 | 44 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 45 | private static ViewPagerGlowSetter newInstanceLollipop(ViewPager view, Filter filter) { 46 | EdgeEffect leftEdgeEffect = getEdgeEffect(view, LEFT_EDGE); 47 | EdgeEffect rightEdgeEffect = getEdgeEffect(view, RIGHT_EDGE); 48 | return new GlowSetterLollipop(filter, leftEdgeEffect, rightEdgeEffect); 49 | } 50 | 51 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 52 | private static EdgeEffect getEdgeEffect(ViewPager viewPager, String edgeFieldName) { 53 | FieldAccessor edgeField = new FieldAccessor<>(viewPager, edgeFieldName, EdgeEffectCompat.class); 54 | FieldAccessor edgeEffectAccessor = new FieldAccessor<>(edgeField.get(), EDGE_EFFECT, EdgeEffect.class); 55 | return edgeEffectAccessor.get(); 56 | } 57 | 58 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 59 | private static ViewPagerGlowSetter newInstanceIcs(ViewPager viewPager, Filter filter) { 60 | Resources resources = viewPager.getResources(); 61 | int glowId = getAndroidDrawableIdentifier(resources, OVERSCROLL_GLOW); 62 | int edgeId = getAndroidDrawableIdentifier(resources, OVERSCROLL_EDGE); 63 | EdgeEffect leftEdgeEffect = getEdgeEffect(viewPager, LEFT_EDGE); 64 | EdgeEffect rightEdgeEffect = getEdgeEffect(viewPager, RIGHT_EDGE); 65 | return new GlowSetterIcs(filter, resources, glowId, edgeId, leftEdgeEffect, rightEdgeEffect); 66 | } 67 | 68 | private static int getAndroidDrawableIdentifier(Resources resources, String overscrollGlow) { 69 | return resources.getIdentifier(overscrollGlow, DRAWABLE, ANDROID); 70 | } 71 | 72 | static FieldAccessor getDrawableAccessor(EdgeEffect edgeEffect, String fieldName) { 73 | return new FieldAccessor<>(edgeEffect, fieldName, Drawable.class); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/setter/ViewPagerGlowSetterLegacy.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | import com.stylingandroid.prism.filter.Filter; 6 | 7 | final class ViewPagerGlowSetterLegacy extends ViewPagerGlowSetter { 8 | 9 | ViewPagerGlowSetterLegacy(Filter filter) { 10 | super(filter); 11 | } 12 | 13 | @Override 14 | public void onSetColour(@ColorInt int colour) { 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/setter/ViewPagerSetterFactory.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | import com.stylingandroid.prism.Setter; 7 | import com.stylingandroid.prism.filter.Filter; 8 | 9 | public class ViewPagerSetterFactory implements SetterFactory { 10 | private static final ViewPagerSetterFactory INSTANCE = new ViewPagerSetterFactory(); 11 | 12 | public static void register() { 13 | ColourSetterFactory.registerFactory(INSTANCE); 14 | } 15 | 16 | public static void unregister() { 17 | ColourSetterFactory.unregisterFactory(INSTANCE); 18 | } 19 | 20 | @Override 21 | public Setter getColourSetter(View view, Filter filter) { 22 | if (view instanceof ViewPager) { 23 | return ViewPagerGlowSetter.newInstance((ViewPager) view, filter); 24 | } 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/viewpager/ColorProvider.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | public interface ColorProvider { 6 | @ColorInt int getColor(int position); 7 | int getCount(); 8 | } 9 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/viewpager/ColorProviderAdapter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | class ColorProviderAdapter implements ColourProvider { 6 | private final ColorProvider colorProvider; 7 | 8 | public ColorProviderAdapter(@NonNull ColorProvider colorProvider) { 9 | this.colorProvider = colorProvider; 10 | } 11 | 12 | @Override 13 | public int getColour(int position) { 14 | return colorProvider.getColor(position); 15 | } 16 | 17 | @Override 18 | public int getCount() { 19 | return colorProvider.getCount(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/viewpager/ColourAnimator.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager; 2 | 3 | import com.stylingandroid.prism.viewpager.compat.ArgbEvaluatorCompat; 4 | 5 | class ColourAnimator { 6 | private static final ArgbEvaluatorCompat ARGB_EVALUATOR = ArgbEvaluatorCompat.newInstance(); 7 | private final int startColour; 8 | private final int startPosition; 9 | private final int endColour; 10 | private final int endPosition; 11 | private final int range; 12 | 13 | public static ColourAnimator newInstance(int startPosition, int endPosition, ColourProvider colourProvider) { 14 | int startPos = Math.min(startPosition, endPosition); 15 | int endPos = Math.max(startPosition, endPosition); 16 | int startColour = colourProvider.getColour(startPos); 17 | int endColour = colourProvider.getColour(endPos); 18 | int range = endPos - startPos; 19 | return new ColourAnimator(startPos, startColour, endPos, endColour, range); 20 | } 21 | 22 | ColourAnimator(int startPosition, int startColour, int endPosition, int endColour, int range) { 23 | this.startPosition = Math.min(startPosition, endPosition); 24 | this.endPosition = Math.max(startPosition, endPosition); 25 | this.startColour = startColour; 26 | this.endColour = endColour; 27 | this.range = range; 28 | } 29 | 30 | @SuppressWarnings("PMD.UselessParentheses") 31 | public int getColourFor(int position, float positionOffset) { 32 | float offset; 33 | if (range > 1) { 34 | offset = ((float) (position - startPosition) / range) + (positionOffset / (float) range); 35 | } else if (position == endPosition && positionOffset == 0f) { 36 | offset = 1f; 37 | } else { 38 | offset = positionOffset; 39 | } 40 | 41 | return (int) ARGB_EVALUATOR.evaluate(offset, startColour, endColour); 42 | } 43 | 44 | @SuppressWarnings("PMD.UselessParentheses") 45 | public boolean isOutsideRange(int position, float offset) { 46 | return position < startPosition || (position == endPosition && offset > 0f) || position > endPosition; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/viewpager/ColourProvider.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | public interface ColourProvider { 6 | @ColorInt int getColour(int position); 7 | int getCount(); 8 | } 9 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/viewpager/ViewPagerTrigger.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager; 2 | 3 | import android.support.v4.view.ViewPager; 4 | 5 | import com.stylingandroid.prism.BaseTrigger; 6 | import com.stylingandroid.prism.Setter; 7 | import com.stylingandroid.prism.setter.ViewPagerSetterFactory; 8 | 9 | public class ViewPagerTrigger extends BaseTrigger implements ViewPager.OnPageChangeListener { 10 | private final ColourProvider colourProvider; 11 | private ColourAnimator colourAnimator; 12 | private int currentPosition; 13 | 14 | public static ViewPagerTrigger newInstance(ViewPager viewPager, ColorProvider colorProvider) { 15 | ColourProvider colourProvider = new ColorProviderAdapter(colorProvider); 16 | return newInstance(viewPager, colourProvider); 17 | } 18 | 19 | public static ViewPagerTrigger newInstance(ViewPager viewPager, ColourProvider colourProvider) { 20 | ViewPagerTrigger viewPagerTrigger = new ViewPagerTrigger(colourProvider); 21 | viewPager.addOnPageChangeListener(viewPagerTrigger); 22 | viewPagerTrigger.onPageSelected(0); 23 | ViewPagerSetterFactory.register(); 24 | return viewPagerTrigger; 25 | } 26 | 27 | ViewPagerTrigger(ColourProvider colourProvider) { 28 | this.colourProvider = colourProvider; 29 | } 30 | 31 | @Override 32 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 33 | boolean transientChange = true; 34 | if (colourAnimator != null && colourAnimator.isOutsideRange(position, positionOffset)) { 35 | colourAnimator = null; 36 | } 37 | if (colourAnimator == null) { 38 | int endPosition; 39 | if (isScrollingRight(position)) { 40 | currentPosition = position; 41 | endPosition = Math.min(colourProvider.getCount() - 1, position + 1); 42 | } else { 43 | currentPosition = Math.min(colourProvider.getCount() - 1, position + 1); 44 | endPosition = position; 45 | } 46 | colourAnimator = createColourAnimator(currentPosition, endPosition); 47 | } 48 | int newColour = colourAnimator.getColourFor(position, positionOffset); 49 | if (positionOffset == 0 && currentPosition != position) { 50 | colourAnimator = null; 51 | newColour = colourProvider.getColour(position); 52 | transientChange = false; 53 | } 54 | if (transientChange) { 55 | setTransientColour(newColour); 56 | } else { 57 | setColour(newColour); 58 | } 59 | } 60 | 61 | private boolean isScrollingRight(int position) { 62 | return position == currentPosition; 63 | } 64 | 65 | @Override 66 | public void onPageScrollStateChanged(int state) { 67 | if (state == ViewPager.SCROLL_STATE_IDLE && colourAnimator != null) { 68 | int newColour = colourProvider.getColour(currentPosition); 69 | setColour(newColour); 70 | colourAnimator = null; 71 | } 72 | } 73 | 74 | @Override 75 | public void onPageSelected(int position) { 76 | colourAnimator = createColourAnimator(currentPosition, position); 77 | currentPosition = position; 78 | } 79 | 80 | private ColourAnimator createColourAnimator(int startPosition, int endPosition) { 81 | return ColourAnimator.newInstance(startPosition, endPosition, colourProvider); 82 | } 83 | 84 | @Override 85 | public void addSetter(Setter setter) { 86 | boolean shouldInitialise = hasNoColourSetters(); 87 | super.addSetter(setter); 88 | if (shouldInitialise) { 89 | ViewPagerSetterFactory.register(); 90 | int newColour = colourProvider.getColour(currentPosition); 91 | setColour(newColour); 92 | } 93 | } 94 | 95 | @Override 96 | public void removeSetter(Setter setter) { 97 | super.removeSetter(setter); 98 | if (hasNoColourSetters()) { 99 | ViewPagerSetterFactory.unregister(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /prism-viewpager/src/main/java/com/stylingandroid/prism/viewpager/compat/ArgbEvaluatorCompat.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager.compat; 2 | 3 | import android.animation.ArgbEvaluator; 4 | import android.annotation.TargetApi; 5 | import android.os.Build; 6 | 7 | public abstract class ArgbEvaluatorCompat { 8 | public static ArgbEvaluatorCompat newInstance() { 9 | return newInstance(Build.VERSION.SDK_INT); 10 | } 11 | 12 | static ArgbEvaluatorCompat newInstance(int buildVersion) { 13 | if (buildVersion >= Build.VERSION_CODES.HONEYCOMB) { 14 | return new ArgbEvaluatorHoneycomb(); 15 | } 16 | return new ArgbEvaluatorLegacy(); 17 | } 18 | 19 | public abstract Object evaluate(float fraction, Object startValue, Object endValue); 20 | 21 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 22 | static class ArgbEvaluatorHoneycomb extends ArgbEvaluatorCompat { 23 | private final ArgbEvaluator argbEvaluator; 24 | 25 | ArgbEvaluatorHoneycomb() { 26 | this(new ArgbEvaluator()); 27 | } 28 | 29 | ArgbEvaluatorHoneycomb(ArgbEvaluator argbEvaluator) { 30 | this.argbEvaluator = argbEvaluator; 31 | } 32 | 33 | @Override 34 | public Object evaluate(float fraction, Object startValue, Object endValue) { 35 | return argbEvaluator.evaluate(fraction, startValue, endValue); 36 | } 37 | } 38 | 39 | static class ArgbEvaluatorLegacy extends ArgbEvaluatorCompat { 40 | private static final int EIGHT_BITS = 8; 41 | private static final int SIXTEEN_BITS = 16; 42 | private static final int TWENTY_FOUR_BITS = 24; 43 | private static final int ALL_BITS = 0xff; 44 | 45 | @Override 46 | @SuppressWarnings("PMD.UselessParentheses") 47 | public Object evaluate(float fraction, Object startValue, Object endValue) { 48 | int startInt = (Integer) startValue; 49 | int startA = (startInt >> TWENTY_FOUR_BITS) & ALL_BITS; 50 | int startR = (startInt >> SIXTEEN_BITS) & ALL_BITS; 51 | int startG = (startInt >> EIGHT_BITS) & ALL_BITS; 52 | int startB = startInt & ALL_BITS; 53 | int endInt = (Integer) endValue; 54 | int endA = (endInt >> TWENTY_FOUR_BITS) & ALL_BITS; 55 | int endR = (endInt >> SIXTEEN_BITS) & ALL_BITS; 56 | int endG = (endInt >> EIGHT_BITS) & ALL_BITS; 57 | int endB = endInt & ALL_BITS; 58 | return ((startA + (int) (fraction * (endA - startA))) << TWENTY_FOUR_BITS) 59 | | ((startR + (int) (fraction * (endR - startR))) << SIXTEEN_BITS) 60 | | ((startG + (int) (fraction * (endG - startG))) << EIGHT_BITS) 61 | | ((startB + (int) (fraction * (endB - startB)))); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /prism-viewpager/src/test/java/com/stylingandroid/prism/viewpager/ColorProviderAdapterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.mockito.Mock; 6 | import org.mockito.MockitoAnnotations; 7 | 8 | import static org.mockito.Matchers.anyInt; 9 | import static org.mockito.Mockito.atLeastOnce; 10 | import static org.mockito.Mockito.verify; 11 | 12 | public class ColorProviderAdapterTest { 13 | @Mock 14 | private ColorProvider colorProvider; 15 | 16 | private ColourProvider colourProvider; 17 | 18 | @Before 19 | public void setUp() throws Exception { 20 | MockitoAnnotations.initMocks(this); 21 | colourProvider = new ColorProviderAdapter(colorProvider); 22 | } 23 | 24 | @Test 25 | public void givenAColorProviderWrappedInAColourProviderCompatThenGetColorMethodIsCalled() { 26 | colourProvider.getColour(0); 27 | verify(colorProvider, atLeastOnce()).getColor(anyInt()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /prism-viewpager/src/test/java/com/stylingandroid/prism/viewpager/compat/ArgbEvaluatorCompatTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager.compat; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.fest.assertions.api.Assertions.assertThat; 6 | 7 | public class ArgbEvaluatorCompatTest { 8 | 9 | @Test 10 | public void givenAPreHoneycombAndroidVersionThenALegacyArgbEvaluatorIsReturned() { 11 | ArgbEvaluatorCompat argbEvaluator = ArgbEvaluatorCompat.newInstance(10); 12 | assertThat(argbEvaluator).isInstanceOf(ArgbEvaluatorCompat.ArgbEvaluatorLegacy.class); 13 | } 14 | 15 | @Test 16 | public void givenNoAndroidVersionThenALegacyArgbEvaluatorIsReturned() { 17 | ArgbEvaluatorCompat argbEvaluator = ArgbEvaluatorCompat.newInstance(); 18 | assertThat(argbEvaluator).isInstanceOf(ArgbEvaluatorCompat.ArgbEvaluatorLegacy.class); 19 | } 20 | 21 | @Test 22 | public void givenAPostHoneycombAndroidVersionThenAHoneycombArgbEvaluatorIsReturned() { 23 | ArgbEvaluatorCompat argbEvaluator = ArgbEvaluatorCompat.newInstance(22); 24 | assertThat(argbEvaluator).isInstanceOf(ArgbEvaluatorCompat.ArgbEvaluatorHoneycomb.class); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /prism-viewpager/src/test/java/com/stylingandroid/prism/viewpager/compat/ArgbEvaluatorHoneycombTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager.compat; 2 | 3 | import android.animation.ArgbEvaluator; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.mockito.Mock; 8 | import org.mockito.MockitoAnnotations; 9 | 10 | import static org.mockito.Matchers.any; 11 | import static org.mockito.Matchers.anyFloat; 12 | import static org.mockito.Mockito.atLeastOnce; 13 | import static org.mockito.Mockito.verify; 14 | 15 | public class ArgbEvaluatorHoneycombTest { 16 | @Mock 17 | private ArgbEvaluator inbuiltArgbEvaluator; 18 | 19 | private ArgbEvaluatorCompat argbEvaluator; 20 | 21 | @Before 22 | public void setUp() throws Exception { 23 | MockitoAnnotations.initMocks(this); 24 | argbEvaluator = new ArgbEvaluatorCompat.ArgbEvaluatorHoneycomb(inbuiltArgbEvaluator); 25 | } 26 | 27 | @Test 28 | public void givenAArgbEvaluatorHoneycombThenTheInbuiltArgbEvaluatorIsUsed() { 29 | argbEvaluator.evaluate(1f, 0x000000, 0x0000FF); 30 | verify(inbuiltArgbEvaluator, atLeastOnce()).evaluate(anyFloat(), any(), any()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /prism-viewpager/src/test/java/com/stylingandroid/prism/viewpager/compat/ArgbEvaluatorLegacyTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.viewpager.compat; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collection; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.junit.runners.Parameterized; 12 | 13 | import static org.fest.assertions.api.Assertions.assertThat; 14 | 15 | @RunWith(Parameterized.class) 16 | public class ArgbEvaluatorLegacyTest { 17 | private final float fraction; 18 | @ColorInt 19 | private final int expected; 20 | 21 | private ArgbEvaluatorCompat argbEvaluator; 22 | 23 | @ColorInt 24 | private int startColour; 25 | 26 | @ColorInt 27 | private int endColour; 28 | 29 | @Before 30 | public void setUp() throws Exception { 31 | argbEvaluator = new ArgbEvaluatorCompat.ArgbEvaluatorLegacy(); 32 | startColour = 0x000000; 33 | endColour = 0x0000FF; 34 | } 35 | 36 | public ArgbEvaluatorLegacyTest(float fraction, @ColorInt int expected) { 37 | this.fraction = fraction; 38 | this.expected = expected; 39 | } 40 | 41 | @Test 42 | public void givenTheLegacyArgbEvaluatorAndASpecificFractionThenTheCorrectColourIsCalculated() { 43 | int calculated = (int)argbEvaluator.evaluate(fraction, startColour, endColour); 44 | assertThat(calculated).isEqualTo(expected); 45 | } 46 | 47 | @Parameterized.Parameters 48 | public static Collection values() { 49 | return Arrays.asList(new Object[][] { 50 | {0f, 0}, 51 | {0.1f, 25}, 52 | {0.2f, 51}, 53 | {0.3f, 76}, 54 | {0.4f, 102}, 55 | {0.5f, 127}, 56 | {0.6f, 153}, 57 | {0.7f, 178}, 58 | {0.8f, 204}, 59 | {0.9f, 229}, 60 | {1f, 255}, 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /prism/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /prism/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | minSdkVersion 7 9 | targetSdkVersion 22 10 | testHandleProfiling true 11 | testFunctionalTest true 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | debug { 19 | testCoverageEnabled = true 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile 'com.android.support:support-annotations:22.2.0' 26 | 27 | testCompile 'junit:junit:4.12' 28 | testCompile 'org.mockito:mockito-core:1.10.19' 29 | testCompile 'org.easytesting:fest-assert-core:2.0M10' 30 | testCompile 'org.powermock:powermock-module-junit4:1.6.2' 31 | testCompile 'org.powermock:powermock-api-mockito:1.6.2' 32 | testCompile project(':test-lib') 33 | } 34 | 35 | ext { 36 | libraryName = 'prism' 37 | libraryDescription = 'A dynamic UI colouring library' 38 | libraryVersion = project.libraryVersion 39 | bintrayDryRun = isDryRun() 40 | } 41 | 42 | apply from: '../config/bintray.gradle' 43 | apply from: '../config/jacoco.gradle' 44 | apply from: '../config/static_analysis.gradle' 45 | -------------------------------------------------------------------------------- /prism/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/markallison/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /prism/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/BaseTrigger.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class BaseTrigger implements Trigger { 9 | private final List setters = new ArrayList<>(); 10 | 11 | @Override 12 | public void addSetter(Setter setter) { 13 | setters.add(setter); 14 | } 15 | 16 | @Override 17 | public void removeSetter(Setter setter) { 18 | setters.remove(setter); 19 | } 20 | 21 | public boolean hasNoColourSetters() { 22 | return setters.isEmpty(); 23 | } 24 | 25 | protected void setColour(@ColorInt int colour) { 26 | for (Setter setter : setters) { 27 | setter.setColour(colour); 28 | } 29 | } 30 | 31 | protected void setTransientColour(@ColorInt int colour) { 32 | for (Setter setter : setters) { 33 | setter.setTransientColour(colour); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/ColorSetter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | public interface ColorSetter { 6 | void setColor(@ColorInt int color); 7 | 8 | void setTransientColor(@ColorInt int color); 9 | } 10 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/Prism.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import android.support.annotation.ColorInt; 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | import android.view.Window; 7 | import android.widget.TextView; 8 | 9 | import com.stylingandroid.prism.filter.Filter; 10 | import com.stylingandroid.prism.filter.SystemChromeFilter; 11 | import com.stylingandroid.prism.setter.ColourSetterFactory; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | public class Prism implements Setter, ColorSetter { 17 | private final List setters; 18 | private final List triggers; 19 | 20 | Prism(List triggers, List setters) { 21 | this.triggers = triggers; 22 | this.setters = setters; 23 | } 24 | 25 | @Override 26 | public void setColour(@ColorInt int colour) { 27 | for (Setter setter : setters) { 28 | setter.setColour(colour); 29 | } 30 | } 31 | 32 | @Override 33 | public void setTransientColour(@ColorInt int colour) { 34 | for (Setter setter : setters) { 35 | setter.setTransientColour(colour); 36 | } 37 | } 38 | 39 | @Override 40 | public void setColor(@ColorInt int color) { 41 | setColour(color); 42 | } 43 | 44 | @Override 45 | public void setTransientColor(@ColorInt int color) { 46 | setTransientColour(color); 47 | } 48 | 49 | public void add(Trigger trigger) { 50 | triggers.add(trigger); 51 | trigger.addSetter(this); 52 | } 53 | 54 | public void remove(Trigger trigger) { 55 | trigger.removeSetter(this); 56 | triggers.remove(trigger); 57 | } 58 | 59 | public void destroy() { 60 | for (Trigger trigger : triggers) { 61 | remove(trigger); 62 | } 63 | setters.clear(); 64 | } 65 | 66 | public static final class Builder { 67 | private static final Filter STATUS_BAR_COLOUR_FILTER = new SystemChromeFilter(); 68 | private final List setters; 69 | private final List triggers; 70 | 71 | public static Builder newInstance() { 72 | List setters = new ArrayList<>(); 73 | List triggers = new ArrayList<>(); 74 | return new Builder(triggers, setters); 75 | } 76 | 77 | private Builder(@NonNull List triggers, @NonNull List setters) { 78 | this.triggers = triggers; 79 | this.setters = setters; 80 | } 81 | 82 | public Builder background(@NonNull View view) { 83 | return background(view, ColourSetterFactory.IDENTITY_COLOUR_FILTER); 84 | } 85 | 86 | public Builder background(@NonNull View view, @NonNull Filter filter) { 87 | return add(ColourSetterFactory.getBackgroundSetter(view, filter)); 88 | } 89 | 90 | public Builder background(@NonNull Window window) { 91 | return background(window, STATUS_BAR_COLOUR_FILTER); 92 | } 93 | 94 | public Builder background(@NonNull Window window, @NonNull Filter filter) { 95 | return add(ColourSetterFactory.getBackgroundSetter(window, filter)); 96 | } 97 | 98 | public Builder add(@NonNull Setter setter) { 99 | if (setter != null) { 100 | setters.add(setter); 101 | } 102 | return this; 103 | } 104 | 105 | public Builder add(@NonNull ColorSetter setter) { 106 | if (setter != null) { 107 | setters.add(new SetterAdapter(setter)); 108 | } 109 | return this; 110 | } 111 | 112 | public Builder add(@NonNull Trigger trigger) { 113 | if (trigger != null) { 114 | triggers.add(trigger); 115 | } 116 | return this; 117 | } 118 | 119 | public Builder text(@NonNull TextView view) { 120 | return text(view, ColourSetterFactory.IDENTITY_COLOUR_FILTER); 121 | } 122 | 123 | public Builder text(@NonNull TextView view, @NonNull Filter filter) { 124 | return add(ColourSetterFactory.getTextSetter(view, filter)); 125 | } 126 | 127 | public Builder colour(@NonNull View view) { 128 | return colour(view, ColourSetterFactory.IDENTITY_COLOUR_FILTER); 129 | } 130 | 131 | public Builder colour(@NonNull View view, @NonNull Filter filter) { 132 | return add(ColourSetterFactory.getColourSetter(view, filter)); 133 | } 134 | 135 | public Builder color(@NonNull View view) { 136 | return colour(view, ColourSetterFactory.IDENTITY_COLOUR_FILTER); 137 | } 138 | 139 | public Builder color(@NonNull View view, @NonNull Filter filter) { 140 | return colour(view, filter); 141 | } 142 | 143 | public Prism build() { 144 | Prism prism = new Prism(triggers, setters); 145 | for (Trigger trigger : triggers) { 146 | trigger.addSetter(prism); 147 | } 148 | return prism; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/Setter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | public interface Setter { 6 | void setColour(@ColorInt int colour); 7 | 8 | void setTransientColour(@ColorInt int colour); 9 | } 10 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/SetterAdapter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | public class SetterAdapter implements Setter { 6 | private final ColorSetter colorSetter; 7 | 8 | public SetterAdapter(ColorSetter colorSetter) { 9 | this.colorSetter = colorSetter; 10 | } 11 | 12 | @Override 13 | public void setColour(@ColorInt int colour) { 14 | colorSetter.setColor(colour); 15 | } 16 | 17 | @Override 18 | public void setTransientColour(@ColorInt int colour) { 19 | colorSetter.setTransientColor(colour); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/Trigger.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | public interface Trigger { 4 | void addSetter(Setter setter); 5 | 6 | void removeSetter(Setter setter); 7 | } 8 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/CompoundFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | public class CompoundFilter implements Filter { 4 | private final GenericFilter firstFilter; 5 | private final GenericFilter secondFilter; 6 | 7 | public CompoundFilter(GenericFilter firstFilter, GenericFilter secondFilter) { 8 | this.firstFilter = firstFilter; 9 | this.secondFilter = secondFilter; 10 | } 11 | 12 | @Override 13 | public Integer filter(Integer colour) { 14 | INTERMEDIATE intermediate = firstFilter.filter(colour); 15 | return secondFilter.filter(intermediate); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/Filter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | public interface Filter extends GenericFilter { 4 | } 5 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/GenericFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | public interface GenericFilter { 4 | OUTPUT filter(INPUT colour); 5 | } 6 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/IdentityFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | public class IdentityFilter extends RepeatableFilter { 4 | @Override 5 | public Integer onFilter(Integer colour) { 6 | return colour; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/RepeatableFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | public abstract class RepeatableFilter implements Filter { 4 | private int lastInput = 0; 5 | private int lastOutput; 6 | 7 | public RepeatableFilter() { 8 | lastOutput = onFilter(lastInput); 9 | } 10 | 11 | public final Integer filter(Integer colour) { 12 | if (lastInput != colour) { 13 | lastInput = colour; 14 | lastOutput = onFilter(colour); 15 | } 16 | return lastOutput; 17 | } 18 | 19 | public abstract Integer onFilter(Integer colour); 20 | } 21 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/ShadeFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import android.graphics.Color; 4 | 5 | public class ShadeFilter extends RepeatableFilter { 6 | private static final float DEFAULT_SHADE_FACTOR = 0.2f; 7 | private final float shadeFactor; 8 | 9 | public ShadeFilter() { 10 | this(DEFAULT_SHADE_FACTOR); 11 | } 12 | 13 | public ShadeFilter(float shadeFactor) { 14 | super(); 15 | this.shadeFactor = 1f - shadeFactor; 16 | } 17 | 18 | @Override 19 | public Integer onFilter(Integer colour) { 20 | return Color.argb( 21 | Color.alpha(colour), 22 | (int) ((float) Color.red(colour) * shadeFactor), 23 | (int) ((float) Color.green(colour) * shadeFactor), 24 | (int) ((float) Color.blue(colour) * shadeFactor)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/SystemChromeFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | public class SystemChromeFilter extends ShadeFilter { 4 | } 5 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/filter/TintFilter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import android.graphics.Color; 4 | 5 | public class TintFilter extends RepeatableFilter { 6 | private static final float DEFAULT_TINT_FACTOR = 0.2f; 7 | private static final int HEX_FF = 0xFF; 8 | private final float tintFactor; 9 | 10 | public TintFilter() { 11 | this(DEFAULT_TINT_FACTOR); 12 | } 13 | 14 | public TintFilter(float tintFactor) { 15 | super(); 16 | this.tintFactor = tintFactor; 17 | } 18 | 19 | @Override 20 | public Integer onFilter(Integer colour) { 21 | int red = Color.red(colour); 22 | int green = Color.green(colour); 23 | int blue = Color.blue(colour); 24 | return Color.argb( 25 | Color.alpha(colour), 26 | red + (int) ((float) (HEX_FF - red) * tintFactor), 27 | green + (int) ((float) (HEX_FF - green) * tintFactor), 28 | blue + (int) ((float) (HEX_FF - blue) * tintFactor)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/BaseSetter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | import com.stylingandroid.prism.Setter; 6 | import com.stylingandroid.prism.filter.Filter; 7 | 8 | public abstract class BaseSetter implements Setter { 9 | private final Filter filter; 10 | private final boolean transientChanges; 11 | private int lastColour = 0; 12 | 13 | protected BaseSetter(Filter filter) { 14 | this(filter, true); 15 | } 16 | 17 | protected BaseSetter(Filter filter, boolean transientChanges) { 18 | this.filter = filter; 19 | this.transientChanges = transientChanges; 20 | } 21 | 22 | @Override 23 | public final void setColour(@ColorInt int colour) { 24 | if (colour != lastColour) { 25 | lastColour = colour; 26 | onSetColour(filter.filter(colour)); 27 | } 28 | } 29 | 30 | @Override 31 | public final void setTransientColour(@ColorInt int colour) { 32 | if (transientChanges) { 33 | setColour(colour); 34 | } 35 | } 36 | 37 | public abstract void onSetColour(@ColorInt int colour); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/ColourSetterFactory.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.view.View; 4 | import android.view.Window; 5 | import android.widget.TextView; 6 | 7 | import com.stylingandroid.prism.Setter; 8 | import com.stylingandroid.prism.filter.Filter; 9 | import com.stylingandroid.prism.filter.IdentityFilter; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public final class ColourSetterFactory { 15 | public static final Filter IDENTITY_COLOUR_FILTER = new IdentityFilter(); 16 | private static final List FACTORIES = new ArrayList<>(); 17 | 18 | private ColourSetterFactory() { 19 | //NO-OP 20 | } 21 | 22 | static void registerFactory(SetterFactory factory) { 23 | FACTORIES.add(factory); 24 | } 25 | 26 | static void unregisterFactory(SetterFactory factory) { 27 | FACTORIES.remove(factory); 28 | } 29 | 30 | public static Setter getBackgroundSetter(View view, Filter filter) { 31 | if (FabSetter.isFab(view)) { 32 | return new FabSetter(view, getNullSafeFilter(filter)); 33 | } 34 | return new ViewBackgroundSetter(view, getNullSafeFilter(filter)); 35 | } 36 | 37 | public static Setter getBackgroundSetter(Window window, Filter filter) { 38 | return new SystemChromeSetter(window, getNullSafeFilter(filter)); 39 | } 40 | 41 | public static Setter getTextSetter(TextView view, Filter filter) { 42 | return new TextSetter(view, getNullSafeFilter(filter)); 43 | } 44 | 45 | public static Setter getColourSetter(View view, Filter filter) { 46 | Setter setter = null; 47 | for (SetterFactory factory : FACTORIES) { 48 | setter = factory.getColourSetter(view, getNullSafeFilter(filter)); 49 | } 50 | if (setter == null) { 51 | if (FabSetter.isFab(view)) { 52 | setter = new FabSetter(view, getNullSafeFilter(filter)); 53 | } else { 54 | setter = new ViewBackgroundSetter(view, getNullSafeFilter(filter)); 55 | } 56 | } 57 | return setter; 58 | } 59 | 60 | public static Setter getColorSetter(View view, Filter filter) { 61 | return getColourSetter(view, filter); 62 | } 63 | 64 | private static Filter getNullSafeFilter(Filter filter) { 65 | if (filter != null) { 66 | return filter; 67 | } 68 | return IDENTITY_COLOUR_FILTER; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/FabSetter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.content.res.ColorStateList; 4 | import android.support.annotation.ColorInt; 5 | import android.view.View; 6 | 7 | import com.stylingandroid.prism.filter.Filter; 8 | 9 | class FabSetter extends BaseSetter { 10 | private static final String CLASS_NAME = "android.support.design.widget.FloatingActionButton"; 11 | private static final String METHOD_NAME = "setBackgroundTintList"; 12 | private static final int ALPHA_OPAQUE = 0xFF; 13 | private final MethodInvoker methodInvoker; 14 | 15 | public static boolean isFab(View view) { 16 | if (view == null) { 17 | return false; 18 | } 19 | ReflectiveCache reflectiveCache = ReflectiveCache.getInstance(); 20 | return view.getClass().getCanonicalName().startsWith(CLASS_NAME) 21 | && reflectiveCache.hasMethod(view.getClass(), METHOD_NAME, ColorStateList.class); 22 | } 23 | 24 | public FabSetter(View view, Filter filter) { 25 | super(filter); 26 | methodInvoker = new MethodInvoker<>(view, METHOD_NAME, ColorStateList.class); 27 | } 28 | 29 | @Override 30 | public void onSetColour(@ColorInt int colour) { 31 | ColorStateList colorStateList = ColorStateList.valueOf(colour).withAlpha(ALPHA_OPAQUE); 32 | methodInvoker.invoke(colorStateList); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/FieldAccessor.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.util.Log; 4 | 5 | import java.lang.ref.WeakReference; 6 | import java.lang.reflect.Field; 7 | 8 | public class FieldAccessor { 9 | private static final String TAG = FieldAccessor.class.getSimpleName(); 10 | private final WeakReference viewWeakReference; 11 | private final Field field; 12 | private final Class clazz; 13 | 14 | public FieldAccessor(Object object, String name, Class clazz) { 15 | this.viewWeakReference = new WeakReference<>(object); 16 | ReflectiveCache reflectiveCache = ReflectiveCache.getInstance(); 17 | field = reflectiveCache.getField(object.getClass(), name, clazz); 18 | this.clazz = clazz; 19 | } 20 | 21 | public void set(TYPE value) { 22 | Object object = viewWeakReference.get(); 23 | if (object != null) { 24 | field.setAccessible(true); 25 | try { 26 | field.set(object, value); 27 | } catch (IllegalAccessException e) { 28 | Log.w(TAG, "Illegal access", e); 29 | } 30 | } 31 | } 32 | 33 | public TYPE get() { 34 | TYPE ret = null; 35 | Object object = viewWeakReference.get(); 36 | if (object != null) { 37 | field.setAccessible(true); 38 | try { 39 | Object returnedObject = field.get(object); 40 | if (clazz.isInstance(returnedObject)) { 41 | ret = clazz.cast(returnedObject); 42 | } 43 | } catch (IllegalAccessException e) { 44 | Log.w(TAG, "Illegal access", e); 45 | } 46 | } 47 | return ret; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/MethodInvoker.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.util.Log; 4 | 5 | import java.lang.ref.WeakReference; 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | class MethodInvoker { 10 | private static final String TAG = MethodInvoker.class.getSimpleName(); 11 | private final WeakReference viewWeakReference; 12 | private final Method method; 13 | 14 | public MethodInvoker(Object object, String name, Class clazz) { 15 | this.viewWeakReference = new WeakReference<>(object); 16 | Class[] params = new Class[]{clazz}; 17 | ReflectiveCache reflectiveCache = ReflectiveCache.getInstance(); 18 | method = reflectiveCache.getMethod(object.getClass(), name, params); 19 | } 20 | 21 | public void invoke(TYPE value) { 22 | Object object = viewWeakReference.get(); 23 | if (object != null) { 24 | try { 25 | method.invoke(object, value); 26 | } catch (IllegalAccessException e) { 27 | Log.w(TAG, "Illegal access", e); 28 | } catch (InvocationTargetException e) { 29 | Log.w(TAG, "Invocation target", e); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/ReflectiveCache.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.annotation.NonNull; 4 | 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.Method; 7 | import java.util.Arrays; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | final class ReflectiveCache { 12 | private static ReflectiveCache instance; 13 | private final Map methodCache; 14 | private final Map fieldCache; 15 | 16 | public static ReflectiveCache getInstance() { 17 | if (instance == null) { 18 | Map methodMap = new HashMap<>(); 19 | Map fieldMap = new HashMap<>(); 20 | instance = new ReflectiveCache(methodMap, fieldMap); 21 | } 22 | return instance; 23 | } 24 | 25 | ReflectiveCache(Map methodCache, Map fieldCache) { 26 | this.methodCache = methodCache; 27 | this.fieldCache = fieldCache; 28 | } 29 | 30 | public boolean hasMethod(Class clazz, String name, Class... params) { 31 | return getMethod(clazz, name, params) != null; 32 | } 33 | 34 | public Method getMethod(Class clazz, String name, Class... params) { 35 | Signature signature = new Signature(clazz, name, params); 36 | Method method = methodCache.get(signature); 37 | if (method == null) { 38 | try { 39 | method = clazz.getMethod(name, params); 40 | } catch (NoSuchMethodException e) { 41 | method = null; 42 | } 43 | methodCache.put(signature, method); 44 | } 45 | return method; 46 | } 47 | 48 | public boolean hasField(Class clazz, String name, Class param) { 49 | return getField(clazz, name, param) != null; 50 | } 51 | 52 | public Field getField(Class clazz, String name, Class param) { 53 | Signature signature = new Signature(clazz, name, param); 54 | Field field = fieldCache.get(signature); 55 | if (field == null) { 56 | try { 57 | field = clazz.getDeclaredField(name); 58 | } catch (NoSuchFieldException e) { 59 | field = null; 60 | } 61 | fieldCache.put(signature, field); 62 | } 63 | return field; 64 | } 65 | 66 | private static final class Signature { 67 | private static final int HASH_MULTIPLIER = 31; 68 | private final Class clazz; 69 | private final String name; 70 | private final Class[] params; 71 | 72 | private Signature(@NonNull Class clazz, @NonNull String name, @NonNull Class... params) { 73 | this.clazz = clazz; 74 | this.name = name; 75 | this.params = params; 76 | } 77 | 78 | @Override 79 | public boolean equals(Object o) { 80 | if (this == o) { 81 | return true; 82 | } 83 | if (o == null || getClass() != o.getClass()) { 84 | return false; 85 | } 86 | 87 | Signature signature = (Signature) o; 88 | 89 | if (!clazz.equals(signature.clazz)) { 90 | return false; 91 | } 92 | if (!name.equals(signature.name)) { 93 | return false; 94 | } 95 | // Probably incorrect - comparing Object[] arrays with Arrays.equals 96 | return Arrays.equals(params, signature.params); 97 | 98 | } 99 | 100 | @Override 101 | public int hashCode() { 102 | int result = clazz.hashCode(); 103 | result = HASH_MULTIPLIER * result + name.hashCode(); 104 | result = HASH_MULTIPLIER * result + Arrays.hashCode(params); 105 | return result; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/SetterFactory.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.view.View; 4 | 5 | import com.stylingandroid.prism.Setter; 6 | import com.stylingandroid.prism.filter.Filter; 7 | 8 | public interface SetterFactory { 9 | Setter getColourSetter(View view, Filter filter); 10 | } 11 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/SystemChromeSetter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.support.annotation.ColorInt; 6 | import android.view.Window; 7 | 8 | import com.stylingandroid.prism.filter.Filter; 9 | 10 | class SystemChromeSetter extends BaseSetter { 11 | private final Window window; 12 | private final int osVersion; 13 | 14 | public SystemChromeSetter(Window window, Filter filter) { 15 | this(window, filter, Build.VERSION.SDK_INT); 16 | } 17 | 18 | SystemChromeSetter(Window window, Filter filter, int osVersion) { 19 | super(filter); 20 | this.window = window; 21 | this.osVersion = osVersion; 22 | } 23 | 24 | @Override 25 | public void onSetColour(@ColorInt int colour) { 26 | if (osVersion >= Build.VERSION_CODES.LOLLIPOP) { 27 | setStatusBarColour(colour); 28 | setNavigationBarColour(colour); 29 | } 30 | } 31 | 32 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 33 | public void setStatusBarColour(@ColorInt int colour) { 34 | window.setStatusBarColor(colour); 35 | } 36 | 37 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 38 | public void setNavigationBarColour(@ColorInt int colour) { 39 | window.setNavigationBarColor(colour); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/TextSetter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.annotation.ColorInt; 4 | import android.widget.TextView; 5 | 6 | import com.stylingandroid.prism.filter.Filter; 7 | 8 | public class TextSetter extends BaseSetter { 9 | private final TextView view; 10 | 11 | public TextSetter(TextView view, Filter filter) { 12 | super(filter); 13 | this.view = view; 14 | } 15 | 16 | @Override 17 | public void onSetColour(@ColorInt int colour) { 18 | view.setTextColor(colour); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /prism/src/main/java/com/stylingandroid/prism/setter/ViewBackgroundSetter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.annotation.ColorInt; 4 | import android.view.View; 5 | 6 | import com.stylingandroid.prism.filter.Filter; 7 | 8 | class ViewBackgroundSetter extends BaseSetter { 9 | private final View view; 10 | 11 | public ViewBackgroundSetter(View view, Filter filter) { 12 | super(filter); 13 | this.view = view; 14 | } 15 | 16 | @Override 17 | public void onSetColour(@ColorInt int colour) { 18 | view.setBackgroundColor(colour); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /prism/src/test/java/android/support/design/widget/FloatingActionButton.java: -------------------------------------------------------------------------------- 1 | package android.support.design.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.ColorStateList; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | 8 | public class FloatingActionButton extends View { 9 | public static final int DEFAULT = 345; 10 | private Integer privateField = DEFAULT; 11 | private final Integer finalField = DEFAULT; 12 | 13 | public FloatingActionButton(Context context) { 14 | super(context); 15 | } 16 | 17 | public FloatingActionButton(Context context, AttributeSet attrs) { 18 | super(context, attrs); 19 | } 20 | 21 | public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) { 22 | super(context, attrs, defStyleAttr); 23 | } 24 | 25 | public void setBackgroundTintList(ColorStateList colorStateList) { 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/BuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.res.ColorStateList; 5 | import android.graphics.Color; 6 | import android.os.Build; 7 | import android.support.design.widget.FloatingActionButton; 8 | import android.view.View; 9 | import android.view.Window; 10 | import android.widget.TextView; 11 | 12 | import com.stylingandroid.prism.setter.StatusBarSetterAccessor; 13 | 14 | import org.junit.Assert; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.junit.runner.RunWith; 18 | import org.mockito.Mock; 19 | import org.mockito.MockitoAnnotations; 20 | import org.powermock.core.classloader.annotations.PrepareForTest; 21 | import org.powermock.modules.junit4.PowerMockRunner; 22 | 23 | import static org.mockito.Matchers.any; 24 | import static org.mockito.Matchers.anyInt; 25 | import static org.mockito.Mockito.*; 26 | import static org.mockito.Mockito.when; 27 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 28 | 29 | @RunWith(PowerMockRunner.class) 30 | @PrepareForTest({Color.class, ColorStateList.class}) 31 | public class BuilderTest { 32 | @Mock 33 | private Trigger trigger; 34 | 35 | @Mock 36 | private View view; 37 | 38 | @Mock 39 | private TextView textView; 40 | 41 | @Mock 42 | private FloatingActionButton floatingActionButton; 43 | 44 | @Mock 45 | private Window window; 46 | 47 | @Mock 48 | private ColorStateList colorStateList; 49 | 50 | @Before 51 | public void setUp() throws Exception { 52 | MockitoAnnotations.initMocks(this); 53 | MockUtils.mockColor(); 54 | mockStatic(ColorStateList.class); 55 | when(ColorStateList.valueOf(anyInt())).thenReturn(colorStateList); 56 | when(colorStateList.withAlpha(anyInt())).thenReturn(colorStateList); 57 | } 58 | 59 | @Test 60 | public void givenNoTriggerThenPrismCreationDoesNotNPE() { 61 | try { 62 | Prism.Builder.newInstance().build(); 63 | } catch (Exception e) { 64 | Assert.fail(); 65 | } 66 | } 67 | 68 | @Test 69 | public void givenANonNullTriggerThenPrismCreationSetsTheTriggerCorrectly() { 70 | Prism.Builder.newInstance().add(trigger).build(); 71 | verify(trigger, atLeastOnce()).addSetter(any(Setter.class)); 72 | } 73 | 74 | @Test 75 | public void givenAVanillaViewThenBackgroundSetsTheBackgroundColour() { 76 | Setter setter = Prism.Builder.newInstance().add(trigger).background(view).build(); 77 | setter.setColour(ColourUtils.TEST_COLOUR); 78 | verify(view, atLeastOnce()).setBackgroundColor(ColourUtils.TEST_COLOUR); 79 | } 80 | 81 | @Test 82 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 83 | public void givenAWindowOnLollipopThenSetColourSetsTheStatusBarColour() { 84 | StatusBarSetterAccessor setter = StatusBarSetterAccessor.newInstance(window, Build.VERSION_CODES.LOLLIPOP); 85 | Setter colourSetter = Prism.Builder.newInstance().add(trigger).add(setter).build(); 86 | colourSetter.setColour(ColourUtils.TEST_COLOUR); 87 | verify(window, atLeastOnce()).setStatusBarColor(ColourUtils.TEST_COLOUR); 88 | } 89 | 90 | @Test 91 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 92 | public void givenAWindowOnPreLollipopThenSetColourDoesNotSetTheStatusBarColour() { 93 | Setter setter = Prism.Builder.newInstance().add(trigger).background(window).build(); 94 | setter.setColour(ColourUtils.TEST_COLOUR); 95 | verify(window, never()).setStatusBarColor(ColourUtils.TEST_COLOUR); 96 | } 97 | 98 | @Test 99 | public void givenATextViewThenSetColourSetsTheTextColour() { 100 | Setter setter = Prism.Builder.newInstance().add(trigger).text(textView).build(); 101 | setter.setColour(ColourUtils.TEST_COLOUR); 102 | verify(textView, atLeastOnce()).setTextColor(ColourUtils.TEST_COLOUR); 103 | } 104 | 105 | @Test 106 | public void givenAFABThenSetColourSetsTheTintColour() { 107 | Setter setter = Prism.Builder.newInstance().add(trigger).colour(floatingActionButton).build(); 108 | setter.setColour(ColourUtils.TEST_COLOUR); 109 | verify(floatingActionButton, atLeastOnce()).setBackgroundTintList(any(ColorStateList.class)); 110 | } 111 | 112 | @Test 113 | public void givenANullViewThenCreatingABuilderDoesNotThrowAnNpe() { 114 | try { 115 | Prism.Builder.newInstance().background((View) null).build(); 116 | } catch (Exception e) { 117 | Assert.fail(); 118 | } 119 | } 120 | 121 | @Test 122 | public void givenANullSetterThenCreatingABuilderDoesNotThrowAnNpe() { 123 | try { 124 | Prism.Builder.newInstance().add((Setter) null).build(); 125 | } catch (Exception e) { 126 | Assert.fail(); 127 | } 128 | } 129 | 130 | @Test 131 | public void givenANullTriggerThenCreatingABuilderDoesNotThrowAnNpe() { 132 | try { 133 | Prism.Builder.newInstance().add((Trigger) null).build(); 134 | } catch (Exception e) { 135 | Assert.fail(); 136 | } 137 | } 138 | 139 | @Test 140 | public void givenANullFilterThenCreatingABuilderDoesNotThrowAnNpe() { 141 | try { 142 | Prism.Builder.newInstance().background(view, null).build(); 143 | } catch (Exception e) { 144 | Assert.fail(); 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/MockUtils.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import android.graphics.Color; 4 | 5 | import org.mockito.invocation.InvocationOnMock; 6 | import org.mockito.stubbing.Answer; 7 | 8 | import static org.mockito.Matchers.anyInt; 9 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 10 | import static org.powermock.api.mockito.PowerMockito.when; 11 | 12 | public final class MockUtils { 13 | public static void mockColor() { 14 | mockStatic(Color.class); 15 | when(Color.argb(anyInt(), anyInt(), anyInt(), anyInt())).thenAnswer( 16 | new Answer() { 17 | @Override 18 | public Integer answer(InvocationOnMock invocation) throws Throwable { 19 | Object[] args = invocation.getArguments(); 20 | return ColourUtils.argb((int) args[0], (int) args[1], (int) args[2], (int) args[3]); 21 | } 22 | }); 23 | when(Color.rgb(anyInt(), anyInt(), anyInt())).thenAnswer( 24 | new Answer() { 25 | @Override 26 | public Integer answer(InvocationOnMock invocation) throws Throwable { 27 | Object[] args = invocation.getArguments(); 28 | return ColourUtils.rgb((int) args[0], (int) args[1], (int) args[2]); 29 | } 30 | }); 31 | when(Color.alpha(anyInt())).thenAnswer( 32 | new Answer() { 33 | @Override 34 | public Integer answer(InvocationOnMock invocation) throws Throwable { 35 | Object[] args = invocation.getArguments(); 36 | return (int) args[0] >>> ColourUtils.TWENTY_FOUR_BITS; 37 | } 38 | }); 39 | when(Color.red(anyInt())).thenAnswer( 40 | new Answer() { 41 | @Override 42 | public Integer answer(InvocationOnMock invocation) throws Throwable { 43 | Object[] args = invocation.getArguments(); 44 | return ((int)args[0] >> ColourUtils.SIXTEEN_BITS) & 0xFF; 45 | } 46 | }); 47 | when(Color.green(anyInt())).thenAnswer( 48 | new Answer() { 49 | @Override 50 | public Integer answer(InvocationOnMock invocation) throws Throwable { 51 | Object[] args = invocation.getArguments(); 52 | return ((int) args[0] >> ColourUtils.EIGHT_BITS) & 0xFF; 53 | } 54 | }); 55 | when(Color.blue(anyInt())).thenAnswer( 56 | new Answer() { 57 | @Override 58 | public Integer answer(InvocationOnMock invocation) throws Throwable { 59 | Object[] args = invocation.getArguments(); 60 | return (int) args[0] & 0xFF; 61 | } 62 | }); 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/SetterAdapterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.mockito.Mock; 6 | import org.mockito.MockitoAnnotations; 7 | 8 | import static org.mockito.Matchers.anyInt; 9 | import static org.mockito.Mockito.atLeastOnce; 10 | import static org.mockito.Mockito.verify; 11 | 12 | public class SetterAdapterTest { 13 | @Mock 14 | private ColorSetter colorSetter; 15 | 16 | private Setter setter; 17 | 18 | @Before 19 | public void setUp() throws Exception { 20 | MockitoAnnotations.initMocks(this); 21 | setter = new SetterAdapter(colorSetter); 22 | } 23 | 24 | @Test 25 | public void givenAColourSetterWrappedInASetterAdapterThenSetColorIsCalled() { 26 | setter.setColour(1); 27 | verify(colorSetter, atLeastOnce()).setColor(anyInt()); 28 | } 29 | 30 | @Test 31 | public void givenAColourSetterWrappedInASetterAdapterThenTransientSetColorIsCalled() { 32 | setter.setTransientColour(1); 33 | verify(colorSetter, atLeastOnce()).setTransientColor(anyInt()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/filter/IdentityFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import com.stylingandroid.prism.ColourUtils; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collection; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.junit.runners.Parameterized; 12 | 13 | import static org.fest.assertions.api.Assertions.assertThat; 14 | 15 | @RunWith(Parameterized.class) 16 | public class IdentityFilterTest { 17 | private final int colour; 18 | private IdentityFilter identityFilter; 19 | 20 | public IdentityFilterTest(int colour) { 21 | this.colour = colour; 22 | } 23 | 24 | @Before 25 | public void setup() { 26 | identityFilter = new IdentityFilter(); 27 | } 28 | 29 | @Test 30 | public void givenVariousInputsTheOutputAlwaysMatchesTheInput() { 31 | int output = identityFilter.filter(colour); 32 | assertThat(output).isEqualTo(colour); 33 | } 34 | 35 | @Parameterized.Parameters 36 | public static Collection sampleColours() { 37 | return Arrays.asList( 38 | ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_000, ColourUtils.HEX_000), 39 | ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_000, ColourUtils.HEX_000), 40 | ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_255, ColourUtils.HEX_000), 41 | ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_000, ColourUtils.HEX_255), 42 | ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_255, ColourUtils.HEX_000), 43 | ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_000, ColourUtils.HEX_255), 44 | ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_255, ColourUtils.HEX_255), 45 | ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_255, ColourUtils.HEX_255)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/filter/RepeatableFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.mockito.Mock; 6 | import org.mockito.MockitoAnnotations; 7 | 8 | import static org.mockito.Matchers.anyInt; 9 | import static org.mockito.Mockito.times; 10 | import static org.mockito.Mockito.verify; 11 | import static org.mockito.Mockito.when; 12 | 13 | public class RepeatableFilterTest { 14 | @Mock 15 | private RepeatableFilter repeatableColourFilter; 16 | 17 | @Before 18 | public void setup() { 19 | MockitoAnnotations.initMocks(this); 20 | when(repeatableColourFilter.onFilter(anyInt())).thenReturn(0); 21 | } 22 | 23 | @Test 24 | public void givenSpecificColourValueCalculationIsOnlyPerformedOnce() throws Exception { 25 | repeatableColourFilter.filter(1); 26 | repeatableColourFilter.filter(1); 27 | repeatableColourFilter.filter(1); 28 | repeatableColourFilter.filter(1); 29 | repeatableColourFilter.filter(1); 30 | repeatableColourFilter.filter(1); 31 | verify(repeatableColourFilter, times(1)).onFilter(1); 32 | } 33 | 34 | @Test 35 | public void givenDifferentColourValuesCalculationIsPerformedEachTime() throws Exception { 36 | for (int i = 1; i < 6; i++) { 37 | repeatableColourFilter.filter(i); 38 | } 39 | verify(repeatableColourFilter, times(5)).onFilter(anyInt()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/filter/ShadeFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import android.graphics.Color; 4 | 5 | import com.stylingandroid.prism.ColourUtils; 6 | import com.stylingandroid.prism.MockUtils; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.powermock.core.classloader.annotations.PrepareForTest; 12 | import org.powermock.modules.junit4.PowerMockRunner; 13 | 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | 16 | @RunWith(PowerMockRunner.class) 17 | @PrepareForTest(Color.class) 18 | public class ShadeFilterTest { 19 | private static final float ONE_HUNDRED_PERCENT = 1f; 20 | private static final float ZERO_PERCENT = 0f; 21 | private static final int HEX_102 = 0x66; 22 | 23 | @Before 24 | public void setup() { 25 | MockUtils.mockColor(); 26 | } 27 | 28 | @Test 29 | public void givenASpecificColourForAZeroPercentTintThenTheCorrectOutputColourIsProduced() throws Exception { 30 | int inputColour = ColourUtils.rgb(ColourUtils.HEX_128, ColourUtils.HEX_128, ColourUtils.HEX_128); 31 | ShadeFilter shadeFilter = new ShadeFilter(ZERO_PERCENT); 32 | int outputColour = shadeFilter.filter(inputColour); 33 | assertThat(outputColour).isEqualTo(inputColour); 34 | } 35 | 36 | @Test 37 | public void givenASpecificColourForAOneHundredPercentTintThenTheCorrectOutputColourIsProduced() throws Exception { 38 | int inputColour = ColourUtils.rgb(ColourUtils.HEX_128, ColourUtils.HEX_128, ColourUtils.HEX_128); 39 | int expectedColour = ColourUtils.rgb(ColourUtils.HEX_000, ColourUtils.HEX_000, ColourUtils.HEX_000); 40 | ShadeFilter shadeFilter = new ShadeFilter(ONE_HUNDRED_PERCENT); 41 | int outputColour = shadeFilter.filter(inputColour); 42 | assertThat(outputColour).isEqualTo(expectedColour); 43 | } 44 | 45 | @Test 46 | public void givenASpecificColourForADefaultTintThenTheCorrectOutputColourIsProduced() throws Exception { 47 | int inputColour = ColourUtils.rgb(ColourUtils.HEX_128, ColourUtils.HEX_128, ColourUtils.HEX_128); 48 | int expected = ColourUtils.rgb(HEX_102, HEX_102, HEX_102); 49 | ShadeFilter shadeFilter = new ShadeFilter(); 50 | int outputColour = shadeFilter.filter(inputColour); 51 | assertThat(outputColour).isEqualTo(expected); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/filter/SystemChromeFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import android.graphics.Color; 4 | 5 | import com.stylingandroid.prism.ColourUtils; 6 | import com.stylingandroid.prism.MockUtils; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.powermock.core.classloader.annotations.PrepareForTest; 12 | import org.powermock.modules.junit4.PowerMockRunner; 13 | 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | 16 | @RunWith(PowerMockRunner.class) 17 | @PrepareForTest(Color.class) 18 | public class SystemChromeFilterTest { 19 | private static final int HEX_102 = 0x66; 20 | 21 | @Before 22 | public void setup() { 23 | MockUtils.mockColor(); 24 | } 25 | 26 | @Test 27 | public void givenASpecifiedColourThenCorrectColourIsProduced() { 28 | int inputColour = ColourUtils.rgb(ColourUtils.HEX_128, ColourUtils.HEX_128, ColourUtils.HEX_128); 29 | int expected = ColourUtils.rgb(HEX_102, HEX_102, HEX_102); 30 | SystemChromeFilter systemChromeFilter = new SystemChromeFilter(); 31 | int outputColour = systemChromeFilter.filter(inputColour); 32 | assertThat(outputColour).isEqualTo(expected); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/filter/TintFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.filter; 2 | 3 | import android.graphics.Color; 4 | 5 | import com.stylingandroid.prism.ColourUtils; 6 | import com.stylingandroid.prism.MockUtils; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.powermock.core.classloader.annotations.PrepareForTest; 12 | import org.powermock.modules.junit4.PowerMockRunner; 13 | 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | 16 | @RunWith(PowerMockRunner.class) 17 | @PrepareForTest(Color.class) 18 | public class TintFilterTest { 19 | private static final float ONE_HUNDRED_PERCENT = 1f; 20 | private static final float ZERO_PERCENT = 0f; 21 | private static final int HEX_153 = 0x99; 22 | 23 | @Before 24 | public void setup() { 25 | MockUtils.mockColor(); 26 | } 27 | 28 | @Test 29 | public void givenASpecificColourForAOneHundredPercentTintThenTheCorrectOutputColourIsProduced() throws Exception { 30 | int inputColour = ColourUtils.rgb(ColourUtils.HEX_128, ColourUtils.HEX_128, ColourUtils.HEX_128); 31 | int expectedColour = ColourUtils.rgb(ColourUtils.HEX_255, ColourUtils.HEX_255, ColourUtils.HEX_255); 32 | TintFilter tintFilter = new TintFilter(ONE_HUNDRED_PERCENT); 33 | int outputColour = tintFilter.filter(inputColour); 34 | assertThat(outputColour).isEqualTo(expectedColour); 35 | } 36 | 37 | @Test 38 | public void givenASpecificColourForAZeroPercentTintThenTheCorrectOutputColourIsProduced() throws Exception { 39 | int inputColour = ColourUtils.rgb(ColourUtils.HEX_128, ColourUtils.HEX_128, ColourUtils.HEX_128); 40 | TintFilter tintFilter = new TintFilter(ZERO_PERCENT); 41 | int outputColour = tintFilter.filter(inputColour); 42 | assertThat(outputColour).isEqualTo(inputColour); 43 | } 44 | 45 | @Test 46 | public void givenASpecificColourForADefaultTintThenTheCorrectOutputColourIsProduced() throws Exception { 47 | int inputColour = ColourUtils.rgb(ColourUtils.HEX_128, ColourUtils.HEX_128, ColourUtils.HEX_128); 48 | int expected = ColourUtils.rgb(HEX_153, HEX_153, HEX_153); 49 | TintFilter tintFilter = new TintFilter(); 50 | int outputColour = tintFilter.filter(inputColour); 51 | assertThat(outputColour).isEqualTo(expected); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/BaseSetterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | import com.stylingandroid.prism.ColourUtils; 6 | import com.stylingandroid.prism.filter.Filter; 7 | import com.stylingandroid.prism.filter.IdentityFilter; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import static org.fest.assertions.api.Assertions.assertThat; 13 | 14 | public class BaseSetterTest { 15 | private IdentityFilter identityFilter; 16 | 17 | @Before 18 | public void setup() { 19 | identityFilter = new IdentityFilter(); 20 | } 21 | 22 | @Test 23 | public void givenATransientColourSetterTransientEventsAreHandled() { 24 | TransientSetter colourSetter = new TransientSetter(identityFilter); 25 | colourSetter.setTransientColour(ColourUtils.TEST_COLOUR); 26 | assertThat(colourSetter.onSetColourCalled).isTrue(); 27 | } 28 | 29 | @Test 30 | public void givenATransientColourSetterNonTransientEventsAreHandled() { 31 | TransientSetter colourSetter = new TransientSetter(identityFilter); 32 | colourSetter.setColour(ColourUtils.TEST_COLOUR); 33 | assertThat(colourSetter.onSetColourCalled).isTrue(); 34 | } 35 | 36 | @Test 37 | public void givenANonTransientColourSetterTransientEventsAreNotHandled() { 38 | NonTransientSetter colourSetter = new NonTransientSetter(identityFilter); 39 | colourSetter.setTransientColour(ColourUtils.TEST_COLOUR); 40 | assertThat(colourSetter.onSetColourCalled).isFalse(); 41 | } 42 | 43 | @Test 44 | public void givenANonTransientColourSetterNonTransientEventsAreHandled() { 45 | NonTransientSetter colourSetter = new NonTransientSetter(identityFilter); 46 | colourSetter.setColour(ColourUtils.TEST_COLOUR); 47 | assertThat(colourSetter.onSetColourCalled).isTrue(); 48 | } 49 | 50 | private class TransientSetter extends BaseSetter { 51 | private boolean onSetColourCalled = false; 52 | 53 | protected TransientSetter(Filter filter) { 54 | super(filter, true); 55 | } 56 | 57 | @Override 58 | public void onSetColour(@ColorInt int colour) { 59 | onSetColourCalled = true; 60 | } 61 | } 62 | 63 | private class NonTransientSetter extends BaseSetter { 64 | private boolean onSetColourCalled = false; 65 | 66 | protected NonTransientSetter(Filter filter) { 67 | super(filter, false); 68 | } 69 | 70 | @Override 71 | public void onSetColour(@ColorInt int colour) { 72 | onSetColourCalled = true; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/FabSetterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.content.res.ColorStateList; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.view.View; 6 | 7 | import com.stylingandroid.prism.ColourUtils; 8 | import com.stylingandroid.prism.filter.IdentityFilter; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.mockito.Mock; 14 | import org.mockito.MockitoAnnotations; 15 | import org.powermock.core.classloader.annotations.PrepareForTest; 16 | import org.powermock.modules.junit4.PowerMockRunner; 17 | 18 | import static org.fest.assertions.api.Assertions.assertThat; 19 | import static org.mockito.Matchers.any; 20 | import static org.mockito.Matchers.anyInt; 21 | import static org.mockito.Mockito.*; 22 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 23 | 24 | @RunWith(PowerMockRunner.class) 25 | @PrepareForTest(ColorStateList.class) 26 | public class FabSetterTest { 27 | @Mock 28 | private FloatingActionButton floatingActionButton; 29 | @Mock 30 | private View vanillaView; 31 | @Mock 32 | private ColorStateList colorStateList; 33 | 34 | @Before 35 | public void setUp() throws Exception { 36 | MockitoAnnotations.initMocks(this); 37 | mockStatic(ColorStateList.class); 38 | when(ColorStateList.valueOf(anyInt())).thenReturn(colorStateList); 39 | when(colorStateList.withAlpha(anyInt())).thenReturn(colorStateList); 40 | } 41 | 42 | @Test 43 | public void givenAFabThenIsFabReturnsTrue() { 44 | assertThat(FabSetter.isFab(floatingActionButton)).isTrue(); 45 | } 46 | 47 | @Test 48 | public void givenAVanillaViewThenIsFabReturnsTrue() { 49 | assertThat(FabSetter.isFab(vanillaView)).isFalse(); 50 | } 51 | 52 | @Test 53 | public void givenAFabThenTheSetterMethodIsCalledCorrectly() { 54 | FabSetter fabColourSetter = new FabSetter(floatingActionButton, new IdentityFilter()); 55 | fabColourSetter.setColour(ColourUtils.TEST_COLOUR); 56 | verify(floatingActionButton, times(1)).setBackgroundTintList(any(ColorStateList.class)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/FieldAccessorTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.content.Context; 4 | import android.support.design.widget.FloatingActionButton; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.mockito.Mock; 9 | import org.mockito.MockitoAnnotations; 10 | 11 | import static org.fest.assertions.api.Assertions.assertThat; 12 | 13 | public class FieldAccessorTest { 14 | private static final int VALUE = 654; 15 | 16 | @Mock 17 | private Context context; 18 | 19 | private FloatingActionButton floatingActionButton; 20 | 21 | @Before 22 | public void setUp() throws Exception { 23 | MockitoAnnotations.initMocks(this); 24 | floatingActionButton = new FloatingActionButton(context); 25 | } 26 | 27 | @Test 28 | public void givenAnObjectThenFileAccessorReturnsCorrectValue() { 29 | FieldAccessor fieldAccessor = new FieldAccessor<>(floatingActionButton, "privateField", Integer.class); 30 | int value = fieldAccessor.get(); 31 | assertThat(value).isEqualTo(FloatingActionButton.DEFAULT); 32 | } 33 | 34 | @Test 35 | public void givenAnObjectThenFileAccessorCorrectSetsTheValue() { 36 | FieldAccessor fieldAccessor = new FieldAccessor<>(floatingActionButton, "privateField", Integer.class); 37 | fieldAccessor.set(VALUE); 38 | int value = fieldAccessor.get(); 39 | assertThat(value).isEqualTo(VALUE); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/SetterFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.content.Context; 4 | import android.support.design.widget.FloatingActionButton; 5 | import android.view.View; 6 | import android.view.Window; 7 | import android.widget.TextView; 8 | 9 | import com.stylingandroid.prism.Setter; 10 | import com.stylingandroid.prism.filter.Filter; 11 | import com.stylingandroid.prism.filter.IdentityFilter; 12 | 13 | import org.junit.After; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.mockito.Mock; 17 | import org.mockito.MockitoAnnotations; 18 | 19 | import static org.fest.assertions.api.Assertions.assertThat; 20 | import static org.mockito.Matchers.any; 21 | import static org.mockito.Matchers.isA; 22 | import static org.mockito.Mockito.when; 23 | 24 | public class SetterFactoryTest { 25 | @Mock 26 | private SetterFactory setterFactory; 27 | 28 | @Mock 29 | private Setter setter; 30 | 31 | @Mock 32 | private Setter windowSetter; 33 | 34 | @Mock 35 | private CustomView customView; 36 | 37 | @Mock 38 | private FloatingActionButton floatingActionButton; 39 | 40 | @Mock 41 | private TextView textView; 42 | 43 | @Mock 44 | private View vanillaView; 45 | 46 | @Mock 47 | private Window window; 48 | 49 | private Filter identity; 50 | 51 | @Before 52 | public void setUp() throws Exception { 53 | MockitoAnnotations.initMocks(this); 54 | when(setterFactory.getColourSetter(isA(CustomView.class), any(Filter.class))).thenReturn(setter); 55 | ColourSetterFactory.registerFactory(setterFactory); 56 | identity = new IdentityFilter(); 57 | } 58 | 59 | @After 60 | public void teardown() { 61 | ColourSetterFactory.unregisterFactory(setterFactory); 62 | } 63 | 64 | @Test 65 | public void givenAStandardViewWhenRequestingABackgroundSetterThenAViewBackgroundColourSetterIsReturned() { 66 | Setter setter = ColourSetterFactory.getBackgroundSetter(vanillaView, identity); 67 | assertThat(setter).isInstanceOf(ViewBackgroundSetter.class); 68 | } 69 | 70 | @Test 71 | public void givenAStandardViewWhenRequestingAColourSetterThenAViewBackgroundColourSetterIsReturned() { 72 | Setter setter = ColourSetterFactory.getColourSetter(vanillaView, identity); 73 | assertThat(setter).isInstanceOf(ViewBackgroundSetter.class); 74 | } 75 | 76 | @Test 77 | public void givenATextViewWhenRequestingABackgroundSetterThenAViewBackgroundColourSetterIsReturned() { 78 | Setter setter = ColourSetterFactory.getBackgroundSetter(textView, identity); 79 | assertThat(setter).isInstanceOf(ViewBackgroundSetter.class); 80 | } 81 | 82 | @Test 83 | public void givenATextViewWhenRequestingAColourSetterThenABackgroundColourSetterIsReturned() { 84 | Setter setter = ColourSetterFactory.getColourSetter(textView, identity); 85 | assertThat(setter).isInstanceOf(ViewBackgroundSetter.class); 86 | } 87 | 88 | @Test 89 | public void givenATextViewWhenRequestingATextSetterThenATextColourSetterIsReturned() { 90 | Setter setter = ColourSetterFactory.getTextSetter(textView, identity); 91 | assertThat(setter).isInstanceOf(TextSetter.class); 92 | } 93 | 94 | @Test 95 | public void givenAFabViewWhenRequestingAColourSetterThenAFabColourSetterIsReturned() { 96 | Setter setter = ColourSetterFactory.getColourSetter(floatingActionButton, identity); 97 | assertThat(setter).isInstanceOf(FabSetter.class); 98 | } 99 | 100 | @Test 101 | public void givenACustomViewWhenRequestingAColourSetterThenACustomColourSetterIsReturned() { 102 | Setter setter = ColourSetterFactory.getColourSetter(customView, identity); 103 | assertThat(setter).isEqualTo(this.setter); 104 | } 105 | 106 | @Test 107 | public void givenAWindowRequestingABackgroundSetterThenAStatusBarSetterSetterIsReturned() { 108 | Setter setter = ColourSetterFactory.getBackgroundSetter(window, identity); 109 | assertThat(setter).isInstanceOf(SystemChromeSetter.class); 110 | } 111 | 112 | private class CustomView extends View { 113 | public CustomView(Context context) { 114 | super(context); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/StatusBarSetterAccessor.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.support.annotation.ColorInt; 4 | import android.view.Window; 5 | 6 | import com.stylingandroid.prism.filter.Filter; 7 | import com.stylingandroid.prism.filter.IdentityFilter; 8 | 9 | public class StatusBarSetterAccessor extends BaseSetter { 10 | private final SystemChromeSetter systemChromeSetter; 11 | 12 | public static StatusBarSetterAccessor newInstance(Window window, int osVersion) { 13 | IdentityFilter identityFilter = new IdentityFilter(); 14 | SystemChromeSetter setter = new SystemChromeSetter(window, identityFilter, osVersion); 15 | return new StatusBarSetterAccessor(setter, identityFilter); 16 | } 17 | 18 | private StatusBarSetterAccessor(SystemChromeSetter systemChromeSetter, Filter filter) { 19 | super(filter); 20 | this.systemChromeSetter = systemChromeSetter; 21 | } 22 | 23 | @Override 24 | public void onSetColour(@ColorInt int colour) { 25 | systemChromeSetter.setColour(colour); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/SystemChromeSetterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.view.Window; 6 | 7 | import com.stylingandroid.prism.Setter; 8 | import com.stylingandroid.prism.ColourUtils; 9 | import com.stylingandroid.prism.filter.IdentityFilter; 10 | 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.mockito.Mock; 14 | import org.mockito.MockitoAnnotations; 15 | 16 | import static org.mockito.Matchers.anyInt; 17 | import static org.mockito.Mockito.atLeast; 18 | import static org.mockito.Mockito.never; 19 | import static org.mockito.Mockito.verify; 20 | 21 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 22 | public class SystemChromeSetterTest { 23 | @Mock 24 | private Window window; 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | MockitoAnnotations.initMocks(this); 29 | } 30 | 31 | @Test 32 | public void givenAWindowOnLollipopOrLaterThenTheStatusBarSetterMethodIsCalledCorrectly() { 33 | Setter setter = new SystemChromeSetter(window, new IdentityFilter(), Build.VERSION_CODES.LOLLIPOP); 34 | setter.setColour(ColourUtils.TEST_COLOUR); 35 | verify(window, atLeast(1)).setStatusBarColor(anyInt()); 36 | verify(window, atLeast(1)).setNavigationBarColor(anyInt()); 37 | } 38 | 39 | @Test 40 | public void givenAWindowOnLollipopOrLaterThenTheNavigationBarSetterMethodIsCalledCorrectly() { 41 | Setter setter = new SystemChromeSetter(window, new IdentityFilter(), Build.VERSION_CODES.LOLLIPOP); 42 | setter.setColour(ColourUtils.TEST_COLOUR); 43 | verify(window, atLeast(1)).setNavigationBarColor(anyInt()); 44 | } 45 | 46 | @Test 47 | public void givenAWindowPreLollipopThenTheStatusBarSetterMethodIsNotCalled() { 48 | Setter setter = new SystemChromeSetter(window, new IdentityFilter()); 49 | setter.setColour(ColourUtils.TEST_COLOUR); 50 | verify(window, never()).setStatusBarColor(anyInt()); 51 | } 52 | 53 | @Test 54 | public void givenAWindowPreLollipopThenTheNavigationBarSetterMethodIsNotCalled() { 55 | Setter setter = new SystemChromeSetter(window, new IdentityFilter()); 56 | setter.setColour(ColourUtils.TEST_COLOUR); 57 | verify(window, never()).setNavigationBarColor(anyInt()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/TextSetterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.widget.TextView; 4 | 5 | import com.stylingandroid.prism.ColourUtils; 6 | import com.stylingandroid.prism.filter.IdentityFilter; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | 13 | import static org.mockito.Matchers.anyInt; 14 | import static org.mockito.Mockito.atLeast; 15 | import static org.mockito.Mockito.verify; 16 | 17 | public class TextSetterTest { 18 | @Mock 19 | private TextView textView; 20 | 21 | private TextSetter textColourSetter; 22 | 23 | @Before 24 | public void setUp() throws Exception { 25 | MockitoAnnotations.initMocks(this); 26 | textColourSetter = new TextSetter(textView, new IdentityFilter()); 27 | } 28 | 29 | @Test 30 | public void givenAViewThenSetBackgroundColorIsCalled() { 31 | textColourSetter.setColour(ColourUtils.TEST_COLOUR); 32 | verify(textView, atLeast(1)).setTextColor(anyInt()); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /prism/src/test/java/com/stylingandroid/prism/setter/ViewBackgroundSetterTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.setter; 2 | 3 | import android.view.View; 4 | 5 | import com.stylingandroid.prism.ColourUtils; 6 | import com.stylingandroid.prism.filter.IdentityFilter; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | 13 | import static org.mockito.Matchers.anyInt; 14 | import static org.mockito.Mockito.atLeast; 15 | import static org.mockito.Mockito.verify; 16 | 17 | public class ViewBackgroundSetterTest { 18 | @Mock 19 | private View view; 20 | 21 | private ViewBackgroundSetter backgroundColourSetter; 22 | 23 | @Before 24 | public void setUp() throws Exception { 25 | MockitoAnnotations.initMocks(this); 26 | backgroundColourSetter = new ViewBackgroundSetter(view, new IdentityFilter()); 27 | } 28 | 29 | @Test 30 | public void givenAViewThenSetBackgroundColorIsCalled() { 31 | backgroundColourSetter.setColour(ColourUtils.TEST_COLOUR); 32 | verify(view, atLeast(1)).setBackgroundColor(anyInt()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sample-palette/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample-palette/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | applicationId "com.stylingandroid.prism.sample.palette" 9 | minSdkVersion 7 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.android.support:appcompat-v7:22.2.0' 24 | compile 'com.android.support:design:22.2.0' 25 | compile 'com.android.support:support-v4:22.2.0' 26 | compile project(':prism') 27 | compile project(':prism-palette') 28 | } 29 | 30 | apply from: '../config/static_analysis.gradle' 31 | -------------------------------------------------------------------------------- /sample-palette/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/markallison/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample-palette/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /sample-palette/src/main/java/com/stylingandroid/prism/sample/palette/ImageLoadTask.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.sample.palette; 2 | 3 | import android.graphics.Bitmap; 4 | import android.net.Uri; 5 | import android.os.AsyncTask; 6 | import android.provider.MediaStore; 7 | 8 | import java.lang.ref.WeakReference; 9 | 10 | class ImageLoadTask extends AsyncTask { 11 | private final WeakReference activityWeakReference; 12 | 13 | public static ImageLoadTask newInstance(MainActivity activity) { 14 | WeakReference activityWeakReference = new WeakReference(activity); 15 | return new ImageLoadTask(activityWeakReference); 16 | } 17 | 18 | ImageLoadTask(WeakReference activityWeakReference) { 19 | this.activityWeakReference = activityWeakReference; 20 | } 21 | 22 | @Override 23 | protected Bitmap doInBackground(Uri... uris) { 24 | MainActivity activity = activityWeakReference.get(); 25 | Bitmap bitmap = null; 26 | if (activity != null && uris.length > 0) { 27 | try { 28 | bitmap = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), uris[0]); 29 | } catch (Exception e) { 30 | return null; 31 | } 32 | } 33 | return bitmap; 34 | } 35 | 36 | @Override 37 | protected void onPostExecute(Bitmap bitmap) { 38 | super.onPostExecute(bitmap); 39 | MainActivity activity = activityWeakReference.get(); 40 | if (activity != null) { 41 | if (bitmap != null) { 42 | activity.setBitmap(bitmap); 43 | } else { 44 | activity.showError(R.string.load_error); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /sample-palette/src/main/java/com/stylingandroid/prism/sample/palette/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.sample.palette; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Bitmap; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.support.annotation.ColorInt; 8 | import android.support.design.widget.FloatingActionButton; 9 | import android.support.design.widget.Snackbar; 10 | import android.support.v7.app.ActionBar; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.support.v7.widget.Toolbar; 13 | import android.view.View; 14 | import android.widget.ImageView; 15 | import android.widget.TextView; 16 | 17 | import com.stylingandroid.prism.Prism; 18 | import com.stylingandroid.prism.Setter; 19 | import com.stylingandroid.prism.palette.PaletteTrigger; 20 | 21 | public class MainActivity extends AppCompatActivity implements Setter { 22 | private static final int SELECT_IMAGE = 1; 23 | private static final String IMAGE_MIME_TYPE = "image/*"; 24 | 25 | private PaletteTrigger paletteTrigger; 26 | 27 | private Toolbar toolbar; 28 | private FloatingActionButton fab; 29 | private ImageView imageView; 30 | private TextView titleText; 31 | private TextView bodyText; 32 | 33 | private Bitmap bitmap = null; 34 | 35 | private Prism prism = null; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.activity_main); 41 | 42 | toolbar = (Toolbar) findViewById(R.id.toolbar); 43 | fab = (FloatingActionButton) findViewById(R.id.fab); 44 | imageView = (ImageView) findViewById(R.id.image); 45 | 46 | View vibrant = findViewById(R.id.swatch_vibrant); 47 | View vibrantLight = findViewById(R.id.swatch_vibrant_light); 48 | View vibrantDark = findViewById(R.id.swatch_vibrant_dark); 49 | View muted = findViewById(R.id.swatch_muted); 50 | View mutedLight = findViewById(R.id.swatch_muted_light); 51 | View mutedDark = findViewById(R.id.swatch_muted_dark); 52 | 53 | titleText = (TextView) findViewById(R.id.title); 54 | bodyText = (TextView) findViewById(R.id.body); 55 | 56 | paletteTrigger = new PaletteTrigger(); 57 | prism = Prism.Builder.newInstance() 58 | .add(paletteTrigger) 59 | .background(vibrant, paletteTrigger.getVibrantFilter(paletteTrigger.getColour())) 60 | .background(vibrantLight, paletteTrigger.getLightVibrantFilter(paletteTrigger.getColour())) 61 | .background(vibrantDark, paletteTrigger.getDarkVibrantFilter(paletteTrigger.getColour())) 62 | .background(muted, paletteTrigger.getMutedFilter(paletteTrigger.getColour())) 63 | .background(mutedLight, paletteTrigger.getLightMutedFilter(paletteTrigger.getColour())) 64 | .background(mutedDark, paletteTrigger.getDarkMutedFilter(paletteTrigger.getColour())) 65 | .background(titleText, paletteTrigger.getVibrantFilter(paletteTrigger.getColour())) 66 | .text(titleText, paletteTrigger.getVibrantFilter(paletteTrigger.getTitleTextColour())) 67 | .background(bodyText, paletteTrigger.getLightMutedFilter(paletteTrigger.getColour())) 68 | .text(bodyText, paletteTrigger.getLightMutedFilter(paletteTrigger.getBodyTextColour())) 69 | .add(this) 70 | .build(); 71 | 72 | setupToolbar(); 73 | setupFab(); 74 | } 75 | 76 | @Override 77 | protected void onDestroy() { 78 | if (prism != null) { 79 | prism.destroy(); 80 | } 81 | super.onDestroy(); 82 | } 83 | 84 | private void setupToolbar() { 85 | setSupportActionBar(toolbar); 86 | ActionBar actionBar = getSupportActionBar(); 87 | if (actionBar != null) { 88 | actionBar.setDisplayHomeAsUpEnabled(false); 89 | actionBar.setTitle(R.string.app_name); 90 | } 91 | } 92 | 93 | private void setupFab() { 94 | fab.setOnClickListener( 95 | new View.OnClickListener() { 96 | @Override 97 | public void onClick(View v) { 98 | selectImage(); 99 | } 100 | }); 101 | } 102 | 103 | private void selectImage() { 104 | Intent intent = new Intent(); 105 | intent.setType(IMAGE_MIME_TYPE); 106 | intent.setAction(Intent.ACTION_GET_CONTENT); 107 | startActivityForResult( 108 | Intent.createChooser( 109 | intent, 110 | getString(R.string.select_image)), SELECT_IMAGE); 111 | 112 | } 113 | 114 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 115 | if (resultCode == RESULT_OK && requestCode == SELECT_IMAGE) { 116 | Uri selectedImageUri = data.getData(); 117 | loadBitmap(selectedImageUri); 118 | } 119 | } 120 | 121 | private void loadBitmap(Uri selectedImageUri) { 122 | ImageLoadTask imageLoadTask = ImageLoadTask.newInstance(this); 123 | imageLoadTask.execute(selectedImageUri); 124 | } 125 | 126 | public void setBitmap(Bitmap newBitmap) { 127 | titleText.setVisibility(View.GONE); 128 | bodyText.setVisibility(View.GONE); 129 | imageView.setVisibility(View.GONE); 130 | bitmap = newBitmap; 131 | if (bitmap != null) { 132 | paletteTrigger.setBitmap(bitmap); 133 | } 134 | } 135 | 136 | public void showError(int errorId) { 137 | String error = getString(errorId); 138 | Snackbar.make(imageView, error, Snackbar.LENGTH_LONG).show(); 139 | } 140 | 141 | @Override 142 | public void setColour(@ColorInt int colour) { 143 | if (bitmap != null) { 144 | imageView.setImageBitmap(bitmap); 145 | titleText.setVisibility(View.VISIBLE); 146 | bodyText.setVisibility(View.VISIBLE); 147 | imageView.setVisibility(View.VISIBLE); 148 | } 149 | } 150 | 151 | @Override 152 | public void setTransientColour(@ColorInt int colour) { 153 | //NO-OP 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /sample-palette/src/main/res/drawable-hdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/drawable-hdpi/ic_image.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/drawable-mdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/drawable-mdpi/ic_image.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/drawable-xhdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/drawable-xhdpi/ic_image.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/drawable-xxhdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/drawable-xxhdpi/ic_image.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/drawable-xxxhdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/drawable-xxxhdpi/ic_image.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 24 | 25 | 26 | 32 | 33 | 38 | 39 | 44 | 45 | 50 | 51 | 52 | 58 | 59 | 64 | 65 | 70 | 71 | 76 | 77 | 78 | 79 | 89 | 90 | 101 | 102 | 103 | 114 | 115 | 116 | 117 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /sample-palette/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-palette/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-palette/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /sample-palette/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #1E9618 3 | #201E9618 4 | #4EE147 5 | 6 | -------------------------------------------------------------------------------- /sample-palette/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | 4 | -------------------------------------------------------------------------------- /sample-palette/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Prism Palette 3 | Select Image 4 | Unable to load image 5 | Title Text 6 | Body Text 7 | 8 | -------------------------------------------------------------------------------- /sample-palette/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sample-viewpager/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample-viewpager/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | applicationId "com.stylingandroid.prism.sample.viewpager" 9 | minSdkVersion 7 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.android.support:appcompat-v7:22.2.0' 24 | compile 'com.android.support:design:22.2.0' 25 | compile project(':prism') 26 | compile project(':prism-viewpager') 27 | } 28 | 29 | apply from: '../config/static_analysis.gradle' 30 | -------------------------------------------------------------------------------- /sample-viewpager/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/markallison/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/java/com/stylingandroid/prism/sample/viewpager/ColourFragment.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.sample.viewpager; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | public class ColourFragment extends Fragment { 13 | 14 | private static final String KEY_COLOUR = "KEY_COLOUR"; 15 | private static final String KEY_TEXT = "KEY_TEXT"; 16 | 17 | public static Fragment newInstance(Context context, CharSequence name, int colour) { 18 | Bundle args = new Bundle(); 19 | args.putCharSequence(KEY_TEXT, name); 20 | args.putInt(KEY_COLOUR, colour); 21 | return Fragment.instantiate(context, ColourFragment.class.getName(), args); 22 | } 23 | 24 | @Nullable 25 | @Override 26 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | CharSequence name = getArguments().getCharSequence(KEY_TEXT); 28 | int colour = getArguments().getInt(KEY_COLOUR); 29 | TextView view = (TextView) inflater.inflate(R.layout.fragment_colour, container, false); 30 | view.setTextColor(colour); 31 | view.setText(name); 32 | return view; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/java/com/stylingandroid/prism/sample/viewpager/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.sample.viewpager; 2 | 3 | import android.os.Bundle; 4 | import android.support.design.widget.AppBarLayout; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.design.widget.TabLayout; 7 | import android.support.v4.view.GravityCompat; 8 | import android.support.v4.view.ViewPager; 9 | import android.support.v4.widget.DrawerLayout; 10 | import android.support.v7.app.ActionBar; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.support.v7.widget.Toolbar; 13 | import android.view.MenuItem; 14 | import android.view.View; 15 | 16 | import com.stylingandroid.prism.Prism; 17 | import com.stylingandroid.prism.Trigger; 18 | import com.stylingandroid.prism.filter.Filter; 19 | import com.stylingandroid.prism.filter.TintFilter; 20 | import com.stylingandroid.prism.viewpager.ViewPagerTrigger; 21 | 22 | public class MainActivity extends AppCompatActivity { 23 | private static final float TINT_FACTOR_50_PERCENT = 0.5f; 24 | private DrawerLayout drawerLayout; 25 | private View navHeader; 26 | private AppBarLayout appBar; 27 | private Toolbar toolbar; 28 | private TabLayout tabLayout; 29 | private ViewPager viewPager; 30 | private FloatingActionButton fab; 31 | 32 | private Prism prism = null; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_main); 38 | 39 | drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 40 | navHeader = findViewById(R.id.nav_header); 41 | appBar = (AppBarLayout) findViewById(R.id.app_bar); 42 | toolbar = (Toolbar) findViewById(R.id.toolbar); 43 | tabLayout = (TabLayout) findViewById(R.id.tab_layout); 44 | viewPager = (ViewPager) findViewById(R.id.viewpager); 45 | fab = (FloatingActionButton) findViewById(R.id.fab); 46 | 47 | setupToolbar(); 48 | setupViewPager(); 49 | } 50 | 51 | @Override 52 | protected void onDestroy() { 53 | if (prism != null) { 54 | prism.destroy(); 55 | } 56 | super.onDestroy(); 57 | } 58 | 59 | private void setupToolbar() { 60 | setSupportActionBar(toolbar); 61 | ActionBar actionBar = getSupportActionBar(); 62 | if (actionBar != null) { 63 | actionBar.setHomeAsUpIndicator(R.drawable.ic_menu); 64 | actionBar.setDisplayHomeAsUpEnabled(true); 65 | actionBar.setTitle(R.string.app_title); 66 | } 67 | } 68 | 69 | @Override 70 | public boolean onOptionsItemSelected(MenuItem item) { 71 | switch (item.getItemId()) { 72 | case android.R.id.home: 73 | drawerLayout.openDrawer(GravityCompat.START); 74 | return true; 75 | default: 76 | return super.onOptionsItemSelected(item); 77 | } 78 | } 79 | 80 | private void setupViewPager() { 81 | RainbowPagerAdapter adapter = new RainbowPagerAdapter(this, getSupportFragmentManager()); 82 | viewPager.setAdapter(adapter); 83 | Filter tint = new TintFilter(TINT_FACTOR_50_PERCENT); 84 | Trigger trigger = ViewPagerTrigger.newInstance(viewPager, adapter); 85 | prism = Prism.Builder.newInstance() 86 | .add(trigger) 87 | .background(appBar) 88 | .background(getWindow()) 89 | .background(navHeader) 90 | .background(fab, tint) 91 | .colour(viewPager, tint) 92 | .build(); 93 | tabLayout.setupWithViewPager(viewPager); 94 | viewPager.setCurrentItem(0); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/java/com/stylingandroid/prism/sample/viewpager/RainbowPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.sample.viewpager; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentManager; 7 | import android.support.v4.app.FragmentPagerAdapter; 8 | import android.support.v4.app.FragmentTransaction; 9 | import android.view.ViewGroup; 10 | 11 | import com.stylingandroid.prism.viewpager.ColourProvider; 12 | 13 | public class RainbowPagerAdapter extends FragmentPagerAdapter implements ColourProvider { 14 | private static final Rainbow[] COLOURS = { 15 | Rainbow.Red, Rainbow.Orange, Rainbow.Yellow, Rainbow.Green, 16 | Rainbow.Blue, Rainbow.Indigo, Rainbow.Violet 17 | }; 18 | 19 | private final Context context; 20 | 21 | public RainbowPagerAdapter(Context context, FragmentManager fragmentManager) { 22 | super(fragmentManager); 23 | this.context = context; 24 | } 25 | 26 | @Override 27 | public Fragment getItem(int position) { 28 | Rainbow colour = COLOURS[position]; 29 | return ColourFragment.newInstance(context, getPageTitle(position), colour.getColour()); 30 | } 31 | 32 | @Override 33 | public void destroyItem(ViewGroup container, int position, Object object) { 34 | FragmentManager manager = ((Fragment) object).getFragmentManager(); 35 | FragmentTransaction trans = manager.beginTransaction(); 36 | trans.remove((Fragment) object); 37 | trans.commit(); 38 | super.destroyItem(container, position, object); 39 | } 40 | 41 | @Override 42 | public int getCount() { 43 | return COLOURS.length; 44 | } 45 | 46 | @Override 47 | public CharSequence getPageTitle(int position) { 48 | return COLOURS[position].name(); 49 | } 50 | 51 | @Override 52 | public int getColour(int position) { 53 | return COLOURS[position].getColour(); 54 | } 55 | 56 | private enum Rainbow { 57 | Red(Color.rgb(0xFF, 0x00, 0x00)), 58 | Orange(Color.rgb(0xFF, 0x7F, 0x00)), 59 | Yellow(Color.rgb(0xCF, 0xCF, 0x00)), 60 | Green(Color.rgb(0x00, 0xAF, 0x00)), 61 | Blue(Color.rgb(0x00, 0x00, 0xFF)), 62 | Indigo(Color.rgb(0x4B, 0x00, 0x82)), 63 | Violet(Color.rgb(0x7F, 0x00, 0xFF)); 64 | 65 | private final int colour; 66 | 67 | Rainbow(int colour) { 68 | this.colour = colour; 69 | } 70 | 71 | public int getColour() { 72 | return colour; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-hdpi/ic_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-hdpi/ic_block.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-hdpi/ic_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-hdpi/ic_menu.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-mdpi/ic_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-mdpi/ic_block.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-mdpi/ic_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-mdpi/ic_menu.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-xhdpi/ic_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-xhdpi/ic_block.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-xhdpi/ic_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-xhdpi/ic_menu.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-xxhdpi/ic_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-xxhdpi/ic_block.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-xxhdpi/ic_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-xxhdpi/ic_menu.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-xxxhdpi/ic_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-xxxhdpi/ic_block.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/drawable-xxxhdpi/ic_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/drawable-xxxhdpi/ic_menu.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/layout/fragment_colour.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/layout/include_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 27 | 28 | 29 | 30 | 35 | 36 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/layout/nav_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample-viewpager/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #1E9618 3 | #201E9618 4 | #AFFFFFFF 5 | 6 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 50dp 3 | 4 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Prism Demo 3 | Prism Demo 4 | Styling Android 5 | 6 | -------------------------------------------------------------------------------- /sample-viewpager/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | applicationId "com.stylingandroid.prism.sample" 9 | minSdkVersion 8 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | debug { 17 | testCoverageEnabled true 18 | } 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | packagingOptions { 25 | exclude 'LICENSE.txt' 26 | } 27 | } 28 | 29 | dependencies { 30 | compile 'com.android.support:appcompat-v7:22.2.0' 31 | compile 'com.android.support:design:22.2.0' 32 | compile 'com.android.support:support-v4:22.2.0' 33 | compile project(':prism') 34 | 35 | androidTestCompile 'com.android.support.test:runner:0.3' 36 | androidTestCompile 'com.android.support.test:rules:0.3' 37 | androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2' 38 | androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2' 39 | } 40 | 41 | apply from: '../config/static_analysis.gradle' 42 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/markallison/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/androidTest/java/com/stylingandroid/prismpalette/MainActivityTest.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prismpalette; 2 | 3 | import android.graphics.Color; 4 | import android.support.annotation.ColorInt; 5 | import android.support.test.espresso.matcher.BoundedMatcher; 6 | import android.support.test.rule.ActivityTestRule; 7 | import android.support.test.runner.AndroidJUnit4; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | import com.stylingandroid.prism.sample.MainActivity; 12 | import com.stylingandroid.prism.sample.R; 13 | 14 | import org.hamcrest.Description; 15 | import org.hamcrest.Matcher; 16 | import org.junit.Rule; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | 20 | import static android.support.test.espresso.Espresso.onView; 21 | import static android.support.test.espresso.action.ViewActions.click; 22 | import static android.support.test.espresso.assertion.ViewAssertions.matches; 23 | import static android.support.test.espresso.matcher.ViewMatchers.withId; 24 | import static org.hamcrest.Matchers.not; 25 | 26 | @RunWith(AndroidJUnit4.class) 27 | public class MainActivityTest { 28 | @Rule 29 | public ActivityTestRule mainActivityActivityTestRule = new ActivityTestRule<>(MainActivity.class); 30 | 31 | @Test 32 | public void givenTheUserClicksTheFabThenTheColourOfTheTextIsNotRed() { 33 | onView(withId(R.id.fab)).perform(click()); 34 | onView(withId(R.id.text_view)).check(matches(not(withTextColour(Color.RED)))); 35 | } 36 | 37 | @Test 38 | public void givenTheUserClicksTheFabThenTheColourOfTheTextIsGreen() { 39 | onView(withId(R.id.fab)).perform(click()); 40 | onView(withId(R.id.text_view)).check(matches(withTextColour(Color.GREEN))); 41 | } 42 | 43 | @Test 44 | public void givenTheUserClicksTheFabTwiceThenTheColourOfTheTextIsNotRed() { 45 | onView(withId(R.id.fab)).perform(click()); 46 | onView(withId(R.id.fab)).perform(click()); 47 | onView(withId(R.id.text_view)).check(matches(not(withTextColour(Color.RED)))); 48 | } 49 | 50 | @Test 51 | public void givenTheUserClicksTheFabTwiceThenTheColourOfTheTextIsBlue() { 52 | onView(withId(R.id.fab)).perform(click()); 53 | onView(withId(R.id.fab)).perform(click()); 54 | onView(withId(R.id.text_view)).check(matches(withTextColour(Color.BLUE))); 55 | } 56 | 57 | @Test 58 | public void givenTheUserClicksTheFabThreeTimesThenTheColourOfTheTextIsRed() { 59 | onView(withId(R.id.fab)).perform(click()); 60 | onView(withId(R.id.fab)).perform(click()); 61 | onView(withId(R.id.fab)).perform(click()); 62 | onView(withId(R.id.text_view)).check(matches(withTextColour(Color.RED))); 63 | } 64 | 65 | @Test 66 | public void givenADefaultLayoutThenTheColourOfTheTextIsRed() { 67 | onView(withId(R.id.text_view)).check(matches(withTextColour(Color.RED))); 68 | } 69 | 70 | private static Matcher withTextColour(@ColorInt final int colour) { 71 | return new BoundedMatcher(TextView.class) { 72 | @Override 73 | protected boolean matchesSafely(TextView view) { 74 | return colour == view.getCurrentTextColor(); 75 | } 76 | 77 | @Override 78 | public void describeTo(Description description) { 79 | description.appendText("with background colour: "); 80 | } 81 | }; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /sample/src/main/java/com/stylingandroid/prism/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism.sample; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.design.widget.AppBarLayout; 6 | import android.support.design.widget.FloatingActionButton; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.View; 10 | import android.widget.TextView; 11 | 12 | import com.stylingandroid.prism.Prism; 13 | import com.stylingandroid.prism.filter.Filter; 14 | import com.stylingandroid.prism.filter.TintFilter; 15 | 16 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 17 | private static final float TINT_FACTOR_50_PERCENT = 0.5f; 18 | private static final int RED = Color.RED; 19 | private static final int GREEN = Color.GREEN; 20 | private static final int BLUE = Color.BLUE; 21 | 22 | private Prism prism; 23 | private int currentColour = RED; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_main); 29 | 30 | TextView textView = (TextView) findViewById(R.id.text_view); 31 | AppBarLayout appBar = (AppBarLayout) findViewById(R.id.app_bar); 32 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 33 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 34 | 35 | setSupportActionBar(toolbar); 36 | 37 | Filter tint = new TintFilter(TINT_FACTOR_50_PERCENT); 38 | prism = Prism.Builder.newInstance() 39 | .background(appBar) 40 | .background(getWindow()) 41 | .text(textView) 42 | .background(fab, tint) 43 | .build(); 44 | 45 | fab.setOnClickListener(this); 46 | setColour(currentColour); 47 | } 48 | 49 | @Override 50 | protected void onDestroy() { 51 | if (prism != null) { 52 | prism.destroy(); 53 | } 54 | super.onDestroy(); 55 | } 56 | 57 | 58 | private void setColour(int colour) { 59 | if (prism != null) { 60 | prism.setColour(colour); 61 | } 62 | } 63 | 64 | @Override 65 | public void onClick(View v) { 66 | switch (currentColour) { 67 | case RED: 68 | currentColour = GREEN; 69 | break; 70 | case GREEN: 71 | currentColour = BLUE; 72 | break; 73 | case BLUE: 74 | default: 75 | currentColour = RED; 76 | break; 77 | } 78 | setColour(currentColour); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-hdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/drawable-hdpi/ic_image.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-mdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/drawable-mdpi/ic_image.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xhdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/drawable-xhdpi/ic_image.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxhdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/drawable-xxhdpi/ic_image.png -------------------------------------------------------------------------------- /sample/src/main/res/drawable-xxxhdpi/ic_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/drawable-xxxhdpi/ic_image.png -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 24 | 25 | 26 | 33 | 34 | 35 | 36 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StylingAndroid/Prism/b4ec798f5522dbc8d219886ec5b681a0defcebc7/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #1E9618 3 | #201E9618 4 | #4EE147 5 | 6 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Prism 3 | Sample Text 4 | 5 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':prism', ':prism-viewpager', ':prism-palette', ':sample', ':sample-viewpager', ':sample-palette', ':test-lib' 2 | -------------------------------------------------------------------------------- /test-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /test-lib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | } 5 | -------------------------------------------------------------------------------- /test-lib/src/main/java/com/stylingandroid/prism/ColourUtils.java: -------------------------------------------------------------------------------- 1 | package com.stylingandroid.prism; 2 | 3 | public final class ColourUtils { 4 | public static final int HEX_000 = 0x00; 5 | public static final int HEX_255 = 0xFF; 6 | public static final int HEX_128 = 0x80; 7 | public static final int EIGHT_BITS = 8; 8 | public static final int SIXTEEN_BITS = 16; 9 | public static final int TWENTY_FOUR_BITS = 24; 10 | 11 | public static final int TEST_COLOUR = rgb(HEX_255, HEX_255, HEX_255); 12 | 13 | private ColourUtils() { 14 | //NO-OP 15 | } 16 | 17 | public static int rgb(int red, int green, int blue) { 18 | return (HEX_255 << TWENTY_FOUR_BITS) | (red << SIXTEEN_BITS) | (green << EIGHT_BITS) | blue; 19 | } 20 | 21 | public static int argb(int alpha, int red, int green, int blue) { 22 | return (alpha << TWENTY_FOUR_BITS) | (red << SIXTEEN_BITS) | (green << EIGHT_BITS) | blue; 23 | } 24 | } 25 | --------------------------------------------------------------------------------